Загрузка данных


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: number[]) => 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[],
): number[] => {
  const selectedTreeIdSet = new Set(selectedTreeIds);

  return locations
    .filter((option) => selectedTreeIdSet.has(String(option.treeId)))
    .map((option) => Number(option.id))
    .filter(Number.isFinite);
};

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}
    />
  );
};