ldc-groupe/resources/ts/back/Components/DynamicPages/DynamicInputs.tsx

374 lines
17 KiB
TypeScript

// * Packages
import { usePage } from "@inertiajs/react";
import { useEffect, useRef } from "react";
// * Other
import SimpleString from "@/back/Components/Inputs/SimpleString";
import SimpleNumber from "@/back/Components/Inputs/SimpleNumber";
import SimpleSwitch from "@/back/Components/Inputs/SimpleSwitch";
import SimpleWysiwyg from "@/back/Components/Inputs/Wysiwyg/SimpleWysiwyg";
import CompleteInputFile from "@/back/Components/Inputs/CompleteInputFile";
import DynamicList from "@/back/Components/DynamicPages/DynamicList";
import SimpleTextarea from "@/back/Components/Inputs/SimpleTextarea";
import SimpleDatePicker from "@/back/Components/Inputs/SimpleDatePicker";
import SimpleColorPicker from "@/back/Components/Inputs/SimpleColorPicker";
import SimpleYoutubeId from "@/back/Components/Inputs/SimpleYoutubeId";
import SimpleVimeoId from "@/back/Components/Inputs/SimpleVimeoId";
import ModelSelect from "@/back/Components/Inputs/ModelSelect";
import {
ConfigField,
DynamicFieldTypes,
DynamicInternalField,
LaravelEnum,
} from "@/back/types/global";
import str from "@/hooks/use-string";
import useTrans from "@/hooks/use-translations";
import {
extractExcludedIdFromExists,
extractLaravelValidationValue,
extractMinMaxFromValidation,
extractRequiredValidation,
extractTableFromExists,
} from "@/hooks/use-laravel-validation";
type 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 = null,
isChildren = false,
setData,
reset,
parentErrors,
}: DynamicInputsProps) {
// Enums.
const enumDynamicFieldTypes = usePage().props.enumDynamicFieldTypes as DynamicFieldTypes;
const enumElementPosition = usePage().props.enumElementPosition as LaravelEnum;
// Translations.
const transAssociateTo = useTrans("back.form_associate_to");
const transUnsupportedType = useTrans("back.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();
};
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={String(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={String(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}
model="DynamicPage"
required={extractRequiredValidation(
field.validation,
)}
label={getTrans(field.label)}
value={String(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={String(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={String(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={enumDynamicFieldTypes.file.value}
/>
);
// VimeoId input
case enumDynamicFieldTypes.vimeoid.value:
return (
<SimpleVimeoId
name={fieldName}
setData={setData}
value={String(fieldValue)}
required={extractRequiredValidation(
field.validation,
)}
/>
);
// YoutubeId input
case enumDynamicFieldTypes.youtubeid.value:
return (
<SimpleYoutubeId
name={fieldName}
setData={setData}
value={String(fieldValue)}
required={extractRequiredValidation(
field.validation,
)}
/>
);
// Date picker.
case enumDynamicFieldTypes.date.value:
return (
<SimpleDatePicker
name={fieldName}
setData={setData}
date={fieldValue as Date}
hasTime={true}
label={getTrans(field.label)}
/>
);
// Color picker.
case enumDynamicFieldTypes.color.value:
return (
<SimpleColorPicker
name={fieldName}
setData={setData}
value={String(fieldValue)}
label={getTrans(field.label)}
required={extractRequiredValidation(field.validation)}
/>
);
// Model select.
case enumDynamicFieldTypes.model.value:
// Extract only the model name from the validation.
const targetModel = extractTableFromExists(field.validation) || "dynamic_pages";
// Add a custom prefix in the last part of the name.
const newName = fieldName.replace(/([^.\s]+)$/, "reserved_$1");
// Set a state at false.
const initializedRef = useRef(false);
// Set the model name in the custom key only once.
useEffect(() => {
if (initializedRef.current) return;
initializedRef.current = true;
// If the value isn't already present in content.
if (content && !content[`reserved_${field.key}` as keyof typeof content]) {
setData(newName, targetModel);
}
}, [newName, targetModel]);
return (
<ModelSelect
name={fieldName}
targetModel={targetModel}
label={getTrans(field.label)}
exclude={extractExcludedIdFromExists(field.validation)}
placeholder="ex: John Doe"
selected={Number(fieldValue)}
required={extractRequiredValidation(field.validation)}
setData={setData}
/>
);
default:
return (
<p
key={id}
className="text-muted-foreground text-sm"
>
{transUnsupportedType}{" "}
{typeEnum?.label ?? field.type}
</p>
);
}
})}
</div>
);
}