2026-07-09 17:30:05 +02:00
|
|
|
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";
|
2026-07-09 17:31:24 +02:00
|
|
|
import type {
|
|
|
|
|
ConfigField,
|
|
|
|
|
DynamicFieldType,
|
|
|
|
|
DynamicInternalField,
|
2026-07-09 17:30:05 +02:00
|
|
|
} 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
|
2026-07-09 17:31:24 +02:00
|
|
|
key={id}
|
2026-07-09 17:30:05 +02:00
|
|
|
name={fieldName}
|
|
|
|
|
setData={setData}
|
|
|
|
|
value={toStr(fieldValue)}
|
|
|
|
|
required={extractRequiredValidation(field.validation)}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
// YoutubeId input
|
|
|
|
|
case enumDynamicFieldTypes.youtubeid.value:
|
|
|
|
|
return (
|
|
|
|
|
<SimpleYoutubeId
|
2026-07-09 17:31:24 +02:00
|
|
|
key={id}
|
2026-07-09 17:30:05 +02:00
|
|
|
name={fieldName}
|
|
|
|
|
setData={setData}
|
|
|
|
|
value={toStr(fieldValue)}
|
|
|
|
|
required={extractRequiredValidation(field.validation)}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
// Date picker.
|
|
|
|
|
case enumDynamicFieldTypes.date.value:
|
|
|
|
|
return (
|
|
|
|
|
<SimpleDatePicker
|
2026-07-09 17:31:24 +02:00
|
|
|
key={id}
|
2026-07-09 17:30:05 +02:00
|
|
|
name={fieldName}
|
|
|
|
|
setData={setData}
|
|
|
|
|
date={fieldValue as Date}
|
|
|
|
|
hasTime
|
|
|
|
|
label={getTrans(field.label)}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
// Color picker.
|
|
|
|
|
case enumDynamicFieldTypes.color.value:
|
|
|
|
|
return (
|
|
|
|
|
<SimpleColorPicker
|
2026-07-09 17:31:24 +02:00
|
|
|
key={id}
|
2026-07-09 17:30:05 +02:00
|
|
|
name={fieldName}
|
|
|
|
|
setData={setData}
|
|
|
|
|
value={toStr(fieldValue)}
|
|
|
|
|
label={getTrans(field.label)}
|
|
|
|
|
required={extractRequiredValidation(field.validation)}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
// Model select.
|
|
|
|
|
case enumDynamicFieldTypes.model.value:
|
|
|
|
|
return (
|
|
|
|
|
<DynamicWrapperModelSelect
|
2026-07-09 17:31:24 +02:00
|
|
|
key={id}
|
2026-07-09 17:30:05 +02:00
|
|
|
field={field}
|
|
|
|
|
fieldName={fieldName}
|
|
|
|
|
fieldValue={fieldValue}
|
|
|
|
|
setData={setData}
|
|
|
|
|
getTrans={getTrans}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
// Static route select.
|
|
|
|
|
case enumDynamicFieldTypes.staticroute.value:
|
|
|
|
|
return (
|
|
|
|
|
<StaticRouteSelect
|
2026-07-09 17:31:24 +02:00
|
|
|
key={id}
|
2026-07-09 17:30:05 +02:00
|
|
|
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>
|
|
|
|
|
);
|
|
|
|
|
}
|