425 lines
13 KiB
TypeScript
425 lines
13 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { useApiRequest } from "../../utils/useApiRequest";
|
|
import AutoComplete from "../AutoComplete/AutoComplete";
|
|
import { getFaPermissions } from "../../utils/getFaPermissions";
|
|
import { getNestedValue } from "../../utils/getNestedValue";
|
|
|
|
type FormEnterLocationsProps = {
|
|
title: string;
|
|
api: string;
|
|
error?: boolean;
|
|
errorMessage?: any;
|
|
multiple?: boolean;
|
|
onChange?: (data: any) => void;
|
|
onChangeValue?: (data: any) => void;
|
|
keyField?: string;
|
|
secondaryKey?: string | string[];
|
|
tertiaryKey?: string | string[];
|
|
valueField?: string | string[];
|
|
valueField2?: string | string[];
|
|
valueField3?: string | string[];
|
|
filterAddress?: string[];
|
|
filterValue?: string[];
|
|
defaultKey?: string | number | any[];
|
|
valueTemplate?: string;
|
|
valueTemplateProps?: Array<{ [key: string]: "string" | "number" }>;
|
|
groupBy?: string | string[];
|
|
groupFunction?: (item: any) => string;
|
|
selectField?: boolean;
|
|
};
|
|
|
|
export const FormApiBasedAutoComplete = ({
|
|
title,
|
|
api,
|
|
error,
|
|
errorMessage,
|
|
onChange,
|
|
onChangeValue,
|
|
keyField = "id",
|
|
secondaryKey,
|
|
tertiaryKey,
|
|
valueField = "name",
|
|
valueField2,
|
|
valueField3,
|
|
defaultKey,
|
|
multiple = false,
|
|
filterValue,
|
|
filterAddress,
|
|
valueTemplate,
|
|
valueTemplateProps,
|
|
groupBy,
|
|
groupFunction,
|
|
selectField = false,
|
|
}: FormEnterLocationsProps) => {
|
|
const [data, setData] = useState<any>([]);
|
|
const [selectedKeys, setSelectedKeys] = useState<(string | number)[]>([]);
|
|
const [groupedItemsMap, setGroupedItemsMap] = useState<
|
|
Map<string | number, any[]>
|
|
>(new Map());
|
|
|
|
const formatValue = (value: any, fieldKey: string) => {
|
|
if (!valueTemplate || !valueTemplateProps) return value;
|
|
|
|
const templateProp = valueTemplateProps.find((prop) => prop[fieldKey]);
|
|
if (!templateProp) return value;
|
|
|
|
const fieldType = templateProp[fieldKey];
|
|
|
|
if (fieldType === "number") {
|
|
const numValue = typeof value === "number" ? value : Number(value);
|
|
return !isNaN(numValue) ? numValue.toLocaleString() : String(value);
|
|
} else if (fieldType === "string") {
|
|
let result = String(value);
|
|
if (typeof value === "string" && value.includes(",")) {
|
|
result = value.replace(/,/g, "");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
return value;
|
|
};
|
|
|
|
const { data: apiData } = useApiRequest({
|
|
api: api,
|
|
method: "get",
|
|
params: { page: 1, page_size: 1000 },
|
|
queryKey: [api],
|
|
disableBackdrop: defaultKey ? true : false,
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (apiData?.results) {
|
|
let data;
|
|
|
|
if (filterAddress && filterValue) {
|
|
data = apiData.results?.filter(
|
|
(item: any) =>
|
|
!filterValue.includes(getNestedValue(item, filterAddress))
|
|
);
|
|
} else {
|
|
data = apiData.results;
|
|
}
|
|
const d = data?.map((option: any) => ({
|
|
key: option[keyField],
|
|
secondaryKey: secondaryKey
|
|
? typeof secondaryKey === "string"
|
|
? option[secondaryKey]
|
|
: getNestedValue(option, secondaryKey)
|
|
: undefined,
|
|
tertiaryKey: tertiaryKey
|
|
? typeof tertiaryKey === "string"
|
|
? option[tertiaryKey]
|
|
: getNestedValue(option, tertiaryKey)
|
|
: undefined,
|
|
value: valueTemplate
|
|
? valueTemplate
|
|
.replace(
|
|
/v1/g,
|
|
formatValue(
|
|
valueField === "page"
|
|
? getFaPermissions(option[valueField])
|
|
: typeof valueField === "string"
|
|
? option[valueField]
|
|
: getNestedValue(option, valueField),
|
|
"v1"
|
|
)
|
|
)
|
|
.replace(
|
|
/v2/g,
|
|
formatValue(
|
|
valueField2
|
|
? typeof valueField2 === "string"
|
|
? option[valueField2]
|
|
: getNestedValue(option, valueField2)
|
|
: "",
|
|
"v2"
|
|
)
|
|
)
|
|
.replace(
|
|
/v3/g,
|
|
formatValue(
|
|
valueField3
|
|
? typeof valueField3 === "string"
|
|
? option[valueField3]
|
|
: getNestedValue(option, valueField3)
|
|
: "",
|
|
"v3"
|
|
)
|
|
)
|
|
: `${
|
|
valueField === "page"
|
|
? getFaPermissions(option[valueField])
|
|
: typeof valueField === "string"
|
|
? option[valueField]
|
|
: getNestedValue(option, valueField)
|
|
} ${
|
|
valueField2
|
|
? " - " +
|
|
(typeof valueField2 === "string"
|
|
? option[valueField2]
|
|
: getNestedValue(option, valueField2))
|
|
: ""
|
|
} ${
|
|
valueField3
|
|
? "(" +
|
|
(typeof valueField3 === "string"
|
|
? option[valueField3]
|
|
: getNestedValue(option, valueField3)) +
|
|
")"
|
|
: ""
|
|
}`,
|
|
groupValue: groupBy
|
|
? typeof groupBy === "string"
|
|
? option[groupBy]
|
|
: getNestedValue(option, groupBy)
|
|
: undefined,
|
|
}));
|
|
|
|
let finalData = d;
|
|
|
|
if (groupBy) {
|
|
const grouped = new Map<string | number, typeof d>();
|
|
|
|
d.forEach((item: any) => {
|
|
const groupKey = item.groupValue ?? "";
|
|
if (!grouped.has(groupKey)) {
|
|
grouped.set(groupKey, []);
|
|
}
|
|
grouped.get(groupKey)!.push(item);
|
|
});
|
|
|
|
setGroupedItemsMap(grouped);
|
|
|
|
finalData = [];
|
|
grouped.forEach((items, groupKey) => {
|
|
finalData.push({
|
|
key: `__group__${groupKey}`,
|
|
value: groupFunction ? groupFunction(groupKey) : String(groupKey),
|
|
disabled: true,
|
|
isGroupHeader: true,
|
|
originalGroupKey: groupKey,
|
|
});
|
|
finalData.push(...items);
|
|
});
|
|
} else {
|
|
setGroupedItemsMap(new Map());
|
|
}
|
|
|
|
setData(finalData);
|
|
|
|
const actualDataItems = finalData.filter(
|
|
(item: any) => !item.isGroupHeader && !item.disabled
|
|
);
|
|
|
|
if (defaultKey !== undefined && defaultKey !== null) {
|
|
if (multiple) {
|
|
if (Array.isArray(defaultKey)) {
|
|
if (defaultKey.length === 0) {
|
|
setSelectedKeys([]);
|
|
} else {
|
|
const defaultIds = defaultKey.map((item: any) =>
|
|
typeof item === "object" ? item[keyField] : item
|
|
);
|
|
const defaultItems = actualDataItems.filter((item: any) =>
|
|
defaultIds.includes(item.key)
|
|
);
|
|
setSelectedKeys(defaultItems.map((item: any) => item.key));
|
|
if (onChange) {
|
|
if (secondaryKey) {
|
|
console.log("dksk0", defaultItems);
|
|
onChange(
|
|
defaultItems.map((item: any) => {
|
|
return {
|
|
key: item?.key,
|
|
key2: item?.secondaryKey,
|
|
...(tertiaryKey
|
|
? {
|
|
key3: item?.tertiaryKey,
|
|
}
|
|
: {}),
|
|
};
|
|
})
|
|
);
|
|
if (onChangeValue) {
|
|
onChangeValue(
|
|
defaultItems.map((item: any) => item.value.trim())
|
|
);
|
|
}
|
|
} else {
|
|
onChange(defaultItems.map((item: any) => item.key));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (!Array.isArray(defaultKey)) {
|
|
const keyToFind =
|
|
typeof defaultKey === "object"
|
|
? defaultKey[keyField]
|
|
: defaultKey;
|
|
const defaultItem = actualDataItems.find(
|
|
(item: any) => item.key === keyToFind
|
|
);
|
|
if (defaultItem) {
|
|
setSelectedKeys([keyToFind]);
|
|
if (onChange) {
|
|
if (secondaryKey) {
|
|
onChange({
|
|
key1: defaultItem.key,
|
|
key2: defaultItem.secondaryKey,
|
|
...(tertiaryKey ? { key3: defaultItem.tertiaryKey } : {}),
|
|
});
|
|
} else {
|
|
onChange(keyToFind);
|
|
}
|
|
}
|
|
if (onChangeValue) {
|
|
onChangeValue({
|
|
key1: defaultItem.key,
|
|
key2: defaultItem.secondaryKey,
|
|
...(tertiaryKey ? { key3: defaultItem.tertiaryKey } : {}),
|
|
value: defaultItem.value.trim(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, [apiData]);
|
|
|
|
const handleGroupHeaderClick = (groupKey: string | number) => {
|
|
if (!multiple || !groupBy) return;
|
|
|
|
const groupItems = groupedItemsMap.get(groupKey) || [];
|
|
if (groupItems.length === 0) return;
|
|
|
|
const groupItemKeys = groupItems.map((item: any) => item.key);
|
|
const allGroupItemsSelected = groupItemKeys.every((key) =>
|
|
selectedKeys.includes(key)
|
|
);
|
|
|
|
let newSelectedKeys: (string | number)[];
|
|
|
|
if (allGroupItemsSelected) {
|
|
newSelectedKeys = selectedKeys.filter(
|
|
(key) => !groupItemKeys.includes(key)
|
|
);
|
|
} else {
|
|
const newKeys = groupItemKeys.filter(
|
|
(key) => !selectedKeys.includes(key)
|
|
);
|
|
newSelectedKeys = [...selectedKeys, ...newKeys];
|
|
}
|
|
|
|
setSelectedKeys(newSelectedKeys);
|
|
|
|
if (!onChange) return;
|
|
|
|
const selectedItems = data.filter(
|
|
(item: any) =>
|
|
newSelectedKeys.includes(item.key) &&
|
|
!item.isGroupHeader &&
|
|
!item.disabled
|
|
);
|
|
|
|
if (secondaryKey) {
|
|
onChange(
|
|
selectedItems.map((item: any) => ({
|
|
key1: item.key,
|
|
key2: item.secondaryKey,
|
|
...(tertiaryKey ? { key3: item.tertiaryKey } : {}),
|
|
}))
|
|
);
|
|
if (onChangeValue) {
|
|
onChangeValue(selectedItems.map((item: any) => item.value.trim()));
|
|
}
|
|
} else {
|
|
onChange(newSelectedKeys);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<AutoComplete
|
|
multiselect={multiple}
|
|
selectField={selectField}
|
|
data={data}
|
|
selectedKeys={selectedKeys}
|
|
onChange={(newSelectedKeys) => {
|
|
setSelectedKeys(newSelectedKeys);
|
|
|
|
if (!onChange) return;
|
|
|
|
if (multiple) {
|
|
if (secondaryKey) {
|
|
const selectedItems = data.filter(
|
|
(item: any) =>
|
|
newSelectedKeys.includes(item.key) &&
|
|
!item.isGroupHeader &&
|
|
!item.disabled
|
|
);
|
|
|
|
onChange(
|
|
selectedItems.map((item: any) => ({
|
|
key1: item.key,
|
|
key2: item.secondaryKey,
|
|
...(tertiaryKey ? { key3: item.tertiaryKey } : {}),
|
|
}))
|
|
);
|
|
if (onChangeValue) {
|
|
onChangeValue(
|
|
selectedItems.map((item: any) => item.value.trim())
|
|
);
|
|
}
|
|
} else {
|
|
const validKeys = newSelectedKeys.filter(
|
|
(key) => !String(key).startsWith("__group__")
|
|
);
|
|
onChange(validKeys);
|
|
}
|
|
} else {
|
|
if (secondaryKey) {
|
|
const selectedItem = data.find(
|
|
(item: any) =>
|
|
item.key === newSelectedKeys[0] &&
|
|
!item.isGroupHeader &&
|
|
!item.disabled
|
|
);
|
|
if (onChangeValue) {
|
|
onChangeValue({
|
|
value: selectedItem?.value.trim() ?? "",
|
|
key1: selectedItem?.key ?? "",
|
|
key2: selectedItem?.secondaryKey ?? "",
|
|
...(tertiaryKey
|
|
? { key3: selectedItem?.tertiaryKey ?? "" }
|
|
: {}),
|
|
});
|
|
}
|
|
|
|
if (selectedItem) {
|
|
onChange({
|
|
key1: selectedItem.key,
|
|
key2: selectedItem.secondaryKey,
|
|
...(tertiaryKey ? { key3: selectedItem.tertiaryKey } : {}),
|
|
});
|
|
}
|
|
} else {
|
|
const validKey =
|
|
newSelectedKeys[0] &&
|
|
!String(newSelectedKeys[0]).startsWith("__group__")
|
|
? newSelectedKeys[0]
|
|
: "";
|
|
onChange(validKey);
|
|
}
|
|
}
|
|
}}
|
|
title={title}
|
|
error={error}
|
|
helperText={errorMessage}
|
|
onGroupHeaderClick={handleGroupHeaderClick}
|
|
/>
|
|
</>
|
|
);
|
|
};
|