// src/components/common/PaginatedList/PaginatedList.jsx import { useState, useEffect } from 'react'; import { Box, Pagination, PaginationItem, Select, MenuItem, Typography, Stack, } from '@mui/material'; import { CardsSkeleton } from './Skeleton'; import { ExportExitButton, ExportWithTextButton, } from './Buttons/ButtonsActions'; import { exportBulkForms, exportSingleForm } from '../../utils/exportFile'; /** * Универсальный компонент для отображения списка с пагинацией и экспортом * * @param {Object} props * @param {Array} props.items - Массив элементов для отображения * @param {boolean} props.loading - Состояние загрузки * @param {number} props.totalCount - Общее количество элементов * @param {number} props.page - Текущая страница * @param {number} props.limit - Количество элементов на странице * @param {Function} props.onPageChange - Обработчик изменения страницы * @param {Function} props.onLimitChange - Обработчик изменения лимита * @param {Function} props.renderItem - Функция рендеринга элемента * @param {Function} props.getItemId - Функция получения ID элемента * @param {Function} props.getItemTitle - Функция получения заголовка элемента * @param {string} props.entityName - Название сущности (для текстов) * @param {string} props.emptyMessage - Сообщение при пустом списке * @param {number} props.skeletonCount - Количество силуэтов таблиц при загрузки * @param {Object} props.extraActions - Дополнительные действия справа * @param {boolean} props.enableExport - Включить экспорт * @param {Array} props.limitOptions - Опции для выбора лимита * @param {number} props.maxHeight - Максимальная высота контейнера со скроллом * @param {boolean} props.enableScroll - Включить скролл для списка * @param {boolean} props.filterActions - Элементы фильтрации */ export function PaginatedList({ items = [], loading = false, totalCount = 0, page = 1, limit = 20, onPageChange, onLimitChange, renderItem, getItemId, getItemTitle = (item) => `Элемент ${getItemId(item)}`, entityName = 'элементов', emptyMessage = 'Элементы не найдены', skeletonCount = 20, extraActions = null, enableExport = true, limitOptions = [10, 20, 50, 100, 200], maxHeight = 'calc(100vh - 300px)', enableScroll = true, filterActions = null, }) { const [exportMode, setExportMode] = useState(false); const [exportList, setExportList] = useState([]); // Сброс списка экспорта при переключении режима useEffect(() => { setExportList([]); }, [exportMode]); const handleAddToExport = (itemId, checked) => { if (checked) { setExportList((prev) => [...prev, itemId]); } else { setExportList((prev) => prev.filter((id) => id !== itemId)); } }; const handleBulkExport = async () => { await exportBulkForms(exportList); setExportMode(false); }; const handleSingleExport = (itemId) => { const item = items.find((item) => getItemId(item) === itemId); const title = item ? getItemTitle(item) : `Элемент ${itemId}`; exportSingleForm(itemId, title); }; // Если включен экспорт, передаем его пропсы в дочерние элементы const renderItemWithExport = (item) => { if (enableExport) { return renderItem(item, { exportMode, onAddForExport: (checked) => { handleAddToExport(getItemId(item), checked); }, onExportClick: () => { handleSingleExport(getItemId(item)); }, isSelected: exportList.includes(getItemId(item)), }); } return renderItem(item); }; return ( {/* Верхняя панель с экспортом и дополнительными действиями */} {enableExport && (
{filterActions}
{exportMode && ( Выделено {entityName}: {exportList.length} )} {!exportMode ? ( <> setExportMode(true)} height='2.5rem' /> {extraActions} ) : ( <> setExportMode(false)} /> )} )} {/* Контейнер со скроллом для списка */} {/* Список элементов */} {loading ? ( ) : items.length === 0 ? ( {emptyMessage} ) : ( items.map((item) => renderItemWithExport(item)) )} {/* Пагинация */} {!loading && items.length > 0 && ( Показать на странице: Всего: {totalCount} ( )} /> )} ); }