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