File "projectInputSelect.tsx"

Full Path: /var/www/html/gitep_front/src/entities/project/ui/projectInputSelect.tsx
File size: 6.55 KB
MIME-type: text/x-java
Charset: utf-8

import { Flex, Dropdown, Collapse, Input, Empty } from "antd";
import { FilterDropdownContent } from "@/shared/ui/Filters";
import { useState, useMemo, useEffect } from "react";
import { CaretRightOutlined } from "@ant-design/icons";
import styles from "./project-input-select.module.scss";
import { getProjects } from "../api/getProjectsGroups";
import ArrowShow from "@shared/assets/images/icons/arrow-show.svg?react";
import checkSvg from "@shared/assets/images/icons/check-new.svg";
import chevronDown from "@/shared/assets/images/icons/chevron-down.svg";

export const ProjectInputSelect = ({
  index,
  value,
  initialOptions,
  onChange,
  isProjectValidate,
  disabled,
  paymentData,
  onUpdateProject
}: {
  index: any;
  value: number;
  isProjectValidate?: boolean;
  initialOptions: any[];
  onChange: (project: any) => void;
  disabled: boolean;
  paymentData?: any;
  onUpdateProject: (index: number, value: number | null) => void;
}) => {
  const [open, setOpen] = useState<boolean>(false);
  const [searchQuery, setSearchQuery] = useState<string>("");
  const [activeKeys, setActiveKeys] = useState<string[]>([]);
  const [selectedProject, setSelectedProject] = useState<any>(null);

  useEffect(() => {
    const selectedProject = initialOptions
      ?.flatMap((group) => group.projects)
      ?.find((project) => project?.id === value);
      if (selectedProject) {
        setSelectedProject(selectedProject);
      } else {
        // если проект архивный, то устанавливаем его из данных карточки платежа
        // либо очищаем поле
          if (paymentData?.project) {
          setSelectedProject(paymentData?.project);
        } else setSelectedProject(null);
      }
  }, [value, initialOptions, paymentData?.project]);

  const handleSearch = async (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!e.target.value) {
      onUpdateProject(index, null)
    }
    setSelectedProject(null);
    setSearchQuery(e.target.value);
    await getProjects({ search: e.target.value })
    onChange(null);
  };

  const onProjectClick = (project: any) => {
    onChange(project);
    setSelectedProject(project);
    setSearchQuery("");
    setOpen(false);
  };

  const handleCollapseChange = (keys: string | string[]) => {
    setActiveKeys(Array.isArray(keys) ? keys : [keys]);
  };

  const filteredOptions = useMemo(() => {
    if (!searchQuery) return initialOptions;

    return initialOptions
      .map((group) => ({
        ...group,
        projects: group.projects.filter((project: any) =>
          project.offer_number
            .toLowerCase()
            .includes(searchQuery.toLowerCase())
        ),
      }))
      .filter((group) => group.projects.length > 0);
  }, [initialOptions, searchQuery]);
  
  // для автоматического раскрытия групп при открытии дропдауна
  useEffect(() => {
    if (open) {
      const allGroupKeys = filteredOptions.map((_, index) => String(index));
      setActiveKeys(allGroupKeys);
    } else {
      setActiveKeys([]);
    }
  }, [open, filteredOptions]);

  const hasNoData = useMemo(() => {
    return filteredOptions?.every(group => group.projects.length === 0);
  }, [filteredOptions]);
  
  const inputValue = selectedProject ? `${selectedProject.offer_number} ${selectedProject.object_address ? `| ${selectedProject.object_address}` : ''} ${selectedProject.short_description ? `| ${selectedProject.short_description}` : ''}` : searchQuery;
  
  return (
    <Flex vertical>
      <Dropdown
        open={open}
        onOpenChange={setOpen}
        dropdownRender={() => (
          <FilterDropdownContent noInput>
            {hasNoData ? (
              <p style={{padding: '5px 8px', color: 'rgba(0, 0, 0, 0.25)'}}>Ничего не найдено</p>
            ) : (
              <Collapse
                bordered={false}
                ghost
                onChange={handleCollapseChange}
                activeKey={activeKeys}
                expandIcon={({ isActive }) => (
                    <img
                        src={chevronDown}
                        style={{
                          transform: isActive ? "rotate(0deg)" : "rotate(-90deg)",
                        }}
                    />
                )}
                accordion={false}
                className={styles.collapse}
                destroyInactivePanel={false}
              >
                {filteredOptions.map((group, index) => (
                  <Collapse.Panel
                    key={String(index)}
                    header={`${group.name} (${group.projects.length})`}
                    forceRender={true}
                  >
                    {group.projects.map((project: any) => {
                      const isSelected = project.id === selectedProject?.id;

                      return (
                          <div
                              onClick={() => onProjectClick(project)}
                              key={project.id}
                              className={`${styles.projectItem} ${
                                  isSelected ? styles.selected : ""
                              }`}
                          >
                            <span style={{
                              display: "block",
                              width: "310px"
                            }}>{`${project?.offer_number} ${project?.object_address ? `| ${project?.object_address}` : ''} ${project?.short_description ? `| ${project?.short_description}` : ''}`}</span>
                            {isSelected && (
                                <img
                                    src={checkSvg}
                                    alt="selected"
                                    className={styles.checkIcon}
                                />
                            )}
                          </div>
                      )
                    })}
                  </Collapse.Panel>
                ))}
              </Collapse>
            )}
          </FilterDropdownContent>
        )}
        trigger={["click"]}
        disabled={disabled}
      >
        <Input
            status={isProjectValidate ? "error" : ""}
            className={styles["customInput"]}
            placeholder="Выберите проект"
            value={inputValue}
            onChange={handleSearch}
            size="large"
          suffix={
            <ArrowShow
              className={`${styles.arrowIcon} ${open && styles.rotateArrowIcon}`}
              style={{ color: "#98A2B3" }}
            />
          }
        />
      </Dropdown>
    </Flex>
  );
};