From 272e363f4d21fc60436b08de648fe134483c5c18 Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Sun, 14 Jun 2026 12:38:12 +0200 Subject: [PATCH 1/5] fix(14-03): translate FollowUpWidget to Italian (CRM-10) - Replace 6 hardcoded English strings with Italian equivalents - Remove pluralization ternary (Italian "lead" is invariant) --- src/components/admin/dashboard/FollowUpWidget.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/admin/dashboard/FollowUpWidget.tsx b/src/components/admin/dashboard/FollowUpWidget.tsx index 8f5c978..24722f5 100644 --- a/src/components/admin/dashboard/FollowUpWidget.tsx +++ b/src/components/admin/dashboard/FollowUpWidget.tsx @@ -12,34 +12,33 @@ export async function FollowUpWidget() { - Require Follow-up + Richiedi Follow-up {leadsNeedingFollowUp.length > 0 ? ( <>

- {leadsNeedingFollowUp.length} lead{leadsNeedingFollowUp.length !== 1 ? "s" : ""}{" "} - to contact + {leadsNeedingFollowUp.length} lead da contattare

{leadsNeedingFollowUp.length > 3 && ( )} ) : ( -

All leads are up to date!

+

Tutti i lead sono aggiornati!

)}
From ee509cd5fba32132661b0894923bbb2848cdb124 Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Sun, 14 Jun 2026 12:43:00 +0200 Subject: [PATCH 2/5] fix(14-03): type LeadForm useForm with CreateLeadInput (CRM-11) - CreateLeadModal and EditLeadModal use useForm() instead of useForm() - Import CreateLeadInput from lead-validators, remove local z.infer redeclaration - Narrow EditLeadModal status default value to CreateLeadInput["status"], remove 'as any' - Fix FormField generic signature in shared ui/form.tsx (was ControllerProps, broke Control assignability once useForm became concrete) - Rule 3 blocking issue --- src/components/admin/leads/LeadForm.tsx | 11 ++++------- src/components/ui/form.tsx | 13 +++++++------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/components/admin/leads/LeadForm.tsx b/src/components/admin/leads/LeadForm.tsx index caf1926..9e18306 100644 --- a/src/components/admin/leads/LeadForm.tsx +++ b/src/components/admin/leads/LeadForm.tsx @@ -3,8 +3,7 @@ import { useState } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { z } from "zod"; -import { createLeadSchema, LEAD_STAGES } from "@/lib/lead-validators"; +import { createLeadSchema, LEAD_STAGES, type CreateLeadInput } from "@/lib/lead-validators"; import { Lead } from "@/db/schema"; import { createLead, updateLead } from "@/app/admin/leads/actions"; import { @@ -33,12 +32,10 @@ import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; -type CreateLeadInput = z.infer; - export function CreateLeadModal() { const [open, setOpen] = useState(false); const [loading, setLoading] = useState(false); - const form = useForm({ + const form = useForm({ resolver: zodResolver(createLeadSchema), defaultValues: { name: "", @@ -202,14 +199,14 @@ export function CreateLeadModal() { export function EditLeadModal({ lead }: { lead: Lead }) { const [open, setOpen] = useState(false); const [loading, setLoading] = useState(false); - const form = useForm({ + const form = useForm({ resolver: zodResolver(createLeadSchema), defaultValues: { name: lead.name, email: lead.email || "", phone: lead.phone || "", company: lead.company || "", - status: lead.status as any, + status: lead.status as CreateLeadInput["status"], notes: lead.notes || "", }, }); diff --git a/src/components/ui/form.tsx b/src/components/ui/form.tsx index d647caa..f1ec4bc 100644 --- a/src/components/ui/form.tsx +++ b/src/components/ui/form.tsx @@ -27,15 +27,16 @@ const FormFieldContext = React.createContext( {} as FormFieldContextValue ) -const FormField = React.forwardRef< - any, - ControllerProps ->(({ ...props }, ref) => ( +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +>({ + ...props +}: ControllerProps) => ( -)) -FormField.displayName = "FormField" +) const useFormField = () => { const fieldContext = React.useContext(FormFieldContext) From a495d8451185f4e267f6455f9c96f9695d11c0de Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Sun, 14 Jun 2026 12:46:55 +0200 Subject: [PATCH 3/5] fix(14-03): remove dead onSubmit branch in SendQuoteModal (CRM-12) - Remove unreachable if (tab === "new") branch in onSubmit - the new-tab button has its own onClick navigation and never triggers form submit - Escape unescaped double quotes in JSX text (react/no-unescaped-entities) - generate_new field left as-is per plan (optional cleanup, out of scope) - Log pre-existing useForm/onSubmit(data: any) no-explicit-any lint errors to deferred-items.md (out of scope: fixing requires resolving a zodResolver/Resolver generic incompatibility with assignQuoteSchema's optional/default fields) --- .../phases/14-crm-attio-style-fix/deferred-items.md | 9 +++++++++ src/components/admin/leads/SendQuoteModal.tsx | 8 +------- 2 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 .planning/phases/14-crm-attio-style-fix/deferred-items.md diff --git a/.planning/phases/14-crm-attio-style-fix/deferred-items.md b/.planning/phases/14-crm-attio-style-fix/deferred-items.md new file mode 100644 index 0000000..a0fbc01 --- /dev/null +++ b/.planning/phases/14-crm-attio-style-fix/deferred-items.md @@ -0,0 +1,9 @@ +# Deferred Items — Phase 14 (crm-attio-style-fix) + +Items discovered during execution that are out of scope for the current task/plan and deferred for future cleanup. + +## From Plan 14-03 + +| File | Lines | Issue | Reason Deferred | +|------|-------|-------|------------------| +| `src/components/admin/leads/SendQuoteModal.tsx` | 39, 48 | `@typescript-eslint/no-explicit-any` on `useForm()` and `onSubmit(data: any)` | Pre-existing (not introduced by CRM-12's dead-branch removal). Attempted fix: typing `useForm()` with `AssignQuoteInput = z.infer` (local schema has `.optional()`/`.default()` on `generate_new`) triggers a cascading `zodResolver`/`Resolver<...>` generic-incompatibility TS error (3 errors, TS2322/TS2345) between `@hookform/resolvers/zod` and `react-hook-form@7.75`'s 3-generic `Resolver` type — same family of issue fixed for `LeadForm.tsx`'s `FormField` in 14-03 Task 2, but here it surfaces in the resolver/schema layer (input vs output type divergence from `.default()`), not the `FormField` component. Resolving it would require either restructuring `assignQuoteSchema`'s optional/default fields or adding resolver-boundary type assertions — out of scope for CRM-12 (isolated dead-code removal). | diff --git a/src/components/admin/leads/SendQuoteModal.tsx b/src/components/admin/leads/SendQuoteModal.tsx index 48f2d6a..f5588f6 100644 --- a/src/components/admin/leads/SendQuoteModal.tsx +++ b/src/components/admin/leads/SendQuoteModal.tsx @@ -48,12 +48,6 @@ export function SendQuoteModal({ leadId }: { leadId: string }) { async function onSubmit(data: any) { setLoading(true); try { - if (tab === "new") { - // Redirect to quote builder pre-filled with this lead - window.location.href = `/admin/quotes/new?lead_id=${leadId}`; - return; - } - const result = await assignQuoteToLead({ lead_id: leadId, quote_token: data.quote_token, @@ -109,7 +103,7 @@ export function SendQuoteModal({ leadId }: { leadId: string }) { />

Copia il token dal preventivo e incollalo qui. Il lead sarà aggiornato a - "Proposal Sent". + "Proposal Sent".