mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 16:28:12 +00:00
refactor: migrate from most of the custom hooks into the api.ts
This commit is contained in:
@@ -1,7 +1,3 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { isAxiosError } from "axios";
|
||||
import {
|
||||
ActionIcon,
|
||||
Badge,
|
||||
@@ -23,6 +19,8 @@ import {
|
||||
ThemeIcon,
|
||||
Tooltip,
|
||||
} from "@mantine/core";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { isAxiosError } from "axios";
|
||||
import {
|
||||
AlertTriangle,
|
||||
ArrowLeft,
|
||||
@@ -40,14 +38,16 @@ import {
|
||||
Trash2,
|
||||
Weight,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import Breadcrumbs from "@/components/ui/Breadcrumbs";
|
||||
import { bookingsService } from "@/services/bookings.service";
|
||||
import { useAvailableDays } from "@/hooks/trainScheduling/useTrainScheduling";
|
||||
import { api } from "@/auth/http";
|
||||
import { unwrap } from "@/utils/endpoint";
|
||||
import Breadcrumbs from "@/components/ui/Breadcrumbs";
|
||||
import { URL_CONSTANTS } from "@/constants/URLS";
|
||||
import { api as appApi } from "@/services/api";
|
||||
import { bookingsService } from "@/services/bookings.service";
|
||||
import { unwrap } from "@/utils/endpoint";
|
||||
|
||||
interface CompanyOption {
|
||||
id: string;
|
||||
@@ -234,9 +234,11 @@ export default function NewBookingPage() {
|
||||
|
||||
// Day-level pool: fetch only the days that have a departure on the route (no
|
||||
// train, no capacity). The batch engine assigns the train after booking.
|
||||
const { data: availableDays, isLoading: daysLoading } = useAvailableDays(
|
||||
originYardId,
|
||||
destinationYardId,
|
||||
const { data: availableDays, isLoading: daysLoading } = useQuery(
|
||||
appApi.trainScheduling.availableDays.queryOptions({
|
||||
input: { originYardId, destinationYardId },
|
||||
enabled: Boolean(originYardId && destinationYardId),
|
||||
}),
|
||||
);
|
||||
const dayOptions = (availableDays ?? []).map((day) => ({
|
||||
value: day,
|
||||
@@ -392,7 +394,7 @@ export default function NewBookingPage() {
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
<Grid gutter="lg" mt="lg">
|
||||
<Grid gap="lg" mt="lg">
|
||||
{/* LEFT — form */}
|
||||
<Grid.Col span={{ base: 12, lg: 8 }}>
|
||||
<Stack gap="lg">
|
||||
@@ -453,7 +455,6 @@ export default function NewBookingPage() {
|
||||
value={originYardId}
|
||||
onChange={(v) => {
|
||||
setOriginYardId(v);
|
||||
setTrainScheduleId(null);
|
||||
}}
|
||||
searchable
|
||||
disabled={isLoading}
|
||||
|
||||
@@ -15,7 +15,8 @@ import { Label } from "@/components/ui/label";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { FileUploadEntity } from "@edr/types/freight";
|
||||
import { useCreateFileUploadSetting, useUpdateFileUploadSetting } from "@/hooks/useFileUploadSettings";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
|
||||
// import type {
|
||||
// FileUploadEntity,
|
||||
@@ -61,8 +62,8 @@ export default function EditFileUploadSettingDialog({
|
||||
const [description, setDescription] = useState(setting?.description ?? "");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const createMutation = useCreateFileUploadSetting();
|
||||
const updateMutation = useUpdateFileUploadSetting();
|
||||
const createMutation = useMutation(api.fileUploadSettings.create.mutationOptions());
|
||||
const updateMutation = useMutation(api.fileUploadSettings.update.mutationOptions());
|
||||
const pending = createMutation.isPending || updateMutation.isPending;
|
||||
|
||||
const reset = () => {
|
||||
|
||||
@@ -25,12 +25,11 @@ import {
|
||||
Trash2,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
|
||||
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
||||
import { api } from "@/services/api";
|
||||
import { useDeleteFileUploadSetting } from "@/hooks/useFileUploadSettings";
|
||||
import { getMinFiles, type FileUploadSetting } from "@/types/fileUploadSettings";
|
||||
import { DataTable, type ColumnDef } from "@edr/ui-common";
|
||||
|
||||
@@ -44,7 +43,7 @@ export default function FileUploadSettingsPage() {
|
||||
const { data, isLoading, isError, error, refetch } = useQuery(
|
||||
api.fileUploadSettings.list.queryOptions(),
|
||||
);
|
||||
const deleteMutation = useDeleteFileUploadSetting();
|
||||
const deleteMutation = useMutation(api.fileUploadSettings.remove.mutationOptions());
|
||||
|
||||
const fileUploadSettings = useMemo(
|
||||
() => (Array.isArray(data) ? data : []),
|
||||
@@ -202,7 +201,7 @@ export default function FileUploadSettingsPage() {
|
||||
<DeleteFileUploadSettingDialog
|
||||
settingLabel={setting.label}
|
||||
settingCode={setting.code}
|
||||
onConfirm={() => deleteMutation.mutate(setting.id)}
|
||||
onConfirm={() => deleteMutation.mutate({ id: setting.id })}
|
||||
>
|
||||
<ActionIcon
|
||||
variant="default"
|
||||
|
||||
@@ -19,7 +19,8 @@ import type {
|
||||
FileUploadSetting,
|
||||
} from "@/types/fileUploadSettings";
|
||||
import { getMinFiles } from "@/types/fileUploadSettings";
|
||||
import { useReplaceFileUploadFields } from "@/hooks/useFileUploadSettings";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
|
||||
export interface ManageFileUploadFieldsDialogProps {
|
||||
setting: FileUploadSetting;
|
||||
@@ -77,7 +78,9 @@ export default function ManageFileUploadFieldsDialog({
|
||||
|
||||
const [fields, setFields] = useState<DraftField[]>(seed);
|
||||
|
||||
const replaceMutation = useReplaceFileUploadFields();
|
||||
const replaceMutation = useMutation(
|
||||
api.fileUploadSettings.replaceFields.mutationOptions(),
|
||||
);
|
||||
|
||||
const update = (i: number, patch: Partial<DraftField>) =>
|
||||
setFields((prev) =>
|
||||
@@ -145,7 +148,7 @@ export default function ManageFileUploadFieldsDialog({
|
||||
}));
|
||||
|
||||
replaceMutation.mutate(
|
||||
{ settingId: setting.id, fields: payload },
|
||||
{ id: setting.id, fields: payload },
|
||||
{
|
||||
onSuccess: () => setOpen(false),
|
||||
onError: (err) =>
|
||||
|
||||
@@ -31,9 +31,8 @@ import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
|
||||
import EditDropdownSettingDialog from "./EditDropdownSettingDialog";
|
||||
import ManageDropdownOptionsDialog from "./ManageDropdownOptionsDialog";
|
||||
import DeleteDropdownSettingDialog from "./DeleteDropdownSettingDialog";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
import { useDeleteDropdownSetting } from "@/hooks/useDropdownSettings";
|
||||
import type { DropdownSetting } from "@/types/dropdownSettings";
|
||||
import {
|
||||
DataTable,
|
||||
@@ -63,7 +62,7 @@ export default function DropdownSettingsPage() {
|
||||
const { data, isLoading, isError, error } = useQuery(
|
||||
api.dropdownSettings.list.queryOptions(),
|
||||
);
|
||||
const deleteMutation = useDeleteDropdownSetting();
|
||||
const deleteMutation = useMutation(api.dropdownSettings.remove.mutationOptions());
|
||||
|
||||
const dropdownSettings = useMemo<DropdownSetting[]>(
|
||||
() => (Array.isArray(data) ? data : []),
|
||||
@@ -353,7 +352,7 @@ export default function DropdownSettingsPage() {
|
||||
key={`delete-${activeSetting.id}`}
|
||||
settingLabel={activeSetting.label}
|
||||
settingCode={activeSetting.code}
|
||||
onConfirm={() => deleteMutation.mutate(activeSetting.id)}
|
||||
onConfirm={() => deleteMutation.mutate({ id: activeSetting.id })}
|
||||
open={activeDialog === "delete"}
|
||||
onOpenChange={(next) => (next ? null : closeDialog())}
|
||||
/>
|
||||
|
||||
@@ -20,10 +20,9 @@ import type {
|
||||
DropdownSetting,
|
||||
UpdateDropdownSettingDto,
|
||||
} from "@/types/dropdownSettings";
|
||||
import {
|
||||
useCreateDropdownSetting,
|
||||
useUpdateDropdownSetting,
|
||||
} from "@/hooks/useDropdownSettings";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
|
||||
import { api } from "@/services/api";
|
||||
|
||||
export interface EditDropdownSettingDialogProps {
|
||||
mode?: "create" | "edit";
|
||||
@@ -76,8 +75,8 @@ export default function EditDropdownSettingDialog({
|
||||
);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const createMutation = useCreateDropdownSetting();
|
||||
const updateMutation = useUpdateDropdownSetting();
|
||||
const createMutation = useMutation(api.dropdownSettings.create.mutationOptions());
|
||||
const updateMutation = useMutation(api.dropdownSettings.update.mutationOptions());
|
||||
const pending = createMutation.isPending || updateMutation.isPending;
|
||||
|
||||
const reset = () => {
|
||||
|
||||
@@ -18,7 +18,8 @@ import type {
|
||||
CreateDropdownOptionDto,
|
||||
DropdownSetting,
|
||||
} from "@/types/dropdownSettings";
|
||||
import { useReplaceDropdownOptions } from "@/hooks/useDropdownSettings";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
|
||||
export interface ManageDropdownOptionsDialogProps {
|
||||
setting: DropdownSetting;
|
||||
@@ -84,7 +85,9 @@ export default function ManageDropdownOptionsDialog({
|
||||
|
||||
const [options, setOptions] = useState<DraftOption[]>(seed);
|
||||
|
||||
const replaceMutation = useReplaceDropdownOptions();
|
||||
const replaceMutation = useMutation(
|
||||
api.dropdownSettings.replaceOptions.mutationOptions(),
|
||||
);
|
||||
|
||||
const update = (i: number, patch: Partial<DraftOption>) =>
|
||||
setOptions((prev) =>
|
||||
@@ -147,7 +150,7 @@ export default function ManageDropdownOptionsDialog({
|
||||
});
|
||||
|
||||
replaceMutation.mutate(
|
||||
{ settingId: setting.id, options: payload },
|
||||
{ id: setting.id, options: payload },
|
||||
{
|
||||
onSuccess: () => setOpen(false),
|
||||
onError: (err) =>
|
||||
|
||||
@@ -36,30 +36,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@edr/ui-common';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||
import { useCargoTypes } from '@/hooks/use-cargo-types';
|
||||
import { useContainerTypes } from '@/hooks/use-container-types';
|
||||
import {
|
||||
useCreateWagonType,
|
||||
useDeleteWagonType,
|
||||
useUpdateWagonType,
|
||||
useWagonTypes,
|
||||
} from '@/hooks/use-wagon-types';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import {
|
||||
useContainers,
|
||||
useCreateContainer,
|
||||
useDeleteContainer,
|
||||
useUpdateContainer,
|
||||
} from '@/hooks/useContainers';
|
||||
import { useCreateTrain, useDeleteTrain, useTrains, useUpdateTrain } from '@/hooks/useTrains';
|
||||
import { useRouteYards } from '@/hooks/useRoutes';
|
||||
import { useCreateWagon, useDeleteWagon, useUpdateWagon, useWagons } from '@/hooks/useWagons';
|
||||
import {
|
||||
useCreateLocomotive,
|
||||
useDecommissionLocomotive,
|
||||
useLocomotives,
|
||||
useUpdateLocomotive,
|
||||
} from '@/hooks/useLocomotives';
|
||||
import type { Cargo } from '@/services/cargoService';
|
||||
import { DeliverCargoDialog } from '@/components/cargoes/DeliverCargoDialog';
|
||||
import type { Container } from '@/services/containerService';
|
||||
@@ -513,7 +490,7 @@ const optionLabel = (options: { value: string; label: string }[], value?: string
|
||||
options.find((option) => option.value === value)?.label ?? value ?? '-';
|
||||
|
||||
export function TrainMasterDataPage() {
|
||||
const query = useTrains();
|
||||
const query = useQuery(api.trains.list.queryOptions());
|
||||
return (
|
||||
<FleetCrudPage<Train>
|
||||
title="Trains"
|
||||
@@ -521,9 +498,9 @@ export function TrainMasterDataPage() {
|
||||
addLabel="Add Train"
|
||||
data={query.data}
|
||||
isLoading={query.isLoading}
|
||||
create={useCreateTrain()}
|
||||
update={useUpdateTrain()}
|
||||
remove={useDeleteTrain()}
|
||||
create={useMutation(api.trains.create.mutationOptions())}
|
||||
update={useMutation(api.trains.update.mutationOptions())}
|
||||
remove={useMutation(api.trains.remove.mutationOptions())}
|
||||
searchText={(train) => [train.code, train.trainNumber, train.trainName, train.status].join(' ')}
|
||||
columns={[
|
||||
{ key: 'code', label: 'Code' },
|
||||
@@ -548,10 +525,10 @@ export function TrainMasterDataPage() {
|
||||
}
|
||||
|
||||
export function WagonTypesCrudPage() {
|
||||
const query = useWagonTypes();
|
||||
const create = useCreateWagonType();
|
||||
const update = useUpdateWagonType();
|
||||
const remove = useDeleteWagonType();
|
||||
const query = useQuery(api.wagonTypes.list.queryOptions());
|
||||
const create = useMutation(api.wagonTypes.create.mutationOptions());
|
||||
const update = useMutation(api.wagonTypes.update.mutationOptions());
|
||||
const remove = useMutation(api.wagonTypes.remove.mutationOptions());
|
||||
const { toast } = useToast();
|
||||
const [search, setSearch] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
@@ -898,9 +875,9 @@ export function WagonTypesCrudPage() {
|
||||
}
|
||||
|
||||
export function WagonsCrudPage() {
|
||||
const query = useWagons();
|
||||
const { data: wagonTypes = [] } = useWagonTypes();
|
||||
const { data: yards = [] } = useRouteYards();
|
||||
const query = useQuery(api.wagons.list.queryOptions({ input: {} }));
|
||||
const { data: wagonTypes = [] } = useQuery(api.wagonTypes.list.queryOptions());
|
||||
const { data: yards = [] } = useQuery(api.routes.yards.queryOptions());
|
||||
const wagonTypeOptions = wagonTypes.map((type: any) => ({
|
||||
value: type.id,
|
||||
label: `${type.code} - ${type.name}`,
|
||||
@@ -916,9 +893,9 @@ export function WagonsCrudPage() {
|
||||
addLabel="Add Wagon"
|
||||
data={query.data}
|
||||
isLoading={query.isLoading}
|
||||
create={useCreateWagon()}
|
||||
update={useUpdateWagon()}
|
||||
remove={useDeleteWagon()}
|
||||
create={useMutation(api.wagons.create.mutationOptions())}
|
||||
update={useMutation(api.wagons.update.mutationOptions())}
|
||||
remove={useMutation(api.wagons.remove.mutationOptions())}
|
||||
searchText={(wagon) => [
|
||||
wagon.wagonNumber,
|
||||
wagon.wagonTypeId,
|
||||
@@ -986,9 +963,11 @@ export function WagonsCrudPage() {
|
||||
}
|
||||
|
||||
export function ContainersCrudPage() {
|
||||
const query = useContainers();
|
||||
const { data: containerTypes = [] } = useContainerTypes();
|
||||
const { data: wagons = [] } = useWagons();
|
||||
const query = useQuery(api.containers.list.queryOptions());
|
||||
const { data: containerTypes = [] } = useQuery(
|
||||
api.containerTypes.list.queryOptions({ staleTime: Infinity }),
|
||||
);
|
||||
const { data: wagons = [] } = useQuery(api.wagons.list.queryOptions({ input: {} }));
|
||||
const containerTypeOptions = containerTypes.map((type: any) => ({
|
||||
value: type.id,
|
||||
label: type.label ?? type.name ?? type.code,
|
||||
@@ -1004,9 +983,9 @@ export function ContainersCrudPage() {
|
||||
addLabel="Add Container"
|
||||
data={query.data}
|
||||
isLoading={query.isLoading}
|
||||
create={useCreateContainer()}
|
||||
update={useUpdateContainer()}
|
||||
remove={useDeleteContainer()}
|
||||
create={useMutation(api.containers.create.mutationOptions())}
|
||||
update={useMutation(api.containers.update.mutationOptions())}
|
||||
remove={useMutation(api.containers.remove.mutationOptions())}
|
||||
searchText={(container) => [container.containerNumber, container.containerTypeId, container.wagonId, container.status].join(' ')}
|
||||
columns={[
|
||||
{ key: 'containerNumber', label: 'Number' },
|
||||
@@ -1044,8 +1023,10 @@ export function ContainersCrudPage() {
|
||||
|
||||
export function CargoesCrudPage() {
|
||||
const query = useQuery(api.cargoes.list.queryOptions());
|
||||
const { data: cargoTypes = [] } = useCargoTypes();
|
||||
const { data: containers = [] } = useContainers();
|
||||
const { data: cargoTypes = [] } = useQuery(
|
||||
api.cargoTypes.list.queryOptions({ staleTime: Infinity }),
|
||||
);
|
||||
const { data: containers = [] } = useQuery(api.containers.list.queryOptions());
|
||||
const cargoTypeOptions = cargoTypes.map((type: any) => ({
|
||||
value: type.id,
|
||||
label: type.cargoTypeName ?? type.cargo_type_name ?? type.name ?? type.code,
|
||||
@@ -1112,7 +1093,7 @@ export function CargoesCrudPage() {
|
||||
}
|
||||
|
||||
export function LocomotivesCrudPage() {
|
||||
const query = useLocomotives();
|
||||
const query = useQuery(api.locomotives.list.queryOptions());
|
||||
|
||||
return (
|
||||
<FleetCrudPage<Locomotive>
|
||||
@@ -1122,9 +1103,9 @@ export function LocomotivesCrudPage() {
|
||||
addLabel="Add Locomotive"
|
||||
data={query.data}
|
||||
isLoading={query.isLoading}
|
||||
create={useCreateLocomotive()}
|
||||
update={useUpdateLocomotive()}
|
||||
remove={useDecommissionLocomotive()}
|
||||
create={useMutation(api.locomotives.create.mutationOptions())}
|
||||
update={useMutation(api.locomotives.update.mutationOptions())}
|
||||
remove={useMutation(api.locomotives.decommission.mutationOptions())}
|
||||
removeActionLabel="Decommission"
|
||||
removeConfirmMessage="Decommission this locomotive?"
|
||||
removeSuccessMessage="Locomotive decommissioned"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import type { ColumnDef } from "@edr/ui-common";
|
||||
import { Box, Button, Card, Group, Modal, Select, Stack, Text } from "@mantine/core";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { api } from "@/services/api";
|
||||
import {
|
||||
Archive,
|
||||
Circle,
|
||||
@@ -22,14 +25,7 @@ import { formatFleetCell, registerFleetOptionLabels } from "@/components/fleet/f
|
||||
import { useFleetViewMode } from "@/components/fleet/useFleetViewMode";
|
||||
import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
|
||||
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
||||
import { useFleetList, useFleetMutations } from "@/hooks/fleet/useFleet";
|
||||
import { useCargoTypes } from "@/hooks/use-cargo-types";
|
||||
import { useContainerTypes } from "@/hooks/use-container-types";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { useWagonTypes } from "@/hooks/use-wagon-types";
|
||||
import { useContainers } from "@/hooks/useContainers";
|
||||
import { useRouteYards } from "@/hooks/useRoutes";
|
||||
import { useWagons } from "@/hooks/useWagons";
|
||||
import {
|
||||
FLEET_SELECT_NONE,
|
||||
getFleetResource,
|
||||
@@ -90,15 +86,31 @@ const FleetResourcePage = () => {
|
||||
return filters;
|
||||
}, [slug, listFilterValues, search]);
|
||||
|
||||
const { data: allRows = [], isLoading, isError, error } = useFleetList(slug, serverListFilters);
|
||||
const { create, update, remove } = useFleetMutations(slug);
|
||||
const { data: allRows = [], isLoading, isError, error } = useQuery(
|
||||
api.fleet.list.queryOptions({ input: { slug, filters: serverListFilters } }),
|
||||
);
|
||||
const create = useMutation(api.fleet.create.mutationOptions());
|
||||
const update = useMutation(api.fleet.update.mutationOptions());
|
||||
const remove = useMutation(api.fleet.remove.mutationOptions());
|
||||
|
||||
const { data: wagonTypes = [], isLoading: wagonTypesLoading } = useWagonTypes();
|
||||
const { data: containerTypes = [], isLoading: containerTypesLoading } = useContainerTypes();
|
||||
const { data: cargoTypes = [], isLoading: cargoTypesLoading } = useCargoTypes();
|
||||
const { data: wagons = [], isLoading: wagonsLoading } = useWagons();
|
||||
const { data: containers = [], isLoading: containersLoading } = useContainers();
|
||||
const { data: yards = [], isLoading: yardsLoading } = useRouteYards();
|
||||
const { data: wagonTypes = [], isLoading: wagonTypesLoading } = useQuery(
|
||||
api.wagonTypes.list.queryOptions(),
|
||||
);
|
||||
const { data: containerTypes = [], isLoading: containerTypesLoading } = useQuery(
|
||||
api.containerTypes.list.queryOptions({ staleTime: Infinity }),
|
||||
);
|
||||
const { data: cargoTypes = [], isLoading: cargoTypesLoading } = useQuery(
|
||||
api.cargoTypes.list.queryOptions({ staleTime: Infinity }),
|
||||
);
|
||||
const { data: wagons = [], isLoading: wagonsLoading } = useQuery(
|
||||
api.wagons.list.queryOptions({ input: {} }),
|
||||
);
|
||||
const { data: containers = [], isLoading: containersLoading } = useQuery(
|
||||
api.containers.list.queryOptions(),
|
||||
);
|
||||
const { data: yards = [], isLoading: yardsLoading } = useQuery(
|
||||
api.routes.yards.queryOptions(),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setPagination((prev) => ({ pageIndex: 0, pageSize: prev.pageSize }));
|
||||
@@ -316,10 +328,10 @@ const FleetResourcePage = () => {
|
||||
const handleFormSubmit = async (values: Record<string, unknown>) => {
|
||||
try {
|
||||
if (editing && "id" in editing) {
|
||||
await update.mutateAsync({ id: String(editing.id), data: values });
|
||||
await update.mutateAsync({ slug, id: String(editing.id), data: values });
|
||||
toast({ title: `${config.entityLabel} updated` });
|
||||
} else {
|
||||
await create.mutateAsync(values);
|
||||
await create.mutateAsync({ slug, data: values });
|
||||
toast({ title: `${config.entityLabel} created` });
|
||||
}
|
||||
setFormOpen(false);
|
||||
@@ -335,7 +347,7 @@ const FleetResourcePage = () => {
|
||||
const handleRemove = async () => {
|
||||
if (!removeTarget || !("id" in removeTarget)) return;
|
||||
try {
|
||||
await remove.mutateAsync(String(removeTarget.id));
|
||||
await remove.mutateAsync({ slug, id: String(removeTarget.id) });
|
||||
toast({
|
||||
title: config.removeSuccessMessage ?? `${config.entityLabel} removed`,
|
||||
});
|
||||
|
||||
@@ -17,18 +17,14 @@ import {
|
||||
Tooltip,
|
||||
} from "@mantine/core";
|
||||
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
|
||||
import FleetToolbar from "@/components/fleet/FleetToolbar";
|
||||
import { useFleetViewMode } from "@/components/fleet/useFleetViewMode";
|
||||
import RuleEngineListFooter from "@/components/ruleEngine/RuleEngineListFooter";
|
||||
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
||||
import {
|
||||
useCreateRoute,
|
||||
useDeactivateRoute,
|
||||
useRouteYards,
|
||||
useRoutes,
|
||||
useUpdateRoute,
|
||||
} from "@/hooks/useRoutes";
|
||||
import { api } from "@/services/api";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import type { RouteRecord, YardRef } from "@/services/routes.service";
|
||||
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";
|
||||
@@ -71,11 +67,11 @@ export default function RoutesPage() {
|
||||
const { pagination, setPagination } = usePagination({ pageSize: 10 });
|
||||
const { toast } = useToast();
|
||||
|
||||
const routesQuery = useRoutes();
|
||||
const yardsQuery = useRouteYards();
|
||||
const createMutation = useCreateRoute();
|
||||
const updateMutation = useUpdateRoute();
|
||||
const deactivateMutation = useDeactivateRoute();
|
||||
const routesQuery = useQuery(api.routes.list.queryOptions());
|
||||
const yardsQuery = useQuery(api.routes.yards.queryOptions());
|
||||
const createMutation = useMutation(api.routes.create.mutationOptions());
|
||||
const updateMutation = useMutation(api.routes.update.mutationOptions());
|
||||
const deactivateMutation = useMutation(api.routes.deactivate.mutationOptions());
|
||||
|
||||
const filteredRoutes = useMemo(() => {
|
||||
const query = search.trim().toLowerCase();
|
||||
|
||||
@@ -22,8 +22,10 @@ import {
|
||||
} from "lucide-react";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
|
||||
import { usePaymentList, usePaymentSummary } from "@/hooks/usePayments";
|
||||
import { api } from "@/services/api";
|
||||
import type { PaymentMethod, PaymentRow } from "@/services/payments.service";
|
||||
import {
|
||||
Badge,
|
||||
@@ -106,8 +108,12 @@ export default function PaymentsPage() {
|
||||
[query, statuses, method, pagination.pageIndex, pagination.pageSize],
|
||||
);
|
||||
|
||||
const { data, isLoading, isError } = usePaymentList(filter);
|
||||
const { data: summary, isLoading: summaryLoading } = usePaymentSummary();
|
||||
const { data, isLoading, isError } = useQuery(
|
||||
api.payments.list.queryOptions({ input: { filter } }),
|
||||
);
|
||||
const { data: summary, isLoading: summaryLoading } = useQuery(
|
||||
api.payments.summary.queryOptions({ staleTime: 30_000 }),
|
||||
);
|
||||
|
||||
const rows = data?.items ?? [];
|
||||
const total = data?.total ?? 0;
|
||||
|
||||
@@ -46,7 +46,8 @@ import {
|
||||
import { RouteCorridor } from "@/components/trainScheduling/scheduleVisuals";
|
||||
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
||||
import { FREIGHT_BRAND, FREIGHT_BRAND_DARK } from "@/theme/freight-brand";
|
||||
import { useBatchBoard } from "@/hooks/trainScheduling/useTrainScheduling";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
import type { BatchBoardSchedule } from "@/types/trainScheduling";
|
||||
|
||||
const fmtTons = (n: number) =>
|
||||
@@ -368,7 +369,9 @@ function CardSkeleton() {
|
||||
|
||||
export default function BatchBoardPage() {
|
||||
const navigate = useNavigate();
|
||||
const { data, isLoading, isError, isFetching, refetch } = useBatchBoard();
|
||||
const { data, isLoading, isError, isFetching, refetch } = useQuery(
|
||||
api.trainScheduling.batchBoard.queryOptions({ refetchInterval: 30_000 }),
|
||||
);
|
||||
const { viewMode, setViewMode } = useFleetViewMode("batch-board");
|
||||
const { pagination, setPagination } = usePagination({ pageSize: 10 });
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
@@ -52,11 +52,8 @@ import {
|
||||
WindowStatusPill,
|
||||
} from "@/components/trainScheduling/batchVisuals";
|
||||
import { RouteCorridor } from "@/components/trainScheduling/scheduleVisuals";
|
||||
import {
|
||||
useBatchBoardDetail,
|
||||
useRunAllocation,
|
||||
useScheduleDetail,
|
||||
} from "@/hooks/trainScheduling/useTrainScheduling";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import type {
|
||||
BatchBoardBookingDetail,
|
||||
@@ -429,8 +426,16 @@ export default function BatchScheduleDetailPage() {
|
||||
const { scheduleId } = useParams<{ scheduleId: string }>();
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
const { data, isLoading, isFetching, refetch } = useBatchBoardDetail(scheduleId);
|
||||
const runAllocation = useRunAllocation(scheduleId ?? "");
|
||||
const { data, isLoading, isFetching, refetch } = useQuery(
|
||||
api.trainScheduling.batchBoardDetail.queryOptions({
|
||||
input: { scheduleId: scheduleId ?? "" },
|
||||
enabled: Boolean(scheduleId),
|
||||
refetchInterval: 30_000,
|
||||
}),
|
||||
);
|
||||
const runAllocation = useMutation(
|
||||
api.trainScheduling.runAllocation.mutationOptions(),
|
||||
);
|
||||
|
||||
const hasAssignedWagons = useMemo(
|
||||
() =>
|
||||
@@ -443,7 +448,12 @@ export default function BatchScheduleDetailPage() {
|
||||
[data],
|
||||
);
|
||||
|
||||
const scheduleDetailQuery = useScheduleDetail(scheduleId, "CONTAINER");
|
||||
const scheduleDetailQuery = useQuery(
|
||||
api.trainScheduling.scheduleDetail.queryOptions({
|
||||
input: { id: scheduleId ?? "", freightType: "CONTAINER" },
|
||||
enabled: Boolean(scheduleId),
|
||||
}),
|
||||
);
|
||||
|
||||
// Batch bookings by state for the composition side panel (payment / expired lists).
|
||||
const batchBookings = useMemo(() => {
|
||||
@@ -550,7 +560,7 @@ export default function BatchScheduleDetailPage() {
|
||||
|
||||
const handleRunAllocation = () => {
|
||||
runAllocation
|
||||
.mutateAsync()
|
||||
.mutateAsync({ scheduleId: scheduleId ?? "" })
|
||||
.then((result) => {
|
||||
const failed = result.issues.filter((i) => i.status === "FAILED").length;
|
||||
const deferred = result.deferred.length;
|
||||
|
||||
@@ -28,7 +28,8 @@ import { PageContainer } from "@/components/page";
|
||||
import { RouteCorridorTrack } from "@/components/trainScheduling/RouteCorridorTrack";
|
||||
import { RouteCorridor, StatusPill } from "@/components/trainScheduling/scheduleVisuals";
|
||||
import { freightBrand } from "@/theme/freight-brand";
|
||||
import { useTrainTrack, useScheduleMutations } from "@/hooks/trainScheduling/useTrainScheduling";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
|
||||
const parseError = (error: unknown, fallback: string) => {
|
||||
@@ -81,8 +82,15 @@ function MetaStat({
|
||||
export default function TrainScheduleTrackPage() {
|
||||
const { scheduleId } = useParams<{ scheduleId: string }>();
|
||||
const { toast } = useToast();
|
||||
const trackQuery = useTrainTrack(scheduleId);
|
||||
const { recordCheckpoint } = useScheduleMutations(scheduleId);
|
||||
const trackQuery = useQuery(
|
||||
api.trainScheduling.trainTrack.queryOptions({
|
||||
input: { id: scheduleId ?? "" },
|
||||
enabled: Boolean(scheduleId),
|
||||
}),
|
||||
);
|
||||
const recordCheckpoint = useMutation(
|
||||
api.trainScheduling.recordCheckpoint.mutationOptions(),
|
||||
);
|
||||
|
||||
if (trackQuery.isLoading) {
|
||||
return (
|
||||
|
||||
@@ -56,11 +56,8 @@ import { shouldShowContainerPlacementStep } from "@/components/trainScheduling/s
|
||||
import { TrainCompositionDiagram } from "@/components/trainScheduling/TrainCompositionDiagram";
|
||||
import { WagonPlanGrid } from "@/components/trainScheduling/WagonPlanGrid";
|
||||
import { WorkflowRail, WorkflowStep } from "@/components/trainScheduling/WorkflowStep";
|
||||
import {
|
||||
useEligibleBookings,
|
||||
useScheduleDetail,
|
||||
useScheduleMutations,
|
||||
} from "@/hooks/trainScheduling/useTrainScheduling";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import type {
|
||||
ContainerPlacement,
|
||||
@@ -91,7 +88,12 @@ export default function TrainScheduleV2DetailPage() {
|
||||
const [maintenanceOpen, setMaintenanceOpen] = useState(false);
|
||||
const autoPreviewedRef = useRef(false);
|
||||
|
||||
const detailQuery = useScheduleDetail(scheduleId);
|
||||
const detailQuery = useQuery(
|
||||
api.trainScheduling.scheduleDetail.queryOptions({
|
||||
input: { id: scheduleId ?? "" },
|
||||
enabled: Boolean(scheduleId),
|
||||
}),
|
||||
);
|
||||
const schedule = detailQuery.data;
|
||||
const freightType: FreightType | undefined = schedule?.freightType as FreightType | undefined;
|
||||
|
||||
@@ -111,12 +113,17 @@ export default function TrainScheduleV2DetailPage() {
|
||||
const eligibleFreightType =
|
||||
freightType === "CONTAINER" || freightType === "BULK" ? freightType : undefined;
|
||||
|
||||
const eligibleQuery = useEligibleBookings(
|
||||
eligibleFilters,
|
||||
Boolean(schedule),
|
||||
eligibleFreightType,
|
||||
const eligibleQuery = useQuery(
|
||||
api.trainScheduling.eligibleBookings.queryOptions({
|
||||
input: { filters: eligibleFilters, freightType: eligibleFreightType },
|
||||
enabled: Boolean(schedule),
|
||||
}),
|
||||
);
|
||||
const { preview, assign, unassign, finalize, dispatch } = useScheduleMutations(scheduleId);
|
||||
const preview = useMutation(api.trainScheduling.preview.mutationOptions());
|
||||
const assign = useMutation(api.trainScheduling.assignBookings.mutationOptions());
|
||||
const unassign = useMutation(api.trainScheduling.unassignBooking.mutationOptions());
|
||||
const finalize = useMutation(api.trainScheduling.finalizeSchedule.mutationOptions());
|
||||
const dispatch = useMutation(api.trainScheduling.dispatchSchedule.mutationOptions());
|
||||
|
||||
const assignedIds = useMemo(
|
||||
() => (schedule?.bookings ?? []).map((b) => b.id),
|
||||
|
||||
@@ -39,13 +39,9 @@ import {
|
||||
RouteCorridor,
|
||||
StatusPill,
|
||||
} from "@/components/trainScheduling/scheduleVisuals";
|
||||
import {
|
||||
useAvailableLocomotives,
|
||||
useScheduleList,
|
||||
useScheduleMutations,
|
||||
} from "@/hooks/trainScheduling/useTrainScheduling";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { api } from "@/services/api";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { useRoutes } from "@/hooks/useRoutes";
|
||||
import type { TrainScheduleListItem } from "@/types/trainScheduling";
|
||||
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";
|
||||
|
||||
@@ -88,10 +84,17 @@ export default function TrainScheduleV2ListPage() {
|
||||
const [scheduleDate, setScheduleDate] = useState("");
|
||||
const [locomotiveId, setLocomotiveId] = useState("");
|
||||
|
||||
const schedulesQuery = useScheduleList();
|
||||
const routesQuery = useRoutes();
|
||||
const locomotivesQuery = useAvailableLocomotives(routeId || undefined);
|
||||
const { create, cancel } = useScheduleMutations();
|
||||
const schedulesQuery = useQuery(
|
||||
api.trainScheduling.scheduleList.queryOptions({ input: {} }),
|
||||
);
|
||||
const routesQuery = useQuery(api.routes.list.queryOptions());
|
||||
const locomotivesQuery = useQuery(
|
||||
api.trainScheduling.availableLocomotives.queryOptions({
|
||||
input: { routeId: routeId || undefined },
|
||||
}),
|
||||
);
|
||||
const create = useMutation(api.trainScheduling.createSchedule.mutationOptions());
|
||||
const cancel = useMutation(api.trainScheduling.cancelSchedule.mutationOptions());
|
||||
|
||||
const activeRoutes = useMemo(
|
||||
() => (routesQuery.data ?? []).filter((r) => r.isActive),
|
||||
|
||||
@@ -2,13 +2,17 @@ import { useParams, Link } from "react-router-dom";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { Badge, Button, Card, Group, Loader, SimpleGrid, Stack, Text } from "@mantine/core";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { AssignWagonDialog } from "@/components/wagons/AssignWagonDialog";
|
||||
import { WagonsTable } from "@/components/wagons/WagonsTable";
|
||||
import { useTrain } from "@/hooks/useTrains";
|
||||
import { api } from "@/services/api";
|
||||
|
||||
export default function TrainDetailPage() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const { data: train, isLoading } = useTrain(id!);
|
||||
const { data: train, isLoading } = useQuery(
|
||||
api.trains.getById.queryOptions({ input: { id: id ?? "" }, enabled: !!id }),
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user