213 lines
6.9 KiB
JavaScript
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 { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { NameTask, TaskInfoContainer } from '../../components/common/SwitchFormTask/SwitchFormTask.style';
import { Box, CircularProgress, Stack } from '@mui/material';
import { toast } from 'react-toastify';
import { DictVspApi } from '../../api/dict-vsp';
import { SspApi } from '../../api/ssp';
import { useAuth } from '../../app/context/AuthProvider';
import { BackButton } from '../../components/common/Buttons/BackButton';
import { HeaderPortal } from '../../components/common/HeaderPortal';
import { ROLES_NAME_ID } from '../../constants/constants';
import { PageContainer } from '../../components/common/PageContainer';
import DictVspFilters from './components/DictVspFilters';
import DictVspModals from './components/DictVspModals';
import TableDictVsp from './components/TableDictVsp';
import { buildVspListParams, vspMatchesStatus } from './utils/vspListParams';
const DictVspInfo = () => {
const portalContent = (
<TaskInfoContainer>
<BackButton to='/dicts-navigator' />
<NameTask>Справочник</NameTask>
</TaskInfoContainer>
);
return <HeaderPortal>{portalContent}</HeaderPortal>;
};
function DictVspPage() {
const [isLoading, setIsLoading] = useState(true);
const [dictVspData, setDictVspData] = useState([]);
const [ssps, setSsps] = useState([]);
const [selectedSsp, setSelectedSsp] = useState(null);
// AURORA-1883: статус ВСП и период закрытия; список ВСП перезагружается с сервера при их смене.
const [status, setStatus] = useState('active');
const [closeDates, setCloseDates] = useState({ closeDateStart: '', closeDateEnd: '' });
const [isListLoading, setIsListLoading] = useState(true);
const listRequestRef = useRef(0);
const { user } = useAuth();
const modalsRef = useRef(null);
const listFilter = useMemo(() => ({ status, ...closeDates }), [status, closeDates]);
const loadVspList = useCallback(async () => {
if (!user) return;
const requestId = ++listRequestRef.current;
setIsListLoading(true);
try {
const vspResponse = await DictVspApi.get(buildVspListParams(listFilter));
if (requestId !== listRequestRef.current) return;
if (!vspResponse.success) {
toast.error('Ошибка загрузки справочника');
return;
}
setDictVspData(vspResponse.result || []);
} catch (error) {
if (requestId !== listRequestRef.current) return;
toast.error(error.response?.data?.message || 'Ошибка загрузки справочника');
} finally {
if (requestId === listRequestRef.current) setIsListLoading(false);
}
}, [user, listFilter]);
useEffect(() => {
loadVspList();
}, [loadVspList]);
const loadData = useCallback(async () => {
if (!user) return;
setIsLoading(true);
try {
const isAdmin = user.role_id === ROLES_NAME_ID.admin;
const sspResponse = isAdmin ? await SspApi.getAll({ is_active: true }) : null;
if (isAdmin) {
if (!sspResponse.success) {
toast.error('Ошибка загрузки списка ССП');
return;
}
setSsps(sspResponse.result);
} else {
setSsps(user.org_units ?? []);
}
} catch (error) {
console.error('Error loading data:', error);
toast.error(error.response?.data?.message || 'Ошибка загрузки данных');
} finally {
setIsLoading(false);
}
}, [user]);
useEffect(() => {
loadData();
}, [loadData]);
const handleAdd = useCallback(
async (formData) => {
try {
const response = await DictVspApi.create(formData);
if (response.success) {
toast.success('ВСП успешно создан');
if (vspMatchesStatus(response.result, status)) {
setDictVspData((prev) => [...prev, response.result]);
}
} else {
toast.error(response.message || 'Ошибка создания ВСП');
}
} catch (error) {
console.error('Error adding VSP:', error);
toast.error(error.response?.data?.message || 'Ошибка создания ВСП');
throw error;
}
},
[status],
);
const handleEdit = useCallback(
async (formData) => {
try {
const response = await DictVspApi.update(formData.id, formData);
if (response.success) {
toast.success('ВСП успешно обновлен');
// AURORA-1883: ВСП, переставший подходить под статус (например, закрыт в «Действующих»), уходит из списка.
setDictVspData((prev) => {
const rest = prev.filter((v) => v.id !== formData.id);
return vspMatchesStatus(response.result, status) ? [...rest, response.result] : rest;
});
} else {
toast.error(response.message || 'Ошибка обновления ВСП');
}
} catch (error) {
console.error('Error editing VSP:', error);
toast.error(error.response?.data?.message || 'Ошибка обновления ВСП');
throw error;
}
},
[status],
);
const handleDelete = useCallback(async (vspId) => {
try {
const response = await DictVspApi.delete(vspId);
if (response.success) {
toast.success('ВСП успешно удален');
setDictVspData((prev) => [...prev.filter((v) => v.id !== vspId)]);
} else {
toast.error(response.message || 'Ошибка удаления ВСП');
}
} catch (error) {
console.error('Error deleting VSP:', error);
toast.error(error.response?.data?.message || 'Ошибка удаления ВСП');
throw error;
}
}, []);
const handleAddClick = useCallback(() => modalsRef.current?.openAdd(), []);
const handleEditClick = useCallback((item) => modalsRef.current?.openEdit(item), []);
const handleExportClick = useCallback(() => modalsRef.current?.openExport(), []);
if (isLoading) {
return (
<>
<DictVspInfo />
<div className='flex justify-center pt-12'>
<CircularProgress />
</div>
</>
);
}
return (
<>
<DictVspInfo />
{/* <HeaderSwitch /> */}
<PageContainer>
<Stack sx={{ alignItems: 'stretch', width: '100%' }}>
<Box sx={{ width: '100%' }}>
<DictVspFilters
ssps={ssps}
onSspChange={setSelectedSsp}
selectedSsp={selectedSsp}
showSsp={user.role_id !== ROLES_NAME_ID.executor_rf}
status={status}
onStatusChange={setStatus}
closeDateStart={closeDates.closeDateStart}
closeDateEnd={closeDates.closeDateEnd}
onCloseDateChange={setCloseDates}
/>
<TableDictVsp
data={dictVspData}
selectedSsp={selectedSsp}
onAddClick={handleAddClick}
onEditClick={handleEditClick}
onExportClick={handleExportClick}
loading={isLoading || isListLoading}
/>
<DictVspModals
ref={modalsRef}
ssps={ssps}
onAdd={handleAdd}
onEdit={handleEdit}
onDelete={handleDelete}
listFilter={listFilter}
/>
</Box>
</Stack>
</PageContainer>
</>
);
}
export default DictVspPage;