/** * Table Hook Template * * Generates use{Module}TableStructure.tsx for table column definitions. */ import { FrontendTemplateData, FrontendField } from "../types/template-data.interface"; import { toCamelCase, pluralize } from "../transformers/name-transformer"; /** * Generate the table structure hook file content * * @param data - Frontend template data * @returns Generated file content */ export function generateTableHookTemplate(data: FrontendTemplateData): string { const { names, fields, extendsContent, tableFieldNames } = data; const fieldColumnEntries = generateFieldColumnEntries(data); const hasAuthors = extendsContent; const hasRelevance = fields.some((f) => f.name === "relevance"); return `"use client"; import { ${names.pascalCase}Fields } from "@/features/${data.importTargetDir}/${names.kebabCase}/data/${names.pascalCase}Fields"; import { ${names.pascalCase}Interface } from "@/features/${data.importTargetDir}/${names.kebabCase}/data/${names.pascalCase}Interface"; import { cellDate, cellId${hasAuthors ? ", ContributorsList" : ""} } from "@carlonicora/nextjs-jsonapi/components"; import { Modules } from "@carlonicora/nextjs-jsonapi/core";${ extendsContent ? ` import { ContentInterface } from "@carlonicora/nextjs-jsonapi/core";` : "" } import { registerTableGenerator, TableContent, usePageUrlGenerator, UseTableStructureHook, } from "@carlonicora/nextjs-jsonapi/client"; import { Link, Tooltip, TooltipContent, TooltipTrigger } from "@carlonicora/nextjs-jsonapi/components"; import { ColumnDef } from "@tanstack/react-table"; import { useTranslations } from "next-intl"; import { useMemo } from "react"; export const use${names.pascalCase}TableStructure: UseTableStructureHook<${names.pascalCase}Interface, ${names.pascalCase}Fields> = (params) => { const t = useTranslations(); const generateUrl = usePageUrlGenerator(); const tableData = useMemo(() => { return params.data.map((${names.camelCase}: ${names.pascalCase}Interface) => { const entry: TableContent<${names.pascalCase}Interface> = { jsonApiData: ${names.camelCase}, }; entry[${names.pascalCase}Fields.${names.camelCase}Id] = ${names.camelCase}.id; params.fields.forEach((field) => { entry[field] = ${names.camelCase}[field as keyof ${names.pascalCase}Interface]; }); return entry; }); }, [params.data, params.fields]); const fieldColumnMap: Partial any>> = { [${names.pascalCase}Fields.${names.camelCase}Id]: () => cellId({ name: "${names.camelCase}Id", checkedIds: params.checkedIds, toggleId: params.toggleId, }), ${fieldColumnEntries} [${names.pascalCase}Fields.createdAt]: () => cellDate({ name: "createdAt", title: t(\`common.date.create\`), }), [${names.pascalCase}Fields.updatedAt]: () => cellDate({ name: "updatedAt", title: t(\`common.date.update\`), }), }; const columns = useMemo(() => { return params.fields.map((field) => fieldColumnMap[field]?.()).filter((col) => col !== undefined) as ColumnDef< TableContent<${names.pascalCase}Interface> >[]; }, [params.fields, fieldColumnMap, t, generateUrl]); return useMemo(() => ({ data: tableData, columns: columns }), [tableData, columns]); }; registerTableGenerator(Modules.${names.pascalCase}, use${names.pascalCase}TableStructure); `; } /** * Generate field column map entries */ function generateFieldColumnEntries(data: FrontendTemplateData): string { const { names, fields, extendsContent, relationships } = data; const entries: string[] = []; // Name field (with link and tooltip for tldr if Content-extending) if (fields.some((f) => f.name === "name") || extendsContent) { entries.push(` [${names.pascalCase}Fields.name]: () => ({ id: "name", accessorKey: "name", header: t(\`features.${names.camelCase.toLowerCase()}.fields.name.label\`), cell: ({ row }: { row: TableContent<${names.pascalCase}Interface> }) => { const ${names.camelCase}: ${names.pascalCase}Interface = row.original.jsonApiData; return ( {${names.camelCase}.name} ${ extendsContent ? ` {${names.camelCase}.tldr}` : ` {${names.camelCase}.name}` } ); }, enableSorting: false, enableHiding: false, }),`); } // Authors field for Content-extending modules if (extendsContent) { entries.push(` [${names.pascalCase}Fields.authors]: () => ({ id: "authors", accessorKey: "authors", header: t(\`generic.relationships.author.label\`), cell: ({ row }: { row: TableContent }) => { const content: ContentInterface = row.original.jsonApiData; return ; }, enableSorting: false, enableHiding: false, }),`); } // Other displayable fields (excluding id, name, tldr, abstract, content, dates) const displayableFields = fields.filter( (f) => !["id", "name", "tldr", "abstract", "content", "createdAt", "updatedAt"].includes(f.name), ); displayableFields.forEach((field) => { if (field.type === "string") { entries.push(` [${names.pascalCase}Fields.${field.name}]: () => ({ id: "${field.name}", accessorKey: "${field.name}", header: t(\`features.${names.camelCase.toLowerCase()}.fields.${field.name}.label\`), cell: ({ row }: { row: TableContent<${names.pascalCase}Interface> }) => { const ${names.camelCase}: ${names.pascalCase}Interface = row.original.jsonApiData; return {${names.camelCase}.${field.name}}; }, enableSorting: false, enableHiding: false, }),`); } else if (field.type === "boolean") { entries.push(` [${names.pascalCase}Fields.${field.name}]: () => ({ id: "${field.name}", accessorKey: "${field.name}", header: t(\`features.${names.camelCase.toLowerCase()}.fields.${field.name}.label\`), cell: ({ row }: { row: TableContent<${names.pascalCase}Interface> }) => { const ${names.camelCase}: ${names.pascalCase}Interface = row.original.jsonApiData; return {${names.camelCase}.${field.name} ? t(\`generic.yes\`) : t(\`generic.no\`)}; }, enableSorting: false, enableHiding: false, }),`); } else if (field.type === "number") { entries.push(` [${names.pascalCase}Fields.${field.name}]: () => ({ id: "${field.name}", accessorKey: "${field.name}", header: t(\`features.${names.camelCase.toLowerCase()}.fields.${field.name}.label\`), cell: ({ row }: { row: TableContent<${names.pascalCase}Interface> }) => { const ${names.camelCase}: ${names.pascalCase}Interface = row.original.jsonApiData; return {${names.camelCase}.${field.name}?.toString()}; }, enableSorting: false, enableHiding: false, }),`); } else if (field.type === "date" || field.type === "datetime") { entries.push(` [${names.pascalCase}Fields.${field.name}]: () => cellDate({ name: "${field.name}", title: t(\`features.${names.camelCase.toLowerCase()}.fields.${field.name}.label\`), }),`); } }); // Relationship columns (rendered when flagged for table display) relationships .filter((rel) => rel.showInTable) .forEach((rel) => { const key = rel.single ? toCamelCase(rel.alias || rel.variant || rel.name) : pluralize(toCamelCase(rel.alias || rel.name)); const accessor = rel.single ? `${names.camelCase}.${key}?.name ?? ""` : `${names.camelCase}.${key}.map((r) => r.name).join(", ")`; entries.push(` [${names.pascalCase}Fields.${key}]: () => ({ id: "${key}", accessorKey: "${key}", header: t(\`features.${names.camelCase.toLowerCase()}.relationships.${key.toLowerCase()}.label\`), cell: ({ row }: { row: TableContent<${names.pascalCase}Interface> }) => { const ${names.camelCase}: ${names.pascalCase}Interface = row.original.jsonApiData; return {${accessor}}; }, enableSorting: false, enableHiding: false, }),`); }); return entries.join("\n"); }