import Joi from "joi"; import React, { useEffect } from "react"; import { Navigate, useParams } from "react-router-dom"; import { toast } from "react-toastify"; import { useTranslation } from "react-i18next"; import { Namespaces } from "../../../i18n/i18n"; import { InputType } from "../../../components/common/Input"; import { renderInput, renderButton, renderError, renderSelect, renderInputNumber, renderInputTextarea, renderGlossaryPicker, renderSequencePicker, } from "../../../components/common/formHelpers"; import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef"; import customFieldsService, { numberParams, textParams, } from "./services/customFieldsService"; import Option from "../../../components/common/option"; import { GeneralIdRef } from "./../../../utils/GeneralIdRef"; import { CustomFieldValue, SystemGlossaries, } from "../glossary/services/glossaryService"; import Loading from "../../../components/common/Loading"; import { useFormWithGuard } from "../../../components/common/useFormRouter"; interface CustomFieldDetailsProps { editMode?: boolean; } const CustomFieldDetails: React.FC = ({ editMode = false, }) => { const { customFieldId } = useParams<{ customFieldId: string }>(); const { t } = useTranslation(Namespaces.Common); const labelName = t("Name"); const labelFieldType = t("FieldType"); const labelMultiLine = t("MultiLine"); const labelDefaultValue = t("DefaultValue"); const labelMinValue = t("MinimumValue"); const labelMaxValue = t("MaximumValue"); const labelStep = t("Step"); const labelRequired = t("Required"); const labelMinEntries = t("MinEntries"); const labelMaxEntries = t("MaxEntriesEmptyUnlimited"); let labelRefElementId = t("SequenceFormGlossary"); const labelApply = t("Save"); const labelSave = t("SaveAndClose"); const form = useFormWithGuard({ loaded: false, data: { name: "", fieldType: "Text", defaultValue: "", multiLine: false, minEntries: 0, maxEntries: 1, refElementId: undefined, minValue: undefined, maxValue: undefined, step: undefined, required: false, }, errors: {}, redirect: "", }); form.schema = { name: Joi.string().required().max(450).label(labelName), fieldType: Joi.string().required().label(labelFieldType), multiLine: Joi.boolean().label(labelMultiLine), minEntries: Joi.number().min(0).label(labelMinEntries), maxEntries: Joi.number().empty("").label(labelMaxEntries), refElementId: Joi.when("fieldType", { is: Joi.string().valid("Sequence"), then: Joi.object({ id: Joi.optional(), guid: Joi.optional(), }).required(), }).when("fieldType", { is: Joi.string().valid("Glossary"), then: Joi.array() .min(1) .items( Joi.object({ displayValue: Joi.string().optional(), value: Joi.object({ id: Joi.optional(), guid: Joi.optional(), }).required(), }), ) .required(), }), minValue: Joi.number().allow("").label(labelMinValue), maxValue: Joi.number().allow("").label(labelMaxValue), step: Joi.number().optional().allow("").min(0).label(labelStep), required: Joi.boolean().label(labelRequired), //defaultValue: Joi.string().allow("").label(labelDefaultValue) defaultValue: Joi.when("fieldType", { is: Joi.string().valid("Number"), then: Joi.when("minValue", { is: Joi.any().valid(null, ""), then: Joi.number(), otherwise: Joi.number() .min(Joi.ref("minValue")) .message(t("DefaultMustBeGreaterThanOrEqualToMinimumValue")), }) .when("maxValue", { is: Joi.any().valid(null, ""), then: Joi.number(), otherwise: Joi.number() .max(Joi.ref("maxValue")) .message(t("DefaultMustBeLessThanOrEqualToMaximumValue")), }) .allow(""), otherwise: Joi.string().allow(""), }).label(labelDefaultValue), }; const isEditMode = () => { return editMode; }; useEffect(() => { const loadData = async () => { if (customFieldId !== undefined) { try { const loadedData = await customFieldsService.getField( BigInt(customFieldId), ); if (loadedData) { const newData = { ...form.state.data }; newData.name = loadedData.name; newData.fieldType = loadedData.fieldType; newData.defaultValue = loadedData.defaultValue; newData.minEntries = loadedData.minEntries; newData.maxEntries = loadedData.maxEntries; switch (newData.fieldType) { case "Glossary": let convertedRefElementId: CustomFieldValue = { value: loadedData.refElementId, }; newData.refElementId = [convertedRefElementId]; newData.required = loadedData.minEntries > 0; break; case "Sequence": newData.refElementId = loadedData.refElementId; break; case "Domain": newData.required = loadedData.minEntries > 0; break; } if (loadedData.parameters !== undefined) { switch (newData.fieldType) { case "Number": newData.required = loadedData.minEntries > 0; const parameters: numberParams = JSON.parse( loadedData.parameters, ); newData.minValue = parameters.minValue ?? undefined; newData.maxValue = parameters.maxValue ?? undefined; newData.step = parameters.step ?? undefined; break; case "Text": const textParameters: textParams = JSON.parse( loadedData.parameters, ); newData.multiLine = textParameters.multiLine ?? false; break; } } form.setState({ loaded: true, data: newData }); } else { form.setState({ loaded: false }); } } catch (ex: any) { form.handleGeneralError(ex); } } if (!editMode) form.setState({ loaded: true }); }; loadData(); }, [customFieldId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps const doSubmit = async (buttonName: string) => { try { const { name, fieldType } = form.state.data; const nameStr = typeof name === "string" ? name : ""; const fieldTypeStr = typeof fieldType === "string" ? fieldType : ""; let { refElementId, defaultValue, minEntries, maxEntries, required } = form.state.data; let numberParams: numberParams | undefined = undefined; let textParams: textParams | undefined = undefined; let params; let refElementIdValue: GeneralIdRef | undefined; switch (fieldTypeStr) { case "Sequence": minEntries = 1; maxEntries = 1; defaultValue = ""; refElementIdValue = refElementId as GeneralIdRef; break; case "FormTemplate": minEntries = 1; maxEntries = 1; defaultValue = ""; break; case "Domain": minEntries = required ? 1 : 0; maxEntries = maxEntries === 0 ? undefined : maxEntries; defaultValue = ""; break; case "Glossary": minEntries = required ? 1 : 0; maxEntries = maxEntries === 0 ? undefined : maxEntries; defaultValue = ""; refElementIdValue = (refElementId as CustomFieldValue[])[0] .value as GeneralIdRef; break; case "Text": minEntries = 1; maxEntries = 1; let { multiLine } = form.state.data; textParams = { multiLine: Boolean(multiLine) }; params = textParams; refElementIdValue = undefined; break; case "Number": refElementIdValue = undefined; let { minValue, maxValue, step } = form.state.data; const minValueNum = minValue === null || minValue === undefined || minValue === "" ? undefined : Number(minValue); const maxValueNum = maxValue === null || maxValue === undefined || maxValue === "" ? undefined : Number(maxValue); const stepNum = step === null || step === undefined || step === "" ? undefined : Number(step); numberParams = { minValue: minValueNum, maxValue: maxValueNum, step: stepNum, }; params = numberParams; minEntries = required ? 1 : 0; maxEntries = 1; break; default: refElementIdValue = undefined; } const minEntriesValue = typeof minEntries === "number" ? minEntries : minEntries === undefined || minEntries === null || minEntries === "" ? 0 : Number(minEntries); const cleanMaxEntries: Number | undefined = maxEntries === "" ? undefined : Number(maxEntries); const defaultValueStr = typeof defaultValue === "string" ? defaultValue : defaultValue === undefined || defaultValue === null ? "" : String(defaultValue); if (isEditMode()) { var generalIdRef = MakeGeneralIdRef(BigInt(customFieldId!)); const response = await customFieldsService.putField( generalIdRef, nameStr, fieldTypeStr, defaultValueStr, minEntriesValue, cleanMaxEntries, refElementIdValue, params, ); if (response) { toast.info(t("CustomFieldEdited")); } } else { const response = await customFieldsService.postField( nameStr, fieldTypeStr, defaultValueStr, minEntriesValue, cleanMaxEntries, refElementIdValue, params, ); if (response) { toast.info(t("NewCustomFieldAdded")); } } if (buttonName === "save") form.setState({ redirect: "/customfields" }); form.markAsSaved(); } catch (ex: any) { form.handleGeneralError(ex); } }; const handleSubmit = (e: React.FormEvent) => { form.handleSubmit(e, doSubmit); }; if (form.state.redirect) return ; const { fieldType } = form.state.data; const fieldTypeValue = typeof fieldType === "string" ? fieldType : ""; let mode = t("Add"); if (isEditMode()) mode = t("Edit"); const fieldTypeOptions: Option[] = [ { _id: "Text", name: t("Text") }, { _id: "Number", name: t("Number") }, { _id: "Sequence", name: t("Sequence") }, { _id: "FormTemplate", name: t("FormTemplate") }, { _id: "Glossary", name: t("Glossary") }, { _id: "Domain", name: t("Domain") }, ]; switch (fieldTypeValue) { case "Sequence": labelRefElementId = t("Sequence"); break; case "FormTemplate": labelRefElementId = t("Form"); break; case "Glossary": labelRefElementId = t("Glossary"); break; } return (

{mode} {t("CustomField")}

{renderError("_general", form.state.errors)} {renderInput( "name", labelName, form.state.data, form.state.errors, InputType.text, false, "", "", 0, true, undefined, form.handleChange, )} {renderSelect( "fieldType", labelFieldType, form.state.data, form.state.errors, fieldTypeOptions, form.handleSelectChange, )} {fieldTypeValue === "Domain" && ( <> {renderInput( "required", labelRequired, form.state.data, form.state.errors, InputType.checkbox, false, "", "", 0, true, undefined, form.handleChange, )} {renderInputNumber( "maxEntries", labelMaxEntries, form.state.data, form.state.errors, false, "", undefined, undefined, 1, form.handleChange, )} )} {fieldTypeValue === "Glossary" && ( <> {renderGlossaryPicker( true, "refElementId", labelRefElementId, form.state.data, form.state.errors, 1, SystemGlossaries, form.handleGlossaryPickerChange, )} {renderInput( "required", labelRequired, form.state.data, form.state.errors, InputType.checkbox, false, "", "", 0, true, undefined, form.handleChange, )} {renderInputNumber( "maxEntries", labelMaxEntries, form.state.data, form.state.errors, false, "", undefined, undefined, 1, form.handleChange, )} )} {fieldTypeValue === "Sequence" && ( <> {renderSequencePicker( true, "refElementId", labelRefElementId, form.state.data, form.state.errors, form.handlePickerChange, )} )} {fieldTypeValue === "Text" && ( <> {renderInput( "multiLine", labelMultiLine, form.state.data, form.state.errors, InputType.checkbox, false, "", "", 0, true, undefined, form.handleChange, )} {form.state.data.multiLine === true && renderInputTextarea( true, "defaultValue", labelDefaultValue, form.state.data, form.state.errors, false, "", form.handleTextAreaChange, )} {form.state.data.multiLine === false && renderInput( "defaultValue", labelDefaultValue, form.state.data, form.state.errors, InputType.text, false, "", "", 0, true, undefined, form.handleChange, )} )} {fieldTypeValue === "Number" && ( <> {renderInput( "required", labelRequired, form.state.data, form.state.errors, InputType.checkbox, false, "", "", 0, true, undefined, form.handleChange, )} {renderInputNumber( "minValue", labelMinValue, form.state.data, form.state.errors, false, "", undefined, undefined, 1, form.handleChange, )} {renderInputNumber( "maxValue", labelMaxValue, form.state.data, form.state.errors, false, "", undefined, undefined, 1, form.handleChange, )} {renderInput( "step", labelStep, form.state.data, form.state.errors, InputType.number, false, "", "", 0, true, undefined, form.handleChange, )} {renderInputNumber( "defaultValue", labelDefaultValue, form.state.data, form.state.errors, false, "", undefined, undefined, 1, form.handleChange, )} )} {![ "Domain", "Glossary", "Sequence", "FormTemplate", "Text", "Number", ].includes(fieldTypeValue) && ( <> {renderInput( "defaultValue", labelDefaultValue, form.state.data, form.state.errors, InputType.text, false, "", "", 0, true, undefined, form.handleChange, )} {renderInput( "minEntries", labelMinEntries, form.state.data, form.state.errors, InputType.number, false, "", "", 0, true, undefined, form.handleChange, )} {renderInput( "maxEntries", labelMaxEntries, form.state.data, form.state.errors, InputType.number, false, "", "", 0, true, undefined, form.handleChange, )} )} {isEditMode() && renderButton(labelApply, form.state.errors, "apply")} {renderButton(labelSave, form.state.errors, "save")}
); }; export default CustomFieldDetails;