import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; import { ruRU } from "@mui/x-data-grid/locales"; import { authStore, carrierStore, languageStore, routeStore, selectedCityStore, SearchInput } from "@shared"; import { useEffect, useState, useMemo } from "react"; import { observer } from "mobx-react-lite"; import { Map, Pencil, Trash2, Minus, Monitor } from "lucide-react"; import { useNavigate } from "react-router-dom"; import { CreateButton, DeleteModal, LanguageSwitcher } from "@widgets"; import { Box, CircularProgress, Tooltip } from "@mui/material"; export const RouteListPage = observer(() => { const { routes, getRoutes, deleteRoute, sightCounts, stationCounts, countsLoading, loadCounts } = routeStore; const { carriers, getCarriers } = carrierStore; const navigate = useNavigate(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isBulkDeleteModalOpen, setIsBulkDeleteModalOpen] = useState(false); const [rowId, setRowId] = useState(null); const [ids, setIds] = useState([]); const [isLoading, setIsLoading] = useState(false); const [paginationModel, setPaginationModel] = useState({ page: 0, pageSize: 50, }); const { language } = languageStore; const canWriteRoutes = authStore.canWrite("routes"); const canShowRoutePreview = authStore.canWrite("stations") && authStore.canWrite("sights") && authStore.canWrite("routes"); const canShowActionsColumn = canWriteRoutes || canShowRoutePreview; const [searchQuery, setSearchQuery] = useState(""); useEffect(() => { const fetchData = async () => { setIsLoading(true); await getCarriers("ru"); await getCarriers("en"); await getCarriers("zh"); await getRoutes(); setIsLoading(false); const routeIds = routeStore.routes.data.map((r) => r.id); loadCounts(routeIds); }; fetchData(); }, [language, selectedCityStore.cityVersion]); const columns: GridColDef[] = [ { field: "carrier_id", headerName: "Перевозчик", width: 250, renderCell: (params: GridRenderCellParams) => { return (
{params.value ? ( carriers[language].data.find( (carrier) => carrier.id == params.value )?.short_name ) : ( )}
); }, }, { field: "route_name", headerName: "Название маршрута", flex: 1, renderCell: (params: GridRenderCellParams) => { return (
{params.value ? ( params.value ) : ( )}
); }, }, { field: "route_number", headerName: "Номер маршрута", flex: 1, renderCell: (params: GridRenderCellParams) => { return (
{params.value ? ( params.value ) : ( )}
); }, }, { field: "route_sys_number", headerName: "Номер трассы маршрута", description: "Уникальный номер трассы маршрута, в т.ч. используемый системой \"Говорящий город\"", flex: 1, renderCell: (params: GridRenderCellParams) => { return (
{params.value ? ( params.value ) : ( )}
); }, }, { field: "route_direction", headerName: "Направление", flex: 1, renderCell: (params: GridRenderCellParams) => { return (

{params.row.route_direction}

); }, }, { field: "sightCount", headerName: "Достопримечательности", width: 180, align: "center" as const, headerAlign: "center" as const, sortable: true, renderHeader: (params: any) => ( {params.colDef.headerName} ), renderCell: (params: GridRenderCellParams) => (
{params.value === null ? : params.value}
), }, { field: "stationCount", headerName: "Остановки", width: 120, align: "center" as const, headerAlign: "center" as const, sortable: true, renderHeader: (params: any) => ( {params.colDef.headerName} ), renderCell: (params: GridRenderCellParams) => (
{params.value === null ? : params.value}
), }, ...(canShowActionsColumn ? [{ field: "actions", headerName: "Действия", width: 250, align: "center" as const, headerAlign: "center" as const, sortable: false, renderCell: (params: GridRenderCellParams) => { return (
{canWriteRoutes && ( )} {canShowRoutePreview && ( )} {canShowRoutePreview && ( )} {canWriteRoutes && ( )}
); }, }] : []), ]; const rows = useMemo(() => { const { selectedCityId } = selectedCityStore; if (!selectedCityId) { return []; } const query = searchQuery.trim().toLowerCase(); let filtered = routes.data; if (selectedCityId) { const cityCarrierIds = new Set( carriers["ru"].data .filter((c) => c.city_id === selectedCityId) .map((c) => c.id) ); filtered = filtered.filter((route) => cityCarrierIds.has(route.carrier_id)); } return filtered .filter( (route) => !query || (route.route_name ?? "").toLowerCase().includes(query) || String(route.route_number ?? "").toLowerCase().includes(query) ) .map((route) => ({ id: route.id, carrier_id: route.carrier_id, route_number: route.route_number, route_sys_number: route.route_sys_number, route_direction: route.route_direction ? "Прямой" : "Обратный", route_name: route.route_name, sightCount: sightCounts.has(route.id) ? sightCounts.get(route.id) : null, stationCount: stationCounts.has(route.id) ? stationCounts.get(route.id) : null, })); }, [routes.data, carriers["ru"].data, selectedCityStore.selectedCityId, searchQuery, sightCounts.size, stationCounts.size, countsLoading]); return ( <>

Маршруты

{canWriteRoutes && ( )}
{canWriteRoutes && ids.length > 0 && (
)} canWriteRoutes && navigate(`/route/${params.row.id}/edit`)} checkboxSelection={canWriteRoutes} disableRowSelectionExcludeModel disableRowSelectionOnClick loading={isLoading} paginationModel={paginationModel} onPaginationModelChange={setPaginationModel} pageSizeOptions={[50]} localeText={ruRU.components.MuiDataGrid.defaultProps.localeText} onRowSelectionModelChange={ canWriteRoutes ? (newSelection: any) => { if (Array.isArray(newSelection)) { const selectedIds = newSelection.map((id: string | number) => Number(id) ); setIds(selectedIds); } else if ( newSelection && typeof newSelection === "object" && "ids" in newSelection ) { const idsSet = newSelection.ids as Set; const selectedIds = Array.from(idsSet).map( (id: string | number) => Number(id) ); setIds(selectedIds); } else { setIds([]); } } : undefined } slots={{ noRowsOverlay: () => ( {isLoading ? ( ) : !selectedCityStore.selectedCityId ? ( "Выберите город" ) : ( "Нет маршрутов" )} ), }} />
{ if (rowId) { deleteRoute(rowId); } setIsDeleteModalOpen(false); setRowId(null); }} onCancel={() => { setIsDeleteModalOpen(false); setRowId(null); }} /> { await Promise.all(ids.map((id) => deleteRoute(id))); getRoutes(); setIsBulkDeleteModalOpen(false); setIds([]); }} onCancel={() => { setIsBulkDeleteModalOpen(false); }} /> ); });