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


import { SideFilterSelect } from '@/shared/components/SideFilterSelect/SideFilterSelect';
import { Helpers } from '@/shared/lib';
import { CheckIcon, SortIcon } from '@sber-friend/flamingo-icons';
import { Badge, Box, Button, Dropdown } from '@shared/components';
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

type LocationEvent = ChangeEvent<{ name?: string; value: unknown }>;

type CommonLocationFiltersProps = {
  'data-fui-tid'?: string;
  withDropdown?: boolean;
  isRooms?: boolean;

  regionId: string[];
  cityId: string[];
  placeId: string[];
  floorId: string[];
  roomId: string[];

  setRegionId: (regionId: string[]) => void;
  setCityId: (cityId: string[]) => void;
  setPlaceId: (placeId: string[]) => void;
  setFloorId: (floorId: string[]) => void;
  setRoomId: (roomId: string[]) => void;
};

type TreeIdLocationFiltersProps = CommonLocationFiltersProps & {
  outputIdType?: 'treeId';
  ids?: number[];
  onLocationIdsChange: (locationIds: number[]) => void;
};

type IdLocationFiltersProps = CommonLocationFiltersProps & {
  outputIdType: 'id';
  ids?: string[];
  onLocationIdsChange: (locationIds: string[]) => void;
};

type LocationFiltersProps =
  | TreeIdLocationFiltersProps
  | IdLocationFiltersProps;

const getDeepestTreeIds = ({
  regionId,
  cityId,
  placeId,
  floorId,
  roomId,
}: Pick<
  CommonLocationFiltersProps,
  'regionId' | 'cityId' | 'placeId' | 'floorId' | 'roomId'
>) => {
  if (roomId?.length > 0) {
    return roomId;
  }

  if (floorId?.length > 0) {
    return floorId;
  }

  if (placeId?.length > 0) {
    return placeId;
  }

  if (cityId?.length > 0) {
    return cityId;
  }

  return regionId;
};

export const LocationFilters = ({
  'data-fui-tid': tid,
  isRooms = false,
  ids,
  regionId,
  cityId,
  placeId,
  floorId,
  roomId,
  setRegionId,
  setCityId,
  setFloorId,
  setPlaceId,
  setRoomId,
  onLocationIdsChange,
  withDropdown = true,
  outputIdType = 'treeId',
}: LocationFiltersProps) => {
  const { t } = useTranslation('locations');
  const [anchorElement, setAnchorElement] = useState(null);

  useEffect(() => {
    if (ids?.length === 0) {
      setRegionId([]);
      setCityId([]);
      setPlaceId([]);
      setFloorId([]);
      setRoomId([]);
    }
  }, [ids, setCityId, setFloorId, setPlaceId, setRegionId, setRoomId]);

  const locationTreeIds = getDeepestTreeIds({
    regionId,
    cityId,
    placeId,
    floorId,
    roomId,
  });

  useEffect(() => {
    if (outputIdType === 'treeId') {
      (onLocationIdsChange as (locationIds: number[]) => void)(
        Helpers.convertStringsToNumbers(locationTreeIds),
      );
    }
  }, [locationTreeIds, onLocationIdsChange, outputIdType]);

  const handleSelectedLocationIdsChange = useCallback(
    (locationIds: string[]) => {
      if (outputIdType === 'id') {
        (onLocationIdsChange as (locationIds: string[]) => void)(locationIds);
      }
    },
    [onLocationIdsChange, outputIdType],
  );

  const handleChangeRegion = (event: LocationEvent) => {
    const { value } = event.target;

    setRegionId(value as string[]);
    setCityId([]);
    setPlaceId([]);
    setFloorId([]);
    setRoomId([]);
  };

  const handleChangeCity = (event: LocationEvent) => {
    const { value } = event.target;

    setCityId(value as string[]);
    setPlaceId([]);
    setFloorId([]);
    setRoomId([]);
  };

  const handleChangePlace = (event: LocationEvent) => {
    const { value } = event.target;

    setPlaceId(value as string[]);
    setFloorId([]);
    setRoomId([]);
  };

  const handleChangeFloor = (event: LocationEvent) => {
    const { value } = event.target;

    setFloorId(value as string[]);
    setRoomId([]);
  };

  const handleChangeRoom = (event: LocationEvent) => {
    const { value } = event.target;

    setRoomId(value as string[]);
  };

  const handleReset = () => {
    setRegionId([]);
    setCityId([]);
    setPlaceId([]);
    setFloorId([]);
    setRoomId([]);

    if (outputIdType === 'id') {
      (onLocationIdsChange as (locationIds: string[]) => void)([]);
      return;
    }

    (onLocationIdsChange as (locationIds: number[]) => void)([]);
  };

  const handleOpen = (event: any) => {
    setAnchorElement(event.currentTarget);
  };

  const handleClose = (event: any) => {
    event.preventDefault();
    setAnchorElement(null);
  };

  const filtersContent = (
    <>
      <SideFilterSelect
        value={regionId}
        label={t('region')}
        onChange={handleChangeRegion}
        onSelectedLocationIdsChange={handleSelectedLocationIdsChange}
        multiple
        isRoot
      />
      <SideFilterSelect
        value={cityId}
        parentIds={regionId}
        label={t('city')}
        onChange={handleChangeCity}
        onSelectedLocationIdsChange={handleSelectedLocationIdsChange}
        multiple
      />
      <SideFilterSelect
        value={placeId}
        parentIds={cityId}
        label={t('place')}
        onChange={handleChangePlace}
        onSelectedLocationIdsChange={handleSelectedLocationIdsChange}
        multiple
      />
      <SideFilterSelect
        value={floorId}
        parentIds={placeId}
        label={t('floor')}
        onChange={handleChangeFloor}
        onSelectedLocationIdsChange={handleSelectedLocationIdsChange}
        multiple
        isFloor
      />
      {isRooms && (
        <SideFilterSelect
          value={roomId}
          parentIds={floorId}
          label={t('room')}
          onChange={handleChangeRoom}
          onSelectedLocationIdsChange={handleSelectedLocationIdsChange}
          multiple
        />
      )}
      <Button size='small' onClick={handleReset}>
        {t('common:buttons.reset')}
      </Button>
    </>
  );

  if (!withDropdown) {
    return filtersContent;
  }

  return (
    <Badge
      invisible={
        !regionId?.length &&
        !cityId?.length &&
        !placeId?.length &&
        !floorId?.length &&
        !roomId?.length
      }
      badgeContent={<CheckIcon />}
      color='primary'
    >
      <Dropdown
        data-fui-tid={tid}
        size='small'
        icon={<SortIcon />}
        onClickButton={handleOpen}
        onClosePopover={handleClose}
        zIndexMenu={100}
        anchorElement={anchorElement}
      >
        <Box
          display='flex'
          gridGap={8}
          flexDirection='column'
          p={2}
          minWidth={330}
          maxWidth={330}
        >
          {filtersContent}
        </Box>
      </Dropdown>
    </Badge>
  );
};