metis-desk/modules/companies/src/web/components/company-form.tsx

81 lines
2.8 KiB
TypeScript
Raw Normal View History

import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@repo/shadcn-ui/components/button";
import { Checkbox } from "@repo/shadcn-ui/components/checkbox";
import { Input } from "@repo/shadcn-ui/components/input";
import { Label } from "@repo/shadcn-ui/components/label";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useId } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type { CompanyRequestDTO, CompanySummaryDTO } from "../../common";
import { CompanyRequestSchema } from "../../common";
import { companyApi, companyKeys } from "../api/company-api";
import { CompanyFeedback } from "./company-feedback";
export function CompanyForm({
company,
csrfToken,
onCreated,
onSaved,
showTitle = true,
}: {
company?: CompanySummaryDTO;
csrfToken: string;
onCreated?: (id: string) => void;
onSaved?: () => void;
showTitle?: boolean;
}) {
const { t } = useTranslation("companies");
const id = useId();
const client = useQueryClient();
const form = useForm<CompanyRequestDTO>({
resolver: zodResolver(CompanyRequestSchema),
defaultValues: { name: company?.name ?? "", active: company?.active ?? true },
});
const mutation = useMutation({
mutationFn: (values: CompanyRequestDTO) => companyApi.save(company?.id, values, csrfToken),
onSuccess: async (response) => {
client.setQueryData(companyKeys.detail(response.company.id), response);
await client.invalidateQueries({ queryKey: companyKeys.list });
if (company) {
form.reset({ name: response.company.name, active: response.company.active });
} else {
form.reset();
onCreated?.(response.company.id);
}
onSaved?.();
},
});
return (
<form className="space-y-4" onSubmit={form.handleSubmit((values) => mutation.mutate(values))}>
{showTitle && (
<h2 className="text-lg font-semibold">{t(company ? "editCompany" : "newCompany")}</h2>
)}
<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="flex items-center gap-2">
<Checkbox
checked={form.watch("active")}
id={`${id}-active`}
onCheckedChange={(checked) =>
form.setValue("active", checked === true, { shouldDirty: true })
}
/>
<Label htmlFor={`${id}-active`}>{t("activeCompany")}</Label>
</div>
<CompanyFeedback
error={mutation.error}
invalid={Object.keys(form.formState.errors).length > 0}
success={mutation.isSuccess}
/>
<Button disabled={mutation.isPending} type="submit">
{t(mutation.isPending ? "saving" : "save")}
</Button>
</form>
);
}