Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
gilour
/
gitep_front
/
src
/
pages
/
ProjectPage
:
ProjectPage.tsx
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
import TableComponent from "@/shared/ui/TableComponent/TableComponent"; import {Button, Checkbox, Flex, notification, Tag, Typography, Modal, Tooltip} from "antd"; import { TableRowSelection } from "antd/es/table/interface"; import React, { useEffect, useMemo, useState, useRef } from "react"; import { useMediaQuery } from "react-responsive"; import styles from './project.module.scss'; import { HeaderProject } from "./header/Header"; import { SortableBlock } from "./SortableBlock/SortableBlock"; import { useUnit } from "effector-react"; import ArrowShow from "@shared/assets/images/icons/arrow-show.svg?react"; import ArrowShowRight from "@shared/assets/images/icons/arrow-show-right.svg?react"; import { TotalBlock } from "./TotalBlock/TotalBlock"; import { DrawerComponent } from "@/shared/ui/DrawerComponent/DrawerComponent"; import { AddGroupContent } from "./addGroup/AddGroupContent"; import { AddProjectContent } from "./addProject/AddProjectContent"; import { GroupReadDrawer } from "./groupReadDrawer/groupReadDrawer"; import { createGroup } from "@/entities/payment-card/api/createGroup"; import { getGroupList } from "@/entities/payment-card/api/getGroupList"; import { createProject } from "@/entities/payment-card/api/createProject"; import { ProjectReadDrawer } from "./projectReadDrawer/ProjectReadDrawer"; import { getProjectItem } from "@/entities/project/api/getProjectItem"; import { getGroupProject } from "@/entities/project/api/getGroupProject"; import { updateProject } from "@/entities/payment-card/api/updateProject"; import { updateGroup } from "@/entities/payment-card/api/updateGroup"; import { postExcelFile } from "@/entities/project/api/postExcelFile"; import { $projectItemStore } from "@/entities/project/model"; import { useStore } from "effector-react"; import { $roleStore, $permissionStore } from "@features/roles/store/stores" import isEqual from 'lodash.isequal'; import { Helmet } from "react-helmet"; import { formatWholeSum } from '@/shared/lib'; const getAllChildKeys = (data: any[], key: string): React.Key[] => { const group = data.find(item => item.key === key); return group?.children?.map((child: any) => child.key) || []; }; const defaultProjectData = { offer_number: '', object_address: '', short_description: '', description: '', project_group_id: '', project_limits: 1222, status: 'active' } const defaultGroupData = { name: '', description: '', projects: [] } interface IStats { in_work: number income: number outcome: number } export const ProjectPage = () => { const tableToBig = useMediaQuery({ query: '(min-width: 769px)' }) const projectDataItem = useUnit($projectItemStore); const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]); const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>([]); const [sortField, setSortField] = useState<string>('name'); const [sortDirection, setSortDirection] = useState<'ASC' | 'DESC'>('ASC'); const [currentTab, setCurrentTab] = useState('current') const [isRowDrawerOpen, setIsRowDrawerOpen] = useState(false); const [openChildRow, setOpenChildRow] = useState(false); const [isAddProject, setIsAddProject] = useState(false) const [isAddGroup, setIsAddGroup] = useState(false) const [recordData, setRecordData]: any = useState(null) const [projectItemData, setProjectItemData]: any = useState(null) const [groupItemData, setGroupItemData]: any = useState(null) const [projects, setProjects] = useState([]) const [stats, setStats] = useState<IStats>({in_work: 0, income: 0, outcome: 0}) const [search, setSearch] = useState('') const [isEditDrawer, setIsEditDrawer] = useState(false) const[IsEditablebyRole, setIsEditableByRole] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [isModalProjectOpen, setIsModalProjectOpen] = useState(false); const [initialGroupData, setInitialGroupData] = useState(defaultGroupData); const [initialProjectData, setInitialProjectData] = useState(defaultProjectData); const roleStore = useUnit($roleStore).role; const transformedData = useMemo(() => { return projects?.map((group: any, groupIndex) => ({ key: group.id ? `group_${group.id}` : `ungrouped_${groupIndex}`, id: group.id ? group.id : '', supplier: group.name, totalAmountPayments: group.total_payments?.total_amount_payment, inProcess: group.total_payments?.in_process, isGroup: true, total_amounts: { total_credit: group.total_amounts.total_credit, total_debit: group.total_amounts.total_debit, }, total_limits: { credit: group.total_limits.credit, debit: group.total_limits.debit, }, subtitle: group.description || '', children: group.projects.map((project: any, projectIndex: number) => ({ key: project.id ? `${project.id}` : '', supplier: project.offer_number, totalAmountPayments: project?.project_payments?.total_amount_payment, inProcess: project?.project_payments?.in_process, isGroup: false, total_amounts: { total_credit: project.project_amounts.credit, total_debit: project.project_amounts.debit, }, total_limits: { credit: project.project_limits.credit, debit: project.project_limits.debit, }, payments: 0, ...project, })), })); }, [projects]); const prevTransformedRef = React.useRef<any[]>([]); useEffect(() => { if (!search) { prevTransformedRef.current = transformedData; return; } if (expandedRowKeys.length > 0) return; if (isEqual(prevTransformedRef.current, transformedData)) { prevTransformedRef.current = transformedData; return; } const defaultGroupKeys = transformedData .filter((g: any) => g.isGroup) .map((g: any) => g.key); if (defaultGroupKeys.length > 0) { setExpandedRowKeys(defaultGroupKeys as React.Key[]); } prevTransformedRef.current = transformedData; }, [search, transformedData, expandedRowKeys]); const [groupData, setGroupData]: any = useState({ name: '', description: '', projects: [], }) const [projectData, setProjectData] = useState({ offer_number: '', object_address: '', short_description: '', description: '', project_group_id: '', project_limits: 1222, status: 'active' }) const [projectId, setProjectId] = useState(null) const [groupId, setGroupId] = useState(null) const getProject = async() => { const { data }: any = await getGroupList({ search: search, sort: sortField, sort_direction: sortDirection, type: currentTab }) const ungroupedProjects = data.data.projects_without_groups || []; const ungroupedTotals = ungroupedProjects.reduce( (acc: any, project: any) => { acc.credit += parseFloat(project.project_limits.credit) || 0; acc.debit += parseFloat(project.project_limits.debit) || 0; acc.total_credit += project.project_amounts.credit || 0; acc.total_debit += project.project_amounts.debit || 0; return acc; }, { credit: 0, debit: 0, total_credit: 0, total_debit: 0 } ); const totalPayments = ungroupedProjects.reduce( (acc: any, project: any) => { return { in_process: acc.in_process + (project.total_payments?.in_process || 0), total_amount_payment: acc.total_amount_payment + (project.total_payments?.total_amount_payment || 0), };}, { in_process: 0, total_amount_payment: 0 } ); const ungroupedGroup = { id: null, name: "Не в группе", description: null, total_limits: { credit: ungroupedTotals.credit, debit: ungroupedTotals.debit, }, total_amounts: { total_credit: ungroupedTotals.total_credit, total_debit: ungroupedTotals.total_debit, }, total_payments: totalPayments, projects: ungroupedProjects, }; const allGroups: any = [ungroupedGroup, ...(data.data.projects_groups || [])]; setProjects(allGroups); setStats(data.data.header) } useEffect(() => { }, [projectDataItem]) useEffect(() => { getProject() }, [search, sortField, sortDirection, currentTab]) const isFirstRenderGroup = useRef(true); useEffect(() => { if (isFirstRenderGroup.current && isAddGroup) { setInitialGroupData({ ...groupData }); isFirstRenderGroup.current = false; } }, [isAddGroup]); const isFirstRender = useRef(true); useEffect(() => { // if (isFirstRender.current && isAddProject) { setInitialProjectData({...projectData}); isFirstRender.current = false; // } }, [isAddProject]); const formatterNumberPayments = (value: number): string => { const absValue = Math.abs(value); const lastTwo = absValue % 100; const lastOne = absValue % 10; if (lastTwo >= 11 && lastTwo <= 14) { return `${value} платежей`; } if (lastOne === 1) { return `${value} платеж`; } if (lastOne >= 2 && lastOne <= 4) { return `${value} платежа`; } return `${value} платежей`; }; const columns = [ { title: <Flex style={{marginLeft: '30px'}}>Название</Flex>, dataIndex: 'supplier', key: 'article', render: (value:any, record: any) => { const fullText = `${value} ${record.object_address ? `| ${record.object_address}` : ''} ${record.short_description ? `| ${record.short_description}` : ''}`; return ( <Tooltip placement="bottomRight" color="#344054" title={fullText}> <span className={styles.projectName} style={{marginLeft: '30px'}}> {!record.children ? fullText : value} </span> </Tooltip> ) } }, { title: <Flex justify="end">Доходы, ₽</Flex>, width: 140, key: 'total_amounts', dataIndex: 'total_amounts', render: (value: number, record: any) => <Flex style={{flexDirection: 'column', lineHeight: '1.3', marginLeft: 'auto'}} align="end"><span style={{color: '#52C41A'}}>{formatWholeSum(record.total_amounts.total_credit)}</span> <span style={{color: '#98A2B3', fontSize: '12px', fontWeight: 400}}>{`[${formatWholeSum(record.total_limits.credit)}]`}</span></Flex> }, { title: <Flex justify="end">Расходы, ₽</Flex>, dataIndex: 'expense', key: 'expense', width: 140, render: (value: number, record: any) => record.children ? ( <Flex style={{flexDirection: 'column', lineHeight: '1.3', marginLeft: 'auto'}} align="end"><span style={{color: '#101828'}}>{formatWholeSum(+record.total_amounts.total_debit)}</span> <span style={{color: '#FF4d4F', fontSize: '12px', fontWeight: 400}}>[{formatWholeSum(+record.total_limits.debit)}]</span></Flex> ) : <Flex style={{flexDirection: 'column', lineHeight: '1.3', marginLeft: 'auto'}} align="end"><span style={{color: '#101828'}}>{formatWholeSum(record.total_amounts.total_debit)}</span> <span style={{color: '#FF4d4F', fontSize: '12px', fontWeight: 400}}>{`[${formatWholeSum(+record.total_limits.debit)}]`}</span></Flex>, }, { title: 'Платежи в процессе', dataIndex: 'payments', width: 200, render: (value: number, record: any) => ( <Flex gap={8}> <Tag color="#EAECF0" style={{ color: '#101828' }}> {formatterNumberPayments(record?.inProcess || record?.total_payments?.in_process || 0)} ┆ {formatWholeSum(record.totalAmountPayments || record?.total_payments?.total_amount_payment || 0)} ₽ </Tag> </Flex> ), }, ]; const { totalIncome, totalExpense, selectedCount } = useMemo(() => { const selectedKeysSet = new Set(selectedKeys); let totalIncome = 0; let totalExpense = 0; let count = 0; transformedData.forEach(group => { if (selectedKeysSet.has(group.key)) { totalIncome += group.total_amounts.total_credit || 0; totalExpense += group.total_amounts.total_debit || 0; count++; return; } group.children?.forEach((project: any) => { if (selectedKeysSet.has(project.key)) { totalIncome += project.total_amounts.total_credit || 0; totalExpense += project.total_amounts.total_debit || 0; count++; } }); }); return { totalIncome, totalExpense, selectedCount: count }; }, [selectedKeys, transformedData]); const permissionsRaw = useUnit($permissionStore).permissions as any; const permissionsStore = Array.isArray(permissionsRaw) ? permissionsRaw : typeof permissionsRaw === 'string' ? permissionsRaw.split(',').filter(Boolean) : []; const allowedRoles: any = ['accountant', 'superAdmin']; const allowedCollaboratorProject: any = ['collaborator']; const isAllowedProjectEdit = () => { const isRoleAllowed = allowedRoles.includes(roleStore); return ( (isRoleAllowed) || (allowedCollaboratorProject && permissionsStore.includes("project_management")) ); }; const handleRowClick = (record: any) => { return { onClick: async (event: React.MouseEvent) => { if (record.isGroup) { event.stopPropagation(); const { data }: any = await getGroupProject(record.id) setGroupItemData(data.data) setIsRowDrawerOpen(true); setRecordData(record) setIsEditableByRole(isAllowedProjectEdit()) } if (!record.isGroup) { event.stopPropagation(); const { data }: any = await getProjectItem(record.id) setProjectItemData(data.data) setOpenChildRow(true) setRecordData(record) setIsEditableByRole(isAllowedProjectEdit()) } }, }; }; const handleGroupSelect = (groupKey: string, checked: boolean) => { const childKeys = getAllChildKeys(transformedData, groupKey); setSelectedKeys(prev => checked ? [...prev, ...childKeys] : prev.filter(k => !childKeys.includes(k)) ); }; const handleSingleSelect = (key: React.Key, checked: boolean) => { setSelectedKeys(prev => checked ? [...prev, key] : prev.filter(k => k !== key) ); }; const rowSelection: TableRowSelection<any> = useMemo(() => ({ selectedRowKeys: selectedKeys, onChange: (keys) => setSelectedKeys(keys || []), columnWidth: 45, renderCell: (checked, record) => { const stop = (e: React.MouseEvent) => { e.stopPropagation(); }; if (record.isGroup) { const childrenKeys = getAllChildKeys(transformedData, record.key); const allSelected = childrenKeys.every(k => selectedKeys.includes(k)); const indeterminate = !allSelected && childrenKeys.some(k => selectedKeys.includes(k)); if (childrenKeys.length === 0 && !record.project_group_id) { return ( <div onClick={stop}> <Checkbox checked={checked} onClick={(e) => { e.stopPropagation(); handleSingleSelect(record.key, !checked); }} /> </div> )} return ( <div onClick={stop}> <Checkbox checked={allSelected} indeterminate={indeterminate} onClick={(e) => { e.stopPropagation(); handleGroupSelect(record.key, !allSelected); }} /> </div> ); } return ( <div onClick={stop}> <Checkbox checked={checked} onClick={(e) => { e.stopPropagation(); handleSingleSelect(record.key, !checked); }} /> </div> ); } }), [selectedKeys, transformedData]); const createGroupHandler = async() => { try { await createGroup(groupData); notification.success({ message: 'Успех', description: 'Группа успешно создана', }); getProject() setIsAddGroup(false); setGroupData(defaultGroupData) await getProject(); } catch (err) { notification.error({ message: 'Ошибка', description: 'Не удалось создать группу', }); } } const createProjectHandler = async() => { try{ await createProject(projectData) notification.success({ message: 'Успех', description: 'Проект успешно создан', }); getProject() setIsAddProject(false); setProjectData(defaultProjectData) }catch(err) { notification.error({ message: 'Ошибка', description: 'Не удалось создать проект', }); } } const updateProjectHandler = async() => { if(!projectId) { return } try{ await updateProject(projectData, projectId) setRecordData({ description: projectData.description, supplier: projectData.offer_number, object_address: projectData.object_address, short_description: projectData.short_description, id: projectData.project_group_id, }); notification.success({ message: 'Успех', description: 'Проект успешно отредактирован', }); getProject() setIsAddProject(false); // setOpenChildRow(false) setIsEditDrawer(false); setProjectData(defaultProjectData); setInitialProjectData({...projectData}); }catch(err) { notification.error({ message: 'Ошибка', description: 'Не удалось отредактировать проект', }); } } const updateGroupHandler = async() => { if(!groupId) { return } try{ const payload = { ...groupData, projects: groupData.projects.join(',') }; await updateGroup(payload, groupId) setRecordData({ supplier: groupData.name, }); notification.success({ message: 'Успех', description: 'Группа успешно отредактирована', }); getProject() setIsAddGroup(false); // setIsRowDrawerOpen(false) setGroupData(defaultGroupData) }catch(err) { notification.error({ message: 'Ошибка', description: 'Не удалось отредактировать группу', }); } } const excelUpload = async () => { try { const filteredArrayOfSelectedKeys = selectedKeys.filter((item:any) => !isNaN(item)); const { data }: any = await postExcelFile({ids: filteredArrayOfSelectedKeys}); const originalUrl = data.data.url; // const modifiedUrl = originalUrl // .replace('gitep.dev-top-it.ru', 'gitep.dev-top-it.ru:8080'); const relativePath = originalUrl.split('://')[1]?.split('/').slice(1).join('/'); const modifiedUrl = originalUrl ? new URL(`/${relativePath}`, import.meta.env.VITE_BASE_URL).href : undefined; if (modifiedUrl) { const encodedUrl = encodeURI(modifiedUrl); window.open(encodedUrl, '_blank'); } } catch (error) { console.error('Ошибка загрузки файла:', error); } }; const handleSortChange = (field: string, direction: 'ASC' | 'DESC') => { setSortField(field); setSortDirection(direction); }; const handleSegmentChange = (value: string) => { if(value === 'current') { setCurrentTab('current') } else { setCurrentTab('archive') } }; const closeWithoutSave = () => { setIsModalOpen(false); setIsModalProjectOpen(false); setGroupData(defaultGroupData); setProjectData(defaultProjectData); }; const tableRef = useRef<HTMLDivElement>(null); const [tableHeight, setTableHeight] = useState(600); useEffect(() => { const calculateHeight = () => { if (tableRef.current) { const viewportHeight = window.innerHeight; const tableTop = 130; const paddingBottom = 100; const height = viewportHeight - tableTop - paddingBottom; setTableHeight(Math.max(height, 300)); } }; calculateHeight(); window.addEventListener('resize', calculateHeight); return () => window.removeEventListener('resize', calculateHeight); }, []); return ( <div className={styles.wrapper}> <Helmet> <title>Проекты | Платежи</title> </Helmet> {tableToBig && <HeaderProject transformedData={transformedData} workLength={stats.in_work} income={stats.income} outcome={stats.outcome} /> } <SortableBlock sortField={sortField} sortDirection={sortDirection} onSortChange={handleSortChange} currentTab={currentTab} handleSegmentChange={handleSegmentChange} onSearch={(value) => setSearch(value)} setAddGroup={() => setIsAddGroup(true)} setAddProject={() => setIsAddProject(true)} roleStore={roleStore} /> <Flex vertical style={{ height: 'calc(100vh - 172px)' }}> <TableComponent tableRef={tableRef} columns={columns} dataSource={transformedData} className={styles.wrapperTable} rowSelection={rowSelection} groupedView rowClassName={(record) => record.isGroupHeader ? 'group-row' : 'child-row' } expandable={{ expandedRowKeys, onExpand: (expanded, record) => { setExpandedRowKeys(prev => expanded ? [...prev, record.key] : prev.filter(key => key !== record.key)) }, }} expandIcon={({ expanded, onExpand, record }) => record.children && record.children.length > 0 ? ( <span onClick={(e) => { e.stopPropagation() onExpand(record, e) }} style={{ marginRight: 8, transition: "all 0.3s", position: 'absolute', left: '14px', top: '20px' }} > {expanded ? ( <ArrowShow width={16} height={16} /> ) : ( <ArrowShowRight width={16} height={16} /> )} </span> ) : null } onRow={handleRowClick} virtual scroll={{ x: 'auto', y: tableHeight }} components={{ body: { cell: (props: any) => ( <td {...props} style={{ ...props.style, display: 'flex', alignItems: 'center'}} /> ), }, }} /> {selectedKeys.length ? ( <TotalBlock downloadExcelHadler={excelUpload} selectedCount={selectedCount} totalIncome={totalIncome} totalExpense={totalExpense} /> ) : ''} </Flex> {/* {selectedKeys.length ? ( <TotalBlock downloadExcelHadler={excelUpload} selectedCount={selectedCount} totalIncome={totalIncome} totalExpense={totalExpense} /> ) : ''} */} <DrawerComponent open={isAddGroup} zIndexCustom={2000} IsEditablebyRole={IsEditablebyRole} handleClose={async () => { getProject() // setGroupData(defaultGroupData) setIsEditDrawer(false) const isDataChanged = groupData.name !== initialGroupData.name || groupData.description !== initialGroupData.description || !isEqual(groupData.projects, initialGroupData.projects); if (isDataChanged) { setIsModalOpen(true); } else { setGroupData(defaultGroupData); } setIsAddGroup(false) }} id={projectItemData?.id} title={`${isEditDrawer ? (recordData?.supplier ? recordData?.supplier: 'Название группы') : 'Новая группа'}`} content={<AddGroupContent isAddGroup={isAddGroup} isOpen={isAddGroup} isEdit={isEditDrawer} recordData={recordData} groupData={groupData} setGroupData={(data: any) => setGroupData({ ...groupData, ...data })}/>} footer={ <Flex gap={12} className={styles.footer}> <Button onClick={() => setIsAddGroup(false)} size="large">Отменить</Button> <Button onClick={isEditDrawer ? updateGroupHandler : createGroupHandler} disabled={!groupData?.name?.trim()} size="large" >Готово</Button> </Flex> } /> <DrawerComponent open={isAddProject} zIndexCustom={2000} IsEditablebyRole={IsEditablebyRole} handleClose={async() => { getProject() setIsAddProject(false) setIsEditDrawer(false) const isDataChanged = !isEqual(projectData, initialProjectData); if (isDataChanged) { setIsModalProjectOpen(true); } else { setProjectData(defaultProjectData); } setInitialProjectData(defaultProjectData); }} id={projectItemData?.id} title={isEditDrawer ? `${recordData.supplier} | ${recordData.object_address} | ${recordData.short_description}` : 'Новый проект'} content={ <AddProjectContent isOpen={isAddProject} isEditDrawer={isEditDrawer} projectData={projectData} setProjectData={(data: Partial<typeof projectData>) => setProjectData(prev => ({...prev, ...data}))} />} footer={ <Flex gap={12} className={styles.footer}> <Button onClick={() => setIsAddProject(false)} size="large">Отменить</Button> <Button onClick={isEditDrawer ? updateProjectHandler : createProjectHandler} size="large">Готово</Button> </Flex> } /> <DrawerComponent open={isRowDrawerOpen} handleClose={async() => { getProject() setIsRowDrawerOpen(false) }} title={recordData ? recordData.supplier : ''} id={projectItemData?.id} zIndexCustom={100} idGroup={recordData?.id} updateTable={() => getProject()} subtitle={recordData ? recordData.subtitle : ''} isRead clickEditItem={() => { setIsEditDrawer(true) setGroupId(recordData.id) setGroupData({ name: groupItemData.name, description: groupItemData.description, projects: recordData?.children?.map((it: any) => it.id), }) setIsAddGroup(true) }} width={900} content={<GroupReadDrawer isRowDrawerOpen={isRowDrawerOpen} idGroup={recordData?.id} openChildRow={isRowDrawerOpen} IsEditablebyRole={IsEditablebyRole}/>} footer={<></>} IsEditablebyRole={IsEditablebyRole} /> <DrawerComponent open={openChildRow} handleClose={async() => { getProject() setOpenChildRow(false) }} projectItemData={projectItemData} zIndexCustom={100} clickEditItem={() => { setIsEditDrawer(true) setProjectId(recordData.id) setProjectData({ offer_number: projectItemData.offer_number, object_address: projectItemData.object_address, short_description: projectItemData.short_description, description: projectItemData.description, project_group_id: projectItemData?.project_group?.id || null, project_limits: projectItemData.project_limits, status: projectItemData.status }) setIsAddProject(true) }} id={projectItemData?.id} title={recordData ? `${recordData.supplier} | ${recordData.object_address} | ${recordData.short_description}` : ''} subtitle={recordData ? recordData.description : ''} isProject updateTable={() => getProject()} isRead width={900} content={<ProjectReadDrawer projectData={projectItemData} openChildRow={openChildRow} IsEditablebyRole={IsEditablebyRole} />} footer={<></>} IsEditablebyRole={IsEditablebyRole} /> <Modal title={<p className={styles["modal-save__title"]}>Выйти без сохранения?</p>} className={styles["modal-save"]} width={460} closable={false} open={isModalOpen} onOk={() => (isEditDrawer ? updateGroupHandler : createGroupHandler)()} onCancel={() => setIsAddGroup(true)} footer={(_, { }) => ( <> <Button style={{ width: '100%' }} className="primary-red-btn" onClick={() => closeWithoutSave()} > Закрыть без сохранения </Button> </> )} > <Flex vertical gap={32}> <p className={styles["modal-save__text"]}>Данные не были сохранены. Хотите сохранить их перед выходом?</p> <Flex vertical gap={8}> <Button type="primary" key="back" onClick={() => (setIsAddGroup(true), setIsModalOpen(false))}> Вернуться </Button> <Button onClick={() => {(isEditDrawer ? updateGroupHandler : createGroupHandler)() setIsModalOpen(false) }}> Сохранить и закрыть </Button> </Flex> </Flex> </Modal> <Modal title={<p className={styles["modal-save__title"]}>Выйти без сохранения?</p>} className={styles["modal-save"]} width={460} closable={false} open={isModalProjectOpen} // onOk={() => (isEditDrawer ? updateProjectHandler : createProjectHandler)()} onCancel={() => setIsAddProject(false)} footer={(_, { }) => ( <> <Button style={{ width: '100%' }} className="primary-red-btn" onClick={() => closeWithoutSave()} > Закрыть без сохранения </Button> </> )} > <Flex vertical gap={32}> <p className={styles["modal-save__text"]}>Данные не были сохранены. Хотите сохранить их перед выходом?</p> <Flex vertical gap={8}> <Button type="primary" key="back" onClick={() => (setProjectData({ ...projectData }), setIsAddProject(true), setIsModalProjectOpen(false))}> Вернуться </Button> <Button onClick={() => {(isEditDrawer ? updateProjectHandler : createProjectHandler)() setIsModalProjectOpen(false) }}> Сохранить и закрыть </Button> </Flex> </Flex> </Modal> </div> ); };