metis-desk/modules/companies/src/web/components/site-form.tsx
David a232595a71 feat: add catalog template form and inventory management features
- Implemented CatalogTemplateForm for creating and managing asset templates.
- Added inventory management components including AssetInventoryPage and related forms.
- Introduced internationalization support for asset and inventory components in English and Spanish.
- Created tests for catalog and inventory functionalities to ensure proper rendering and behavior.
- Established API interactions for inventory management and asset catalog retrieval.
- Enhanced user experience with form dialogs for quick creation of sites and persons within company inventory.
2026-10-04 18:36:09 +02:00

93 lines
3.0 KiB
TypeScript

import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@repo/shadcn-ui/components/button";
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 { Textarea } from "@repo/shadcn-ui/components/textarea";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useId } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type { SiteDTO, SiteRequestDTO } from "../../common";
import { SiteRequestSchema } from "../../common";
import { EntityHelp } from "../access/entity-help";
import { companyApi, companyKeys } from "../api/company-api";
import { CompanyFeedback } from "./company-feedback";
export function SiteForm({
site,
companyId,
csrfToken,
onSaved,
showTitle = true,
}: {
site?: SiteDTO;
companyId: string;
csrfToken: string;
onSaved?: (id: string) => void;
showTitle?: boolean;
}) {
const { t } = useTranslation("companies");
const id = useId();
const client = useQueryClient();
const form = useForm<SiteRequestDTO>({
resolver: zodResolver(SiteRequestSchema),
defaultValues: { name: site?.name ?? "", address: site?.address ?? "" },
});
const mutation = useMutation({
mutationFn: (values: SiteRequestDTO) =>
companyApi.site(
companyId,
site?.id,
{ ...values, address: values.address?.trim() ? values.address : null },
csrfToken
),
onSuccess: (response) => {
client.setQueryData(companyKeys.detail(companyId), response);
if (!site) {
form.reset();
}
const saved = site
? response.company.sites.find((item) => item.id === site.id)
: response.company.sites.at(-1);
if (saved) {
onSaved?.(saved.id);
}
},
});
return (
<form className="space-y-4" onSubmit={form.handleSubmit((values) => mutation.mutate(values))}>
{showTitle && <h3 className="text-lg font-semibold">{t(site ? "editSite" : "newSite")}</h3>}
<div className="space-y-2">
<Label htmlFor={`${id}-name`}>{t("name")}</Label>
<Input id={`${id}-name`} maxLength={100} required {...form.register("name")} />
</div>
<div className="space-y-2">
<Label htmlFor={`${id}-address`}>{t("addressOptional")}</Label>
<Textarea
className="min-h-40"
id={`${id}-address`}
maxLength={10000}
rows={6}
{...form.register("address")}
/>
<p className="text-xs text-muted-foreground">{t("addressHelp")}</p>
</div>
<CompanyFeedback
error={mutation.error}
invalid={Object.keys(form.formState.errors).length > 0}
success={mutation.isSuccess}
/>
<EntityHelp kind="site" />
<FormActions>
<Button disabled={mutation.isPending} type="submit">
{t(mutation.isPending ? "saving" : "save")}
</Button>
</FormActions>
</form>
);
}