metis-desk/modules/companies/src/web/access/access-field-control.tsx

122 lines
3.7 KiB
TypeScript
Raw Normal View History

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 {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@repo/shadcn-ui/components/select";
import { Textarea } from "@repo/shadcn-ui/components/textarea";
import type { UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type { AccessField } from "./access-fields";
import type { AccessFormValues } from "./access-form-values";
type Option = { value: string; label: string };
export function AccessFieldControl({
field,
id,
form,
value,
options,
disabled,
onSelected,
}: {
field: AccessField;
id: string;
form: UseFormReturn<AccessFormValues>;
value: string | boolean | string[] | undefined;
options: readonly Option[];
disabled: boolean;
onSelected: (value: string) => void;
}) {
const { t } = useTranslation("access");
if (field.type === "boolean") {
return (
<div className="flex items-center gap-2">
<Checkbox
checked={Boolean(value)}
id={id}
onCheckedChange={(checked) => form.setValue(field.key, checked === true)}
/>
<Label htmlFor={id}>{t(field.key)}</Label>
</div>
);
}
if (field.type === "permissions") {
return (
<fieldset className="space-y-2">
<legend className="text-sm font-medium">{t(field.key)}</legend>
{options.map((option) => (
<div className="flex items-center gap-2" key={option.value}>
<Checkbox
checked={Array.isArray(value) && value.includes(option.value)}
id={`${id}-${option.value}`}
onCheckedChange={(checked) => {
const values = Array.isArray(value) ? value : [];
form.setValue(
field.key,
checked
? [...values, option.value]
: values.filter((item) => item !== option.value)
);
}}
/>
<Label htmlFor={`${id}-${option.value}`}>{option.label}</Label>
</div>
))}
{!options.length && <p className="text-sm text-muted-foreground">{t("noPermissions")}</p>}
</fieldset>
);
}
return (
<div className="space-y-2">
<Label htmlFor={id}>
{t(field.key)}
{field.required ? "" : t("optional")}
</Label>
{field.type === "note" ? (
<Textarea id={id} maxLength={4000} rows={4} {...form.register(field.key)} />
) : field.type === "select" ? (
<Select
disabled={disabled}
items={[{ value: "", label: t("choose") }, ...options]}
onValueChange={(selected) => {
if (typeof selected === "string") {
onSelected(selected);
}
}}
value={stringValue(value)}
>
<SelectTrigger className="w-full" id={id}>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="">{t("choose")}</SelectItem>
{options.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
) : (
<Input
id={id}
maxLength={field.key === "name" ? 100 : 255}
required={field.required}
type={field.type === "date" ? "date" : "text"}
{...form.register(field.key)}
/>
)}
</div>
);
}
function stringValue(value: string | boolean | string[] | undefined) {
return typeof value === "string" ? value : "";
}