ldc-laravel-base-project/resources/ts/back/Components/DynamicPages/DynamicInputs.tsx
2026-07-09 17:32:17 +02:00

364 lines
12 KiB
TypeScript

import { usePage } from "@inertiajs/react";
import { Fragment } from "react/jsx-runtime";
import { DynamicInputRegistry } from "@/back/Components/DynamicPages/DynamicInputRegistry";
import DynamicList from "@/back/Components/DynamicPages/DynamicList";
import DynamicWrapperModelSelect from "@/back/Components/DynamicPages/DynamicWrapperModelSelect";
import CompleteInputFile from "@/back/Components/Inputs/CompleteInputFile";
import SimpleColorPicker from "@/back/Components/Inputs/SimpleColorPicker";
import SimpleDatePicker from "@/back/Components/Inputs/SimpleDatePicker";
import SimpleNumber from "@/back/Components/Inputs/SimpleNumber";
import SimpleString from "@/back/Components/Inputs/SimpleString";
import SimpleSwitch from "@/back/Components/Inputs/SimpleSwitch";
import SimpleTextarea from "@/back/Components/Inputs/SimpleTextarea";
import SimpleVimeoId from "@/back/Components/Inputs/SimpleVimeoId";
import SimpleYoutubeId from "@/back/Components/Inputs/SimpleYoutubeId";
import StaticRouteSelect from "@/back/Components/Inputs/StaticRouteSelect";
import SimpleWysiwyg from "@/back/Components/Inputs/Wysiwyg/SimpleWysiwyg";
import type {
ConfigField,
DynamicFieldType,
DynamicInternalField,
} from "@/back/types/dynamic-pages";
import {
extractLaravelValidationValue,
extractMinMaxFromValidation,
extractRequiredValidation,
} from "@/hooks/use-laravel-validation";
import str from "@/hooks/use-string";
import useTrans from "@/hooks/use-translations";
interface DynamicInputsProps {
name: string;
config: ConfigField[];
content: DynamicInternalField | null;
isChildren?: boolean;
setData: (
name: string,
value: string | number | boolean | File | object | null,
) => void;
reset: (name?: string) => void;
parentErrors?: Record<string, string> | null;
}
// Allows to get specific input from enum value.
export default function DynamicInputs({
name,
config,
content,
isChildren = false,
setData,
reset,
parentErrors,
}: DynamicInputsProps) {
// Enums.
const enumDynamicFieldTypes = usePage().props
.enumDynamicFieldTypes as DynamicFieldType;
// Translations.
const transAssociateTo = useTrans("uwil-backend::back.form_associate_to");
const transUnsupportedType = useTrans(
"uwil-dynamic-pages::trans.unsupported_type",
);
/**
* Get a translation for a specific field label.
* Need to recreate useTrans hook to avoid hook error.
* @param fieldLabel string
* @returns string
*/
const getTrans = (fieldLabel: string): string => {
return str(transAssociateTo.split("|")[0].replace(":attribute", fieldLabel))
.ucFirst()
.value();
};
const toStr = (val: unknown): string => {
if (val === null || val === undefined) return "";
if (
typeof val === "string" ||
typeof val === "number" ||
typeof val === "boolean"
) {
return String(val);
}
return "";
};
return (
<div className="grid grid-cols-1 md:grid-cols-2 items-start gap-4">
{/* Loop on all config elements. */}
{Object.entries(config).map(([id, field]) => {
// Get the enum value from the element type value.
const typeEnum = Object.values(enumDynamicFieldTypes).find(
(def) => def.value === field.type,
);
// Set the name of the current field.
const fieldName = `${name}.${field.key}`;
// Set the content value from the config key.
const fieldValue = content?.[field.key as keyof typeof content] ?? "";
switch (field.type) {
// String input.
case enumDynamicFieldTypes.string.value:
return (
<SimpleString
key={id}
name={fieldName}
label={getTrans(field.label)}
required={extractRequiredValidation(field.validation)}
value={toStr(fieldValue)}
setData={setData}
parentErrors={parentErrors}
/>
);
// Textarea input.
case enumDynamicFieldTypes.textarea.value:
return (
<SimpleTextarea
key={id}
name={fieldName}
label={getTrans(field.label)}
required={extractRequiredValidation(field.validation)}
value={toStr(fieldValue)}
setData={setData}
parentErrors={parentErrors}
/>
);
// Wysiwyg input.
case enumDynamicFieldTypes.wysiwyg.value:
return (
<div key={id} className="col-span-1 md:col-span-2">
<SimpleWysiwyg
name={fieldName}
tableName="dynamic_pages"
required={extractRequiredValidation(field.validation)}
label={getTrans(field.label)}
value={toStr(fieldValue)}
setData={setData}
parentErrors={parentErrors}
/>
</div>
);
// Numbers input.
case enumDynamicFieldTypes.number.value:
return (
<SimpleNumber
key={id}
name={fieldName}
label={getTrans(field.label)}
limits={extractMinMaxFromValidation(field.validation)}
required={extractRequiredValidation(field.validation)}
value={Number(fieldValue)}
setData={setData}
/>
);
// Switch input.
case enumDynamicFieldTypes.boolean.value:
return (
<div key={id} className="grid grid-cols-1 gap-1.5">
<SimpleSwitch
label={`${getTrans(field.label)} ${extractRequiredValidation(field.validation) ? " *" : ""}`}
name={fieldName}
checked={Boolean(fieldValue)}
setData={setData}
/>
</div>
);
// Url input.
case enumDynamicFieldTypes.url.value:
return (
<SimpleString
key={id}
name={fieldName}
label={getTrans(field.label)}
type="url"
placeholder="ex: https://..."
required={extractRequiredValidation(field.validation)}
value={toStr(fieldValue)}
setData={setData}
/>
);
// Image input.
case enumDynamicFieldTypes.image.value:
return (
<CompleteInputFile
key={id}
fileName="fichier"
name={fieldName}
label={getTrans(field.label)}
setData={setData}
reset={reset}
value={fieldValue as string | File | null}
required={extractRequiredValidation(field.validation)}
maxFileSize={extractLaravelValidationValue(
field.validation,
"max",
)}
allowedFormats={extractLaravelValidationValue(
field.validation,
"mimes",
)}
validationRules={{
width: extractLaravelValidationValue(
field.validation,
"dimensions",
"width",
),
height: extractLaravelValidationValue(
field.validation,
"dimensions",
"height",
),
}}
/>
);
// Email input.
case enumDynamicFieldTypes.email.value:
return (
<SimpleString
key={id}
name={fieldName}
label={getTrans(field.label)}
type="email"
placeholder="ex: john.doe@ldc.fr"
required={extractRequiredValidation(field.validation)}
value={toStr(fieldValue)}
setData={setData}
/>
);
// List input.
case enumDynamicFieldTypes.list.value:
return (
<DynamicList
key={id}
name={fieldName}
parentName={name}
content={content}
field={field}
value={Array.isArray(fieldValue) ? fieldValue : []}
enumLabel={enumDynamicFieldTypes.list.label}
setData={setData}
reset={reset}
isChildren={isChildren}
/>
);
// File input.
case enumDynamicFieldTypes.file.value:
return (
<CompleteInputFile
key={id}
name={fieldName}
label={getTrans(field.label)}
setData={setData}
reset={reset}
value={fieldValue as string | File | null}
required={extractRequiredValidation(field.validation)}
maxFileSize={extractLaravelValidationValue(
field.validation,
"max",
)}
allowedFormats={extractLaravelValidationValue(
field.validation,
"mimes",
)}
inputType="file"
/>
);
// VimeoId input
case enumDynamicFieldTypes.vimeoid.value:
return (
<SimpleVimeoId
key={id}
name={fieldName}
setData={setData}
value={toStr(fieldValue)}
required={extractRequiredValidation(field.validation)}
/>
);
// YoutubeId input
case enumDynamicFieldTypes.youtubeid.value:
return (
<SimpleYoutubeId
key={id}
name={fieldName}
setData={setData}
value={toStr(fieldValue)}
required={extractRequiredValidation(field.validation)}
/>
);
// Date picker.
case enumDynamicFieldTypes.date.value:
return (
<SimpleDatePicker
key={id}
name={fieldName}
setData={setData}
date={fieldValue as Date}
hasTime
label={getTrans(field.label)}
/>
);
// Color picker.
case enumDynamicFieldTypes.color.value:
return (
<SimpleColorPicker
key={id}
name={fieldName}
setData={setData}
value={toStr(fieldValue)}
label={getTrans(field.label)}
required={extractRequiredValidation(field.validation)}
/>
);
// Model select.
case enumDynamicFieldTypes.model.value:
return (
<DynamicWrapperModelSelect
key={id}
field={field}
fieldName={fieldName}
fieldValue={fieldValue}
setData={setData}
getTrans={getTrans}
/>
);
// Static route select.
case enumDynamicFieldTypes.staticroute.value:
return (
<StaticRouteSelect
key={id}
name={fieldName}
label={getTrans(field.label)}
selected={fieldValue as number}
setData={setData}
required={extractRequiredValidation(field.validation)}
/>
);
default: {
// Check in custom types.
const customInput = DynamicInputRegistry.get(
typeEnum?.name ?? "type",
fieldName,
fieldValue,
field,
setData,
parentErrors,
);
if (customInput) {
return <Fragment key={id}>{customInput}</Fragment>;
}
// Show message if no type is matching.
return (
<p key={id} className="text-muted-foreground text-sm">
{transUnsupportedType} {typeEnum?.label ?? field.type}
</p>
);
}
}
})}
</div>
);
}