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 { ChangeEvent, useState } from 'react';
export type SideFilterSelectProps = {
value: string[] | string;
onChange: NonNullable<SelectProps['onChange']>;
parentIds?: string[] | string;
isRoot?: boolean;
isFloor?: boolean;
onSelectedLocationIdsChange?: (locationIds: string[]) => void;
} & Omit<SelectProps, 'onChange' | 'value' | 'options'>;
type LocationEvent = ChangeEvent<{ name?: string; value: unknown }>;
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: unknown): string[] => {
if (Array.isArray(value)) {
return value.map(String);
}
return value ? [String(value)] : [];
};
const getSelectedLocationIds = (
locations: Location[],
selectedTreeIds: string[],
): string[] => {
const selectedTreeIdSet = new Set(selectedTreeIds);
return locations
.filter((option) => selectedTreeIdSet.has(String(option.treeId)))
.map((option) => option.id)
.filter((id): id is NonNullable<typeof id> => id !== null && id !== undefined)
.map(String);
};
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 handleChange: NonNullable<SelectProps['onChange']> = (...args) => {
const event = args[0] as LocationEvent;
const selectedTreeIds = normalizeValue(event.target.value);
onChange(...args);
onSelectedLocationIdsChange?.(
getSelectedLocationIds(location, selectedTreeIds),
);
};
const innerOption = location?.map((option) => ({
value: String(option.treeId),
label: getLocationLabel(option, parentIds),
}));
return (
<Select
label={label}
options={innerOption}
value={value}
onChange={handleChange}
disabled={disabled || (!isRoot && !location.length)}
{...rest}
/>
);
};