152 lines
4.5 KiB
TypeScript
152 lines
4.5 KiB
TypeScript
import { type ReactNode } from "react";
|
|
|
|
import type { ConfigField } from "@/back/types/dynamic-pages";
|
|
import {
|
|
Accordion,
|
|
AccordionContent,
|
|
AccordionItem,
|
|
AccordionTrigger,
|
|
} from "@/components/ui/accordion";
|
|
import str from "@/hooks/use-string";
|
|
import useTrans from "@/hooks/use-translations";
|
|
import { cn, GetTranslation } from "@/lib/utils";
|
|
|
|
type ChildItem = Record<string, unknown> & { id: string | number };
|
|
|
|
type FieldValue = string | number | boolean | null | undefined | ChildItem[];
|
|
|
|
const RenderRows = (
|
|
currentValue: Record<string, unknown>,
|
|
currentConfig: ConfigField[],
|
|
hasBorders = false,
|
|
path = "",
|
|
): ReactNode => {
|
|
const tableNotKnownTrans = str(useTrans("uwil-backend::back.table_not_known"))
|
|
.ucFirst()
|
|
.value();
|
|
|
|
return currentConfig.map((field, index) => {
|
|
const hasChildren = !!field.children?.length;
|
|
const accordionKey = path
|
|
? `${path}.${field.key}-${String(index)}`
|
|
: `${field.key}-${String(index)}`;
|
|
|
|
const rowContent = (currentHasChildren = false) => {
|
|
const cellClasses = "break-words whitespace-normal";
|
|
const placeholderClasses =
|
|
"text-sm text-muted-foreground break-words whitespace-normal";
|
|
const fieldValue = currentValue[field.key] as FieldValue;
|
|
|
|
let cellContent: ReactNode;
|
|
if (currentHasChildren) {
|
|
const count = Array.isArray(fieldValue) ? fieldValue.length : 0;
|
|
cellContent = (
|
|
<p className={placeholderClasses}>
|
|
{GetTranslation("uwil-dynamic-pages::trans.element", {
|
|
params: { count: String(count) },
|
|
choice: count > 1 ? 2 : 1,
|
|
})}
|
|
</p>
|
|
);
|
|
} else if (fieldValue !== null && fieldValue !== undefined) {
|
|
const displayValue = Array.isArray(fieldValue)
|
|
? null
|
|
: typeof fieldValue === "boolean"
|
|
? GetTranslation(
|
|
fieldValue ? "uwil-backend::back.yes" : "uwil-backend::back.no",
|
|
)
|
|
: String(fieldValue);
|
|
|
|
cellContent = displayValue ? (
|
|
<p className={cellClasses}>{displayValue}</p>
|
|
) : (
|
|
<p className={placeholderClasses}>{tableNotKnownTrans}</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>
|
|
);
|
|
};
|
|
|
|
const childItems = currentValue[field.key];
|
|
const hasChildItems =
|
|
hasChildren && Array.isArray(childItems) && childItems.length > 0;
|
|
|
|
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>
|
|
)}
|
|
|
|
{hasChildItems && (
|
|
<AccordionContent className="px-4">
|
|
<div className="space-y-1">
|
|
{(childItems as ChildItem[]).map((childItem) => (
|
|
<div key={String(childItem.id)} className="border rounded-md">
|
|
{RenderRows(
|
|
childItem,
|
|
field.children ?? [],
|
|
false,
|
|
`${accordionKey}-${String(childItem.id)}`,
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</AccordionContent>
|
|
)}
|
|
</AccordionItem>
|
|
);
|
|
});
|
|
};
|
|
|
|
interface DynamicPageDetailsProps {
|
|
value: Record<string, unknown>;
|
|
config: ConfigField[];
|
|
}
|
|
|
|
export default function DynamicPageDetails({
|
|
value,
|
|
config,
|
|
}: DynamicPageDetailsProps) {
|
|
const transLabel = str(useTrans("uwil-dynamic-pages::trans.attributes.label"))
|
|
.ucFirst()
|
|
.value();
|
|
const transValue = str(useTrans("uwil-dynamic-pages::trans.attributes.value"))
|
|
.ucFirst()
|
|
.value();
|
|
|
|
return (
|
|
<Accordion type="multiple" className="w-full divide-y">
|
|
<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>
|
|
|
|
{RenderRows(value, config, true)}
|
|
</Accordion>
|
|
);
|
|
}
|