Skip to content

Commit ea254fb

Browse files
committed
fix: apply code review findings (#5)
- Fix negative pie chart values in Calculator (Math.max(0, ...)) - Unify warningCopy between Planning and public-copy.ts - Add View Transitions API type augmentation - Standardize QuoteBuilder Suspense fallback - Add AGENTS.md with coding guidelines
1 parent 2ed5dc5 commit ea254fb

6 files changed

Lines changed: 184 additions & 21 deletions

File tree

AGENTS.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# AGENTS.md - EasyPIVA Coding Guidelines
2+
3+
## Build / Lint / Test Commands
4+
5+
```bash
6+
# Development
7+
bun dev # Start dev server on port 3000
8+
9+
# Build & Preview
10+
bun run build # Production build to dist/
11+
bun run preview # Preview production build
12+
13+
# Quality Checks
14+
bun run typecheck # TypeScript check (tsc --noEmit)
15+
bun run lint # ESLint check
16+
bun run test # Run all tests (vitest run)
17+
bun run test:watch # Watch mode for tests
18+
19+
# Single test file
20+
bun test src/lib/calculations/index.test.ts
21+
22+
# Single test by name
23+
bun test -- --testNamePattern="calculateForfettario"
24+
25+
# Formatting
26+
bun run format # Prettier write
27+
bun run format:check # Prettier check
28+
29+
# CI pipeline
30+
bun run ci # format:check + typecheck + lint + test + build
31+
```
32+
33+
## Tech Stack
34+
35+
- **React 19** + **TypeScript 5.8** + **Vite 6**
36+
- **Tailwind CSS v4** with `@tailwindcss/vite`
37+
- **Zustand** for state management (with persist middleware)
38+
- **React Hook Form** + **Zod** for forms and validation
39+
- **Recharts** for charts, **motion** (framer-motion) for animations
40+
- **jsPDF** + **html2canvas** for PDF export
41+
- **shadcn/ui** components (located in `/components/ui/`)
42+
43+
## Project Structure
44+
45+
```
46+
src/
47+
pages/ # Route pages (lazy loaded)
48+
components/ # React components (non-ui)
49+
lib/
50+
calculations/ # Pure business logic (well tested)
51+
quote/ # Quote builder logic
52+
fiscal-data.ts # Tax constants and ATECO categories
53+
format.ts # Currency/date formatting
54+
public-copy.ts # UI text constants
55+
store/ # Zustand stores
56+
test/setup.ts # Vitest setup
57+
components/ui/ # shadcn/ui components (Button, Input, etc.)
58+
```
59+
60+
## Code Style Guidelines
61+
62+
### Imports
63+
64+
- Use `@/` alias for src imports: `import { Button } from '@/components/ui/button'`
65+
- Use `@/components/` for shadcn UI components (resolves to `./components/`)
66+
- Group imports: React, external libs, internal (@/), types, styles
67+
- Use `type` imports: `import type { ForfettarioInput } from './types'`
68+
69+
### Formatting (Prettier)
70+
71+
- semi: true
72+
- singleQuote: true
73+
- trailingComma: 'all'
74+
- printWidth: 100
75+
- No parentheses around single arrow function params
76+
77+
### Types & Naming
78+
79+
- **Types**: PascalCase, descriptive: `ForfettarioInput`, `InpsCalculation`
80+
- **Functions**: camelCase, verb-noun: `calculateInps`, `formatCurrency`
81+
- **Components**: PascalCase, noun: `Button`, `QuoteBuilder`
82+
- **Constants**: UPPER_SNAKE_CASE for true constants: `LIMITS.ricavi`
83+
- **Files**: kebab-case for utilities, PascalCase for components
84+
- Use explicit return types for exported functions
85+
- Prefer `interface` for object shapes, `type` for unions/aliases
86+
87+
### Error Handling
88+
89+
- Guard clauses for early returns (see `calculateInps`)
90+
- Use Zod for runtime validation
91+
- Type narrowing with `typeof` checks
92+
- Optional chaining for nested access: `parsed.state?.hasAcceptedDisclaimer`
93+
94+
### Components
95+
96+
- Use `cva` (class-variance-authority) for variant-based components
97+
- Forward refs where needed
98+
- Use `cn()` utility from `@/lib/utils` for class merging
99+
- Dark mode: use `dark:` prefix classes, not conditional logic
100+
101+
### Business Logic
102+
103+
- Keep calculations pure (no side effects)
104+
- Input types in `types.ts`, implementations in named files
105+
- Test business logic thoroughly (see `src/lib/calculations/*.test.ts`)
106+
- Use `DomainWarning` pattern for validation feedback
107+
108+
### State Management
109+
110+
- Zustand stores in `src/store/`
111+
- Use `persist` middleware for localStorage
112+
- Handle SSR safely: `typeof window === 'undefined'` checks
113+
114+
### Testing
115+
116+
- Vitest with jsdom environment
117+
- Tests alongside source files: `*.test.ts`
118+
- E2E tests in `tests/e2e/` (Playwright)
119+
- Use `@testing-library/react` for component tests
120+
- Mock external libs (html2canvas, localStorage)
121+
122+
## Key Patterns
123+
124+
### View Transitions API
125+
126+
```typescript
127+
// Type augmentation exists in src/types/view-transitions.d.ts
128+
if (document.startViewTransition) {
129+
const transition = document.startViewTransition(() => {
130+
flushSync(() => toggleThemeMode());
131+
});
132+
transition.finished.finally(() => {
133+
/* cleanup */
134+
});
135+
}
136+
```
137+
138+
### Currency Formatting
139+
140+
```typescript
141+
import { formatCurrency } from '@/lib/format';
142+
formatCurrency(value, 0); // "€1.234"
143+
```
144+
145+
### Warning Pattern
146+
147+
```typescript
148+
type DomainWarning = { code: WarningCode; severity: 'warning' | 'critical' };
149+
// Use warningCopy from '@/lib/public-copy' for UI text
150+
```
151+
152+
## Performance Notes
153+
154+
- HMR disabled in AI Studio (DISABLE_HMR env var)
155+
- Lazy load pages in App.tsx
156+
- html2canvas is dynamically imported only when needed
157+
158+
## Italian Language
159+
160+
- All UI copy is in Italian
161+
- Comments should be in English for code clarity

src/App.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,7 @@ export default function App() {
7474
<Route
7575
path="preventivo"
7676
element={
77-
<Suspense
78-
fallback={
79-
<div className="p-6 text-sm text-zinc-500">Caricamento preventivo...</div>
80-
}
81-
>
77+
<Suspense fallback={<RouteFallback />}>
8278
<QuoteBuilder />
8379
</Suspense>
8480
}

src/lib/public-copy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ export const warningCopy: Record<WarningCode, { title: string; message: string }
88
'revenue-over-85000': {
99
title: 'Attenzione',
1010
message:
11-
"I ricavi ragguagliati superano 85.000€. Uscirai dal regime forfettario l'anno prossimo.",
11+
"Hai superato la soglia degli 85.000€. L'anno prossimo uscirai dal regime forfettario e passerai al regime ordinario, ma per l'anno in corso mantieni i benefici fiscali.",
1212
},
1313
'revenue-over-100000': {
1414
title: 'CRITICO',
1515
message:
16-
"I ricavi superano 100.000€. Uscita immediata dal regime forfettario nell'anno in corso!",
16+
"Hai superato la soglia dei 100.000€. Esci IMMEDIATAMENTE dal regime forfettario nell'anno in corso. Dovrai applicare l'IVA sulle fatture successive all'incasso che ha causato il superamento.",
1717
},
1818
'employee-costs-over-limit': {
1919
title: 'Attenzione',

src/pages/Calculator.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export default function Calculator() {
9191
{ name: 'Contributi INPS', value: stimaInps.totale, color: 'var(--color-chart-3)' },
9292
{
9393
name: 'Costi Forfettari',
94-
value: values.ricavi - redditoLordo,
94+
value: Math.max(0, values.ricavi - redditoLordo),
9595
color: 'var(--color-chart-4)',
9696
},
9797
];

src/pages/Planning.tsx

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,7 @@ import {
1616
import { motion } from 'motion/react';
1717
import { buildPlanningProjection } from '@/lib/calculations';
1818
import { formatCurrency } from '@/lib/format';
19-
20-
const warningCopy = {
21-
'revenue-over-85000': {
22-
title: 'Attenzione',
23-
message:
24-
"Hai superato la soglia degli 85.000€. L'anno prossimo uscirai dal regime forfettario e passerai al regime ordinario, ma per l'anno in corso mantieni i benefici fiscali.",
25-
},
26-
'revenue-over-100000': {
27-
title: 'CRITICO',
28-
message:
29-
"Hai superato la soglia dei 100.000€. Esci IMMEDIATAMENTE dal regime forfettario nell'anno in corso. Dovrai applicare l'IVA sulle fatture successive all'incasso che ha causato il superamento.",
30-
},
31-
} as const;
19+
import { warningCopy } from '@/lib/public-copy';
3220

3321
const mesi = ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'];
3422

src/types/view-transitions.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Type augmentation for View Transitions API
3+
* @see https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
4+
*/
5+
6+
interface ViewTransition {
7+
finished: Promise<void>;
8+
ready: Promise<void>;
9+
updateCallbackDone: Promise<void>;
10+
}
11+
12+
declare global {
13+
interface Document {
14+
startViewTransition?(updateCallback: () => void | Promise<void>): ViewTransition;
15+
}
16+
}
17+
18+
export {};

0 commit comments

Comments
 (0)