"use client" 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, } from "@/shared/components/form" import { RhfEmployeeSelectField } from "@/modules/employees/rhf-employee-select-field" 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 } from "@/shared/lib/utils" import { LEAVE_REQUEST_ROUTES } from "@garage/api" import { z } from "zod" const LEAVE_TYPES = ["annual", "sick", "unpaid", "maternity", "paternity", "other"] as const const relationFieldSchema = z.object({ value: z.string(), label: z.string() }).nullable() const schema = z.object({ employee: relationFieldSchema.refine((v) => !!v?.value, "Employee is required"), leave_type: z.enum(LEAVE_TYPES), start_date: z.string().min(1, "Start date is required"), end_date: z.string().min(1, "End date is required"), reason: z.string().max(2000).optional(), }) type LeaveFormValues = z.infer const DEFAULT_VALUES: LeaveFormValues = { employee: null, leave_type: "annual", start_date: "", end_date: "", reason: "", } const TYPE_SELECT_OPTIONS = LEAVE_TYPES.map((v) => ({ value: v, label: v.replace(/^./, (c) => c.toUpperCase()), })) export type LeaveRequestFormProps = { resourceId?: string | null initialData?: unknown onSuccess?: () => void /** Pre-fill the employee select when opened from an employee detail page. */ presetEmployee?: { id: number | string; label: string } | null } function mapToFormValues(data: unknown, preset?: { id: number | string; label: string } | null): LeaveFormValues { const d = (data as any)?.data ?? data ?? {} const empLabel = d.employee ? `${d.employee.first_name ?? ""} ${d.employee.last_name ?? ""}`.trim() : "" const formatDate = (v: unknown) => { if (!v || typeof v !== "string") return "" return v.length >= 10 ? v.slice(0, 10) : v } return { employee: d.employee_id ? toRelation(d.employee_id, empLabel || `Employee #${d.employee_id}`) : (preset ? toRelation(preset.id, preset.label) : null), leave_type: d.leave_type || "annual", start_date: formatDate(d.start_date), end_date: formatDate(d.end_date), reason: d.reason || "", } } export function LeaveRequestForm({ resourceId, initialData, onSuccess, presetEmployee }: LeaveRequestFormProps) { const api = useAuthApi() const { form, isEditing } = useResourceForm({ schema, defaultValues: presetEmployee ? { ...DEFAULT_VALUES, employee: toRelation(presetEmployee.id, presetEmployee.label) } : DEFAULT_VALUES, resourceId, initialData, initialize: (id) => api.leaveRequests.show(id), queryKey: [LEAVE_REQUEST_ROUTES.BY_ID, resourceId], mapToFormValues: (data) => mapToFormValues(data, presetEmployee), }) const { mutate, error, isPending } = useFormMutation(form, { mutationFn: (values: LeaveFormValues) => { const payload = { employee_id: toId(values.employee) ?? 0, leave_type: values.leave_type, start_date: values.start_date, end_date: values.end_date, reason: values.reason || undefined, } const promise = isEditing && resourceId ? api.leaveRequests.update(resourceId, payload) : api.leaveRequests.create(payload as any) toast.promise(promise, { loading: isEditing ? "Updating..." : "Submitting...", success: isEditing ? "Leave request updated" : "Leave request submitted", error: isEditing ? "Failed to update" : "Failed to submit", }) return promise }, onSuccess: () => { form.reset() onSuccess?.() }, }) return ( mutate(values)}> {error && ( {isEditing ? "Failed to update" : "Failed to submit"} {error.message} )}
) }