import { useMemo, useState, useRef } from 'react'; import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table'; import { Box, Typography, IconButton, Button, Stack } from '@mui/material'; import { EditPenSvg } from '../../../components/common/icons/icons'; import ModalEditAddVsp from './Modals/ModalEditAddVsp'; import { PrimaryButton, PrimaryOutlinedButton, } from '../../../components/common/Buttons/Buttons'; import { useAuth } from '../../../app/context/AuthProvider'; import { ROLES_NAME_ID } from '../../../constants'; import ModalExport from './Modals/ModalExport'; const TableDictVsp = ({ data, onEdit, onDelete, onAdd, loading = false, ssps, selectedSsp, }) => { const { user } = useAuth(); const [modalOpen, setModalOpen] = useState(false); const [modalExportOpen, setModalExportOpen] = useState(false); const [editingItem, setEditingItem] = useState(null); const [saveLoading, setSaveLoading] = useState(false); const tableContainerRef = useRef(null); const filteredData = useMemo(() => { if (!selectedSsp) { return data; } return data.filter((item) => item.ssp_id === selectedSsp.id); }, [data, selectedSsp]); const handleEdit = (item) => { setEditingItem(item); setModalOpen(true); }; const handleAdd = () => { setEditingItem(null); setModalOpen(true); }; const handleExport = () => [setModalExportOpen(true)]; const handleSave = async (formData) => { setSaveLoading(true); try { if (editingItem) { await onEdit?.({ ...formData, id: editingItem.id }); } else { await onAdd?.(formData); } setModalOpen(false); } catch (error) { console.error('Error saving:', error); } finally { setSaveLoading(false); } }; const columns = useMemo( () => [ { accessorKey: 'index', header: '№', size: 60, minSize: 50, maxSize: 70, enableColumnActions: false, enableSorting: false, Cell: ({ row }) => ( {row.index + 1} ), }, { accessorKey: 'system_code', header: 'Код РФ', size: 180, minSize: 50, maxSize: 100, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'registration_number', header: 'Регистрационный номер ВСП', size: 180, minSize: 150, maxSize: 200, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'regional_branch', header: 'Региональный филиал/ССП', size: 120, minSize: 100, maxSize: 150, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'vsp_type', header: 'Тип ВСП', size: 120, minSize: 100, maxSize: 150, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'address', header: 'Адрес объекта', size: 250, minSize: 200, maxSize: 350, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'approved_format', header: 'Утверждённый формат', size: 150, minSize: 120, maxSize: 180, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'open_date', header: 'Дата открытия ВСП', size: 130, minSize: 110, maxSize: 150, Cell: ({ cell }) => { const date = cell.getValue(); return ( {date ? new Date(date).toLocaleDateString('ru-RU') : '-'} ); }, enableColumnActions: false, enableSorting: false, }, { accessorKey: 'close_date', header: 'Дата закрытия ВСП', size: 130, minSize: 110, maxSize: 150, Cell: ({ cell }) => { const date = cell.getValue(); return ( {date ? new Date(date).toLocaleDateString('ru-RU') : '-'} ); }, enableColumnActions: false, enableSorting: false, }, { accessorKey: 'location_form', header: 'Форма расположения ВСП', size: 170, minSize: 140, maxSize: 200, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'numbers', header: 'Штатная численность ВСП', size: 170, minSize: 140, maxSize: 200, Cell: ({ cell }) => { const value = cell.getValue(); return ( {value !== undefined && value !== null ? value : '-'} ); }, enableColumnActions: false, enableSorting: false, }, { accessorKey: 'area', header: 'Площадь', size: 100, minSize: 80, maxSize: 120, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'rent_contract_num', header: 'Номер договора', size: 130, minSize: 110, maxSize: 160, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, { accessorKey: 'rent_end_date', header: 'Дата окончания договора', size: 150, minSize: 130, maxSize: 170, Cell: ({ cell }) => { const date = cell.getValue(); return ( {date ? new Date(date).toLocaleDateString('ru-RU') : '-'} ); }, enableColumnActions: false, enableSorting: false, }, { accessorKey: 'notes', header: 'Примечания', size: 200, minSize: 150, maxSize: 300, Cell: ({ cell }) => ( {cell.getValue() || '-'} ), enableColumnActions: false, enableSorting: false, }, ], [], ); const table = useMaterialReactTable({ columns, data: filteredData, enableEditing: true, enableRowActions: true, enableTopToolbar: true, enableColumnFilters: false, enableGlobalFilter: false, enableSorting: false, enablePagination: false, positionActionsColumn: 'last', // Включаем изменение размера колонок для лучшего UX при горизонтальном скролле // enableColumnResizing: true, columnResizeMode: 'onChange', enableToolbarInternalActions: false, initialState: { columnPinning: { left: ['index', 'system_code', 'registration_number'], right: ['mrt-row-actions'], }, }, renderTopToolbar: () => ( Справочник объектов Экспортировать {user.role_id == ROLES_NAME_ID.admin && ( + Добавить объект )} ), muiTopToolbarProps: { sx: { backgroundColor: '#F9FAFB', minHeight: 'auto', padding: '1rem 1rem 0 1rem', position: 'sticky', top: 0, zIndex: 10, '& .MuiToolbar-root': { padding: 0, minHeight: 'auto', width: '100%', }, }, }, displayColumnDefOptions: { 'mrt-row-actions': { header: 'Действия', size: 80, muiTableHeadCellProps: { align: 'center', }, muiTableBodyCellProps: { align: 'center', }, }, }, renderRowActions: ({ row }) => ( <> handleEdit(row.original)} sx={{ padding: '4px', '&:hover': { backgroundColor: 'rgba(0, 0, 0, 0.04)', }, }} title="Редактировать" > ), state: { isLoading: loading, }, muiTablePaperProps: { sx: { borderRadius: '.63rem', border: '1px solid #f2f2f2', boxShadow: 'none', overflow: 'hidden', position: 'relative', padding: '20px', width: '100%', }, }, muiTableContainerProps: { ref: tableContainerRef, sx: { maxHeight: 'calc(100vh - 450px)', minHeight: '40rem', width: '100%', marginTop: '1.5rem', overflowX: 'auto', // Включаем горизонтальный скролл overflowY: 'auto', // Вертикальный скролл position: 'relative', // Добавляем индикатор скролла для лучшего UX '&::-webkit-scrollbar': { height: '8px', width: '8px', }, '&::-webkit-scrollbar-track': { backgroundColor: '#f1f1f1', borderRadius: '4px', }, '&::-webkit-scrollbar-thumb': { backgroundColor: '#c1c1c1', borderRadius: '4px', '&:hover': { backgroundColor: '#a8a8a8', }, }, }, }, // Обеспечиваем минимальную ширину таблицы для скролла muiTableProps: { sx: { minWidth: 'max-content', // Таблица будет занимать минимум необходимую ширину width: '100%', }, }, muiTableBodyRowProps: { sx: { '& .MuiTableCell-root': { padding: '0.75rem', }, '&:hover': { backgroundColor: 'white !important', }, '&:hover td::after': { opacity: '0 !important', backgroundColor: 'transparent !important', }, '&:hover .MuiTableCell-root': { backgroundColor: 'white !important', }, }, }, muiTableHeadProps: { sx: { position: 'sticky', top: 0, zIndex: 10, }, }, muiTableHeadRowProps: { sx: { position: 'sticky', backgroundColor: '#F9FAFB', color: '#4A5565', fontSize: '0.88rem', '& .MuiTableCell-root': { padding: '1rem 0.75rem', fontWeight: 'bold', backgroundColor: '#F9FAFB', whiteSpace: 'nowrap', // Заголовки тоже не переносим }, '& .Mui-TableHeadCell-Content': { '& .Mui-TableHeadCell-Content-Labels': { overflow: 'visible', }, '& .MuiSvgIcon-root': { fontSize: '1.2rem', marginLeft: '8px', overflow: 'visible !important', }, }, }, }, muiTableBodyCellProps: { sx: { padding: '0.75rem', fontSize: '0.75rem', lineHeight: '150%', color: '#364153', whiteSpace: 'nowrap', // Предотвращаем перенос текста }, }, muiTableHeadCellProps: { sx: { padding: '1rem 0.75rem', fontSize: 'inherit', fontWeight: 'bold', whiteSpace: 'nowrap', // Заголовки не переносим '& .MuiSvgIcon-root': { fontSize: '1.2rem', marginLeft: '4px', flexShrink: 0, }, }, }, muiBottomToolbarProps: { sx: { display: 'none', }, }, localization: { noRecordsToDisplay: 'Нет данных для отображения', }, }); return ( <> setModalOpen(false)} onSave={handleSave} onDelete={onDelete} initialData={editingItem} loading={saveLoading} ssps={ssps} /> setModalExportOpen(false)} ssps={ssps} /> ); }; export default TableDictVsp;