import { useEffect, useMemo, useState } from 'react'; import { ProjectsApi } from '../../api/projects'; import { CardsSkeleton } from '../../components/common/Skeleton'; import SearchComponent from '../../components/common/SearchComponent'; import { ProjectCardComponent } from './ProjectCard'; import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch'; import { PageContainer, TasksContainer } from '../StyledForPage'; import { Box, FormControl, Button, Stack, Pagination, PaginationItem, Select, MenuItem, Typography, IconButton, Tooltip, TextField, Autocomplete, } from '@mui/material'; import { toast } from 'react-toastify'; import { ModalCreateProject } from './ModalCreateProject'; import { ROLES_NAME_ID, } from '../../constants/constants'; import { useAuth } from '../../app/context/AuthProvider'; import { PrimaryButton, PrimaryOutlinedButton } from '../../components/common/Buttons/Buttons'; import { ExportExitButton, ExportWithTextButton, } from '../../components/common/Buttons/ButtonsActions'; import { exportBulkForms, exportSingleForm } from '../../utils/exportFile'; import { WhitePlus } from '../../components/common/icons/icons'; import { useNavigate } from 'react-router-dom'; import { PaginatedList } from '../../components/common/PaginatedList'; import { DEFAULT_PROJECT_CONFIG } from '../../constants/projectConfig'; import { SspApi } from '../../api/ssp'; import NavigationToggle from '../../components/common/NavigationToggle'; export { DEFAULT_PROJECT_CONFIG } from '../../constants/projectConfig'; export default function ProjectsPage() { const navigate = useNavigate(); const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); const [modalOpen, setModalOpen] = useState(false); // Новые фильтры const [yearFilter, setYearFilter] = useState(''); const [branchFilter, setBranchFilter] = useState(''); // Pagination state const [page, setPage] = useState(1); const [limit, setLimit] = useState(20); const [totalCount, setTotalCount] = useState(0); const { user } = useAuth(); const [exportMode, setExportMode] = useState(false); const [exportList, setExportList] = useState([]); const [projectData, setProjectData] = useState(DEFAULT_PROJECT_CONFIG); // Получаем список годов для фильтра (можно динамически или задать диапазон) const yearOptions = useMemo(() => { const currentYear = new Date().getFullYear(); const years = []; for (let year = currentYear - 5; year <= currentYear + 2; year++) { years.push(year); } return years; }, []); useEffect(() => { if (!user) return; if (user.role_id == ROLES_NAME_ID.admin) { SspApi.getAll().then(data => { if (data.success) { setProjectData(prev => ({ ...prev, 'ССП/РФ': { ...prev['ССП/РФ'], options: data.result } })) return; } toast.error('Ошибка при получении ССП/РФ'); }); return; } setProjectData(prev => ({ ...prev, 'ССП/РФ': { ...prev['ССП/РФ'], options: user.org_units, } })) }, [user]) const openModal = () => { setModalOpen(true); }; const mapFormDataToApi = (formData) => { const apiData = { name: formData['Название проекта'] || '', project_type: formData['Тип проекта развития'] || null, vsp_format: formData['Формат ВСП'] || null, object_address: formData['Адрес объекта'] || '', staff_count: formData['Целевая численность, чел.'] || 0, placement_type: formData['Тип размещения'] || null, total_area: formData['Площадь размещения, м2'] || 0, year: formData['Год'] || null, branch_id: formData['ССП/РФ'] || null, }; return apiData; }; const handleCreateProject = async (formData) => { try { const apiData = mapFormDataToApi(formData); await ProjectsApi.create(apiData); setPage(1); loadProjects(1, limit); setModalOpen(false); toast.success('Проект успешно создан'); } catch (error) { toast.error( error.response?.data?.detail || error.response?.data?.message || 'Ошибка при создании проекта', ); } }; const loadProjects = async (currentPage = page, currentLimit = limit) => { setLoading(true); try { const skip = (currentPage - 1) * currentLimit; const params = { offset: skip, limit: currentLimit, // Добавляем фильтры в параметры запроса ...(yearFilter && { year: parseInt(yearFilter) }), ...(branchFilter && { branch_id: parseInt(branchFilter.id) }), }; const res = await ProjectsApi.list(params); const data = res.result; setItems(data); setTotalCount(res.count); } catch (error) { toast.error('Ошибка загрузки проектов'); } finally { setLoading(false); } }; // Сбрасываем страницу при изменении любых фильтров useEffect(() => { setPage(1); loadProjects(1, limit); }, [yearFilter, branchFilter]); const handlePageChange = (event, value) => { setPage(value); loadProjects(value, limit); }; const handleLimitChange = (event) => { const newLimit = event.target.value; setLimit(newLimit); setPage(1); loadProjects(1, newLimit); }; // Сброс всех фильтров const handleClearFilters = () => { setYearFilter(''); setBranchFilter(''); setPage(1); }; useEffect(() => { loadProjects(page, limit); }, []); useEffect(() => { setExportList([]); }, [exportMode]); const handleChangeToExportList = (projectId, checked) => { if (checked) { setExportList((prev) => [...prev, projectId]); } else { const newExportList = exportList.filter((t) => t != projectId); setExportList(newExportList); } }; const handleBulkExport = async () => { await exportBulkForms(exportList); setExportMode(false); }; const handleSingleExport = (projectId, projectTitle) => { exportSingleForm(projectId, projectTitle); }; const handleRefresh = () => { loadProjects(page, limit); toast.info('Список проектов обновлен'); }; if (!user) return null; return ( <> navigate(path)} /> ( )} getItemId={(project) => project.id} getItemTitle={(project) => project.name || 'Проект'} extraActions={ user.role_id === ROLES_NAME_ID.admin && ( } height='2.5rem' > Создать проект ) } filterActions={ option.title || option.name || '-'} value={branchFilter} onChange={(event, newValue) => setBranchFilter(newValue)} sx={{ width: 200 }} renderInput={(params) => ( )} /> Сбросить } /> setModalOpen(false)} onCreate={handleCreateProject} config={projectData} /> ); }