ldc-ovoteam/resources/ts/front/Pages/DynamicPageDefault.tsx
Jérémy Munsch cd2d8ed397
refactor(i18n): replace GetTranslation with trans function
- Updated translation utility to improve consistency and reduce redundancy.
- Removed deprecated useTrans hook and related code.
- Introduced a new Zustand store for managing translations and locale settings.
- Cleaned up unused hooks and files related to localization.
2026-10-19 17:43:33 +02:00

235 lines
7.2 KiB
TypeScript

import { usePage } from "@inertiajs/react";
import { CheckIcon, XIcon } from "lucide-react";
import { type ReactNode } from "react";
import type {
ConfigField,
DynamicFieldType,
DynamicPageModelWithRelations,
} from "@/back/types/dynamic-pages";
import SafeHtml from "@/components/safe-html";
import AppLayout from "@/front/Layouts/AppLayout";
import { cn } from "@/lib/utils";
import { AppEnv } from "@/types";
import Head from "../Components/Base/Head";
import PageHeader from "../Components/Theme/PageHeader";
import Section from "../Components/Theme/Section";
interface DynamicPageDefaultProps {
dynamicPageModel: DynamicPageModelWithRelations;
}
export default function DynamicPageDefault({
dynamicPageModel,
}: Readonly<DynamicPageDefaultProps>) {
const { url, locale, fallbackLocale } = usePage().props.appEnv as AppEnv;
const enumDynamicFieldTypes = usePage().props
.enumDynamicFieldTypes as DynamicFieldType;
const currentLocaleContent =
dynamicPageModel.content?.[locale] ??
dynamicPageModel.content?.[fallbackLocale];
const currentLocaleConfig = dynamicPageModel.config
? (dynamicPageModel.config.config[locale] ??
dynamicPageModel.config.config[fallbackLocale])
: null;
const currentLocaleTitle =
dynamicPageModel.title[locale] ?? dynamicPageModel.title[fallbackLocale];
const joinUrl = (...parts: string[]): string =>
parts.map((part) => part.replace(/^\/+|\/+$/g, "")).join("/");
const renderField = (key: string, value: unknown): ReactNode => {
const configField = currentLocaleConfig?.find(
(item: ConfigField) => item.key === key,
);
if (!configField) {
return <span>{String(value)}</span>;
}
switch (configField.type) {
// Wysiwyg case.
case enumDynamicFieldTypes.wysiwyg.value:
return <SafeHtml html={String(value)} />;
// Number case.
case enumDynamicFieldTypes.number.value:
return <span>{Number(value).toLocaleString(locale)}</span>;
// Boolean case.
case enumDynamicFieldTypes.boolean.value:
return (
<span className={value ? "text-green-600" : "text-red-600"}>
{value ? <CheckIcon /> : <XIcon />}
</span>
);
// Link case.
case enumDynamicFieldTypes.url.value:
return (
<a
href={String(value)}
target="_blank"
rel="noopener noreferrer"
className="underline text-blue-600"
>
{String(value)}
</a>
);
// E-mail case.
case enumDynamicFieldTypes.email.value:
return (
<a
href={`mailto:${String(value)}`}
className="underline text-blue-600"
>
{String(value)}
</a>
);
// Image case.
case enumDynamicFieldTypes.image.value:
return (
<img
src={joinUrl(url, String(value))}
alt={key}
className="max-w-xs max-h-48 object-contain"
/>
);
// File case.
case enumDynamicFieldTypes.file.value:
return (
<a
href={joinUrl(url, String(value))}
target="_blank"
rel="noopener noreferrer"
className="underline text-blue-600"
>
{String(value).split("/").pop()}
</a>
);
// List case.
case enumDynamicFieldTypes.list.value: {
const currentValue = value as {
order: string;
[key: string]: string;
}[];
return (
<ul>
{currentValue.map((item, index) => (
<li
key={item.order}
className={cn({
"border-b pb-2 mb-2": index < currentValue.length - 1,
})}
>
{Object.entries(item).map((content) => (
<ol key="itemContent">
{content[0]}: {content[1]}
</ol>
))}
</li>
))}
</ul>
);
}
// Vimeo ID case.
case enumDynamicFieldTypes.vimeoid.value:
return (
<a
href={`https://player.vimeo.com/video/${String(value)}`}
target="_blank"
rel="noopener noreferrer"
className="underline text-blue-600"
>
{String(value).split("/").pop()}
</a>
);
// Youtube ID case.
case enumDynamicFieldTypes.youtubeid.value:
return (
<a
href={`https://www.youtube.com/embed/${String(value)}`}
target="_blank"
rel="noopener noreferrer"
className="underline text-blue-600"
>
{String(value).split("/").pop()}
</a>
);
// Date case.
case enumDynamicFieldTypes.date.value:
return (
<span>{new Date(String(value)).toLocaleDateString(locale)}</span>
);
// Color case.
case enumDynamicFieldTypes.color.value:
return (
<span className="flex items-center gap-2">
<span
className="inline-block w-5 h-5 rounded-sm border"
style={{ backgroundColor: String(value) }}
/>
{String(value)}
</span>
);
// Model case.
case enumDynamicFieldTypes.model.value: {
const reservedValue = currentLocaleContent?.[
`reserved_${key}` as keyof typeof currentLocaleContent
] as unknown as string;
return (
<span>
{String(value)}{" "}
<span className="text-gray-500">({reservedValue})</span>
</span>
);
}
// Static route case.
case enumDynamicFieldTypes.staticroute.value:
return (value as string | null) ? (
<a href={String(value)} className="underline text-blue-600">
{String(value)}
</a>
) : (
<p>/</p>
);
// Default for string/textarea.
default:
return <span>{String(value)}</span>;
}
};
return (
<AppLayout>
<Head seoTitle={currentLocaleTitle} />
<PageHeader
title={{
text: currentLocaleTitle,
}}
description={{
text: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo mollitia minus cum obcaecati necessitatibus? Molestias, harum. Sapiente eos ipsa ullam esse laborum id libero consectetur voluptate labore eaque. Optio, corporis?",
}}
/>
<Section className="text-start tiptap">
{currentLocaleConfig && currentLocaleContent ? (
<table className="w-1/2 mx-auto border-collapse">
<tbody>
{Object.entries(currentLocaleContent)
.filter(([key]) => !key.startsWith("reserved_model_"))
.map(([key, value]) => (
<tr key={key} className="border-b">
<th className="text-left font-medium p-2 w-1/4 align-top">
{key}
</th>
<td className="p-2">{renderField(key, value)}</td>
</tr>
))}
</tbody>
</table>
) : (
<SafeHtml html={String(currentLocaleContent)} />
)}
</Section>
</AppLayout>
);
}