first commit

This commit is contained in:
2026-01-19 13:08:58 +03:30
commit 850b4a3f1e
293 changed files with 51775 additions and 0 deletions

View File

@@ -0,0 +1,416 @@
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) {
onChange({
key1: defaultItems.map((item: any) => item.key),
key2: defaultItems.map((item: any) => item.secondaryKey),
...(tertiaryKey
? {
key3: defaultItems.map(
(item: any) => item.tertiaryKey
),
}
: {}),
});
} 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}
/>
</>
);
};