307 lines
8.3 KiB
JavaScript
307 lines
8.3 KiB
JavaScript
import styled from '@emotion/styled';
|
||
import { Box, Chip, Stack } from '@mui/material';
|
||
// src/components/common/ProjectCardComponent/ProjectCardComponent.jsx
|
||
import { useEffect, useState } from 'react';
|
||
import { useNavigate } from 'react-router-dom';
|
||
import { toast } from 'react-toastify';
|
||
import { ProjectsApi } from '../../api/projects';
|
||
import { IconWithContent } from '../../components/common/IconWithContent';
|
||
import { CheckBoxCheckSvg, CheckBoxUncheckSvg, DateIcon, UserIcon } from '../../components/common/icons/icons';
|
||
import { ModalCreateProject } from './ModalCreateProject';
|
||
|
||
const ProjectCard = styled.div`
|
||
width: 26.8rem;
|
||
height: 15rem;
|
||
display: flex;
|
||
padding: 1.25rem;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
box-sizing: border-box;
|
||
border: 0.06rem solid var(--Stroke, rgba(0, 0, 0, 0.1));
|
||
border-radius: 1rem;
|
||
box-shadow:
|
||
0rem 2rem 4rem -2rem rgba(0, 0, 0, 0.02),
|
||
0rem 4rem 6rem -1rem rgba(0, 0, 0, 0.02);
|
||
background: var(--White, rgba(255, 255, 255, 1));
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
position: relative;
|
||
|
||
&:hover {
|
||
transform: translateY(-5px);
|
||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
|
||
}
|
||
`;
|
||
|
||
const CardHeader = styled.div`
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
`;
|
||
|
||
const ProjectId = styled.div`
|
||
font-size: 0.75rem;
|
||
font-weight: 400;
|
||
line-height: 1rem;
|
||
letter-spacing: 0rem;
|
||
text-align: left;
|
||
color: rgba(0, 0, 0, 0.6);
|
||
`;
|
||
|
||
const CardBody = styled.div`
|
||
width: 100%;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.8125rem;
|
||
justify-content: flex-end;
|
||
height: 100%;
|
||
`;
|
||
|
||
const ProjectTitle = styled.div`
|
||
font-size: 1rem;
|
||
font-weight: 500;
|
||
color: var(--Text-Primary, #333);
|
||
line-height: 1.63;
|
||
margin: 0;
|
||
padding: 0;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
`;
|
||
|
||
const StatusChip = styled(Chip)`
|
||
font-size: 0.7rem;
|
||
height: 1.5rem;
|
||
background-color: ${({ status }) => {
|
||
switch (status) {
|
||
case 'active':
|
||
return '#4caf50';
|
||
case 'completed':
|
||
return '#2196f3';
|
||
case 'paused':
|
||
return '#ff9800';
|
||
case 'archived':
|
||
return '#9e9e9e';
|
||
default:
|
||
return '#9e9e9e';
|
||
}
|
||
}};
|
||
color: white;
|
||
`;
|
||
|
||
const LevelChip = styled(Chip)`
|
||
font-size: 0.6rem;
|
||
height: 1.25rem;
|
||
background-color: rgba(0, 0, 0, 0.08);
|
||
color: rgba(0, 0, 0, 0.7);
|
||
`;
|
||
|
||
const ProjectInfoGrid = styled.div`
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem;
|
||
margin-top: 0.25rem;
|
||
`;
|
||
|
||
const InfoChip = styled(Chip)`
|
||
font-size: 0.6rem;
|
||
height: 1.25rem;
|
||
background-color: rgba(0, 0, 0, 0.05);
|
||
color: rgba(0, 0, 0, 0.7);
|
||
`;
|
||
|
||
const getStatusLabel = (status) => {
|
||
const statusMap = {
|
||
active: 'Активный',
|
||
completed: 'Завершен',
|
||
paused: 'Приостановлен',
|
||
archived: 'Архивирован',
|
||
};
|
||
return statusMap[status] || status || 'Не указан';
|
||
};
|
||
|
||
export const ProjectCardComponent = ({
|
||
project,
|
||
projectDataInit,
|
||
exportMode = false,
|
||
isLoadingFile = false,
|
||
onAddForExport,
|
||
onExportClick,
|
||
}) => {
|
||
const navigate = useNavigate();
|
||
const {
|
||
id,
|
||
name,
|
||
org_unit_name,
|
||
years,
|
||
status,
|
||
level,
|
||
project_type,
|
||
vsp_format,
|
||
placement_type,
|
||
object_address,
|
||
staff_count,
|
||
total_area,
|
||
report_count,
|
||
parent_id,
|
||
} = project;
|
||
|
||
const [isEditModalOpen, setEditModalOpen] = useState(false);
|
||
const [currentName, setCurrentName] = useState(name || '');
|
||
const [isChecked, setIsChecked] = useState(false);
|
||
const [editFormData, setEditFormData] = useState({});
|
||
const [projectData, setProjectData] = useState(projectDataInit);
|
||
|
||
useEffect(() => {
|
||
setIsChecked(false);
|
||
}, [exportMode]);
|
||
|
||
// Функция для подготовки данных проекта к редактированию
|
||
const prepareProjectDataForEdit = () => {
|
||
return {
|
||
'ССП/РФ': project.org_unit_id || null,
|
||
Год: years || null,
|
||
'Тип проекта развития': project_type || null,
|
||
'Название проекта': currentName,
|
||
'Формат ВСП': vsp_format || null,
|
||
'Адрес объекта': object_address || '',
|
||
'Целевая численность, чел.': staff_count || 0,
|
||
'Тип размещения': placement_type || null,
|
||
'Площадь размещения, м2': total_area || 0,
|
||
};
|
||
};
|
||
|
||
const handleOpenEdit = (event) => {
|
||
event.stopPropagation();
|
||
setEditFormData(prepareProjectDataForEdit());
|
||
setEditModalOpen(true);
|
||
};
|
||
|
||
const handleCloseEdit = () => {
|
||
setEditModalOpen(false);
|
||
setEditFormData({});
|
||
};
|
||
|
||
const handleCheckboxClick = (event) => {
|
||
event.stopPropagation();
|
||
if (!isLoadingFile) {
|
||
setIsChecked(!isChecked);
|
||
onAddForExport(!isChecked);
|
||
} else {
|
||
toast.warning('Файл формируется!');
|
||
}
|
||
};
|
||
|
||
const handleExportProject = (event) => {
|
||
event.stopPropagation();
|
||
onExportClick?.(id, name);
|
||
};
|
||
|
||
const handleNavigate = () => {
|
||
if (!exportMode) {
|
||
navigate(`/project/${id}`);
|
||
}
|
||
};
|
||
|
||
// Обновленная функция обновления проекта
|
||
const updateProject = async (formData) => {
|
||
try {
|
||
const projectData = {
|
||
name: formData['Название проекта'] || currentName,
|
||
project_type: formData['Тип проекта развития'] || null,
|
||
vsp_format: formData['Формат ВСП'] || null,
|
||
object_address: formData['Адрес объекта'] || '',
|
||
staff_count: Number(formData['Целевая численность, чел.']) || 0,
|
||
placement_type: formData['Тип размещения'] || null,
|
||
total_area: Number(formData['Площадь размещения, м2']) || 0,
|
||
year: formData['Год'] ? Number(formData['Год']) : null,
|
||
branch_id: formData['ССП/РФ'] || null,
|
||
};
|
||
|
||
await ProjectsApi.update(id, projectData);
|
||
|
||
// Обновляем локальные данные
|
||
setCurrentName(projectData.name);
|
||
setEditModalOpen(false);
|
||
toast.success('Данные проекта успешно обновлены');
|
||
|
||
// Можно добавить рефреш данных или перезагрузку страницы
|
||
window.location.reload(); // или используйте callback для обновления списка
|
||
} catch (error) {
|
||
toast.error(error?.response?.data?.detail || 'Не удалось обновить данные проекта');
|
||
}
|
||
};
|
||
|
||
const handleSaveProject = async (formData) => {
|
||
await updateProject(formData);
|
||
};
|
||
|
||
const getInitials = (name) => {
|
||
if (!name) return '?';
|
||
const words = name.split(' ');
|
||
if (words.length >= 2) {
|
||
return `${words[0][0]}${words[1][0]}`.toUpperCase();
|
||
}
|
||
return name.substring(0, 2).toUpperCase();
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<ProjectCard onClick={handleNavigate} key={id}>
|
||
<Box sx={{ width: '100%' }}>
|
||
<CardHeader>
|
||
<ProjectId>ID: {id}</ProjectId>
|
||
<Stack direction={'row'} spacing={'.5rem'} sx={{}}>
|
||
{!exportMode && (
|
||
<>
|
||
{status && <StatusChip status={status} label={getStatusLabel(status)} size='small' />}
|
||
{/* {Пока нет редактирование + экспорт} */}
|
||
{/* <ExportButton onClick={handleExportProject} />
|
||
<Edit onClick={handleOpenEdit} /> */}
|
||
</>
|
||
)}
|
||
</Stack>
|
||
</CardHeader>
|
||
|
||
<ProjectTitle>{currentName}</ProjectTitle>
|
||
|
||
<ProjectInfoGrid>
|
||
{project_type && <InfoChip label={`Тип: ${project_type}`} size='small' />}
|
||
{report_count !== undefined && report_count !== null && <InfoChip label={`Отчетов: ${report_count}`} size='small' />}
|
||
</ProjectInfoGrid>
|
||
</Box>
|
||
|
||
<Stack
|
||
sx={{
|
||
direction: 'row',
|
||
justifyContent: 'space-between',
|
||
width: '100%',
|
||
alignItems: 'end',
|
||
}}>
|
||
<CardBody>
|
||
<IconWithContent icon={<DateIcon />}>{years.join(', ') || 'Год не указан'}</IconWithContent>
|
||
<IconWithContent icon={<UserIcon />}>{org_unit_name || 'Организация не указана'}</IconWithContent>
|
||
</CardBody>
|
||
|
||
{exportMode && <div>{isChecked ? <CheckBoxCheckSvg size='1.625rem' /> : <CheckBoxUncheckSvg size='1.625rem' />}</div>}
|
||
</Stack>
|
||
</ProjectCard>
|
||
|
||
<ModalCreateProject
|
||
open={isEditModalOpen}
|
||
onClose={handleCloseEdit}
|
||
onCreate={handleSaveProject}
|
||
config={projectData}
|
||
initialData={editFormData}
|
||
isEdit={true}
|
||
projectId={id}
|
||
/>
|
||
</>
|
||
);
|
||
};
|