feat: pagination for tables with deleted station directions

This commit is contained in:
2025-12-24 15:43:25 +03:00
parent 39e11ad5ca
commit a3d574a79c
20 changed files with 448 additions and 302 deletions

View File

@@ -78,7 +78,6 @@ type LinkedItemsProps<T> = {
disableCreation?: boolean;
updatedLinkedItems?: T[];
refresh?: number;
routeDirection?: boolean;
};
export const LinkedItems = <
@@ -128,7 +127,6 @@ const LinkedItemsContentsInner = <
disableCreation = false,
updatedLinkedItems,
refresh,
routeDirection,
}: LinkedItemsProps<T>) => {
const { language } = languageStore;
@@ -153,11 +151,6 @@ const LinkedItemsContentsInner = <
const availableItems = allItems
.filter((item) => !linkedItems.some((linked) => linked.id === item.id))
.filter((item) => {
if (routeDirection === undefined) return true;
return item.direction === routeDirection;
})
.filter((item) => {
const selectedCityId = selectedCityStore.selectedCityId;
if (selectedCityId && "city_id" in item) {
@@ -513,12 +506,6 @@ const LinkedItemsContentsInner = <
{type === "edit" && !disableCreation && (
<Stack gap={2} mt={2}>
<Typography variant="subtitle1">Добавить остановки</Typography>
{routeDirection !== undefined && (
<Typography variant="body2" color="textSecondary">
Показываются только остановки для{" "}
{routeDirection ? "прямого" : "обратного"} направления
</Typography>
)}
<Tabs
value={activeTab}
@@ -547,6 +534,7 @@ const LinkedItemsContentsInner = <
<TextField
{...params}
label="Выберите остановку"
placeholder="Введите название или описание остановки..."
fullWidth
/>
)}
@@ -554,16 +542,15 @@ const LinkedItemsContentsInner = <
option.id === value?.id
}
filterOptions={(options, { inputValue }) => {
const searchWords = inputValue
.toLowerCase()
.split(" ")
.filter(Boolean);
if (!inputValue.trim()) return options;
const query = inputValue.toLowerCase();
return options.filter((option) => {
const optionWords = String(option.name)
.toLowerCase()
.split(" ");
return searchWords.every((searchWord) =>
optionWords.some((word) => word.startsWith(searchWord))
const name = String(option.name || "").toLowerCase();
const description = String(
option.description || ""
).toLowerCase();
return (
name.includes(query) || description.includes(query)
);
});
}}

View File

@@ -575,7 +575,6 @@ export const RouteEditPage = observer(() => {
onUpdate={() => {
routeStore.getRoute(Number(id));
}}
routeDirection={editRouteData.route_direction}
/>
<div className="flex w-full justify-between">

View File

@@ -17,6 +17,10 @@ export const RouteListPage = observer(() => {
const [rowId, setRowId] = useState<number | null>(null);
const [ids, setIds] = useState<number[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [paginationModel, setPaginationModel] = useState({
page: 0,
pageSize: 50,
});
const { language } = languageStore;
useEffect(() => {
@@ -149,28 +153,39 @@ export const RouteListPage = observer(() => {
<CreateButton label="Создать маршрут" path="/route/create" />
</div>
<div
className="flex justify-end mb-5 duration-300"
style={{ opacity: ids.length > 0 ? 1 : 0 }}
>
<button
className="px-4 py-2 bg-red-500 text-white rounded flex gap-2 items-center"
onClick={() => setIsBulkDeleteModalOpen(true)}
>
<Trash2 size={20} className="text-white" /> Удалить выбранные (
{ids.length})
</button>
</div>
{ids.length > 0 && (
<div className="flex justify-end mb-5 duration-300">
<button
className="px-4 py-2 bg-red-500 text-white rounded flex gap-2 items-center"
onClick={() => setIsBulkDeleteModalOpen(true)}
>
<Trash2 size={20} className="text-white" /> Удалить выбранные (
{ids.length})
</button>
</div>
)}
<DataGrid
rows={rows}
columns={columns}
hideFooter
checkboxSelection
disableRowSelectionExcludeModel
loading={isLoading}
paginationModel={paginationModel}
onPaginationModelChange={setPaginationModel}
pageSizeOptions={[50]}
localeText={ruRU.components.MuiDataGrid.defaultProps.localeText}
onRowSelectionModelChange={(newSelection) => {
setIds(Array.from(newSelection.ids as unknown as number[]));
onRowSelectionModelChange={(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<string | number>;
const selectedIds = Array.from(idsSet).map((id: string | number) => Number(id));
setIds(selectedIds);
} else {
setIds([]);
}
}}
slots={{
noRowsOverlay: () => (