webui/src/components/pickers/GlossaryPicker.tsx

139 lines
3.6 KiB
TypeScript

import React, { useEffect, useState, useCallback } from "react";
import Select from "../common/Select";
import Option from "../common/option";
import { GeneralIdRef, MakeGeneralIdRef } from "../../utils/GeneralIdRef";
import glossariesService, {
CustomFieldValue,
SystemGlossaries,
} from "../../modules/manager/glossary/services/glossaryService";
import MultiSelect from "../common/MultiSelect";
interface GlossaryPickerProps {
includeLabel?: boolean;
name: string;
label: string;
rootItem?: GeneralIdRef;
error?: string;
values: CustomFieldValue[];
maxEntries?: number;
onChange?: (name: string, values: CustomFieldValue[]) => void;
}
export default function GlossaryPicker({
includeLabel,
name,
label,
rootItem,
error,
values,
maxEntries,
onChange,
}: GlossaryPickerProps) {
const [options, setOptions] = useState<Option[]>([]);
const [selectedOptions, setSelectedOptions] = useState<Option[]>([]);
useEffect(() => {
async function load() {
const actualRootItem = rootItem ?? SystemGlossaries;
const glossary = await glossariesService.getGlossaryItem(actualRootItem);
if (glossary) {
const opts: Option[] = glossary.children.map(
(x: { id: any; name: any }) => ({
_id: x.id,
name: x.name,
}),
);
const selected: Option[] = [];
if (values) {
for (const option of values) {
const foundOption = opts.filter(
(x) =>
Number(x._id) === Number((option.value as GeneralIdRef).id),
)[0];
if (foundOption) selected.push(foundOption);
}
}
setOptions(opts);
setSelectedOptions(selected);
}
}
load();
}, [rootItem, values]);
const doOnChange = useCallback(
(newSelectedOptions: Option[]) => {
const vals: CustomFieldValue[] = newSelectedOptions.map((x) => ({
value: MakeGeneralIdRef(x._id as unknown as bigint),
displayValue: x.name,
}));
if (onChange) onChange(name, vals);
},
[onChange, name],
);
const handleChange = useCallback(
(e: React.ChangeEvent<HTMLSelectElement>) => {
const input = e.currentTarget;
const id: number = Number(input.value);
const newSelected = options.filter((x) => x._id === id);
setSelectedOptions(newSelected);
doOnChange(newSelected);
},
[options, doOnChange],
);
const handleAdd = useCallback(
(item: Option) => {
const newSelected = [...selectedOptions, item];
setSelectedOptions(newSelected);
doOnChange(newSelected);
},
[selectedOptions, doOnChange],
);
const handleDelete = useCallback(
(item: Option) => {
const newSelected = selectedOptions.filter((x) => x !== item);
setSelectedOptions(newSelected);
doOnChange(newSelected);
},
[selectedOptions, doOnChange],
);
if (maxEntries === 1) {
const value = selectedOptions[0]?._id;
return (
<Select
includeLabel={includeLabel}
name={name}
label={label}
error={error}
value={value}
options={options}
includeBlankFirstEntry={true}
onChange={handleChange}
/>
);
} else {
return (
<MultiSelect
includeLabel={includeLabel}
name={name}
label={label}
error={error}
options={options}
selectedOptions={selectedOptions}
onAdd={handleAdd}
onDelete={handleDelete}
/>
);
}
}