File "articleInputSelect.tsx"
Full Path: /var/www/html/gitep_front/src/entities/article/ui/articleInputSelect.tsx
File size: 8.44 KB
MIME-type: text/x-java
Charset: utf-8
import React, { useState, useEffect, useMemo } from 'react';
import { Flex, Select } from 'antd';
import styles from './article-input-select.module.scss';
import ArrowShow from '@shared/assets/images/icons/arrow-show.svg?react';
import CheckSvg from '@shared/assets/images/icons/check-new.svg';
import { belongsToProject, safeFind } from '@/pages/main/utils';
import { useUnit } from 'effector-react';
const { Option, OptGroup } = Select;
import { $articlesGroupsStore } from '@/entities/article/model';
interface Organization {
id: number;
name: string;
}
interface OrganizationSelectProps {
initialOptions?: Organization[];
isArticleValidate?: boolean;
value?: number | null;
onChange?: (value: number) => void;
onSearch?: (value: string) => void;
disabled: boolean;
paymentCard: any;
index: number;
}
const ArticleInputSelect: React.FC<OrganizationSelectProps> = ({
initialOptions = [],
value,
isArticleValidate,
onChange,
onSearch,
disabled,
paymentCard,
index,
}) => {
const [options, setOptions] = useState<Organization[]>(initialOptions);
const [selectedValue, setSelectedValue] = useState<number | null | undefined>(
value,
);
const [searchQuery, setSearchQuery] = useState<string>('');
const [open, setOpen] = useState<boolean>(false);
const articles = useUnit($articlesGroupsStore).articlesGroups;
const isArticleBelongProject = (articleId: any) => {
const art = safeFind(
articles,
(a: any) => String(a.id) === String(articleId),
);
return belongsToProject(art, paymentCard?.distributions[index]?.project_id);
};
useEffect(() => {
if (paymentCard?.distributions[index]?.project_id) {
const filteredArticlesByPaymentType = articles.filter((article: any) =>
paymentCard.payment_type === 'reception_from_1c'
? article.article_type === 'credit'
: article.article_type === 'debit',
);
const idsToRemove = new Set(initialOptions.map((item) => item.id));
const articlesWithoutExistArticleInProject =
filteredArticlesByPaymentType.filter(
(item: any) => !idsToRemove.has(item.id),
);
setOptions(
Array.isArray(initialOptions)
? [...initialOptions, ...articlesWithoutExistArticleInProject]
: [],
);
} else {
setOptions(
Array.isArray(initialOptions)
? initialOptions.filter((option: any) => !option.default_in_project)
: [],
);
}
}, [initialOptions, paymentCard?.distributions[index]?.project_id]);
useEffect(() => {
setSelectedValue(value);
}, [value]);
// разделение статей на группы
const groupedOptions = useMemo(() => {
const filteredOptions = options.filter((item: any) => item.id !== 1);
if (!searchQuery) {
return {
projectArticles: filteredOptions.filter((option) =>
isArticleBelongProject(option.id),
),
nonProjectArticles: filteredOptions.filter(
(option) => !isArticleBelongProject(option.id),
),
};
}
const filteredBySearch = filteredOptions.filter((option) =>
option.name.toLowerCase().includes(searchQuery.toLowerCase()),
);
return {
projectArticles: filteredBySearch.filter((option) =>
isArticleBelongProject(option.id),
),
nonProjectArticles: filteredBySearch.filter(
(option) => !isArticleBelongProject(option.id),
),
};
}, [options, searchQuery, paymentCard?.distributions[index]?.project_id]);
const handleSelectChange = (value: number) => {
setSelectedValue(value);
onChange?.(value);
setOpen(false);
};
const handleClear = () => {
setSelectedValue(null);
setSearchQuery('');
};
const handleSearch = (searchText: string) => {
setSearchQuery(searchText);
onSearch?.(searchText);
};
const handleDropdownOpenChange = (open: boolean) => {
setOpen(open);
if (!open) {
setSearchQuery('');
}
};
const renderOptions = () => {
const hasProject = paymentCard?.distributions[index]?.project_id;
if (!hasProject || searchQuery) {
const allOptions = [
...groupedOptions.projectArticles,
...groupedOptions.nonProjectArticles,
];
return allOptions.map((option) => (
<Option key={option.id} value={option.id} label={option.name}>
<Flex
align='center'
justify='space-between'
style={{ width: '100%' }}
>
<span
style={{
maxWidth: '260px',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{option.name}
{hasProject && !isArticleBelongProject(option.id) && (
<span style={{ marginLeft: '8px', fontSize: '12px' }}>
Не в проекте
</span>
)}
</span>
{option.id === selectedValue && <img src={CheckSvg} alt='' />}
</Flex>
</Option>
));
}
return (
<>
{/* В проекте */}
{groupedOptions.projectArticles.length > 0 && (
<OptGroup
key='in-project'
label={
<span style={{ fontSize: '12px', fontWeight: 400 }}>
В проекте
</span>
}
>
{groupedOptions.projectArticles.map((option) => (
<Option
key={`in-${option.id}`}
value={option.id}
label={option.name}
>
<Flex
align='center'
justify='space-between'
style={{ width: '100%' }}
>
<span
style={{
maxWidth: '260px',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{option.name}
</span>
{option.id === selectedValue && <img src={CheckSvg} alt='' />}
</Flex>
</Option>
))}
</OptGroup>
)}
{/* "Не в проекте" */}
{groupedOptions.nonProjectArticles.length > 0 && (
<OptGroup
key='not-in-project'
label={
<span style={{ fontSize: '12px', fontWeight: 400 }}>
Не в проекте
</span>
}
>
{groupedOptions.nonProjectArticles.map((option) => (
<Option
key={`out-${option.id}`}
value={option.id}
label={option.name}
>
<Flex
align='center'
justify='space-between'
style={{ width: '100%' }}
>
<span
style={{
maxWidth: '260px',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{option.name}
</span>
{option.id === selectedValue && <img src={CheckSvg} alt='' />}
</Flex>
</Option>
))}
</OptGroup>
)}
{groupedOptions.projectArticles.length === 0 &&
groupedOptions.nonProjectArticles.length === 0 && (
<Option disabled value='no-data'>
Нет доступных статей
</Option>
)}
</>
);
};
return (
<Select
showSearch
style={{ width: '100%', height: '40px' }}
placeholder='Выберите статью'
onChange={handleSelectChange}
onClear={handleClear}
allowClear
onSearch={handleSearch}
value={selectedValue}
status={isArticleValidate ? 'error' : ''}
notFoundContent={options.length === 0 ? 'Ничего не найдено' : null}
filterOption={false}
disabled={disabled}
open={open}
onDropdownVisibleChange={handleDropdownOpenChange}
suffixIcon={<ArrowShow className={styles.arrowIcon} />}
optionFilterProp='children'
optionLabelProp='label'
popupMatchSelectWidth={400}
>
{renderOptions()}
</Select>
);
};
export default ArticleInputSelect;