ldc-groupe/resources/ts/back/Components/DynamicPages/DynamicPageDetails.tsx
2026-02-12 16:13:54 +01:00

162 lines
5.8 KiB
TypeScript

// * Packages
import { ReactNode } from "react";
// * Components shadcn
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
// * Other
import str from "@/hooks/use-string";
import useTrans from "@/hooks/use-translations";
import { ConfigField } from "@/back/types/dynamic-pages";
import { cn, GetTranslation } from "@/lib/utils";
type ChildItem = Record<string, string | number | object | ChildItem[]>;
const RenderRows = (
currentValue: string | number | object,
currentConfig: ConfigField[],
hasBorders: boolean = false,
path: string = "",
): ReactNode => {
const tableNotKnownTrans = str(useTrans("back.table_not_known"))
.ucFirst()
.value();
return currentConfig.map((field, index) => {
const hasChildren = !!field.children?.length;
const accordionKey = path
? `${path}.${field.key}-${index}`
: `${field.key}-${index}`;
const rowContent = (currentHasChildren: boolean = false) => {
const cellClasses = "break-words whitespace-normal";
const placeholderClasses =
"text-sm text-muted-foreground break-words whitespace-normal";
const fieldValue =
currentValue[field.key as keyof typeof currentValue];
let cellContent: ReactNode;
if (currentHasChildren) {
const count = Array.isArray(fieldValue)
? Object.values(fieldValue).length
: 0;
cellContent = (
<p className={placeholderClasses}>
{GetTranslation("back.element", {
params: { count: String(count) },
choice: count > 1 ? 2 : 1,
})}
</p>
);
} else if (fieldValue !== null && fieldValue !== undefined) {
cellContent = (
<p className={cellClasses}>
{typeof fieldValue === "boolean"
? GetTranslation(
fieldValue ? "back.yes" : "back.no",
)
: fieldValue}
</p>
);
} else {
cellContent = (
<p className={placeholderClasses}>{tableNotKnownTrans}</p>
);
}
return (
<div className="grid grid-cols-[1fr_1fr_auto] items-center w-full gap-4">
<p className={cellClasses}>{field.label}</p>
{cellContent}
{!currentHasChildren && <div className="w-[16px]" />}
</div>
);
};
return (
<AccordionItem
key={accordionKey}
value={accordionKey}
className="border-none"
>
{hasChildren ? (
<AccordionTrigger
className={cn(
"gap-0 px-4",
{ "rounded-none border-b mb-2": hasBorders },
{ "py-2": !hasBorders },
)}
>
{rowContent(hasChildren)}
</AccordionTrigger>
) : (
<div className="px-4 py-2">{rowContent()}</div>
)}
{hasChildren &&
Array.isArray(
currentValue[field.key as keyof typeof currentValue],
) &&
Object.values(
currentValue[field.key as keyof typeof currentValue],
).length > 0 && (
<AccordionContent className="px-4">
<div className="space-y-1">
{Object.values(
currentValue[
field.key as keyof typeof currentValue
] as ChildItem[],
).map((childItem: ChildItem) => (
<div
key={String(childItem.id)}
className="border rounded-md"
>
{RenderRows(
childItem,
field.children!,
false,
`${accordionKey}-${childItem.id}`,
)}
</div>
))}
</div>
</AccordionContent>
)}
</AccordionItem>
);
});
};
type DynamicPageDetailsProps = {
value: string | object;
config: ConfigField[];
};
export default function DynamicPageDetails({
value,
config,
}: DynamicPageDetailsProps) {
const transLabel = str(useTrans("validation.custom.label"))
.ucFirst()
.value();
const transValue = str(useTrans("validation.custom.value"))
.ucFirst()
.value();
return (
<Accordion type="multiple" className="w-full divide-y">
{/* HEADER */}
<div className="grid grid-cols-[1fr_1fr_auto] text-sm font-medium border-b gap-4 px-4 py-2">
<div>{transLabel}</div>
<div>{transValue}</div>
<div className="w-[16px]" />
</div>
{/* ROWS */}
{RenderRows(value, config, true)}
</Accordion>
);
}