diff --git a/web/src/api/stages.js b/web/src/api/stages.js index 771142d..6b9d669 100644 --- a/web/src/api/stages.js +++ b/web/src/api/stages.js @@ -2,20 +2,25 @@ import api from './client'; export const StagesApi = { createStage(formId, payload) { - return api.put(`/forms/${formId}/stages`, [payload]).then((r) => r.data); + return api.post(`/stages/form/${formId}`, [payload]).then((r) => r.data); }, - updateStage(formId, stage) { + updateStage(payload) { + const { budget_form_id, sheet, phase_code, opens_at, closes_at } = payload; + return api - .patch(`/forms/${formId}/stages/${stage.id}`, stage) + .patch(`/stages/form/${budget_form_id}/${sheet}/${phase_code}`, { + opens_at, + closes_at, + }) .then((r) => r.data); }, - deleteStage(formId, stage) { + deleteStage(formId, sheet, phaseCode) { return api - .delete(`/forms/${formId}/stages/${stage.id}`) + .delete(`/stages/form/${formId}/${sheet}/${phaseCode}`) .then((r) => r.data); }, getStages(formId) { - return api.get(`/forms/${formId}/stages`).then((r) => r.data); + return api.get(`/stages/form/${formId}`).then((r) => r.data); }, createStageAccessHeader(tableId, stageId, payload) { return api diff --git a/web/src/api/tasks.js b/web/src/api/tasks.js index af20cd9..db7291d 100644 --- a/web/src/api/tasks.js +++ b/web/src/api/tasks.js @@ -13,9 +13,6 @@ export const TasksApi = { getById(formId) { return api.get(`/form/${formId}`).then((r) => r.data); }, - getTaskStages(taskId) { - return api.get(`/tasks/${taskId}/stages`).then((r) => r.data); - }, create(payload) { return api.put("/tasks/", payload).then((r) => r.data); }, diff --git a/web/src/components/Stages/AddStagesModal.jsx b/web/src/components/Stages/AddStagesModal.jsx index 41b0ae9..4b41b89 100644 --- a/web/src/components/Stages/AddStagesModal.jsx +++ b/web/src/components/Stages/AddStagesModal.jsx @@ -30,42 +30,40 @@ export const AddStagesModal = ({ isTaskMode = false, isSaving = false, }) => { - const [stageName, setStageName] = useState(''); const [startDate, setStartDate] = useState(null); const [endDate, setEndDate] = useState(null); useEffect(() => { if (stage !== null) { - setStageName(stage.name); - setStartDate(stage.period_start || null); - setEndDate(stage.period_end || null); + setStartDate(stage.opens_at ?? null); + setEndDate(stage.closes_at ?? null); } else { - setStageName(''); setStartDate(null); setEndDate(null); } }, [stage, isOpen]); const handleSave = () => { - const periodStart = formatDateForApi(startDate); - const periodEnd = formatDateForApi(endDate); + const opensAt = formatDateForApi(startDate); + const closesAt = formatDateForApi(endDate); if (stage === null) { - createStage(stageName, periodStart, periodEnd)?.then(() => { + if (!createStage) return; + createStage(opensAt, closesAt)?.then(() => { handleCancel(); }); } else { - stage.name = stageName; - stage.period_start = periodStart; - stage.period_end = periodEnd; - updateStage(stage)?.then(() => { + updateStage({ + ...stage, + opens_at: opensAt, + closes_at: closesAt, + })?.then(() => { handleCancel(); }); } }; const handleCancel = () => { - setStageName(''); setStartDate(null); setEndDate(null); onClose(); @@ -77,7 +75,7 @@ export const AddStagesModal = ({ } }; - const isFormValid = stageName && startDate && endDate; + const isFormValid = startDate && endDate; if (!isOpen) return null; @@ -88,7 +86,7 @@ export const AddStagesModal = ({ - + {stage ? 'Редактирование этапа' : 'Добавление этапа'} @@ -108,22 +106,6 @@ export const AddStagesModal = ({ - - - Название этапа - setStageName(e.target.value)} - placeholder="Введите название этапа" - fullWidth - size="small" - /> - - { - const currentYearValue = new Date().getFullYear(); +const getToday = () => { + const today = new Date(); + today.setHours(0, 0, 0, 0); + return today; +}; - const initialDate = isTaskMode - ? value - ? new Date(value) - : null - : convertYearFromBackend(value); - const initialDisplayYear = initialDate - ? initialDate.getFullYear() - : currentYearValue; +const parseValue = (dateString) => { + if (!dateString) return null; + const date = new Date(dateString); + return Number.isNaN(date.getTime()) ? null : date; +}; - const [selectedYear, setSelectedYear] = useState(initialDisplayYear); +export const Calendar = ({ value, onChange, onClose }) => { + const initialDate = parseValue(value); const [currentDate, setCurrentDate] = useState(initialDate || new Date()); const [selectedDate, setSelectedDate] = useState(initialDate); useEffect(() => { - if (value) { - const date = isTaskMode ? new Date(value) : convertYearFromBackend(value); - if (date) { - setCurrentDate(date); - setSelectedDate(date); - setSelectedYear(date.getFullYear()); - } + const date = parseValue(value); + if (date) { + setCurrentDate(date); + setSelectedDate(date); } - }, [value, isTaskMode]); - - const handleYearChange = (newYear) => { - setSelectedYear(newYear); - setCurrentDate(new Date(newYear, currentDate.getMonth(), 1)); - }; + }, [value]); const year = currentDate.getFullYear(); const month = currentDate.getMonth(); const firstDayOfMonth = new Date(year, month, 1); const lastDayOfMonth = new Date(year, month + 1, 0); - const firstDayOfWeek = (firstDayOfMonth.getDay() + 6) % 7; // Понедельник = 0 + const firstDayOfWeek = (firstDayOfMonth.getDay() + 6) % 7; const daysInMonth = lastDayOfMonth.getDate(); - // Нельзя листать раньше января текущего года - const isPrevMonthDisabled = year === currentYearValue && month === 0; - - // Нельзя листать дальше декабря следующего года - const isNextMonthDisabled = year === currentYearValue + 1 && month === 11; + const today = getToday(); + const isPrevMonthDisabled = + year < today.getFullYear() || + (year === today.getFullYear() && month <= today.getMonth()); const handlePrevMonth = () => { - if (!isPrevMonthDisabled) { - setCurrentDate(new Date(year, month - 1, 1)); - } + if (isPrevMonthDisabled) return; + setCurrentDate(new Date(year, month - 1, 1)); }; const handleNextMonth = () => { - if (!isNextMonthDisabled) { - setCurrentDate(new Date(year, month + 1, 1)); - } + setCurrentDate(new Date(year, month + 1, 1)); }; const handleDateClick = (day) => { const newDate = new Date(year, month, day); + if (isPastDate(newDate)) return; + setSelectedDate(newDate); - // Преобразуем год для бэкенда: текущий - 1970, следующий - 1971 - // Для задач используем реальный год - let yearForBackend = year; - if (!isTaskMode) { - if (selectedYear === currentYearValue) { - yearForBackend = 1970; - } else if (selectedYear === currentYearValue + 1) { - yearForBackend = 1971; - } - } - - const formattedDate = `${yearForBackend}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; + const formattedDate = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; onChange(formattedDate); onClose(); }; - const isToday = (day) => { - const today = new Date(); - return ( - day === today.getDate() && - month === today.getMonth() && - year === today.getFullYear() - ); - }; + const isToday = (day) => + day === today.getDate() && + month === today.getMonth() && + year === today.getFullYear(); + + const isDayPast = (day) => isPastDate(new Date(year, month, day)); const isSelected = (day) => { if (!selectedDate) return false; @@ -119,14 +96,12 @@ export const Calendar = ({ value, onChange, onClose, isTaskMode = false }) => { return ( - - @@ -143,6 +118,7 @@ export const Calendar = ({ value, onChange, onClose, isTaskMode = false }) => { onClick={() => handleDateClick(day)} isToday={isToday(day)} isSelected={isSelected(day)} + isDisabled={isDayPast(day)} > {day} diff --git a/web/src/components/Stages/Calendar/Calendar.styles.jsx b/web/src/components/Stages/Calendar/Calendar.styles.jsx index 1a99e95..40b3537 100644 --- a/web/src/components/Stages/Calendar/Calendar.styles.jsx +++ b/web/src/components/Stages/Calendar/Calendar.styles.jsx @@ -37,7 +37,8 @@ export const CalendarWeekday = styled(Box)` `; export const CalendarDay = styled(Box, { - shouldForwardProp: (prop) => prop !== 'isToday' && prop !== 'isSelected', + shouldForwardProp: (prop) => + prop !== 'isToday' && prop !== 'isSelected' && prop !== 'isDisabled', })` display: flex; align-items: center; @@ -70,4 +71,16 @@ export const CalendarDay = styled(Box, { background: #258141; } `} + + ${(props) => + props.isDisabled && + ` + color: #d1d5db; + cursor: not-allowed; + pointer-events: none; + + &:hover { + background: transparent; + } + `} `; diff --git a/web/src/components/Stages/Calendar/CalendarHeader.jsx b/web/src/components/Stages/Calendar/CalendarHeader.jsx index c3d142c..88210ab 100644 --- a/web/src/components/Stages/Calendar/CalendarHeader.jsx +++ b/web/src/components/Stages/Calendar/CalendarHeader.jsx @@ -6,10 +6,10 @@ import { monthNames } from './constants'; export const CalendarHeader = ({ month, + year, onPrevMonth, onNextMonth, isPrevMonthDisabled, - isNextMonthDisabled, }) => { return ( @@ -20,12 +20,10 @@ export const CalendarHeader = ({ > - {monthNames[month]} - + + {monthNames[month]} {year} + + diff --git a/web/src/components/Stages/Calendar/CalendarInput.jsx b/web/src/components/Stages/Calendar/CalendarInput.jsx index b805b47..4650be0 100644 --- a/web/src/components/Stages/Calendar/CalendarInput.jsx +++ b/web/src/components/Stages/Calendar/CalendarInput.jsx @@ -9,35 +9,13 @@ import { } from '@mui/material'; import { CalendarIcon } from '../../common/icons/icons'; import { Calendar } from './Calendar'; +import { formatDate } from '../../../utils/formatDate'; export const CalendarInput = ({ value, onChange, isTaskMode = false }) => { const [isOpen, setIsOpen] = useState(false); const containerRef = useRef(null); const [anchorPosition, setAnchorPosition] = useState(null); - const formatDateForDisplay = (dateString) => { - if (!dateString) return ''; - - const date = new Date(dateString); - const currentYear = new Date().getFullYear(); - const backendYear = date.getFullYear(); - - const day = String(date.getDate()).padStart(2, '0'); - const month = String(date.getMonth() + 1).padStart(2, '0'); - - if (isTaskMode) { - return `${day}.${month}.${backendYear}`; - } - - if (backendYear === 1970 || backendYear === currentYear) { - return `Текущий год: ${day}.${month}`; - } else if (backendYear === 1971 || backendYear === currentYear + 1) { - return `Следующий год: ${day}.${month}`; - } else { - return `${day}.${month}.${backendYear}`; - } - }; - const handleOpen = () => { if (containerRef.current) { const rect = containerRef.current.getBoundingClientRect(); @@ -58,7 +36,7 @@ export const CalendarInput = ({ value, onChange, isTaskMode = false }) => { <> { value={value} onChange={onChange} onClose={handleClose} - isTaskMode={isTaskMode} /> diff --git a/web/src/components/Stages/Modal.styles.jsx b/web/src/components/Stages/Modal.styles.jsx index d17c5f7..de1817f 100644 --- a/web/src/components/Stages/Modal.styles.jsx +++ b/web/src/components/Stages/Modal.styles.jsx @@ -23,7 +23,7 @@ export const ModalContainer = styled.div` display: flex; flex-direction: column; justify-content: flex-start; - align-items: flex-end; + align-items: stretch; gap: 1rem; padding: 1.25rem; box-sizing: border-box; diff --git a/web/src/components/Stages/SettingModal.jsx b/web/src/components/Stages/SettingModal.jsx index 26b75f4..7ec0ee8 100644 --- a/web/src/components/Stages/SettingModal.jsx +++ b/web/src/components/Stages/SettingModal.jsx @@ -10,7 +10,14 @@ import { useTaskStages } from '../../hooks/useTaskStages'; import { AddStagesModal } from './AddStagesModal'; import { DeleteStageModal } from './DeleteStageModal'; import { WhitePlus } from '../common/icons/icons'; -import { Button, IconButton, Stack, Typography } from '@mui/material'; +import { + Box, + Button, + CircularProgress, + IconButton, + Stack, + Typography, +} from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { StagesTable } from './StagesTable/StagesTable'; @@ -37,10 +44,10 @@ export const SettingModal = ({ const entityId = mode === 'task' ? taskId : formId; useEffect(() => { - if (entityId) { + if (isOpen && entityId) { getStages(); } - }, [entityId, getStages]); + }, [isOpen, entityId, getStages]); const [isAddEditModalOpen, setIsAddEditModalOpen] = useState(false); const [stageForEdit, setStageForEdit] = useState(null); @@ -76,9 +83,12 @@ export const SettingModal = ({ isOpen={isOpen} onClose={onClose} children={ - + - + @@ -87,8 +97,7 @@ export const SettingModal = ({ Этапы {!isTaskMode && ( @@ -102,11 +111,23 @@ export const SettingModal = ({ )} - + {stagesInfo.isLoading ? ( + + + + ) : ( + + )} { diff --git a/web/src/components/Stages/StagesTable/StagesTable.jsx b/web/src/components/Stages/StagesTable/StagesTable.jsx index a18146b..72fbf30 100644 --- a/web/src/components/Stages/StagesTable/StagesTable.jsx +++ b/web/src/components/Stages/StagesTable/StagesTable.jsx @@ -17,13 +17,10 @@ import { StyledTableHeadRow, StyledTableRow, } from './StagesTable.style'; -import { - getStageStatus, - getStatusColors, - convertYearForDisplay, -} from './utils'; +import { getStageStatus, getStatusColors } from './utils'; +import { formatDate } from '../../../utils/formatDate'; import { StageStatusChip } from '../StageStatusChip'; -import { ROLES_NAME_ID } from '../../../constants'; +import { ROLES_NAME_ID, STAGE_ROLE_RUSSIAN_NAME } from '../../../constants'; import { useAuth } from '../../../app/context/AuthProvider'; export const StagesTable = ({ stages, onEdit, onDelete }) => { @@ -63,7 +60,7 @@ export const StagesTable = ({ stages, onEdit, onDelete }) => { - Название + Название таблицы Начало Окончание Статус @@ -81,22 +78,30 @@ export const StagesTable = ({ stages, onEdit, onDelete }) => { ) : ( - stages.map((stage) => { + stages.map((stage, index) => { const status = getStageStatus(stage); const colors = getStatusColors(status); + const rowKey = `${stage.sheet}-${stage.phase_code}-${stage.role}-${index}`; return ( - + - {stage.name} - - - - {convertYearForDisplay(stage.period_start)} + {stage.sheet} + + {STAGE_ROLE_RUSSIAN_NAME[stage.role] ?? stage.role} - {convertYearForDisplay(stage.period_end)} + {formatDate(stage.opens_at)} + + + + + {formatDate(stage.closes_at)} diff --git a/web/src/components/Stages/StagesTable/utils.js b/web/src/components/Stages/StagesTable/utils.js index 27b91fa..6bbeb39 100644 --- a/web/src/components/Stages/StagesTable/utils.js +++ b/web/src/components/Stages/StagesTable/utils.js @@ -1,59 +1,26 @@ -// Конвертации года из бэкенда (1970/1971) в реальный год -export const convertYearFromBackend = (dateString) => { - if (!dateString) return null; - - const date = new Date(dateString); - const backendYear = date.getFullYear(); - const currentYear = new Date().getFullYear(); - - let realYear = backendYear; - if (backendYear === 1970) { - realYear = currentYear; - } else if (backendYear === 1971) { - realYear = currentYear + 1; - } - - return new Date(realYear, date.getMonth(), date.getDate()); -}; - -// Форматирование даты для отображения -export const convertYearForDisplay = (dateString) => { - if (!dateString) return ''; - - const date = convertYearFromBackend(dateString); - if (!date) return ''; - - const day = String(date.getDate()).padStart(2, '0'); - const month = String(date.getMonth() + 1).padStart(2, '0'); - const year = date.getFullYear(); - return `${day}.${month}.${year}`; -}; - export const getStageStatus = (stage) => { - if (!stage.period_start || !stage.period_end) { + const start = stage.opens_at; + const end = stage.closes_at; + + if (!start || !end) { return 'Не определен'; } const now = new Date(); now.setHours(0, 0, 0, 0); - const startDate = convertYearFromBackend(stage.period_start); - const endDate = convertYearFromBackend(stage.period_end); - - if (!startDate || !endDate) { - return 'Не определен'; - } - + const startDate = new Date(start); + const endDate = new Date(end); startDate.setHours(0, 0, 0, 0); endDate.setHours(0, 0, 0, 0); if (now < startDate) { return 'Запланирован'; - } else if (now >= startDate && now < endDate) { - return 'Активен'; - } else { - return 'Завершен'; } + if (now >= startDate && now < endDate) { + return 'Активен'; + } + return 'Завершен'; }; export const getStatusColors = (status) => { diff --git a/web/src/components/Stages/utils.js b/web/src/components/Stages/utils.js index 9ffb9d9..4f0a434 100644 --- a/web/src/components/Stages/utils.js +++ b/web/src/components/Stages/utils.js @@ -6,3 +6,12 @@ export const formatDateForApi = (value) => { const day = String(d.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }; +export const isPastDate = (value) => { + if (!value) return false; + const date = new Date(value); + date.setHours(0, 0, 0, 0); + const today = new Date(); + today.setHours(0, 0, 0, 0); + return date < today; +}; + diff --git a/web/src/components/common/Modal/ModalStyled.jsx b/web/src/components/common/Modal/ModalStyled.jsx index 90693f9..181e752 100644 --- a/web/src/components/common/Modal/ModalStyled.jsx +++ b/web/src/components/common/Modal/ModalStyled.jsx @@ -10,7 +10,7 @@ const ModalContainer = styled.div` display: flex; flex-direction: column; justify-content: flex-start; - align-items: flex-end; + align-items: stretch; padding: 1.25rem; box-sizing: border-box; diff --git a/web/src/components/utils/formatters.js b/web/src/components/utils/formatters.js deleted file mode 100644 index f98db08..0000000 --- a/web/src/components/utils/formatters.js +++ /dev/null @@ -1,9 +0,0 @@ -// TODO: есть уже похожая функция в utils, может модернизировать ее -export const formatToDDMMYYYY = (dateString) => { - const date = new Date(dateString); - const day = String(date.getDate()).padStart(2, '0'); - const month = String(date.getMonth() + 1).padStart(2, '0'); - //у нас год только текущий и следующий, поэтому 1970 считается текущим - const year = date.getFullYear() == 1970 ? 'y' : 'y+1'; - return `${day}.${month}.${year}`; -}; diff --git a/web/src/constants.jsx b/web/src/constants.jsx index debba14..6aa17f7 100644 --- a/web/src/constants.jsx +++ b/web/src/constants.jsx @@ -18,6 +18,12 @@ export const ROLES_ID_RUSSIAN_NAME_ARRAY = [ { id: 3, role: 'Исполнитель' }, ]; +export const STAGE_ROLE_RUSSIAN_NAME = { + ADMIN: 'Администратор', + DFIP: 'Исполнитель ДФИП', + EXECUTOR_RF: 'Исполнитель', +}; + export const TYPES_CELLS = { numeric: 'число', text: 'текст' }; export const EDIT_ACCESS = { 1: 'RESTRICT', 2: 'VIEW', 3: 'EDIT' }; diff --git a/web/src/hooks/useStages.js b/web/src/hooks/useStages.js index 7f7ffdd..fa62e02 100644 --- a/web/src/hooks/useStages.js +++ b/web/src/hooks/useStages.js @@ -12,15 +12,17 @@ export const useStages = (formId) => { const getStages = useCallback(() => { if (!formId) return; + setStagesInfo((prev) => ({ ...prev, isLoading: true })); + StagesApi.getStages(formId) .then((data) => { - setStagesInfo((prev) => ({ - ...prev, - stages: data.result, - isLoading: true, - })); + setStagesInfo({ + stages: data.result ?? [], + isLoading: false, + }); }) .catch((error) => { + setStagesInfo((prev) => ({ ...prev, isLoading: false })); toast.error( error?.response?.data?.detail || 'Ошибка при получении этапов', ); @@ -28,12 +30,11 @@ export const useStages = (formId) => { }, [formId]); const createStage = useCallback( - (stageName, periodStart, periodEnd) => { + (periodStart, periodEnd) => { if (!formId) return Promise.reject('Нет formId'); setIsSaving(true); const payload = { - name: stageName, period_start: periodStart, period_end: periodEnd, }; @@ -65,17 +66,18 @@ export const useStages = (formId) => { if (!formId) return Promise.reject('Нет formId'); setIsSaving(true); - return StagesApi.updateStage(formId, stage) + + return StagesApi.updateStage(stage) .then((data) => { - setStagesInfo((prev) => { - const filterStages = prev.stages.filter( - (curStage) => curStage.id !== stage.id, - ); - const allStages = [...filterStages, data.result].sort( - (a, b) => a.id - b.id, - ); - return { ...prev, stages: allStages }; - }); + setStagesInfo((prev) => ({ + ...prev, + stages: prev.stages.map((curStage) => + curStage.sheet === stage.sheet && + curStage.phase_code === stage.phase_code + ? data.result + : curStage, + ), + })); toast.success('Данные об этапе обновлены'); return data; }) @@ -94,16 +96,21 @@ export const useStages = (formId) => { const deleteStage = useCallback( (stage) => { - if (!formId) return; + const { sheet, phase_code, budget_form_id } = stage; + if (!budget_form_id || !sheet || !phase_code) return; - StagesApi.deleteStage(formId, stage) - .then((data) => { - setStagesInfo((prev) => { - const filterStages = prev.stages.filter( - (curStage) => curStage.id !== stage.id, - ); - return { ...prev, stages: filterStages }; - }); + StagesApi.deleteStage(budget_form_id, sheet, phase_code) + .then(() => { + setStagesInfo((prev) => ({ + ...prev, + stages: prev.stages.filter( + (curStage) => + !( + curStage.sheet === sheet && + curStage.phase_code === phase_code + ), + ), + })); toast.success('Этап успешно удален'); }) .catch((error) => { diff --git a/web/src/hooks/useTaskStages.js b/web/src/hooks/useTaskStages.js index 2a5fbeb..e30b7ce 100644 --- a/web/src/hooks/useTaskStages.js +++ b/web/src/hooks/useTaskStages.js @@ -1,6 +1,6 @@ import { useState, useCallback } from 'react'; -import { TasksApi } from '../api/tasks'; import { toast } from 'react-toastify'; +import { StagesApi } from '../api/stages'; export const useTaskStages = (taskId) => { const [stagesInfo, setStagesInfo] = useState({ @@ -12,17 +12,17 @@ export const useTaskStages = (taskId) => { const getStages = useCallback(() => { if (!taskId) return; - TasksApi.getTaskStages(taskId) + setStagesInfo((prev) => ({ ...prev, isLoading: true })); + + StagesApi.getStages(taskId) .then((data) => { - if (data.result) { - setStagesInfo((prev) => ({ - ...prev, - stages: data.result, - isLoading: true, - })); - } + setStagesInfo({ + stages: data.result ?? [], + isLoading: false, + }); }) .catch((error) => { + setStagesInfo((prev) => ({ ...prev, isLoading: false })); toast.error( error?.response?.data?.detail || 'Ошибка при получении этапов', ); @@ -34,17 +34,18 @@ export const useTaskStages = (taskId) => { if (!taskId) return Promise.reject('Нет taskId'); setIsSaving(true); - return TasksApi.editTaskStages(taskId, stage.id, stage) + + return StagesApi.updateStage(stage) .then((data) => { - setStagesInfo((prev) => { - const filterStages = prev.stages.filter( - (curStage) => curStage.id !== stage.id, - ); - const allStages = [...filterStages, data.result].sort( - (a, b) => a.id - b.id, - ); - return { ...prev, stages: allStages }; - }); + setStagesInfo((prev) => ({ + ...prev, + stages: prev.stages.map((curStage) => + curStage.sheet === stage.sheet && + curStage.phase_code === stage.phase_code + ? data.result + : curStage, + ), + })); toast.success('Данные об этапе обновлены'); return data; }) diff --git a/web/src/index.jsx b/web/src/index.jsx index 66bf879..4acad00 100644 --- a/web/src/index.jsx +++ b/web/src/index.jsx @@ -10,6 +10,7 @@ import theme from './app/theme/theme'; import './index.css'; import App from './App'; import { ToastContainer } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; const baseName = (process.env.REACT_APP_ROOT_PATH || '/').replace(/\/$/, ''); @@ -31,7 +32,7 @@ createRoot(document.getElementById('root')).render( }} > - + diff --git a/web/src/pages/TaskPage/TaskPage.jsx b/web/src/pages/TaskPage/TaskPage.jsx index 3891cc5..a2fdbbf 100644 --- a/web/src/pages/TaskPage/TaskPage.jsx +++ b/web/src/pages/TaskPage/TaskPage.jsx @@ -146,7 +146,7 @@ export default function TaskPage() { value={query} onChange={setQuery} /> - + exportSingleForm(taskId, task?.title ?? 'form')} /> @@ -156,12 +156,14 @@ export default function TaskPage() { > Этапы - setModalStageOpen(false)} - taskId={taskId} - mode="task" - /> + {modalStageOpen && ( + setModalStageOpen(false)} + taskId={taskId} + mode="task" + /> + )}