import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@repo/shadcn-ui/components/button"; import { ContextHelp } from "@repo/shadcn-ui/components/context-help"; import { FormActions } from "@repo/shadcn-ui/components/form-dialog"; import { Input } from "@repo/shadcn-ui/components/input"; import { Label } from "@repo/shadcn-ui/components/label"; import { SelectWithAction } from "@repo/shadcn-ui/components/select-with-action"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useEffect, useId, useRef, useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import type { WorkstationDTO, WorkstationInput } from "../common"; import { WorkstationInputSchema } from "../common"; import type { InventoryLookups } from "./asset-form"; import { catalogApi, catalogKeys } from "./catalog-api"; import { inventoryApi, inventoryKeys } from "./inventory-api"; import { InventoryFeedback } from "./inventory-feedback"; import { WorkstationAssetCreateDialog } from "./workstation-asset-create-dialog"; export function WorkstationForm({ companyId, csrfToken, lookups, workstation, onSaved, }: { companyId: string; csrfToken: string; lookups: InventoryLookups; workstation?: WorkstationDTO | undefined; onSaved: (id: string) => void; }) { const { t } = useTranslation("assets"); const prefix = useId(); const client = useQueryClient(); const mounted = useRef(true); useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []); const form = useForm({ resolver: zodResolver(WorkstationInputSchema), defaultValues: workstation?.values ?? { name: "", active: true, siteId: null, personId: null, assetIds: [], sharedAssetIds: [], }, }); const values = form.watch(); const [quick, setQuick] = useState(false); const [quickField, setQuickField] = useState<"assetIds" | "sharedAssetIds">("assetIds"); const inventory = useQuery({ queryKey: inventoryKeys.company(companyId), queryFn: () => inventoryApi.get(companyId), }); const catalog = useQuery({ queryKey: catalogKeys.scope(companyId), queryFn: () => catalogApi.get(companyId), }); const assets = inventory.data?.assets ?? []; const stations = inventory.data?.workstations ?? []; const occupied = new Set( stations .filter((item) => item.values.active && item.id !== workstation?.id) .flatMap((item) => item.values.assetIds) ); const sharedUsed = new Set( stations .filter((item) => item.values.active && item.id !== workstation?.id) .flatMap((item) => item.values.sharedAssetIds) ); const unavailable = (field: "assetIds" | "sharedAssetIds", id: string) => values.active && (occupied.has(id) || (field === "assetIds" && sharedUsed.has(id))); const add = (field: "assetIds" | "sharedAssetIds", id: string) => { if ( id && mounted.current && ![...form.getValues("assetIds"), ...form.getValues("sharedAssetIds")].includes(id) ) { form.setValue(field, [...form.getValues(field), id]); } }; const mutation = useMutation({ mutationFn: (input: WorkstationInput) => inventoryApi.saveWorkstation(companyId, input, csrfToken, workstation?.id), onSuccess: async (response) => { await client.invalidateQueries({ queryKey: inventoryKeys.company(companyId) }); if (mounted.current) { onSaved(response.workstation.id); } }, }); return ( <>
mutation.mutate(input))}>
lookups.onCreateSite((id) => { if (mounted.current) { form.setValue("siteId", id); } }), }} id={`${prefix}-site`} label={t("site")} onValueChange={(id) => form.setValue("siteId", id || null)} options={lookups.sites.map((item) => ({ value: item.id, label: item.name }))} placeholder={t("noAssignment")} value={values.siteId ?? ""} />
lookups.onCreatePerson((id) => { if (mounted.current) { form.setValue("personId", id); } }), }} id={`${prefix}-person`} label={t("workstationPerson")} onValueChange={(id) => form.setValue("personId", id || null)} options={lookups.people .filter((item) => item.active || item.id === workstation?.values.personId) .map((item) => ({ value: item.id, label: item.name }))} placeholder={t("noAssignment")} value={values.personId ?? ""} />
{(["assetIds", "sharedAssetIds"] as const).map((field) => (
{ setQuickField(field); setQuick(true); }, disabled: !catalog.data, }} disabled={inventory.isPending || values[field].length >= 200} id={`${prefix}-${field}`} label={t( field === "assetIds" ? "addWorkstationAsset" : "addSharedWorkstationAsset" )} onValueChange={(id) => add(field, id)} options={assets .filter( (item) => ![...values.assetIds, ...values.sharedAssetIds].includes(item.id) ) .map((item) => ({ value: item.id, label: unavailable(field, item.id) ? t("workstationOccupied", { name: item.values.name }) : item.values.name, disabled: unavailable(field, item.id), }))} placeholder={t("chooseAsset")} value="" /> {values[field].length ? (
    {values[field].map((id) => (
  • {assets.find((item) => item.id === id)?.values.name ?? id}

    {unavailable(field, id) && (

    {t("inventoryErrors.ASSET_IN_WORKSTATION")}

    )}
  • ))}
) : (

{t(field === "assetIds" ? "noWorkstationAssets" : "noSharedWorkstationAssets")}

)}
))}
{Object.keys(form.formState.errors).length > 0 && (

{t("inventoryErrors.INVALID_REQUEST")}

)} {quick && catalog.data && ( { add(quickField, id); setQuick(false); }} /> )} ); }