100 lines
3.3 KiB
TypeScript
100 lines
3.3 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 { useId } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
import { useTranslation } from "react-i18next";
|
|
import type { z } from "zod/v4";
|
|
|
|
import { AssetDefinitionSchema, type CatalogItemDTO } from "../common";
|
|
|
|
import { CatalogError } from "./catalog-error";
|
|
import { CatalogHelp } from "./catalog-help";
|
|
import type { CatalogSaved } from "./use-catalog-save";
|
|
import { useCatalogSave } from "./use-catalog-save";
|
|
|
|
const schema = AssetDefinitionSchema.options[2];
|
|
export function CatalogRelationForm({
|
|
scope,
|
|
csrfToken,
|
|
item,
|
|
onSaved,
|
|
}: {
|
|
scope: string;
|
|
csrfToken: string;
|
|
item?: CatalogItemDTO | undefined;
|
|
onSaved: CatalogSaved;
|
|
}) {
|
|
const { t } = useTranslation("assets");
|
|
const id = useId();
|
|
const current = item?.values.kind === "relation" ? item.values : undefined;
|
|
const form = useForm<z.infer<typeof schema>>({
|
|
resolver: zodResolver(schema),
|
|
defaultValues: current ?? {
|
|
kind: "relation",
|
|
name: "",
|
|
inverseName: "",
|
|
description: "",
|
|
symmetric: false,
|
|
},
|
|
});
|
|
const mutation = useCatalogSave(scope, csrfToken, onSaved, item?.id);
|
|
const symmetric = form.watch("symmetric");
|
|
return (
|
|
<form className="space-y-4" onSubmit={form.handleSubmit((values) => mutation.mutate(values))}>
|
|
<div className="space-y-2">
|
|
<Label htmlFor={id}>{t("name")}</Label>
|
|
<Input
|
|
id={id}
|
|
maxLength={100}
|
|
required
|
|
{...form.register("name")}
|
|
onChange={(event) => {
|
|
form.setValue("name", event.target.value);
|
|
if (symmetric) {
|
|
form.setValue("inverseName", event.target.value);
|
|
}
|
|
}}
|
|
/>
|
|
</div>
|
|
<label className="flex items-center gap-2 text-sm">
|
|
<input
|
|
checked={symmetric}
|
|
disabled={!!item}
|
|
onChange={(event) => {
|
|
form.setValue("symmetric", event.target.checked);
|
|
if (event.target.checked) {
|
|
form.setValue("inverseName", form.getValues("name"));
|
|
}
|
|
}}
|
|
type="checkbox"
|
|
/>
|
|
{t("symmetric")}
|
|
</label>
|
|
{!symmetric && (
|
|
<div className="space-y-2">
|
|
<Label htmlFor={`${id}-inverse`}>{t("inverseName")}</Label>
|
|
<Input id={`${id}-inverse`} maxLength={100} required {...form.register("inverseName")} />
|
|
</div>
|
|
)}
|
|
<div className="space-y-2">
|
|
<Label htmlFor={`${id}-description`}>{t("description")}</Label>
|
|
<Textarea id={`${id}-description`} maxLength={1000} {...form.register("description")} />
|
|
</div>
|
|
<CatalogError
|
|
error={mutation.error}
|
|
invalid={Object.keys(form.formState.errors).length > 0}
|
|
/>
|
|
<CatalogHelp kind="relation" scope={scope} />
|
|
<FormActions>
|
|
<Button disabled={mutation.isPending} type="submit">
|
|
{t(mutation.isPending ? "saving" : "save")}
|
|
</Button>
|
|
</FormActions>
|
|
</form>
|
|
);
|
|
}
|