diff --git a/.planning/phases/14-crm-attio-style-fix/14-03-SUMMARY.md b/.planning/phases/14-crm-attio-style-fix/14-03-SUMMARY.md new file mode 100644 index 0000000..cb61b0d --- /dev/null +++ b/.planning/phases/14-crm-attio-style-fix/14-03-SUMMARY.md @@ -0,0 +1,128 @@ +--- +phase: 14-crm-attio-style-fix +plan: 03 +subsystem: ui +tags: [react-hook-form, zod, i18n, typescript, shadcn] + +# Dependency graph +requires: [] +provides: + - "FollowUpWidget.tsx fully translated to Italian (no English strings)" + - "LeadForm.tsx CreateLeadModal/EditLeadModal typed with CreateLeadInput (no useForm, no as any)" + - "Shared ui/form.tsx FormField component made properly generic (Control assignability fix)" + - "SendQuoteModal.tsx onSubmit dead 'new' tab branch removed" +affects: [14-01, 14-02] + +# Tech tracking +tech-stack: + added: [] + patterns: + - "FormField in src/components/ui/form.tsx is now a generic function component (TFieldValues/TName) instead of React.forwardRef> — required whenever useForm() uses a concrete (non-any) generic" + +key-files: + created: + - .planning/phases/14-crm-attio-style-fix/deferred-items.md + modified: + - src/components/admin/dashboard/FollowUpWidget.tsx + - src/components/admin/leads/LeadForm.tsx + - src/components/ui/form.tsx + - src/components/admin/leads/SendQuoteModal.tsx + +key-decisions: + - "Fixed shared ui/form.tsx FormField generic signature (Rule 3 blocking issue) — required for LeadForm.tsx's useForm() to type-check against FormField's control prop" + - "Did not retype SendQuoteModal's useForm()/onSubmit(data: any) — attempted fix cascades into a zodResolver/Resolver generic incompatibility from assignQuoteSchema's .optional()/.default() fields; deferred as out-of-scope for CRM-12 (dead-code removal)" + +patterns-established: + - "When introducing useForm() against shadcn's Form/FormField components, verify src/components/ui/form.tsx's FormField generic signature supports concrete Control types (must be a generic function component, not React.forwardRef>)" + +requirements-completed: [CRM-10, CRM-11, CRM-12] + +duration: 12min +completed: 2026-06-14 +--- + +# Phase 14 Plan 03: CRM Residual Bug Fixes (i18n, types, dead code) Summary + +**Translated FollowUpWidget to Italian, typed LeadForm's useForm with CreateLeadInput (fixing a shared FormField generic bug along the way), and removed SendQuoteModal's unreachable "new" tab onSubmit branch** + +## Performance + +- **Duration:** ~12 min +- **Started:** 2026-06-14T10:38:00Z (approx) +- **Completed:** 2026-06-14T10:47:00Z +- **Tasks:** 3 +- **Files modified:** 4 (3 plan-scoped + 1 shared UI component fixed as Rule 3 deviation) + +## Accomplishments +- FollowUpWidget.tsx now displays only Italian copy: "Richiedi Follow-up", "{count} lead da contattare" (no pluralization), "Contatta", "Vedi Tutto ({count})", "Tutti i lead sono aggiornati!" +- LeadForm.tsx's CreateLeadModal and EditLeadModal both use `useForm()` with `CreateLeadInput` imported from `lead-validators.ts` — no `useForm()` or `as any` remains +- Fixed `src/components/ui/form.tsx`'s `FormField` component to be properly generic, resolving a `Control` assignability error that surfaced once `LeadForm.tsx` adopted a concrete generic +- SendQuoteModal.tsx's `onSubmit` no longer contains the unreachable `if (tab === "new") { window.location.href = ...; return; }` branch — the "new" tab's own `onClick`-based navigation is unchanged +- Bonus: fixed `react/no-unescaped-entities` lint error in SendQuoteModal.tsx (escaped `"Proposal Sent"` → `"Proposal Sent"`) + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Translate FollowUpWidget.tsx to Italian (CRM-10)** - `272e363` (fix) +2. **Task 2: Type LeadForm.tsx's useForm with CreateLeadInput (CRM-11)** - `ee509cd` (fix) +3. **Task 3: Remove dead onSubmit branch in SendQuoteModal.tsx (CRM-12)** - `a495d84` (fix) + +_Note: Task 1 verify command (`grep ... && npx tsc --noEmit`) and overall plan verification both passed with `npx tsc --noEmit` exiting 0._ + +## Files Created/Modified +- `src/components/admin/dashboard/FollowUpWidget.tsx` - All 6 hardcoded English strings translated to Italian; pluralization ternary removed +- `src/components/admin/leads/LeadForm.tsx` - `useForm()` → `useForm()` in both CreateLeadModal and EditLeadModal; removed local `type CreateLeadInput = z.infer<...>` redeclaration (now imported from `lead-validators.ts`); `status: lead.status as any` → `status: lead.status as CreateLeadInput["status"]` +- `src/components/ui/form.tsx` - `FormField` changed from `React.forwardRef>` to a generic function component `>` (canonical shadcn pattern), fixing `Control` assignability once `form.control` is concretely typed +- `src/components/admin/leads/SendQuoteModal.tsx` - Removed unreachable `if (tab === "new") {...}` branch from `onSubmit`; escaped unescaped `"` characters in JSX text (react/no-unescaped-entities) +- `.planning/phases/14-crm-attio-style-fix/deferred-items.md` - New file logging the 2 pre-existing `@typescript-eslint/no-explicit-any` lint errors left in SendQuoteModal.tsx (out of scope for CRM-12) + +## Decisions Made +- Fixed `src/components/ui/form.tsx`'s `FormField` generic signature as a Rule 3 (blocking issue) auto-fix during Task 2 — without it, `npx tsc --noEmit` failed with 12 `Control` not assignable to `Control` errors once `useForm()` was introduced. This is the first file in the codebase to use a concrete `useForm()` generic alongside the shared `Form`/`FormField` components, so the bug was previously masked by `useForm()` everywhere. +- Attempted (then reverted) typing `SendQuoteModal.tsx`'s `useForm()`/`onSubmit(data: any)` with a local `AssignQuoteInput = z.infer` type to fully satisfy `npx eslint`'s `no-explicit-any` rule. This cascaded into 3 new `tsc` errors (`Resolver<...>` generic incompatibility) caused by `assignQuoteSchema`'s `.optional()`/`.default()` fields producing divergent Zod input/output types. Reverted to keep `tsc` clean (CRM-12's actual acceptance criteria); logged to `deferred-items.md` as out of scope for this isolated dead-code-removal task. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Fixed FormField generic signature in shared ui/form.tsx** +- **Found during:** Task 2 (LeadForm.tsx useForm typing) +- **Issue:** `FormField` was declared as `React.forwardRef>`. Once `LeadForm.tsx`'s `useForm()` became `useForm()`, `form.control` became `Control`, which TypeScript reported as not assignable to `FormField`'s `control={form.control}` prop typed via `ControllerProps` — 12 `tsc` errors across both modals (one per `FormField` usage). +- **Fix:** Rewrote `FormField` as a generic function component `>(props: ControllerProps)`, matching the canonical (current) shadcn/ui pattern. `FormFieldContext` and `Controller` usage unchanged. +- **Files modified:** `src/components/ui/form.tsx` +- **Verification:** `npx tsc --noEmit` went from 12 errors to 0; `npx eslint src/components/ui/form.tsx` clean +- **Committed in:** `ee509cd` (Task 2 commit) + +**2. [Rule 1 - Lint cleanup] Escaped unescaped double quotes in SendQuoteModal.tsx JSX text** +- **Found during:** Task 3 (SendQuoteModal.tsx dead-branch removal verification) +- **Issue:** `react/no-unescaped-entities` ESLint error on the line `"Proposal Sent".` inside a `

` element (pre-existing, in the same file being edited) +- **Fix:** Replaced literal `"` with `"` → `"Proposal Sent".` +- **Files modified:** `src/components/admin/leads/SendQuoteModal.tsx` +- **Verification:** `npx eslint` error count for this file dropped from 4 to 2 (remaining 2 are unrelated `no-explicit-any`, see below) +- **Committed in:** `a495d84` (Task 3 commit) + +--- + +**Total deviations:** 2 auto-fixed (1 blocking, 1 lint cleanup) +**Impact on plan:** Both fixes were necessary to meet the plan's stated `npx tsc --noEmit`/`npx eslint` exit-0 verification for the modified files. No scope creep beyond what was required to make CRM-10/11/12 type-check and lint cleanly. One additional lint issue (pre-existing `no-explicit-any` in SendQuoteModal.tsx, unrelated to CRM-12) was investigated, found to require an out-of-scope schema/resolver restructuring, and deferred — documented in `deferred-items.md`. + +## Issues Encountered +- `npx eslint src/components/admin/leads/SendQuoteModal.tsx` still reports 2 `@typescript-eslint/no-explicit-any` errors (lines ~39 `useForm()` and ~48 `onSubmit(data: any)`), both pre-existing and unrelated to the CRM-12 dead-branch removal. A fix attempt (typing both with a local `AssignQuoteInput` derived from `assignQuoteSchema`) caused 3 new `tsc` errors due to a `zodResolver`/`Resolver<...>` generic mismatch stemming from `assignQuoteSchema`'s `.optional()`/`.default()` fields (Zod input vs output type divergence). Reverted; logged to `.planning/phases/14-crm-attio-style-fix/deferred-items.md` for future cleanup. This does not block CRM-10/11/12 — all three requirements' acceptance criteria (dead branch removed, Italian translation complete, LeadForm fully typed) are satisfied, and `npx tsc --noEmit` exits 0 across the whole project. + +## Known Stubs +None - no stubs introduced. All three fixes are direct edits to existing, fully-wired components. + +## Threat Flags +None - all three fixes are display-copy translation, compile-time type-tightening, and dead-code removal. No new network endpoints, auth paths, file access, or schema changes introduced. Matches the plan's threat_model dispositions (T-14-11 mitigate via stronger typing — done; T-14-12 and T-14-13 accept — no security-relevant change). + +## User Setup Required +None - no external service configuration required. + +## Next Phase Readiness +- CRM-10, CRM-11, CRM-12 all satisfied — these were the last residual non-UI bugs from Phase 14's scope (the Attio-style table redesign itself is covered by Plans 14-01/14-02) +- `npx tsc --noEmit` exits 0 across the whole project after this plan +- Remaining open item: 2 pre-existing `no-explicit-any` lint errors in `SendQuoteModal.tsx` (deferred-items.md) — not blocking, can be addressed in a future cleanup pass alongside other `assignQuoteSchema`/`zodResolver` typing work + +--- +*Phase: 14-crm-attio-style-fix* +*Completed: 2026-06-14*