ldc-groupe/resources/ts/back/Components/DynamicPages/DynamicPageDetails.tsx

104 lines
4.6 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/global";
import { cn } from "@/lib/utils";
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();
const tableNotKnownTrans = str(useTrans("back.table_not_known")).ucFirst().value();
const RenderRows = (value: string | number | object, config: ConfigField[], hasBorders: boolean = false, path: string = ""): ReactNode =>
config.map((field, index) => {
const hasChildren = !!field.children?.length;
const accordionKey = path ? `${path}.${field.key}-${index}` : `${field.key}-${index}`;
const rowContent = (hasChildren: boolean = false) => {
const cellClasses = "break-words whitespace-normal";
const placeholderClasses = "text-sm text-muted-foreground break-words whitespace-normal";
const fieldValue = value[field.key as keyof typeof value];
const cellContent = hasChildren
? (() => {
const count = Array.isArray(fieldValue)
? Object.values(fieldValue).length
: 0;
return (
<p className={placeholderClasses}>
{useTrans('back.element', {
params: { count: String(count) },
choice: count > 1 ? 2 : 1,
})}
</p>
);
})()
: fieldValue !== null && fieldValue !== undefined
? <p className={cellClasses}>
{(typeof fieldValue === 'boolean') ? useTrans(fieldValue ? 'back.yes' : 'back.no') : fieldValue}
</p>
: <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}
{!hasChildren && <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(value[field.key as keyof typeof value]) && Object.values(value[field.key as keyof typeof value]).length > 0 && (
<AccordionContent className="px-4">
<div className="space-y-1">
{Object.values(value[field.key as keyof typeof value]).map((childItem: any, childIndex: number) => (
<div key={childIndex} className="border rounded-md">
{RenderRows(childItem, field.children!, false, `${accordionKey}-${childIndex}`)}
</div>
))}
</div>
</AccordionContent>
)}
</AccordionItem>
);
});
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>
);
}