import { Button } from "@repo/shadcn-ui/components/button"; import { Card, CardContent } from "@repo/shadcn-ui/components/card"; import { FormDialog } from "@repo/shadcn-ui/components/form-dialog"; import { Input } from "@repo/shadcn-ui/components/input"; import { Label } from "@repo/shadcn-ui/components/label"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@repo/shadcn-ui/components/table"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useId, useState } from "react"; import { useTranslation } from "react-i18next"; import type { CatalogItemDTO } from "../common"; import { catalogApi, catalogKeys } from "./catalog-api"; import { CatalogDefinitionDialog } from "./catalog-definition-dialog"; import { CatalogError, CatalogFieldForm } from "./catalog-form"; import { CatalogTemplateForm } from "./catalog-template-form"; type Editor = { kind: "field" | "template"; item?: CatalogItemDTO; copy?: CatalogItemDTO; }; export function ResourceCatalogPage({ scope, csrfToken }: { scope: string; csrfToken: string }) { const { t } = useTranslation("resources"); const searchId = useId(); const client = useQueryClient(); const [tab, setTab] = useState<"field" | "template">("template"); const [search, setSearch] = useState(""); const [view, setView] = useState(); const [editor, setEditor] = useState(); const query = useQuery({ queryKey: catalogKeys.scope(scope), queryFn: () => catalogApi.get(scope), }); const mutation = useMutation({ mutationFn: ({ item, active }: { item: CatalogItemDTO; active: boolean | null }) => catalogApi.status(scope, item.id, active, csrfToken), onSuccess: async (response) => { await client.invalidateQueries({ queryKey: ["resource-catalog"] }); client.setQueryData(catalogKeys.scope(scope), response); }, }); const items = query.data?.items ?? []; const visible = items.filter( (item) => item.values.kind === tab && item.values.name.toLocaleLowerCase().includes(search.toLocaleLowerCase()) ); return (

{t(scope === "global" ? "title" : "companyTitle")}

{t(scope === "global" ? "introduction" : "companyIntroduction")}

{t("protected")}

{query.isPending &&

{t("loading")}

} {query.isError && ( )}
setSearch(event.target.value)} value={search} />
{query.data && (visible.length ? ( {t("name")} {t("origin")} {t({ field: "type", template: "fields" }[tab])} {t("active")} {t("actions")} {visible.map((item) => ( setEditor({ kind: "template", copy: item })} onEdit={() => setEditor({ kind: tab, item })} onStatus={(active) => mutation.mutate({ item, active })} onView={() => setView(item)} pending={mutation.isPending} scope={scope} /> ))}
) : (

{t("empty")}

))}
setView(undefined)} /> {editor && ( { if (!open) { setEditor(undefined); } }} open title={t(editorTitle(editor))} wide={editor.kind === "template"} > {editor.kind === "field" ? ( setEditor(undefined)} scope={scope} /> ) : ( setEditor(undefined)} scope={scope} /> )} )}
); } function CatalogRow({ item, scope, items, pending, onEdit, onCopy, onView, onStatus, }: { item: CatalogItemDTO; scope: string; items: readonly CatalogItemDTO[]; pending: boolean; onEdit: () => void; onCopy: () => void; onView: () => void; onStatus: (active: boolean | null) => void; }) { const { t } = useTranslation("resources"); const editable = !item.builtin && item.companyId === (scope === "global" ? null : scope); const values = item.values; const inactiveFields = values.kind === "template" && values.fields.some( (field) => !items.find((entry) => entry.id === field.fieldId)?.effectiveActive ); return (

{values.name}

{values.description && (

{values.description}

)} {inactiveFields && (

{t("disabledFieldsNotice")}

)}
{t(item.builtin ? "builtin" : "custom")}

{t(item.companyId ? "own" : "global")}

{values.kind === "field" ? t(values.type) : t("fieldCount", { count: values.fields.length })} {t(item.effectiveActive ? "active" : "inactive")} {scope !== "global" && !item.companyId && (

{t(item.overridden ? "overridden" : "inherited")}

)}
); } function editorTitle(editor: Editor) { if (editor.kind === "field") { return editor.item ? "editField" : "newField"; } return editor.item ? "editTemplate" : "newTemplate"; } function CatalogRowActions({ item, editable, pending, onEdit, onCopy, onView, onStatus, }: { item: CatalogItemDTO; editable: boolean; pending: boolean; onEdit: () => void; onCopy: () => void; onView: () => void; onStatus: (active: boolean | null) => void; }) { const { t } = useTranslation("resources"); return (
{editable && ( )} {item.values.kind === "template" && ( )} {item.overridden && ( )}
); }