chore: merge executor worktree (worktree-agent-aaf61d7161f7818a0)
# Conflicts: # .planning/phases/14-crm-attio-style-fix/deferred-items.md
This commit is contained in:
@@ -0,0 +1,141 @@
|
|||||||
|
---
|
||||||
|
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<any>, no as any)"
|
||||||
|
- "Shared ui/form.tsx FormField component made properly generic (Control<TFieldValues> 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<any, ControllerProps<any,any>> — required whenever useForm<T>() 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<CreateLeadInput>() to type-check against FormField's control prop"
|
||||||
|
- "Did not retype SendQuoteModal's useForm<any>()/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<ConcreteType>() against shadcn's Form/FormField components, verify src/components/ui/form.tsx's FormField generic signature supports concrete Control<T> types (must be a generic function component, not React.forwardRef<any, ControllerProps<any,any>>)"
|
||||||
|
|
||||||
|
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<CreateLeadInput>()` with `CreateLeadInput` imported from `lead-validators.ts` — no `useForm<any>()` or `as any` remains
|
||||||
|
- Fixed `src/components/ui/form.tsx`'s `FormField` component to be properly generic, resolving a `Control<T>` 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<any>()` → `useForm<CreateLeadInput>()` 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<any, ControllerProps<any, any>>` to a generic function component `<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>>` (canonical shadcn pattern), fixing `Control<T>` 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<CreateLeadInput,...>` not assignable to `Control<any,any,any>` errors once `useForm<CreateLeadInput>()` was introduced. This is the first file in the codebase to use a concrete `useForm<T>()` generic alongside the shared `Form`/`FormField` components, so the bug was previously masked by `useForm<any>()` everywhere.
|
||||||
|
- Attempted (then reverted) typing `SendQuoteModal.tsx`'s `useForm<any>()`/`onSubmit(data: any)` with a local `AssignQuoteInput = z.infer<typeof assignQuoteSchema>` 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<CreateLeadInput> typing)
|
||||||
|
- **Issue:** `FormField` was declared as `React.forwardRef<any, ControllerProps<any, any>>`. Once `LeadForm.tsx`'s `useForm<any>()` became `useForm<CreateLeadInput>()`, `form.control` became `Control<CreateLeadInput, any, {...}>`, which TypeScript reported as not assignable to `FormField`'s `control={form.control}` prop typed via `ControllerProps<any, any>` — 12 `tsc` errors across both modals (one per `FormField` usage).
|
||||||
|
- **Fix:** Rewrote `FormField` as a generic function component `<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>>(props: ControllerProps<TFieldValues, TName>)`, 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 `<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 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<any>()` 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*
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
- FOUND: src/components/admin/dashboard/FollowUpWidget.tsx
|
||||||
|
- FOUND: src/components/admin/leads/LeadForm.tsx
|
||||||
|
- FOUND: src/components/admin/leads/SendQuoteModal.tsx
|
||||||
|
- FOUND: src/components/ui/form.tsx
|
||||||
|
- FOUND: .planning/phases/14-crm-attio-style-fix/14-03-SUMMARY.md
|
||||||
|
- FOUND: .planning/phases/14-crm-attio-style-fix/deferred-items.md
|
||||||
|
- FOUND commit: 272e363 (Task 1)
|
||||||
|
- FOUND commit: ee509cd (Task 2)
|
||||||
|
- FOUND commit: a495d84 (Task 3)
|
||||||
|
- FOUND commit: 6b51403 (plan metadata)
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
# Deferred Items — Phase 14
|
# Deferred Items — Phase 14 (crm-attio-style-fix)
|
||||||
|
|
||||||
Items discovered during execution that are out of scope for the current task
|
Items discovered during execution that are out of scope for the current task/plan and deferred for future cleanup.
|
||||||
(per Scope Boundary rule — pre-existing issues in unrelated code paths).
|
|
||||||
|
|
||||||
## 14-01
|
## From Plan 14-01
|
||||||
|
|
||||||
- **`src/app/admin/leads/actions.ts:54`** — pre-existing `@typescript-eslint/no-explicit-any`
|
- **`src/app/admin/leads/actions.ts:54`** — pre-existing `@typescript-eslint/no-explicit-any`
|
||||||
error on `const updateData: Record<string, any> = { updated_at: new Date() };` inside
|
error on `const updateData: Record<string, any> = { updated_at: new Date() };` inside
|
||||||
@@ -18,3 +17,9 @@ Items discovered during execution that are out of scope for the current task
|
|||||||
(4x) for imports `settings`, `ServiceCatalog`, `ProjectOffer`, `OfferPhaseService` — these
|
(4x) for imports `settings`, `ServiceCatalog`, `ProjectOffer`, `OfferPhaseService` — these
|
||||||
predate Phase 14 and are unrelated to the `getLeadsWithTags`/`getLeadFieldOptions` additions
|
predate Phase 14 and are unrelated to the `getLeadsWithTags`/`getLeadFieldOptions` additions
|
||||||
in Task 1.
|
in Task 1.
|
||||||
|
|
||||||
|
## From Plan 14-03
|
||||||
|
|
||||||
|
| File | Lines | Issue | Reason Deferred |
|
||||||
|
|------|-------|-------|------------------|
|
||||||
|
| `src/components/admin/leads/SendQuoteModal.tsx` | 39, 48 | `@typescript-eslint/no-explicit-any` on `useForm<any>()` and `onSubmit(data: any)` | Pre-existing (not introduced by CRM-12's dead-branch removal). Attempted fix: typing `useForm<AssignQuoteInput>()` with `AssignQuoteInput = z.infer<typeof assignQuoteSchema>` (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). |
|
||||||
|
|||||||
@@ -12,34 +12,33 @@ export async function FollowUpWidget() {
|
|||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-center gap-2">
|
<CardTitle className="flex items-center gap-2">
|
||||||
<AlertCircle className="h-5 w-5 text-orange-600" />
|
<AlertCircle className="h-5 w-5 text-orange-600" />
|
||||||
Require Follow-up
|
Richiedi Follow-up
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
{leadsNeedingFollowUp.length > 0 ? (
|
{leadsNeedingFollowUp.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<p className="text-lg font-bold text-orange-900">
|
<p className="text-lg font-bold text-orange-900">
|
||||||
{leadsNeedingFollowUp.length} lead{leadsNeedingFollowUp.length !== 1 ? "s" : ""}{" "}
|
{leadsNeedingFollowUp.length} lead da contattare
|
||||||
to contact
|
|
||||||
</p>
|
</p>
|
||||||
<ul className="space-y-2 text-sm">
|
<ul className="space-y-2 text-sm">
|
||||||
{leadsNeedingFollowUp.slice(0, 3).map((lead) => (
|
{leadsNeedingFollowUp.slice(0, 3).map((lead) => (
|
||||||
<li key={lead.id} className="flex justify-between items-center">
|
<li key={lead.id} className="flex justify-between items-center">
|
||||||
<span>{lead.name}</span>
|
<span>{lead.name}</span>
|
||||||
<Button variant="ghost" size="sm" asChild>
|
<Button variant="ghost" size="sm" asChild>
|
||||||
<Link href={`/admin/leads/${lead.id}`}>Contact</Link>
|
<Link href={`/admin/leads/${lead.id}`}>Contatta</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
{leadsNeedingFollowUp.length > 3 && (
|
{leadsNeedingFollowUp.length > 3 && (
|
||||||
<Button variant="outline" className="w-full" asChild>
|
<Button variant="outline" className="w-full" asChild>
|
||||||
<Link href="/admin/leads">View All ({leadsNeedingFollowUp.length})</Link>
|
<Link href="/admin/leads">Vedi Tutto ({leadsNeedingFollowUp.length})</Link>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-gray-600 text-sm">All leads are up to date!</p>
|
<p className="text-gray-600 text-sm">Tutti i lead sono aggiornati!</p>
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { z } from "zod";
|
import { createLeadSchema, LEAD_STAGES, type CreateLeadInput } from "@/lib/lead-validators";
|
||||||
import { createLeadSchema, LEAD_STAGES } from "@/lib/lead-validators";
|
|
||||||
import { Lead } from "@/db/schema";
|
import { Lead } from "@/db/schema";
|
||||||
import { createLead, updateLead } from "@/app/admin/leads/actions";
|
import { createLead, updateLead } from "@/app/admin/leads/actions";
|
||||||
import {
|
import {
|
||||||
@@ -33,12 +32,10 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
type CreateLeadInput = z.infer<typeof createLeadSchema>;
|
|
||||||
|
|
||||||
export function CreateLeadModal() {
|
export function CreateLeadModal() {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const form = useForm<any>({
|
const form = useForm<CreateLeadInput>({
|
||||||
resolver: zodResolver(createLeadSchema),
|
resolver: zodResolver(createLeadSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: "",
|
name: "",
|
||||||
@@ -202,14 +199,14 @@ export function CreateLeadModal() {
|
|||||||
export function EditLeadModal({ lead }: { lead: Lead }) {
|
export function EditLeadModal({ lead }: { lead: Lead }) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const form = useForm<any>({
|
const form = useForm<CreateLeadInput>({
|
||||||
resolver: zodResolver(createLeadSchema),
|
resolver: zodResolver(createLeadSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: lead.name,
|
name: lead.name,
|
||||||
email: lead.email || "",
|
email: lead.email || "",
|
||||||
phone: lead.phone || "",
|
phone: lead.phone || "",
|
||||||
company: lead.company || "",
|
company: lead.company || "",
|
||||||
status: lead.status as any,
|
status: lead.status as CreateLeadInput["status"],
|
||||||
notes: lead.notes || "",
|
notes: lead.notes || "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -48,12 +48,6 @@ export function SendQuoteModal({ leadId }: { leadId: string }) {
|
|||||||
async function onSubmit(data: any) {
|
async function onSubmit(data: any) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
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({
|
const result = await assignQuoteToLead({
|
||||||
lead_id: leadId,
|
lead_id: leadId,
|
||||||
quote_token: data.quote_token,
|
quote_token: data.quote_token,
|
||||||
@@ -109,7 +103,7 @@ export function SendQuoteModal({ leadId }: { leadId: string }) {
|
|||||||
/>
|
/>
|
||||||
<p className="text-xs text-gray-600">
|
<p className="text-xs text-gray-600">
|
||||||
Copia il token dal preventivo e incollalo qui. Il lead sarà aggiornato a
|
Copia il token dal preventivo e incollalo qui. Il lead sarà aggiornato a
|
||||||
"Proposal Sent".
|
"Proposal Sent".
|
||||||
</p>
|
</p>
|
||||||
<Button type="submit" disabled={loading} className="w-full">
|
<Button type="submit" disabled={loading} className="w-full">
|
||||||
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||||
|
|||||||
@@ -27,15 +27,16 @@ const FormFieldContext = React.createContext<FormFieldContextValue>(
|
|||||||
{} as FormFieldContextValue
|
{} as FormFieldContextValue
|
||||||
)
|
)
|
||||||
|
|
||||||
const FormField = React.forwardRef<
|
const FormField = <
|
||||||
any,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
ControllerProps<any, any>
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||||
>(({ ...props }, ref) => (
|
>({
|
||||||
|
...props
|
||||||
|
}: ControllerProps<TFieldValues, TName>) => (
|
||||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||||
<Controller {...props} />
|
<Controller {...props} />
|
||||||
</FormFieldContext.Provider>
|
</FormFieldContext.Provider>
|
||||||
))
|
)
|
||||||
FormField.displayName = "FormField"
|
|
||||||
|
|
||||||
const useFormField = () => {
|
const useFormField = () => {
|
||||||
const fieldContext = React.useContext(FormFieldContext)
|
const fieldContext = React.useContext(FormFieldContext)
|
||||||
|
|||||||
Reference in New Issue
Block a user