arm-core/web/src/widgets/NewConsoleModal/CompanyOptionRow.tsx

121 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { memo, useCallback, useMemo, useState } from 'react';
import { LegalEntityBrief } from '../../types/api';
import { Checkbox, Empty, Input, Spin } from 'antd';
type RowProps = {
entity: LegalEntityBrief;
checked: boolean;
onToggle: (id: string) => void;
};
const CompanyOptionRow = memo(({ entity, checked, onToggle }: RowProps) => (
<div
role='checkbox'
aria-checked={checked}
tabIndex={0}
onClick={() => onToggle(entity.id)}
onKeyDown={(e) => {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
onToggle(entity.id);
}
}}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
minWidth: 0,
gap: 12,
padding: '10px 8px',
borderRadius: 4,
borderBottom: '1px solid rgba(0, 0, 0, 0.05)',
cursor: 'pointer',
boxSizing: 'border-box',
}}>
<span
style={{
display: 'flex',
alignItems: 'center',
gap: 8,
flex: 1,
minWidth: 0,
overflow: 'hidden',
}}>
<Checkbox checked={checked} tabIndex={-1} style={{ pointerEvents: 'none' }} />
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{entity.name}</span>
</span>
<span style={{ color: '#8c8c8c', flexShrink: 0 }}>{entity.inn}</span>
</div>
));
type CompanyMultiSelectProps = {
companies: LegalEntityBrief[];
loading?: boolean;
// injected by Form.Item:
value?: string[];
onChange?: (value: string[]) => void;
};
export const CompanyMultiSelect: React.FC<CompanyMultiSelectProps> = ({ companies, loading, value = [], onChange }) => {
const [search, setSearch] = useState('');
const toggle = useCallback(
(id: string) => {
const next = value.includes(id) ? value.filter((v) => v !== id) : [...value, id];
onChange?.(next);
},
[value, onChange],
);
const filtered = useMemo(() => {
if (!search) return companies;
const q = search.toLowerCase();
return companies.filter((s) => s.name.toLowerCase().includes(q));
}, [companies, search]);
return (
<div style={{ border: '1px solid #d9d9d9', borderRadius: 8, padding: 12 }} className='multiselect'>
<Input.Search
placeholder='Поиск по ЮЛ'
allowClear
value={search}
onChange={(e) => setSearch(e.target.value)}
style={{ marginBottom: 12 }}
/>
{loading ? (
<div style={{ textAlign: 'center', padding: 24 }}>
<Spin />
</div>
) : null}
{!loading && filtered.length === 0 ? (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={companies.length === 0 ? 'Нет компаний' : 'Нет совпадений'} />
) : (
<div
style={{
maxHeight: 200,
overflowY: 'auto',
display: 'flex',
flexDirection: 'column',
gap: 4,
paddingRight: 16,
overflowX: 'hidden',
}}>
{filtered.map((s) => (
<CompanyOptionRow key={s.id} entity={s} checked={value.includes(s.id)} onToggle={toggle} />
))}
</div>
)}
{!loading && companies.length > 0 && (
<div style={{ marginTop: 8, display: 'flex', gap: 12 }}>
<span style={{ marginLeft: 'auto', color: '#8c8c8c' }}>
Выбрано: {value.length} / {companies.length}
</span>
</div>
)}
</div>
);
};