Summary for 14-03: FollowUpWidget Italian translation (CRM-10), LeadForm typed useForm (CRM-11) + shared FormField generic fix, SendQuoteModal dead branch removal (CRM-12)
10 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | duration | completed | |||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 14-crm-attio-style-fix | 03 | ui |
|
|
|
|
|
|
|
|
12min | 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<CreateLeadInput>()withCreateLeadInputimported fromlead-validators.ts— nouseForm<any>()oras anyremains - Fixed
src/components/ui/form.tsx'sFormFieldcomponent to be properly generic, resolving aControl<T>assignability error that surfaced onceLeadForm.tsxadopted a concrete generic - SendQuoteModal.tsx's
onSubmitno longer contains the unreachableif (tab === "new") { window.location.href = ...; return; }branch — the "new" tab's ownonClick-based navigation is unchanged - Bonus: fixed
react/no-unescaped-entitieslint error in SendQuoteModal.tsx (escaped"Proposal Sent"→"Proposal Sent")
Task Commits
Each task was committed atomically:
- Task 1: Translate FollowUpWidget.tsx to Italian (CRM-10) -
272e363(fix) - Task 2: Type LeadForm.tsx's useForm with CreateLeadInput (CRM-11) -
ee509cd(fix) - 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 removedsrc/components/admin/leads/LeadForm.tsx-useForm<any>()→useForm<CreateLeadInput>()in both CreateLeadModal and EditLeadModal; removed localtype CreateLeadInput = z.infer<...>redeclaration (now imported fromlead-validators.ts);status: lead.status as any→status: lead.status as CreateLeadInput["status"]src/components/ui/form.tsx-FormFieldchanged fromReact.forwardRef<any, ControllerProps<any, any>>to a generic function component<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>>(canonical shadcn pattern), fixingControl<T>assignability onceform.controlis concretely typedsrc/components/admin/leads/SendQuoteModal.tsx- Removed unreachableif (tab === "new") {...}branch fromonSubmit; 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-anylint errors left in SendQuoteModal.tsx (out of scope for CRM-12)
Decisions Made
- Fixed
src/components/ui/form.tsx'sFormFieldgeneric signature as a Rule 3 (blocking issue) auto-fix during Task 2 — without it,npx tsc --noEmitfailed with 12Control<CreateLeadInput,...>not assignable toControl<any,any,any>errors onceuseForm<CreateLeadInput>()was introduced. This is the first file in the codebase to use a concreteuseForm<T>()generic alongside the sharedForm/FormFieldcomponents, so the bug was previously masked byuseForm<any>()everywhere. - Attempted (then reverted) typing
SendQuoteModal.tsx'suseForm<any>()/onSubmit(data: any)with a localAssignQuoteInput = z.infer<typeof assignQuoteSchema>type to fully satisfynpx eslint'sno-explicit-anyrule. This cascaded into 3 newtscerrors (Resolver<...>generic incompatibility) caused byassignQuoteSchema's.optional()/.default()fields producing divergent Zod input/output types. Reverted to keeptscclean (CRM-12's actual acceptance criteria); logged todeferred-items.mdas 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:
FormFieldwas declared asReact.forwardRef<any, ControllerProps<any, any>>. OnceLeadForm.tsx'suseForm<any>()becameuseForm<CreateLeadInput>(),form.controlbecameControl<CreateLeadInput, any, {...}>, which TypeScript reported as not assignable toFormField'scontrol={form.control}prop typed viaControllerProps<any, any>— 12tscerrors across both modals (one perFormFieldusage). - Fix: Rewrote
FormFieldas a generic function component<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>>(props: ControllerProps<TFieldValues, TName>), matching the canonical (current) shadcn/ui pattern.FormFieldContextandControllerusage unchanged. - Files modified:
src/components/ui/form.tsx - Verification:
npx tsc --noEmitwent from 12 errors to 0;npx eslint src/components/ui/form.tsxclean - 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-entitiesESLint error on the line"Proposal Sent".inside a<p>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 eslinterror count for this file dropped from 4 to 2 (remaining 2 are unrelatedno-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.tsxstill reports 2@typescript-eslint/no-explicit-anyerrors (lines ~39useForm<any>()and ~48onSubmit(data: any)), both pre-existing and unrelated to the CRM-12 dead-branch removal. A fix attempt (typing both with a localAssignQuoteInputderived fromassignQuoteSchema) caused 3 newtscerrors due to azodResolver/Resolver<...>generic mismatch stemming fromassignQuoteSchema's.optional()/.default()fields (Zod input vs output type divergence). Reverted; logged to.planning/phases/14-crm-attio-style-fix/deferred-items.mdfor 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, andnpx tsc --noEmitexits 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 --noEmitexits 0 across the whole project after this plan- Remaining open item: 2 pre-existing
no-explicit-anylint errors inSendQuoteModal.tsx(deferred-items.md) — not blocking, can be addressed in a future cleanup pass alongside otherassignQuoteSchema/zodResolvertyping work
Phase: 14-crm-attio-style-fix Completed: 2026-06-14