webui/src/modules/manager/glossary/GlossariesDetails.tsx
2026-02-12 18:12:55 +00:00

276 lines
8.3 KiB
TypeScript

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 { GeneralIdRef, MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
import glossariesService, {
CustomFieldValue,
Glossary,
SystemGlossaries,
} from "./services/glossaryService";
import { CustomField } from "../customfields/services/customFieldsService";
import Loading from "../../../components/common/Loading";
import {
renderError,
renderButton,
renderInput,
renderCustomFields,
renderCustomFieldsEditor,
} from "../../../components/common/formHelpers";
import { useFormWithGuard } from "../../../components/common/useFormRouter";
interface GlossariesDetailsProps {
editMode?: boolean;
}
const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
editMode = false,
}) => {
const { glossaryId } = useParams<{ glossaryId: string }>();
const { t } = useTranslation(Namespaces.Common);
const labelName = t("Name");
const labelChildCustomFieldDefinition = t("CustomFieldForChildEntries");
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useFormWithGuard({
loaded: false,
data: {
id: undefined,
guid: undefined,
name: "",
parent: undefined,
childCustomFieldDefinition: [],
},
errors: {},
redirect: "",
});
form.schema = {
id: Joi.optional(),
guid: Joi.optional(),
name: Joi.string().required().max(450).label(labelName),
parent: Joi.optional(),
childCustomFieldDefinition: Joi.optional().label(
labelChildCustomFieldDefinition,
),
};
useEffect(() => {
const loadData = async () => {
const newData = { ...form.state.data };
if (editMode) {
const generalIdRef = MakeGeneralIdRef(BigInt(glossaryId!));
try {
const loadedData =
await glossariesService.getGlossaryItem(generalIdRef);
if (loadedData) {
newData.name = loadedData.name;
newData.parent = loadedData.parent;
newData.id = loadedData.id;
newData.guid = loadedData.guid;
newData.childCustomFieldDefinition =
loadedData.childCustomFieldDefinition ?? [];
const parentGlossary = newData.parent as Glossary | undefined;
form.setCustomFieldValues(
newData,
loadedData.customFieldValues,
parentGlossary?.childCustomFieldDefinition ?? [],
);
}
} catch (ex: any) {
form.handleGeneralError(ex);
}
} else {
const generalIdRef = MakeGeneralIdRef(BigInt(glossaryId!));
try {
const loadedData =
await glossariesService.getGlossaryItem(generalIdRef);
if (loadedData) {
newData.parent = loadedData;
}
} catch (ex: any) {
form.handleGeneralError(ex);
}
}
form.setState({
loaded: true,
data: newData,
customFields: (newData.parent as Glossary | undefined)
?.childCustomFieldDefinition,
});
};
loadData();
}, [glossaryId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
const handleAdd = (customfield: CustomField) => {
const newData = { ...form.state.data };
const childDefs =
(newData.childCustomFieldDefinition as CustomField[]) ?? [];
childDefs.push(customfield);
newData.childCustomFieldDefinition = childDefs;
form.setState({ data: newData });
};
const handleDelete = (fieldToDelete: CustomField) => {
const newData = { ...form.state.data };
if (fieldToDelete) {
const childDefs =
(newData.childCustomFieldDefinition as CustomField[]) ?? [];
newData.childCustomFieldDefinition = childDefs.filter(
(x) => x !== fieldToDelete,
);
}
form.setState({ data: newData });
};
const doSubmit = async (buttonName: string) => {
try {
const { id, guid, name, parent, childCustomFieldDefinition } =
form.state.data;
const nameStr = typeof name === "string" ? name : "";
const parentGlossary = parent as Glossary | undefined;
const childDefs = (childCustomFieldDefinition as CustomField[]) ?? [];
const idValue = typeof id === "bigint" ? id : undefined;
const guidValue = typeof guid === "string" ? guid : undefined;
const customfieldValues = form.CustomFieldValues();
if (editMode) {
const generalIdRef = MakeGeneralIdRef(idValue, guidValue);
const response = await glossariesService.putGlossaryItem(
generalIdRef,
parentGlossary
? MakeGeneralIdRef(parentGlossary.id, parentGlossary.guid)
: undefined,
nameStr,
childDefs,
customfieldValues,
);
if (response) {
toast.info(t("GlossaryItemEdited"));
}
} else {
const generalIdRef = parentGlossary
? MakeGeneralIdRef(parentGlossary.id, parentGlossary.guid)
: SystemGlossaries;
const response = await glossariesService.postGlossaryItem(
generalIdRef,
nameStr,
childDefs,
customfieldValues,
);
if (response) {
toast.info(t("NewGlossaryItemAdded"));
}
}
const navigateId = parentGlossary ? parentGlossary.id.toString() : "";
if (buttonName === "save")
form.setState({ redirect: "/glossaries/" + navigateId });
form.markAsSaved();
} catch (ex: any) {
form.handleGeneralError(ex);
}
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
form.handleSubmit(e, doSubmit);
};
const { loaded, redirect, data } = form.state;
if (redirect) return <Navigate to={redirect} />;
let mode = t("Add");
if (editMode) mode = t("Edit");
const parentGlossary = data.parent as Glossary | undefined;
const handleCustomFieldChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
if (e.target instanceof HTMLTextAreaElement) {
form.handleTextAreaChange(e as React.ChangeEvent<HTMLTextAreaElement>);
} else {
form.handleCustomFieldChange(e as React.ChangeEvent<HTMLInputElement>);
}
};
const getCustomFieldType = (
field: CustomFieldValue,
customFields: CustomField[],
) => {
return form.getCustomFieldType(field as any, customFields);
};
const handleCustomFieldPickerChange = (
name: string,
value: GeneralIdRef | CustomFieldValue[],
) => {
if (Array.isArray(value)) {
form.handleGlossaryPickerChange(name, value);
} else {
form.handlePickerChange(name, value as GeneralIdRef);
}
};
return (
<Loading loaded={loaded}>
<h1>
{mode} {t("GlossaryItem")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(
"name",
labelName,
form.state.data,
form.state.errors,
InputType.text,
false,
"",
"",
0,
true,
undefined,
form.handleChange,
)}
{renderCustomFields(
parentGlossary?.childCustomFieldDefinition,
form.state.data,
form.state.errors,
handleCustomFieldChange,
handleCustomFieldPickerChange,
getCustomFieldType,
)}
<hr />
{renderCustomFieldsEditor(
"childCustomFieldDefinition",
labelChildCustomFieldDefinition,
form.state.data,
form.state.errors,
(data.childCustomFieldDefinition as CustomField[]) ?? [],
handleAdd,
handleDelete,
)}
<br />
{editMode && renderButton(labelApply, form.state.errors, "apply")}
{renderButton(labelSave, form.state.errors, "save")}
</form>
</Loading>
);
};
export default GlossariesDetails;