# AGENTS.md - Agentic Coding Guidelines for Indecision App ## Project Overview Modernized React 18 application upgraded from legacy Udemy course. Uses functional components with hooks, webpack 5, Babel 7, Jest 29, and TypeScript support. ## Build Commands ```bash # Development npm run build:dev # Webpack 5 development build with dev server npm run dev-server # Same as build:dev # Production npm run build:prod # Webpack 5 production build # Testing npm test # Run all tests with Jest 29 npm test -- --watch # Watch mode for tests npm test -- -t "test name" # Run single test by name # Server npm start # Run Express server (port from env.PORT or 3000) ``` **Running a Single Test:** ```bash # By test name pattern npm test -- -t "handleAddOption" # Watch + single test npm test -- --watch -t "handleAddOption" ``` --- ## Code Style Guidelines ### General Principles - Follow modern React patterns with functional components and hooks - TypeScript support added (optional migration path) - Consistent with Vercel React best practices - Avoid adding unnecessary dependencies ### File Organization ``` src/ ├── app.js # Entry point (React 18 createRoot) ├── components/ # React components (functional with hooks) │ ├── IndecisionApp.js │ ├── AddOption.js │ └── ... ├── styles/ # SCSS files │ ├── styles.scss # Main entry │ ├── base/ # Settings, base styles │ └── components/ # Component-specific styles ├── public/ # Static assets │ └── index.html # HTML template └── playground/ # Scratch files (ignore) ``` ### Imports - React imports first, then third-party, then relative - Order: React → external → components → styles ```javascript import React, { useState, useEffect } from 'react'; import AddOption from './AddOption'; import './styles/styles.scss'; ``` ### Naming Conventions - **Components**: PascalCase (`IndecisionApp.js`, `AddOption.js`) - **Files**: Match component name exactly - **Functions**: Use functional components with hooks - **Methods**: camelCase ```javascript export default function IndecisionApp() { const [options, setOptions] = useState([]); // ... } ``` ### Component Patterns - Use functional components with hooks (useState, useEffect) - Custom hooks for complex logic - Event handlers as inline arrow functions or useCallback - Conditional rendering with && or ternary operators ```javascript export default function MyComponent() { const [value, setValue] = useState(''); const handleClick = () => { // ... }; return (
{value &&

{value}

}
); } ``` ### Props and State - Access via function parameters and hooks - Use useState/useReducer for state management - Use useMemo/useCallback for performance optimization - Never mutate state directly ### CSS Class Names - Use BEM-ish naming: `widget-header`, `widget-header__title`, `button--link` - Component styles in `src/styles/components/_.scss` ### Error Handling - Use try/catch in useEffect or event handlers - Error boundaries for catching render errors (consider implementing) - Console.log for debugging (remove in production) --- ## Testing with Jest + React Testing Library ### Setup - Jest configured in `jest.config.json` - Uses @testing-library/react and @testing-library/jest-dom - JSDOM test environment ### Test File Pattern - Tests live next to components: `ComponentName.test.js` - Or in `__tests__` folder at same level ### Running Tests ```bash npm test # All tests npm test -- -t "pattern" # Tests matching name npm test -- --watch # Watch mode ``` ### Testing Library Usage ```javascript import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; // Render component render(); // Find elements screen.getByRole('button', { name: /submit/i }); screen.getByLabelText(/username/i); // Simulate events userEvent.click(screen.getByRole('button')); userEvent.type(screen.getByRole('textbox'), 'hello'); // Assertions expect(screen.getByText(/hello/i)).toBeInTheDocument(); ``` --- ## webpack Configuration - Entry: `src/app.js` - Output: `public/bundle.js` - Loaders: - babel-loader (JS/JSX) - style-loader + css-loader + sass-loader (SCSS) - style-loader + css-loader (CSS) - Plugins: HtmlWebpackPlugin - DevServer: Hot module replacement, port 8080 --- ## Dependencies (Current Stack) - React 18.2.0 / React DOM 18.2.0 - React Router 6.4.0 - webpack 5.75.0 - Babel 7.x (@babel/core, @babel/preset-env, @babel/preset-react) - Jest 29.x with React Testing Library - Sass 1.55.0 with sass-loader - Normalize.css 8.0.1 - React Modal 3.15.1 - UUID 9.0.0 - Validator 13.7.0 - Express 4.18.0 (server) - TypeScript support (tsconfig.json included) --- ## Working in This Codebase 1. **DO**: Follow modern React patterns with functional components and hooks 2. **DO**: Use useState/useEffect for state and side effects 3. **DO**: Test changes with `npm run build:dev` before committing 4. **DO**: Run `npm test` before submitting 5. **DO**: Consider migrating to TypeScript for new components 6. **DON'T**: Use class components (unless maintaining existing ones temporarily) 7. **DON'T**: Add unnecessary dependencies 8. **DON'T**: Mutate state directly 9. **DON'T**: Use index as key in lists when stable IDs are available --- ## Common Tasks ### Adding a new component 1. Create `src/components/NewComponent.js` 2. Export default functional component with hooks 3. Add corresponding SCSS in `src/styles/components/` 4. Import in parent component ### Running the app locally ```bash npm run dev-server # Then open http://localhost:8080 ``` ### Production build ```bash npm run build:prod # Outputs to public/bundle.js ``` ### Converting class components to functional 1. Replace class with function 2. Convert `this.state` to `useState()` calls 3. Convert lifecycle methods to `useEffect()` 4. Convert methods to useCallback or inline functions 5. Remove `this.` references --- **Last Updated**: 2026-03-25