fix(web): «Новая консолидация» — «+ Создать» от двух ЮЛ, строка ЮЛ — флажок antd (AURORA-1589, PR #166)
Сервер отвечает 422 PERIMETER_TOO_SMALL при одном ЮЛ — кнопка неактивна раньше, у поля «Выберите не меньше двух ЮЛ». Строка ЮЛ — сам Checkbox (label на всю строку) вместо div role="checkbox" (biome useSemanticElements). Предупреждение браузера при начатой форме. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d71c46e846
commit
2fa672a2fb
@ -1,52 +1,36 @@
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
import { LegalEntityBrief } from '../../types/api';
|
||||
import { Checkbox, Empty, Input, Spin } from 'antd';
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
import type { LegalEntityBrief } from '../../types/api';
|
||||
|
||||
type RowProps = {
|
||||
entity: LegalEntityBrief;
|
||||
checked: boolean;
|
||||
onToggle: (id: string) => void;
|
||||
};
|
||||
// Вся строка — флажок antd (<label>): клик по наименованию или ИНН переключает, клавиатура — как у флажка.
|
||||
// Подпись растянута на ширину строки: наименование с многоточием слева, ИНН — колонкой справа.
|
||||
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={{
|
||||
<Checkbox
|
||||
checked={checked}
|
||||
onChange={() => onToggle(entity.id)}
|
||||
styles={{
|
||||
root: {
|
||||
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',
|
||||
},
|
||||
label: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flex: 1, minWidth: 0 },
|
||||
}}>
|
||||
<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 style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', minWidth: 0 }} title={entity.name}>
|
||||
{entity.name}
|
||||
</span>
|
||||
|
||||
<span style={{ color: '#8c8c8c', flexShrink: 0 }}>{entity.inn}</span>
|
||||
</div>
|
||||
</Checkbox>
|
||||
));
|
||||
|
||||
type CompanyMultiSelectProps = {
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Col, Form, Modal, Row, Select, message } from 'antd';
|
||||
import type React from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { ApiError } from '../../api/client';
|
||||
import { useBeforeUnload } from '../../hooks/useBeforeUnload';
|
||||
import { fetchAllLegalEntities, fetchRelatedGroup, fetchRelatedGroups } from '../../services/api/directories/company_groups';
|
||||
import { getCompanyGroupsThunk } from '../../store/slices/companyGroupsSlice/thunks';
|
||||
import { useAppDispatch, useAppSelector } from '../../store/store';
|
||||
import type { ConsolidationCreate, LegalEntityBrief, Quarter, RelatedGroupOut } from '../../types/api';
|
||||
import { membersFirst, preselectMembers } from './preselect';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { MIN_PERIMETER } from '../../utils/consolidations';
|
||||
import { CompanyMultiSelect } from './CompanyOptionRow';
|
||||
import { membersFirst, preselectMembers } from './preselect';
|
||||
|
||||
type Props = {
|
||||
open: boolean;
|
||||
@ -50,7 +52,10 @@ export const NewConsolidationModal: React.FC<Props> = ({ open, onCancel, onOk })
|
||||
}
|
||||
}, [open, raw_rows.length, loading, dispatch]);
|
||||
|
||||
const isSubmitDisabled = !company_group_id || !related_group_id || !year || !semester || !legEntIds?.length;
|
||||
// не меньше двух ЮЛ: иначе сервер ответит 422 PERIMETER_TOO_SMALL
|
||||
const isSubmitDisabled = !company_group_id || !related_group_id || !year || !semester || legEntIds.length < MIN_PERIMETER;
|
||||
// начатая форма — несохранённые правки: браузер предупредит при закрытии вкладки
|
||||
useBeforeUnload(open && !!(company_group_id || related_group_id || year || semester));
|
||||
|
||||
const yearOptions = useMemo(() => {
|
||||
const y = new Date().getFullYear();
|
||||
@ -196,7 +201,15 @@ export const NewConsolidationModal: React.FC<Props> = ({ open, onCancel, onOk })
|
||||
{/* ROW 3 - full width block, only after subgroup is selected */}
|
||||
{related_group_id && (
|
||||
<Col span={24}>
|
||||
<Form.Item name='legal_entity_ids' label='ЮЛ консолидации' rules={[{ required: true, message: 'Выберите хотя бы одно ЮЛ' }]}>
|
||||
<Form.Item
|
||||
name='legal_entity_ids'
|
||||
label='ЮЛ консолидации'
|
||||
rules={[
|
||||
{
|
||||
validator: (_, v: string[] | undefined) =>
|
||||
(v?.length ?? 0) >= MIN_PERIMETER ? Promise.resolve() : Promise.reject(new Error('Выберите не меньше двух ЮЛ')),
|
||||
},
|
||||
]}>
|
||||
<CompanyMultiSelect loading={loadingEntities} companies={legEntities} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user