import { Autocomplete, Box, Button, FormControl, FormLabel, MenuItem, Select, TextField } from '@mui/material';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { findItemPage, positiveInteger, readListVisit, rememberListVisit } from '../../utils/listNavigation';
import { useSearchParams } from 'react-router-dom';
import { toast } from 'react-toastify';
import { SspApi } from '../../api/ssp';
import { TasksApi } from '../../api/tasks';
import { useAuth } from '../../app/context/AuthProvider';
import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch';
import { PrimaryButton } from '../../components/common/Buttons/Buttons';
import { ResetFiltersButton } from '../../components/common/Buttons/ButtonsActions';
import Modal from '../../components/common/Modal/Modal';
import { OrgUnitsAutocompletePaper } from '../../components/common/OrgUnitsAutocompletePaper/OrgUnitsAutocompletePaper';
import { renderOrgUnitValue } from '../../components/common/OrgUnitsAutocompletePaper/renderOrgUnitValue';
import { PaginatedList } from '../../components/common/PaginatedList';
import { TaskCardComponent } from '../../components/common/TaskCardComponent';
import { WhitePlus } from '../../components/common/icons/icons';
import { FORM_TYPE_OPTIONS, FORM_TYPE_TRANSLATE, ORG_UNIT_TYPE_OPTIONS, ROLES_NAME_ID } from '../../constants/constants';
import { PageContainer } from '../StyledForPage';
const modalSelectMenuProps = {
sx: { zIndex: 1301 },
style: { zIndex: 1301 },
};
const modalSelectSx = {
'& .MuiOutlinedInput-notchedOutline': {
borderColor: 'rgba(0,0,0,0.1)',
},
};
export default function TasksPage() {
const [searchParams, setSearchParams] = useSearchParams();
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(false);
const [loadingUpdate, setLoadingUpdate] = useState(false);
const [modalOpen, setModalOpen] = useState(false);
const yearFilter = searchParams.get('year') || '';
const formTypeFilter = searchParams.get('form_type') || '';
const orgUnitsFilter = searchParams.get('org_units') || '';
const deleteStatusFilter = searchParams.get('delete_status') || 'all';
const orgUnitIdsFilter = useMemo(
() =>
orgUnitsFilter
.split(',')
.filter(Boolean)
.map(Number)
.filter((value) => Number.isInteger(value) && value > 0),
[orgUnitsFilter],
);
const page = positiveInteger(searchParams.get('page'), 1);
const limit = [15, 25, 50, 100, 200].includes(Number(searchParams.get('limit'))) ? Number(searchParams.get('limit')) : 25;
const [lastVisit] = useState(() => readListVisit('tasks'));
const listUrl = `/tasks${searchParams.size ? `?${searchParams}` : ''}`;
const restoreVisit = useRef(lastVisit?.url === listUrl ? lastVisit : null);
const requestId = useRef(0);
const setPage = (value) => setSearchParams((params) => {
const next = new URLSearchParams(params);
next.set('page', String(value));
return next;
});
const [totalCount, setTotalCount] = useState(0);
const [sspList, setSspList] = useState([]);
const [formData, setFormData] = useState({
year: '',
orgUnitType: '',
org_unit_id: [],
formTypeCode: '',
});
const yearOptions = useMemo(() => {
const currentYear = new Date().getFullYear();
return Array.from({ length: 8 }, (_, index) => currentYear - 5 + index);
}, []);
const selectedOrgUnits = useMemo(() => sspList.filter((unit) => orgUnitIdsFilter.includes(unit.id)), [sspList, orgUnitIdsFilter]);
const filteredOrgUnits = useMemo(() => {
if (!formData.orgUnitType) return [];
const isSsp = formData.orgUnitType === 'ssp';
return sspList.filter((unit) => unit.is_ssp === isSsp);
}, [sspList, formData.orgUnitType]);
const isAllOrgUnitsSelected = useMemo(() => {
return filteredOrgUnits.length > 0 && filteredOrgUnits.every((unit) => formData.org_unit_id.includes(unit.id));
}, [filteredOrgUnits, formData.org_unit_id]);
const isOrgUnitsIndeterminate = useMemo(() => {
return formData.org_unit_id.length > 0 && !isAllOrgUnitsSelected;
}, [formData.org_unit_id, isAllOrgUnitsSelected]);
const { user } = useAuth();
const updateFilter = (name, value) => {
restoreVisit.current = null;
setSearchParams((currentParams) => {
const nextParams = new URLSearchParams(currentParams);
nextParams.set('page', '1');
if (value) {
nextParams.set(name, value);
} else {
nextParams.delete(name);
}
return nextParams;
});
};
const openModal = () => {
setModalOpen(true);
};
const handleSubmit = async () => {
if (!formData.year || !formData.orgUnitType || formData.org_unit_id.length === 0 || !formData.formTypeCode) {
alert('Пожалуйста, заполните все поля');
return;
}
try {
setLoadingUpdate(true);
await TasksApi.create({
year: Number(formData.year),
form_type_code: formData.formTypeCode,
org_unit_ids: formData.org_unit_id,
});
setPage(1);
loadTasks(1, limit);
setModalOpen(false);
setFormData({
year: '',
orgUnitType: '',
org_unit_id: [],
formTypeCode: '',
});
} catch (error) {
toast.error(error.response?.data?.detail || error.response?.data?.message || 'Ошибка при создании задачи');
} finally {
setLoadingUpdate(false);
}
};
const handleCancel = () => {
setModalOpen(false);
setFormData({
year: '',
orgUnitType: '',
org_unit_id: [],
formTypeCode: '',
});
};
const handleFormChange = (field, value) => {
setFormData((prev) => ({
...prev,
[field]: value,
}));
};
const handleOrgUnitTypeChange = (value) => {
setFormData((prev) => ({
...prev,
orgUnitType: value,
org_unit_id: [],
}));
};
const handleSelectAllOrgUnits = (checked) => {
handleFormChange('org_unit_id', checked ? filteredOrgUnits.map((unit) => unit.id) : []);
};
const loadTasks = useCallback(
async (currentPage, currentLimit) => {
const currentRequest = ++requestId.current;
setLoading(true);
try {
const skip = (currentPage - 1) * currentLimit;
const params = {
offset: skip,
limit: currentLimit,
...(yearFilter && { year: Number(yearFilter) }),
...(formTypeFilter && { form_type: formTypeFilter }),
...(orgUnitIdsFilter.length > 0 && { org_units: orgUnitIdsFilter.join(',') }),
...(user?.role_id === ROLES_NAME_ID.admin && deleteStatusFilter && { delete_status: deleteStatusFilter }),
};
const res = await TasksApi.list(params);
const data = res.result;
if (currentRequest !== requestId.current) return;
const visit = restoreVisit.current;
restoreVisit.current = null;
if (visit && !data.some((item) => String(item.id) === visit.id)) {
const foundPage = await findItemPage({
id: visit.id, currentPage, pageSize: currentLimit, count: res.count,
fetchPage: async (nextPage) => (await TasksApi.list({ ...params, offset: (nextPage - 1) * currentLimit })).result,
isCancelled: () => currentRequest !== requestId.current,
});
if (currentRequest !== requestId.current) return;
if (foundPage) {
const savedUrl = new URL(visit.url, window.location.origin);
savedUrl.searchParams.set('page', String(foundPage));
rememberListVisit('tasks', visit.id, `${savedUrl.pathname}${savedUrl.search}`);
setSearchParams(savedUrl.searchParams, { replace: true });
return;
}
}
setItems(data);
setTotalCount(res.count);
} catch (_error) {
if (currentRequest === requestId.current) toast.error('Ошибка загрузки задач');
} finally {
if (currentRequest === requestId.current) setLoading(false);
}
},
[yearFilter, formTypeFilter, orgUnitIdsFilter, deleteStatusFilter, user?.role_id, setSearchParams],
);
const handlePageChange = (_event, value) => {
restoreVisit.current = null;
setPage(value);
};
const handleLimitChange = (event) => {
const newLimit = event.target.value;
updateFilter('limit', newLimit);
};
useEffect(() => {
if (!user) return;
if (user.role_id !== ROLES_NAME_ID.admin) {
setSspList(user.org_units || []);
return;
}
SspApi.getAll({ is_active: true })
.then((data) => {
if (data.result) {
setSspList(data.result);
}
})
.catch(() => toast.error('Ошибка загрузки подразделений'));
}, [user]);
useEffect(() => {
loadTasks(page, limit);
return () => {
requestId.current++;
};
}, [page, limit, loadTasks]);
const handleFilterChange = (name, value) => {
updateFilter(name, value);
};
const handleClearFilters = () => {
restoreVisit.current = null;
setSearchParams((currentParams) => {
const nextParams = new URLSearchParams(currentParams);
nextParams.set('page', '1');
nextParams.delete('year');
nextParams.delete('form_type');
nextParams.delete('org_units');
nextParams.delete('delete_status');
return nextParams;
});
};
if (!user) return;
return (
<>
(
loadTasks(page, limit)}
{...exportProps}
/>
)}
getItemId={(task) => task.id}
getItemTitle={(task) =>
task.title ||
`${FORM_TYPE_TRANSLATE[task.form_type_code]}_${task.org_unit ? task.org_unit.title : task_org_unit_id}_${task.year}` ||
'Задача'
}
extraActions={
user.role_id === ROLES_NAME_ID.admin && (
} sx={{ height: '2.5rem' }}>
Создать задачу
)
}
filterActions={
option.title || ''}
isOptionEqualToValue={(option, value) => option.id === value.id}
value={selectedOrgUnits}
onChange={(_event, newValue) => handleFilterChange('org_units', newValue.map((unit) => unit.id).join(','))}
renderValue={renderOrgUnitValue}
renderInput={(params) => }
sx={{ width: 480, maxWidth: '100%' }}
/>
{user.role_id === ROLES_NAME_ID.admin && (
)}
}
/>
>
}>
Форма
Год
handleFormChange('year', e.target.value)}
/>
Тип
ССП/Региональный филиал
option.title || ''}
isOptionEqualToValue={(option, value) => option.id === value.id}
renderValue={renderOrgUnitValue}
value={filteredOrgUnits.filter((ssp) => formData.org_unit_id.includes(ssp.id))}
onChange={(_event, newValue) => {
handleFormChange(
'org_unit_id',
newValue.map((ssp) => ssp.id),
);
}}
renderInput={(params) => (
)}
slots={{
paper: OrgUnitsAutocompletePaper,
}}
slotProps={{
paper: {
onSelectAll: handleSelectAllOrgUnits,
isAllSelected: isAllOrgUnitsSelected,
isIndeterminate: isOrgUnitsIndeterminate,
showSelectAll: filteredOrgUnits.length > 0,
},
popper: {
style: { zIndex: 1301 },
},
}}
/>
>
);
}