import {
Location,
useGetLocationChildrenQuery,
} from '@/shared/api/location/client';
import { Helpers } from '@/shared/lib';
import {
useResetLocationFilterSelect,
useSetLocation,
} from '@entities/LocationFiltersList/lib/hooks';
import { Select, SelectProps } from '@shared/components';
import { useEffect, useMemo, useState } from 'react';
export type SideFilterSelectProps = {
value: string[] | string;
onChange: SelectProps['onChange'];
parentIds?: string[] | string;
isRoot?: boolean;
isFloor?: boolean;
onSelectedLocationIdsChange?: (locationIds: number[]) => void;
} & Omit<SelectProps, 'onChange' | 'value' | 'options'>;
const getLocationLabel = (
option: Location,
parentIds?: string[] | string,
): string => {
const hasMultipleParents = Array.isArray(parentIds) && parentIds.length > 1;
if (!hasMultipleParents || !option.pathName) {
return option.name ?? '';
}
return `${option.name}, ${option.pathName}`;
};
const normalizeValue = (value: string[] | string): string[] => {
if (Array.isArray(value)) {
return value;
}
return value ? [value] : [];
};
const toFiniteNumber = (value: unknown): number | null => {
const numberValue = Number(value);
return Number.isFinite(numberValue) ? numberValue : null;
};
export const SideFilterSelect = ({
value,
onChange,
disabled,
label,
parentIds,
isRoot = false,
isFloor = false,
onSelectedLocationIdsChange,
...rest
}: SideFilterSelectProps) => {
const [location, setLocation] = useState<Location[]>([]);
const requestParams = isRoot
? {}
: {
parentId:
typeof parentIds === 'object'
? Helpers.convertStringsToNumbers(parentIds)
: [Number(parentIds)],
};
const requestOptions = isRoot
? {}
: {
skip: typeof parentIds === 'object' ? !parentIds?.length : !parentIds,
};
const { data, status } = useGetLocationChildrenQuery(requestParams, {
...requestOptions,
refetchOnMountOrArgChange: true,
});
useSetLocation({
entity: data,
status,
setter: setLocation,
isFloor,
});
useResetLocationFilterSelect({
setter: setLocation,
ids: parentIds ?? '',
});
const selectedTreeIds = useMemo(() => normalizeValue(value), [value]);
const selectedLocationIds = useMemo(() => {
const selectedTreeIdSet = new Set(selectedTreeIds);
return location
.filter((option) => selectedTreeIdSet.has(String(option.treeId)))
.map((option) => toFiniteNumber(option.id))
.filter((id): id is number => id !== null);
}, [location, selectedTreeIds]);
useEffect(() => {
onSelectedLocationIdsChange?.(selectedLocationIds);
}, [onSelectedLocationIdsChange, selectedLocationIds]);
const innerOption = location?.map((option) => ({
value: String(option.treeId),
label: getLocationLabel(option, parentIds),
}));
return (
<Select
label={label}
options={innerOption}
value={value}
onChange={onChange}
disabled={disabled || (!isRoot && !location.length)}
{...rest}
/>
);
};