"use client" import { useMemo } from "react" import { AlertTriangle, Plus, Save } from "lucide-react" import { Button } from "@/shared/components/ui/button" import { Alert, AlertTitle } from "@/shared/components/ui/alert" import { FieldGroup } from "@/shared/components/ui/field" import { Rhform, RhfTextField, RhfSelectField, RhfTextareaField, RhfAsyncSelectField, RhfAutoGenerateField, RhfDateField, } from "@/shared/components/form" import { toast } from "sonner" import { useAuthApi } from "@/shared/useApi" import { useResourceForm } from "@/shared/hooks/use-resource-form" import { useFormMutation } from "@/shared/hooks/use-form-mutation" import { toRelation, toId, getTodayDate } from "@/shared/lib/utils" import { paymentMadeFormSchema, type PaymentMadeFormValues, } from "./payment-made.schema" import { PAYMENT_MADE_ROUTES, PAYMENT_MODE_ROUTES, EMPLOYEE_ROUTES, PaymentFor, } from "@garage/api" import { RhfVendorSelectField } from "@/modules/vendors/rhf-vendor-select-field" // ── Constants ── const PAYMENT_FOR_OPTIONS = PaymentFor.map((value) => ({ value, label: value.charAt(0).toUpperCase() + value.slice(1), })) // ── Props ── export type PaymentMadeFormProps = { resourceId?: string | null initialData?: unknown onSuccess?: () => void billId?: string | number | null expenseId?: string | number | null } // ── Default values ── const DEFAULT_VALUES: PaymentMadeFormValues & { details: Array<{ bill_id?: string | number | null; amount_paid?: number, expense_id?: string | number | null }> } = { vendor: null, employee: null, payment_mode: null, payment_for: "bill", amount: "", payment_number: "", payment_reference: "", payment_date: getTodayDate(), paid_through: "", notes: "", details: [] } // ── Mapping helpers ── function mapToFormValues(data: unknown): typeof DEFAULT_VALUES { const d = (data as any)?.data ?? data ?? {} // Resolve payment_mode label from nested object (title) or fallback to id const paymentModeId = d.payment_mode_id ?? d.payment_mode?.id const paymentModeLabel = d.payment_mode?.title ?? d.payment_mode?.name ?? d.payment_mode_name return { vendor: toRelation(d.vendor_id, d.vendor?.company_name ?? d.vendor?.name ?? d.vendor_name), employee: toRelation(d.employee_id, d.employee?.first_name ? `${d.employee.first_name} ${d.employee.last_name ?? ""}`.trim() : d.employee_name), payment_mode: toRelation(paymentModeId, paymentModeLabel), payment_for: d.payment_for || "", amount: d.payment_made ? String(d.payment_made) : "", payment_number: d.payment_number || "", payment_reference: d.payment_reference || "", payment_date: d.payment_date || "", paid_through: d.paid_through || "-", notes: d.notes || "-", details: [{ bill_id: d.bill_id, amount_paid: d.amount_paid }], } } function mapFormToPayload(values: PaymentMadeFormValues, billId?: string | number | null, expenseId?: string | number | null) { const paymentDetails = expenseId ? [{ expense_id: expenseId, amount_paid: values.amount ? Number(values.amount) : 0 }] : [{ bill_id: billId, amount_paid: values.amount ? Number(values.amount) : 0 }] return { vendor_id: toId(values.vendor), employee_id: toId(values.employee) || undefined, payment_mode_id: toId(values.payment_mode), payment_for: values.payment_for, amount: values.amount ? Number(values.amount) : 0, payment_number: values.payment_number || undefined, payment_reference: values.payment_reference || undefined, payment_date: values.payment_date, paid_through: values.paid_through || undefined, notes: values.notes || undefined, payment_made: values.amount, details: paymentDetails, ...(billId ? { bill_id: Number(billId) } : {}), ...(expenseId ? { expense_id: Number(expenseId) } : {}), } } // ── Shared mapOption for async selects ── const mapLookupOption = (item: any) => ({ value: String(item.id), label: item.name ?? item.title ?? `#${item.id}`, }) const mapVendorOption = (item: any) => ({ value: String(item.id), label: item.name ?? item.company_name ?? `#${item.id}`, }) const mapEmployeeOption = (item: any) => ({ value: String(item.id), label: item.first_name ? `${item.first_name} ${item.last_name || ""}`.trim() : item.name ?? `#${item.id}`, }) const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) => o.label } // ── Component ── export function PaymentMadeForm({ resourceId, initialData, onSuccess, billId, expenseId }: PaymentMadeFormProps) { const api = useAuthApi() const resolvedInitialData = useMemo(() => { const base: any = { ...(initialData as any) } if (!resourceId) { if (billId) { base.payment_for = "bill" } else if (expenseId) { base.payment_for = "expense" } } return Object.keys(base).length ? base : initialData }, [resourceId, billId, expenseId, initialData]) const { form, isEditing } = useResourceForm({ schema: paymentMadeFormSchema, defaultValues: DEFAULT_VALUES, resourceId, initialData: resolvedInitialData, mapToFormValues, }) const { mutate, error, isPending } = useFormMutation(form, { mutationFn: (values: PaymentMadeFormValues) => { const payload = mapFormToPayload(values, billId, expenseId) const promise = (isEditing && resourceId ? api.paymentMades.update(resourceId, payload as any) : api.paymentMades.create(payload as any)) as Promise toast.promise(promise, { loading: isEditing ? "Updating payment..." : "Recording payment...", success: isEditing ? "Payment updated successfully" : "Payment recorded successfully", error: isEditing ? "Failed to update payment" : "Failed to record payment", }) return promise }, onSuccess: () => { form.reset() onSuccess?.() }, }) return ( mutate(values)}> {error && ( {isEditing ? "Failed to update payment" : "Failed to record payment"} {error.message} )}
api.employees.list()} mapOption={mapEmployeeOption} {...STORE_OBJECT} />
api.paymentModes.list()} mapOption={mapLookupOption} {...STORE_OBJECT} />
) }