"use client"; import type { RouterOutputs } from "@api/trpc/routers/_app"; import { uniqueCurrencies } from "@midday/location/currencies"; import { Collapsible, CollapsibleContent } from "@midday/ui/collapsible"; import { CurrencyInput } from "@midday/ui/currency-input"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@midday/ui/form"; import { Input } from "@midday/ui/input"; import { Label } from "@midday/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@midday/ui/select"; import { SubmitButton } from "@midday/ui/submit-button"; import { Switch } from "@midday/ui/switch"; import { Textarea } from "@midday/ui/textarea"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useEffect } from "react"; import { z } from "zod/v3"; import { SearchCustomers } from "@/components/search-customers"; import { SelectTags } from "@/components/select-tags"; import { useCustomerParams } from "@/hooks/use-customer-params"; import { useLatestProjectId } from "@/hooks/use-latest-project-id"; import { useTrackerParams } from "@/hooks/use-tracker-params"; import { useUserQuery } from "@/hooks/use-user"; import { useZodForm } from "@/hooks/use-zod-form"; import { useTRPC } from "@/trpc/client"; const formSchema = z.object({ id: z.string().uuid().optional(), name: z.string().min(1), description: z.string().optional(), estimate: z.number().optional(), billable: z.boolean().optional().default(false), rate: z.number().min(1).optional(), currency: z.string().optional(), status: z.enum(["in_progress", "completed"]).optional(), customerId: z.string().uuid().nullable().optional(), tags: z .array( z.object({ id: z.string().uuid(), value: z.string(), }), ) .optional(), }); type Props = { data?: RouterOutputs["trackerProjects"]["getById"]; defaultCurrency: string; }; export function TrackerProjectForm({ data, defaultCurrency }: Props) { const isEdit = !!data; const trpc = useTRPC(); const queryClient = useQueryClient(); const { data: user } = useUserQuery(); const { setParams: setTrackerParams } = useTrackerParams(); const { setParams: setCustomerParams } = useCustomerParams(); const { setLatestProjectId } = useLatestProjectId(user?.teamId); const upsertTrackerProjectMutation = useMutation( trpc.trackerProjects.upsert.mutationOptions({ onSuccess: (result) => { setLatestProjectId(result?.id ?? null); queryClient.invalidateQueries({ queryKey: trpc.trackerProjects.get.infiniteQueryKey(), }); queryClient.invalidateQueries({ queryKey: trpc.trackerProjects.getById.queryKey(), }); // Close the tracker project form setTrackerParams({ create: null }); }, }), ); const form = useZodForm(formSchema, { defaultValues: { id: data?.id, name: data?.name ?? undefined, description: data?.description ?? undefined, rate: data?.rate ?? undefined, status: data?.status ?? "in_progress", billable: data?.billable ?? false, estimate: data?.estimate ?? 0, currency: data?.currency ?? defaultCurrency, customerId: data?.customerId ?? undefined, tags: data?.tags?.map((tag) => ({ id: tag.id ?? "", value: tag.name ?? "", })) ?? undefined, }, }); const onSubmit = (data: z.infer) => { const formattedData = { ...data, id: data.id || undefined, description: data.description || null, rate: data.rate || null, currency: data.currency || null, billable: data.billable || false, estimate: data.estimate || null, status: data.status || "in_progress", customerId: data.customerId || null, tags: data.tags?.length ? data.tags : null, }; upsertTrackerProjectMutation.mutate(formattedData); }; useEffect(() => { if (data) { form.reset({ id: data?.id, name: data?.name ?? undefined, description: data?.description ?? undefined, rate: data?.rate ?? undefined, status: data?.status ?? "in_progress", billable: data?.billable ?? false, estimate: data?.estimate ?? 0, currency: data?.currency ?? defaultCurrency, customerId: data?.customerId ?? undefined, tags: data?.tags?.map((tag) => ({ id: tag.id ?? "", value: tag.name ?? "", })) ?? undefined, }); } }, [data]); return (
( Name This is the project display name. )} /> ( Customer field.onChange(id, { shouldDirty: true, shouldValidate: true, }) } selectedId={field.value ?? undefined} onCreate={(name) => { setCustomerParams({ name, createCustomer: true, }); }} onEdit={(id) => { setCustomerParams({ customerId: id, }); }} /> Link a customer to enable direct invoicing. )} />
({ id: tag.id, value: tag.value, label: tag.value, }))} onRemove={(tag) => { form.setValue( "tags", form.getValues("tags")?.filter((t) => t.id !== tag.id), { shouldDirty: true, shouldValidate: true, }, ); }} onSelect={(tag) => { form.setValue( "tags", [ ...(form.getValues("tags") ?? []), { value: tag.value ?? "", id: tag.id ?? "", }, ], { shouldDirty: true, shouldValidate: true, }, ); }} /> Tags help categorize and track project expenses.
( Description