104 lines
4.6 KiB
TypeScript
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>
|
|
);
|
|
}
|