mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 22:25:42 +00:00
refactor: migrate to use the central api obj
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { useCargoesByContainer, useDeliverCargo, useUnloadCargo } from '@/hooks/useCargoes';
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
|
import { api } from '@/services/api';
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
@@ -6,9 +7,14 @@ import { LoadCargoDialog } from './LoadCargoDialog';
|
|||||||
import type { Cargo } from '@/services/cargoService';
|
import type { Cargo } from '@/services/cargoService';
|
||||||
|
|
||||||
export function CargoesTable({ containerId }: { containerId: string }) {
|
export function CargoesTable({ containerId }: { containerId: string }) {
|
||||||
const { data: cargoes, refetch } = useCargoesByContainer(containerId);
|
const { data: cargoes, refetch } = useQuery(
|
||||||
const deliver = useDeliverCargo();
|
api.cargoes.listByContainer.queryOptions({
|
||||||
const unload = useUnloadCargo();
|
input: { containerId },
|
||||||
|
enabled: !!containerId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const deliver = useMutation(api.cargoes.deliver.mutationOptions());
|
||||||
|
const unload = useMutation(api.cargoes.unload.mutationOptions());
|
||||||
|
|
||||||
if (!cargoes?.length) return <div className="text-muted-foreground">No cargoes for this container.</div>;
|
if (!cargoes?.length) return <div className="text-muted-foreground">No cargoes for this container.</div>;
|
||||||
|
|
||||||
@@ -34,8 +40,8 @@ export function CargoesTable({ containerId }: { containerId: string }) {
|
|||||||
<TableCell><Badge variant="outline">{cargo.status}</Badge></TableCell>
|
<TableCell><Badge variant="outline">{cargo.status}</Badge></TableCell>
|
||||||
<TableCell className="space-x-2">
|
<TableCell className="space-x-2">
|
||||||
{cargo.status === 'PENDING' && <LoadCargoDialog cargoId={cargo.id} onSuccess={() => refetch()} />}
|
{cargo.status === 'PENDING' && <LoadCargoDialog cargoId={cargo.id} onSuccess={() => refetch()} />}
|
||||||
{cargo.status === 'LOADED' && <Button size="sm" onClick={() => deliver.mutateAsync(cargo.id).then(() => refetch())}>Deliver</Button>}
|
{cargo.status === 'LOADED' && <Button size="sm" onClick={() => deliver.mutateAsync({ id: cargo.id }).then(() => refetch())}>Deliver</Button>}
|
||||||
{cargo.status === 'LOADED' && <Button size="sm" variant="outline" onClick={() => unload.mutateAsync(cargo.id).then(() => refetch())}>Unload</Button>}
|
{cargo.status === 'LOADED' && <Button size="sm" variant="outline" onClick={() => unload.mutateAsync({ id: cargo.id }).then(() => refetch())}>Unload</Button>}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from
|
|||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
import { useDeliverCargo } from '@/hooks/useCargoes';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import { api } from '@/services/api';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,7 +19,7 @@ export function DeliverCargoDialog({ cargoId, onSuccess }: { cargoId: string; on
|
|||||||
const [receiverName, setReceiverName] = useState('');
|
const [receiverName, setReceiverName] = useState('');
|
||||||
const [pickupDate, setPickupDate] = useState('');
|
const [pickupDate, setPickupDate] = useState('');
|
||||||
const [deliveryRemarks, setDeliveryRemarks] = useState('');
|
const [deliveryRemarks, setDeliveryRemarks] = useState('');
|
||||||
const deliver = useDeliverCargo();
|
const deliver = useMutation(api.cargoes.deliver.mutationOptions());
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const handleDeliver = async () => {
|
const handleDeliver = async () => {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { useLoadCargo } from '@/hooks/useCargoes';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import { api } from '@/services/api';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
|
|
||||||
export function LoadCargoDialog({ cargoId, onSuccess }: { cargoId: string; onSuccess?: () => void }) {
|
export function LoadCargoDialog({ cargoId, onSuccess }: { cargoId: string; onSuccess?: () => void }) {
|
||||||
@@ -11,7 +12,7 @@ export function LoadCargoDialog({ cargoId, onSuccess }: { cargoId: string; onSuc
|
|||||||
const [quantity, setQuantity] = useState(0);
|
const [quantity, setQuantity] = useState(0);
|
||||||
const [weight, setWeight] = useState(0);
|
const [weight, setWeight] = useState(0);
|
||||||
const [volume, setVolume] = useState<number>();
|
const [volume, setVolume] = useState<number>();
|
||||||
const load = useLoadCargo();
|
const load = useMutation(api.cargoes.load.mutationOptions());
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const handleLoad = async () => {
|
const handleLoad = async () => {
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
||||||
import { cargoService, type DeliverCargoPayload } from '@/services/cargoService';
|
|
||||||
|
|
||||||
export const cargoKeys = {
|
|
||||||
all: ['cargoes'] as const,
|
|
||||||
byContainer: (containerId: string) => [...cargoKeys.all, 'container', containerId] as const,
|
|
||||||
details: () => [...cargoKeys.all, 'detail'] as const,
|
|
||||||
detail: (id: string) => [...cargoKeys.details(), id] as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function useCargoes() {
|
|
||||||
return useQuery({ queryKey: cargoKeys.all, queryFn: () => cargoService.getAll().then(res => res.data) });
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useGetCargoes = useCargoes;
|
|
||||||
|
|
||||||
export function useCargoesByContainer(containerId: string) {
|
|
||||||
return useQuery({ queryKey: cargoKeys.byContainer(containerId), queryFn: () => cargoService.getByContainer(containerId).then(res => res.data), enabled: !!containerId });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCargo(id: string) {
|
|
||||||
return useQuery({ queryKey: cargoKeys.detail(id), queryFn: () => cargoService.getById(id).then(res => res.data), enabled: !!id });
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useGetCargo = useCargo;
|
|
||||||
|
|
||||||
export function useCreateCargo() {
|
|
||||||
const qc = useQueryClient();
|
|
||||||
return useMutation({ mutationFn: cargoService.create, onSuccess: () => qc.invalidateQueries({ queryKey: cargoKeys.all }) });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateCargo() {
|
|
||||||
const qc = useQueryClient();
|
|
||||||
return useMutation({ mutationFn: ({ id, data }: any) => cargoService.update(id, data), onSuccess: (_, { id }) => {
|
|
||||||
qc.invalidateQueries({ queryKey: cargoKeys.all });
|
|
||||||
qc.invalidateQueries({ queryKey: cargoKeys.detail(id) });
|
|
||||||
} });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useDeleteCargo() {
|
|
||||||
const qc = useQueryClient();
|
|
||||||
return useMutation({ mutationFn: cargoService.delete, onSuccess: () => qc.invalidateQueries({ queryKey: cargoKeys.all }) });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useLoadCargo() {
|
|
||||||
const qc = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ id, quantity, weight, volume }: any) => cargoService.load(id, quantity, weight, volume),
|
|
||||||
onSuccess: (_, { id }) => qc.invalidateQueries({ queryKey: cargoKeys.all })
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useDeliverCargo() {
|
|
||||||
const qc = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ id, payload }: { id: string; payload?: DeliverCargoPayload }) =>
|
|
||||||
cargoService.deliver(id, payload),
|
|
||||||
onSuccess: () => qc.invalidateQueries({ queryKey: cargoKeys.all })
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUnloadCargo() {
|
|
||||||
const qc = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (id: string) => cargoService.unload(id),
|
|
||||||
onSuccess: () => qc.invalidateQueries({ queryKey: cargoKeys.all })
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,29 @@
|
|||||||
import { QueryClient } from "@tanstack/react-query";
|
import { MutationCache, QueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
/** Single app-wide React Query client (do not nest additional providers). */
|
import type { InvalidatesMeta } from "@/utils/endpoint";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single app-wide React Query client (do not nest additional providers).
|
||||||
|
*
|
||||||
|
* Declarative invalidation: any mutation built via `api.*.mutationOptions()`
|
||||||
|
* (see `services/api.ts` + `utils/endpoint.ts`) carries an `invalidates`
|
||||||
|
* function in its `meta`. The shared `MutationCache` below runs it on success
|
||||||
|
* and invalidates the returned query keys — so invalidation is declared once in
|
||||||
|
* the endpoint definition rather than re-wired in every component.
|
||||||
|
*/
|
||||||
export const queryClient = new QueryClient({
|
export const queryClient = new QueryClient({
|
||||||
|
mutationCache: new MutationCache({
|
||||||
|
onSuccess: (data, variables, _context, mutation) => {
|
||||||
|
const invalidates = mutation.meta?.invalidates as
|
||||||
|
| InvalidatesMeta
|
||||||
|
| undefined;
|
||||||
|
if (typeof invalidates !== "function") return;
|
||||||
|
|
||||||
|
for (const queryKey of invalidates(variables, data)) {
|
||||||
|
void queryClient.invalidateQueries({ queryKey });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
retry: 1,
|
retry: 1,
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { FormEvent, ReactNode, useMemo, useState } from 'react';
|
import { FormEvent, ReactNode, useMemo, useState } from 'react';
|
||||||
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
import { Edit, Eye, Plus, Search, Trash2 } from 'lucide-react';
|
import { Edit, Eye, Plus, Search, Trash2 } from 'lucide-react';
|
||||||
|
|
||||||
|
import { api } from '@/services/api';
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
Badge as MantineBadge,
|
Badge as MantineBadge,
|
||||||
@@ -42,7 +45,6 @@ import {
|
|||||||
useWagonTypes,
|
useWagonTypes,
|
||||||
} from '@/hooks/use-wagon-types';
|
} from '@/hooks/use-wagon-types';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { useCreateCargo, useDeleteCargo, useCargoes, useUpdateCargo } from '@/hooks/useCargoes';
|
|
||||||
import {
|
import {
|
||||||
useContainers,
|
useContainers,
|
||||||
useCreateContainer,
|
useCreateContainer,
|
||||||
@@ -1041,7 +1043,7 @@ export function ContainersCrudPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function CargoesCrudPage() {
|
export function CargoesCrudPage() {
|
||||||
const query = useCargoes();
|
const query = useQuery(api.cargoes.list.queryOptions());
|
||||||
const { data: cargoTypes = [] } = useCargoTypes();
|
const { data: cargoTypes = [] } = useCargoTypes();
|
||||||
const { data: containers = [] } = useContainers();
|
const { data: containers = [] } = useContainers();
|
||||||
const cargoTypeOptions = cargoTypes.map((type: any) => ({
|
const cargoTypeOptions = cargoTypes.map((type: any) => ({
|
||||||
@@ -1059,9 +1061,9 @@ export function CargoesCrudPage() {
|
|||||||
addLabel="Add Cargo"
|
addLabel="Add Cargo"
|
||||||
data={query.data}
|
data={query.data}
|
||||||
isLoading={query.isLoading}
|
isLoading={query.isLoading}
|
||||||
create={useCreateCargo()}
|
create={useMutation(api.cargoes.create.mutationOptions())}
|
||||||
update={useUpdateCargo()}
|
update={useMutation(api.cargoes.update.mutationOptions())}
|
||||||
remove={useDeleteCargo()}
|
remove={useMutation(api.cargoes.remove.mutationOptions())}
|
||||||
searchText={(cargo) => [cargo.cargoReference, cargo.description, cargo.containerId, cargo.status].join(' ')}
|
searchText={(cargo) => [cargo.cargoReference, cargo.description, cargo.containerId, cargo.status].join(' ')}
|
||||||
columns={[
|
columns={[
|
||||||
{ key: 'cargoReference', label: 'Reference' },
|
{ key: 'cargoReference', label: 'Reference' },
|
||||||
|
|||||||
@@ -37,8 +37,724 @@ import {
|
|||||||
import type { BookingDetail } from "@/types/booking";
|
import type { BookingDetail } from "@/types/booking";
|
||||||
import type { IOverviewDashboard, OverviewRange } from "@/types/overview";
|
import type { IOverviewDashboard, OverviewRange } from "@/types/overview";
|
||||||
import { overviewService } from "./overview.service";
|
import { overviewService } from "./overview.service";
|
||||||
|
import {
|
||||||
|
cargoService,
|
||||||
|
type Cargo,
|
||||||
|
type DeliverCargoPayload,
|
||||||
|
} from "./cargoService";
|
||||||
|
import { warehouseService } from "./warehouse.service";
|
||||||
|
import type {
|
||||||
|
AllocationCriteria,
|
||||||
|
AllocationPreviewResult,
|
||||||
|
AllocationRule,
|
||||||
|
ArrivalQueueItem,
|
||||||
|
AutoLoadResult,
|
||||||
|
AutoUnloadArrivedResult,
|
||||||
|
AutoUnloadResult,
|
||||||
|
BookingScheduleView,
|
||||||
|
BulkDispatchResult,
|
||||||
|
BulkInspectPayload,
|
||||||
|
BulkInspectResult,
|
||||||
|
BulkReceivePayload,
|
||||||
|
BulkReceiveResult,
|
||||||
|
DeliverInventoryPayload,
|
||||||
|
EligibleBooking,
|
||||||
|
FeePreview,
|
||||||
|
FeeRule,
|
||||||
|
ImportTrain,
|
||||||
|
ImportTrainItem,
|
||||||
|
ImportUnloadedItem,
|
||||||
|
InspectionAttachment,
|
||||||
|
InspectionReport,
|
||||||
|
InspectionReportPayload,
|
||||||
|
InventoryFilter,
|
||||||
|
InventoryInquiryFilter,
|
||||||
|
InventoryInquiryResult,
|
||||||
|
InventoryMovement,
|
||||||
|
LoadableWagon,
|
||||||
|
LoadInventoryPayload,
|
||||||
|
LoadPassedExportResult,
|
||||||
|
MoveInventoryPayload,
|
||||||
|
PayInvoicePayload,
|
||||||
|
ReadyToLoadRow,
|
||||||
|
ReceiveInventoryPayload,
|
||||||
|
ReleaseOrderPayload,
|
||||||
|
ReserveInventoryPayload,
|
||||||
|
SaveAllocationRulePayload,
|
||||||
|
SaveFeeRulePayload,
|
||||||
|
SaveWarehousePayload,
|
||||||
|
SaveYardPayload,
|
||||||
|
SaveZonePayload,
|
||||||
|
Warehouse,
|
||||||
|
WarehouseActivityLog,
|
||||||
|
WarehouseDashboard,
|
||||||
|
WarehouseFeeInvoice,
|
||||||
|
WarehouseFilter,
|
||||||
|
WarehouseInventoryItem,
|
||||||
|
WarehouseInvoiceFilter,
|
||||||
|
WarehouseLoading,
|
||||||
|
WarehouseYard,
|
||||||
|
WarehouseZone,
|
||||||
|
} from "@/types/warehouse";
|
||||||
|
|
||||||
|
/** Query keys for inventory-lifecycle mutations that ripple across views. */
|
||||||
|
const INVENTORY_INVALIDATIONS: ReadonlyArray<readonly unknown[]> = [
|
||||||
|
["warehouse-inventory"],
|
||||||
|
["warehouse-loadings"],
|
||||||
|
["warehouses"],
|
||||||
|
];
|
||||||
|
|
||||||
export const api = {
|
export const api = {
|
||||||
|
warehouses: {
|
||||||
|
// ── Warehouses ─────────────────────────────────────────────────────────
|
||||||
|
list: endpoint<{ filter?: WarehouseFilter }, Warehouse[]>(
|
||||||
|
"warehouses",
|
||||||
|
"list",
|
||||||
|
({ filter }) => warehouseService.list(filter).then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
getById: endpoint<{ id: string }, Warehouse>(
|
||||||
|
"warehouses",
|
||||||
|
"getById",
|
||||||
|
({ id }) => warehouseService.getById(id).then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
dashboard: endpoint<void, WarehouseDashboard>("warehouses", "dashboard", () =>
|
||||||
|
warehouseService.dashboard().then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
create: endpoint<SaveWarehousePayload, Warehouse>(
|
||||||
|
"warehouses",
|
||||||
|
"create",
|
||||||
|
(payload) => warehouseService.create(payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouses"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
update: endpoint<
|
||||||
|
{ id: string; payload: Partial<SaveWarehousePayload> },
|
||||||
|
Warehouse
|
||||||
|
>(
|
||||||
|
"warehouses",
|
||||||
|
"update",
|
||||||
|
({ id, payload }) =>
|
||||||
|
warehouseService.update(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouses"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
// ── Yards ──────────────────────────────────────────────────────────────
|
||||||
|
listYards: endpoint<{ warehouseId: string }, WarehouseYard[]>(
|
||||||
|
"warehouses",
|
||||||
|
"listYards",
|
||||||
|
({ warehouseId }) =>
|
||||||
|
warehouseService.listYards(warehouseId).then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
createYard: endpoint<
|
||||||
|
{ warehouseId: string; payload: SaveYardPayload },
|
||||||
|
WarehouseYard
|
||||||
|
>(
|
||||||
|
"warehouses",
|
||||||
|
"createYard",
|
||||||
|
({ warehouseId, payload }) =>
|
||||||
|
warehouseService.createYard(warehouseId, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouses"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
updateYard: endpoint<
|
||||||
|
{ id: string; payload: Partial<SaveYardPayload> },
|
||||||
|
WarehouseYard
|
||||||
|
>(
|
||||||
|
"warehouses",
|
||||||
|
"updateYard",
|
||||||
|
({ id, payload }) =>
|
||||||
|
warehouseService.updateYard(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouses"], ["warehouse-yards"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
// ── Zones ──────────────────────────────────────────────────────────────
|
||||||
|
listZones: endpoint<{ yardId: string }, WarehouseZone[]>(
|
||||||
|
"warehouses",
|
||||||
|
"listZones",
|
||||||
|
({ yardId }) => warehouseService.listZones(yardId).then((r) => r.data),
|
||||||
|
({ yardId }) => ["warehouse-yards", yardId, "zones"],
|
||||||
|
),
|
||||||
|
|
||||||
|
createZone: endpoint<
|
||||||
|
{ yardId: string; payload: SaveZonePayload },
|
||||||
|
WarehouseZone
|
||||||
|
>(
|
||||||
|
"warehouses",
|
||||||
|
"createZone",
|
||||||
|
({ yardId, payload }) =>
|
||||||
|
warehouseService.createZone(yardId, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
({ yardId }) => [["warehouse-yards", yardId, "zones"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
updateZone: endpoint<
|
||||||
|
{ id: string; payload: Partial<SaveZonePayload> },
|
||||||
|
WarehouseZone
|
||||||
|
>(
|
||||||
|
"warehouses",
|
||||||
|
"updateZone",
|
||||||
|
({ id, payload }) =>
|
||||||
|
warehouseService.updateZone(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-yards"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
// ── Inventory (queries) ────────────────────────────────────────────────
|
||||||
|
listInventory: endpoint<
|
||||||
|
{ filter?: InventoryFilter },
|
||||||
|
WarehouseInventoryItem[]
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"list",
|
||||||
|
({ filter }) => warehouseService.listInventory(filter).then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
inquiry: endpoint<
|
||||||
|
{ filter: InventoryInquiryFilter },
|
||||||
|
InventoryInquiryResult[]
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"inquiry",
|
||||||
|
({ filter }) => warehouseService.inquiry(filter).then((r) => r.data),
|
||||||
|
({ filter }) => ["warehouse-inventory", "inquiry", filter],
|
||||||
|
),
|
||||||
|
|
||||||
|
eligibleBookings: endpoint<void, EligibleBooking[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"eligible-bookings",
|
||||||
|
() => warehouseService.eligibleBookings().then((r) => r.data),
|
||||||
|
() => ["warehouse-inventory", "eligible-bookings"],
|
||||||
|
),
|
||||||
|
|
||||||
|
readyToLoadExport: endpoint<void, ReadyToLoadRow[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"ready-to-load-export",
|
||||||
|
() => warehouseService.readyToLoadExport().then((r) => r.data),
|
||||||
|
() => ["warehouse-inventory", "ready-to-load-export"],
|
||||||
|
),
|
||||||
|
|
||||||
|
loadedExport: endpoint<void, ReadyToLoadRow[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"loaded-export",
|
||||||
|
() => warehouseService.loadedExport().then((r) => r.data),
|
||||||
|
() => ["warehouse-inventory", "loaded-export"],
|
||||||
|
),
|
||||||
|
|
||||||
|
importArriveQueue: endpoint<void, ImportTrain[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"import-arrive-queue",
|
||||||
|
() => warehouseService.importArriveQueue().then((r) => r.data),
|
||||||
|
() => ["warehouse-inventory", "import-arrive-queue"],
|
||||||
|
),
|
||||||
|
|
||||||
|
importTrainItems: endpoint<{ scheduleId: string }, ImportTrainItem[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"import-train-items",
|
||||||
|
({ scheduleId }) =>
|
||||||
|
warehouseService.importTrainItems(scheduleId).then((r) => r.data),
|
||||||
|
({ scheduleId }) => ["warehouse-inventory", "import-train-items", scheduleId],
|
||||||
|
),
|
||||||
|
|
||||||
|
importUnloadedQueue: endpoint<void, ImportUnloadedItem[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"import-unloaded-queue",
|
||||||
|
() => warehouseService.importUnloadedQueue().then((r) => r.data),
|
||||||
|
() => ["warehouse-inventory", "import-unloaded-queue"],
|
||||||
|
),
|
||||||
|
|
||||||
|
importPickupReadyQueue: endpoint<void, ImportUnloadedItem[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"import-pickup-ready-queue",
|
||||||
|
() => warehouseService.importPickupReadyQueue().then((r) => r.data),
|
||||||
|
() => ["warehouse-inventory", "import-pickup-ready-queue"],
|
||||||
|
),
|
||||||
|
|
||||||
|
loadableWagons: endpoint<void, LoadableWagon[]>(
|
||||||
|
"warehouse",
|
||||||
|
"loadable-wagons",
|
||||||
|
() => warehouseService.loadableWagons().then((r) => r.data),
|
||||||
|
() => ["warehouse", "loadable-wagons"],
|
||||||
|
),
|
||||||
|
|
||||||
|
loadings: endpoint<
|
||||||
|
{ params?: { bookingId?: string; wagonId?: string } },
|
||||||
|
WarehouseLoading[]
|
||||||
|
>(
|
||||||
|
"warehouse-loadings",
|
||||||
|
"list",
|
||||||
|
({ params }) => warehouseService.loadings(params).then((r) => r.data),
|
||||||
|
({ params }) => ["warehouse-loadings", params ?? {}],
|
||||||
|
),
|
||||||
|
|
||||||
|
bookingSchedule: endpoint<{ bookingId: string }, BookingScheduleView>(
|
||||||
|
"warehouse",
|
||||||
|
"booking-schedule",
|
||||||
|
({ bookingId }) =>
|
||||||
|
warehouseService.bookingSchedule(bookingId).then((r) => r.data),
|
||||||
|
({ bookingId }) => ["warehouse", "booking-schedule", bookingId],
|
||||||
|
),
|
||||||
|
|
||||||
|
movements: endpoint<{ id: string }, InventoryMovement[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"movements",
|
||||||
|
({ id }) => warehouseService.movements(id).then((r) => r.data),
|
||||||
|
({ id }) => ["warehouse-inventory", id, "movements"],
|
||||||
|
),
|
||||||
|
|
||||||
|
activity: endpoint<{ id: string }, WarehouseActivityLog[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"activity",
|
||||||
|
({ id }) => warehouseService.activity(id).then((r) => r.data),
|
||||||
|
({ id }) => ["warehouse-inventory", id, "activity"],
|
||||||
|
),
|
||||||
|
|
||||||
|
arrivalQueue: endpoint<void, ArrivalQueueItem[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"arrival-queue",
|
||||||
|
() => warehouseService.arrivalQueue().then((r) => r.data),
|
||||||
|
() => ["warehouse-inventory", "arrival-queue"],
|
||||||
|
),
|
||||||
|
|
||||||
|
inspectionReports: endpoint<{ inventoryId: string }, InspectionReport[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"inspection-reports",
|
||||||
|
({ inventoryId }) =>
|
||||||
|
warehouseService.listInspectionReports(inventoryId).then((r) => r.data),
|
||||||
|
({ inventoryId }) =>
|
||||||
|
["warehouse-inventory", inventoryId, "inspection-reports"],
|
||||||
|
),
|
||||||
|
|
||||||
|
allocationRules: endpoint<void, AllocationRule[]>(
|
||||||
|
"warehouse-allocation-rules",
|
||||||
|
"list",
|
||||||
|
() => warehouseService.listAllocationRules().then((r) => r.data),
|
||||||
|
() => ["warehouse-allocation-rules"],
|
||||||
|
),
|
||||||
|
|
||||||
|
feeRules: endpoint<void, FeeRule[]>(
|
||||||
|
"warehouse-fee-rules",
|
||||||
|
"list",
|
||||||
|
() => warehouseService.listFeeRules().then((r) => r.data),
|
||||||
|
() => ["warehouse-fee-rules"],
|
||||||
|
),
|
||||||
|
|
||||||
|
feePreview: endpoint<{ inventoryId: string }, FeePreview[]>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"fee-preview",
|
||||||
|
({ inventoryId }) =>
|
||||||
|
warehouseService.feePreview(inventoryId).then((r) => r.data),
|
||||||
|
({ inventoryId }) => ["warehouse-inventory", inventoryId, "fee-preview"],
|
||||||
|
),
|
||||||
|
|
||||||
|
invoices: endpoint<{ filter?: WarehouseInvoiceFilter }, WarehouseFeeInvoice[]>(
|
||||||
|
"warehouse-fee-invoices",
|
||||||
|
"list",
|
||||||
|
({ filter }) => warehouseService.listInvoices(filter).then((r) => r.data),
|
||||||
|
({ filter }) => ["warehouse-fee-invoices", filter ?? {}],
|
||||||
|
),
|
||||||
|
|
||||||
|
invoice: endpoint<{ id: string }, WarehouseFeeInvoice>(
|
||||||
|
"warehouse-fee-invoices",
|
||||||
|
"detail",
|
||||||
|
({ id }) => warehouseService.getInvoice(id).then((r) => r.data),
|
||||||
|
({ id }) => ["warehouse-fee-invoices", "detail", id],
|
||||||
|
),
|
||||||
|
|
||||||
|
invoicesForInventory: endpoint<
|
||||||
|
{ inventoryId: string },
|
||||||
|
WarehouseFeeInvoice[]
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"fee-invoices",
|
||||||
|
({ inventoryId }) =>
|
||||||
|
warehouseService.invoicesForInventory(inventoryId).then((r) => r.data),
|
||||||
|
({ inventoryId }) => ["warehouse-inventory", inventoryId, "fee-invoices"],
|
||||||
|
),
|
||||||
|
|
||||||
|
// ── Inventory (mutations) ──────────────────────────────────────────────
|
||||||
|
receiveInventory: endpoint<ReceiveInventoryPayload, WarehouseInventoryItem>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"receive",
|
||||||
|
(payload) => warehouseService.receiveInventory(payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-inventory"], ["warehouses"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
store: endpoint<string, WarehouseInventoryItem>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"store",
|
||||||
|
(id) => warehouseService.store(id).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
reserve: endpoint<ReserveInventoryPayload, WarehouseInventoryItem>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"reserve",
|
||||||
|
(payload) => warehouseService.reserve(payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
markReadyForLoading: endpoint<string, WarehouseInventoryItem>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"mark-ready-for-loading",
|
||||||
|
(id) => warehouseService.markReadyForLoading(id).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
load: endpoint<
|
||||||
|
{ id: string; payload: LoadInventoryPayload },
|
||||||
|
WarehouseInventoryItem
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"load",
|
||||||
|
({ id, payload }) => warehouseService.load(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
dispatch: endpoint<string, WarehouseInventoryItem>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"dispatch",
|
||||||
|
(id) => warehouseService.dispatch(id).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
move: endpoint<
|
||||||
|
{ id: string; payload: MoveInventoryPayload },
|
||||||
|
WarehouseInventoryItem
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"move",
|
||||||
|
({ id, payload }) => warehouseService.move(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
markReadyForPickup: endpoint<string, WarehouseInventoryItem>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"mark-ready-for-pickup",
|
||||||
|
(id) => warehouseService.markReadyForPickup(id).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
release: endpoint<
|
||||||
|
{ id: string; payload: ReleaseOrderPayload },
|
||||||
|
WarehouseInventoryItem
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"release",
|
||||||
|
({ id, payload }) =>
|
||||||
|
warehouseService.release(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
deliver: endpoint<
|
||||||
|
{ id: string; payload: DeliverInventoryPayload },
|
||||||
|
WarehouseInventoryItem
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"deliver",
|
||||||
|
({ id, payload }) =>
|
||||||
|
warehouseService.deliver(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
bulkReceive: endpoint<BulkReceivePayload, BulkReceiveResult>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"bulk-receive",
|
||||||
|
(payload) => warehouseService.receiveBulk(payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
loadPassedExport: endpoint<void, LoadPassedExportResult>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"load-passed-export",
|
||||||
|
() => warehouseService.loadPassedExport().then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
bulkMarkInspected: endpoint<BulkInspectPayload, BulkInspectResult>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"bulk-mark-inspected",
|
||||||
|
(payload) => warehouseService.bulkMarkInspected(payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
bulkDispatchExport: endpoint<string[], BulkDispatchResult>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"bulk-dispatch-export",
|
||||||
|
(inventoryIds) =>
|
||||||
|
warehouseService.bulkDispatchExport(inventoryIds).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
autoUnloadArrivedBookings: endpoint<string, AutoUnloadArrivedResult>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"auto-unload-arrived-bookings",
|
||||||
|
(scheduleId) =>
|
||||||
|
warehouseService
|
||||||
|
.autoUnloadArrivedBookings(scheduleId)
|
||||||
|
.then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => INVENTORY_INVALIDATIONS,
|
||||||
|
),
|
||||||
|
|
||||||
|
autoUnloadArrived: endpoint<void, AutoUnloadResult>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"auto-unload-arrived",
|
||||||
|
() => warehouseService.autoUnloadArrived().then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-inventory"], ["warehouses"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
autoLoadReady: endpoint<void, AutoLoadResult>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"auto-load-ready",
|
||||||
|
() => warehouseService.autoLoadReady().then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-inventory"], ["warehouses"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
unloadBooking: endpoint<
|
||||||
|
{ bookingId: string; payload?: Record<string, unknown> },
|
||||||
|
WarehouseInventoryItem
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"unload-booking",
|
||||||
|
({ bookingId, payload }) =>
|
||||||
|
warehouseService.unloadBooking(bookingId, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-inventory"], ["warehouses"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
createInspectionReport: endpoint<
|
||||||
|
{ inventoryId: string; payload: InspectionReportPayload },
|
||||||
|
InspectionReport
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"create-inspection-report",
|
||||||
|
({ inventoryId, payload }) =>
|
||||||
|
warehouseService
|
||||||
|
.createInspectionReport(inventoryId, payload)
|
||||||
|
.then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
({ inventoryId }) => [
|
||||||
|
["warehouse-inventory", inventoryId, "inspection-reports"],
|
||||||
|
["warehouse-inventory"],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
uploadInspectionAttachments: endpoint<
|
||||||
|
{ reportId: string; files: File[] },
|
||||||
|
InspectionAttachment[]
|
||||||
|
>(
|
||||||
|
"warehouse-inventory",
|
||||||
|
"upload-inspection-attachments",
|
||||||
|
({ reportId, files }) =>
|
||||||
|
warehouseService
|
||||||
|
.uploadInspectionAttachments(reportId, files)
|
||||||
|
.then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
// ── Allocation + fee rules ─────────────────────────────────────────────
|
||||||
|
previewAllocation: endpoint<AllocationCriteria, AllocationPreviewResult | null>(
|
||||||
|
"warehouse-allocation-rules",
|
||||||
|
"preview",
|
||||||
|
(criteria) =>
|
||||||
|
warehouseService.previewAllocation(criteria).then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
createAllocationRule: endpoint<SaveAllocationRulePayload, AllocationRule>(
|
||||||
|
"warehouse-allocation-rules",
|
||||||
|
"create",
|
||||||
|
(payload) =>
|
||||||
|
warehouseService.createAllocationRule(payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-allocation-rules"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
updateAllocationRule: endpoint<
|
||||||
|
{ id: string; payload: Partial<SaveAllocationRulePayload> },
|
||||||
|
AllocationRule
|
||||||
|
>(
|
||||||
|
"warehouse-allocation-rules",
|
||||||
|
"update",
|
||||||
|
({ id, payload }) =>
|
||||||
|
warehouseService.updateAllocationRule(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-allocation-rules"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
deleteAllocationRule: endpoint<string, void>(
|
||||||
|
"warehouse-allocation-rules",
|
||||||
|
"delete",
|
||||||
|
(id) => warehouseService.deleteAllocationRule(id).then(() => undefined),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-allocation-rules"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
createFeeRule: endpoint<SaveFeeRulePayload, FeeRule>(
|
||||||
|
"warehouse-fee-rules",
|
||||||
|
"create",
|
||||||
|
(payload) => warehouseService.createFeeRule(payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-fee-rules"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
updateFeeRule: endpoint<
|
||||||
|
{ id: string; payload: Partial<SaveFeeRulePayload> },
|
||||||
|
FeeRule
|
||||||
|
>(
|
||||||
|
"warehouse-fee-rules",
|
||||||
|
"update",
|
||||||
|
({ id, payload }) =>
|
||||||
|
warehouseService.updateFeeRule(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-fee-rules"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
deleteFeeRule: endpoint<string, void>(
|
||||||
|
"warehouse-fee-rules",
|
||||||
|
"delete",
|
||||||
|
(id) => warehouseService.deleteFeeRule(id).then(() => undefined),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-fee-rules"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
// ── Invoices ───────────────────────────────────────────────────────────
|
||||||
|
generateInvoice: endpoint<
|
||||||
|
{ inventoryId: string; confirmZero?: boolean },
|
||||||
|
WarehouseFeeInvoice
|
||||||
|
>(
|
||||||
|
"warehouse-fee-invoices",
|
||||||
|
"generate",
|
||||||
|
({ inventoryId, confirmZero }) =>
|
||||||
|
warehouseService
|
||||||
|
.generateInvoice(inventoryId, confirmZero)
|
||||||
|
.then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
cancelInvoice: endpoint<string, WarehouseFeeInvoice>(
|
||||||
|
"warehouse-fee-invoices",
|
||||||
|
"cancel",
|
||||||
|
(id) => warehouseService.cancelInvoice(id).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
payInvoice: endpoint<
|
||||||
|
{ id: string; payload: PayInvoicePayload },
|
||||||
|
WarehouseFeeInvoice
|
||||||
|
>(
|
||||||
|
"warehouse-fee-invoices",
|
||||||
|
"pay",
|
||||||
|
({ id, payload }) =>
|
||||||
|
warehouseService.payInvoice(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
gateClearance: endpoint<string, WarehouseInventoryItem>(
|
||||||
|
"warehouse-fee-invoices",
|
||||||
|
"gate-clearance",
|
||||||
|
(inventoryId) =>
|
||||||
|
warehouseService.gateClearance(inventoryId).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
cargoes: {
|
||||||
|
list: endpoint<void, Cargo[]>("cargoes", "list", () =>
|
||||||
|
cargoService.getAll().then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
listByContainer: endpoint<{ containerId: string }, Cargo[]>(
|
||||||
|
"cargoes",
|
||||||
|
"listByContainer",
|
||||||
|
({ containerId }) =>
|
||||||
|
cargoService.getByContainer(containerId).then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
getById: endpoint<{ id: string }, Cargo>("cargoes", "getById", ({ id }) =>
|
||||||
|
cargoService.getById(id).then((r) => r.data),
|
||||||
|
),
|
||||||
|
|
||||||
|
create: endpoint<Partial<Cargo>, Cargo>(
|
||||||
|
"cargoes",
|
||||||
|
"create",
|
||||||
|
(payload) => cargoService.create(payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["cargoes"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
update: endpoint<{ id: string; data: Partial<Cargo> }, Cargo>(
|
||||||
|
"cargoes",
|
||||||
|
"update",
|
||||||
|
({ id, data }) => cargoService.update(id, data).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["cargoes"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
remove: endpoint<string, void>(
|
||||||
|
"cargoes",
|
||||||
|
"remove",
|
||||||
|
(id) => cargoService.delete(id).then(() => undefined),
|
||||||
|
undefined,
|
||||||
|
() => [["cargoes"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
load: endpoint<
|
||||||
|
{ id: string; quantity: number; weight: number; volume?: number },
|
||||||
|
Cargo
|
||||||
|
>(
|
||||||
|
"cargoes",
|
||||||
|
"load",
|
||||||
|
({ id, quantity, weight, volume }) =>
|
||||||
|
cargoService.load(id, quantity, weight, volume).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["cargoes"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
deliver: endpoint<{ id: string; payload?: DeliverCargoPayload }, Cargo>(
|
||||||
|
"cargoes",
|
||||||
|
"deliver",
|
||||||
|
({ id, payload }) =>
|
||||||
|
cargoService.deliver(id, payload).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["cargoes"]],
|
||||||
|
),
|
||||||
|
|
||||||
|
unload: endpoint<{ id: string }, Cargo>(
|
||||||
|
"cargoes",
|
||||||
|
"unload",
|
||||||
|
({ id }) => cargoService.unload(id).then((r) => r.data),
|
||||||
|
undefined,
|
||||||
|
() => [["cargoes"]],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
fileUploadSettings: {
|
fileUploadSettings: {
|
||||||
list: endpoint<void, FileUploadSetting[]>(
|
list: endpoint<void, FileUploadSetting[]>(
|
||||||
"file-upload-settings",
|
"file-upload-settings",
|
||||||
|
|||||||
@@ -12,6 +12,27 @@ export type QueryConfig<T> = Omit<
|
|||||||
"queryKey" | "queryFn"
|
"queryKey" | "queryFn"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query keys a mutation should invalidate on success. Receives the mutation
|
||||||
|
* input and response so keys can be derived from them. Returns a list of query
|
||||||
|
* keys — each is matched as a *prefix* by React Query, so returning a service
|
||||||
|
* root (e.g. `["cargoes"]`) invalidates every query nested under it.
|
||||||
|
*
|
||||||
|
* The keys are surfaced through `mutationOptions().meta.invalidates`; the
|
||||||
|
* app-wide `MutationCache` (see `lib/queryClient.ts`) reads them and invalidates
|
||||||
|
* automatically, so components never wire `onSuccess` invalidation by hand.
|
||||||
|
*/
|
||||||
|
export type InvalidatesFn<TInput, TResponse> = (
|
||||||
|
input: TInput,
|
||||||
|
data: TResponse,
|
||||||
|
) => ReadonlyArray<readonly unknown[]>;
|
||||||
|
|
||||||
|
/** Shape stored in `mutation.meta.invalidates` and consumed by the MutationCache. */
|
||||||
|
export type InvalidatesMeta = (
|
||||||
|
variables: unknown,
|
||||||
|
data: unknown,
|
||||||
|
) => ReadonlyArray<readonly unknown[]>;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Endpoint interfaces
|
// Endpoint interfaces
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -45,6 +66,7 @@ export function endpoint<TInput, TResponse>(
|
|||||||
action: string,
|
action: string,
|
||||||
execute: (input: TInput) => Promise<TResponse>,
|
execute: (input: TInput) => Promise<TResponse>,
|
||||||
queryKeyBuilder?: (input: TInput) => readonly unknown[],
|
queryKeyBuilder?: (input: TInput) => readonly unknown[],
|
||||||
|
invalidates?: InvalidatesFn<TInput, TResponse>,
|
||||||
) {
|
) {
|
||||||
const buildKey = (input?: TInput): readonly unknown[] => {
|
const buildKey = (input?: TInput): readonly unknown[] => {
|
||||||
if (queryKeyBuilder && input !== undefined) {
|
if (queryKeyBuilder && input !== undefined) {
|
||||||
@@ -77,27 +99,25 @@ export function endpoint<TInput, TResponse>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mutationOptions = (
|
const mutationOptions = (
|
||||||
config?: Omit<
|
config?: Omit<UseMutationOptions<TResponse, Error, TInput>, "mutationFn">,
|
||||||
UseMutationOptions<
|
): UseMutationOptions<TResponse, Error, TInput> => {
|
||||||
TResponse,
|
const meta = invalidates
|
||||||
Error,
|
? {
|
||||||
TInput
|
...config?.meta,
|
||||||
>,
|
invalidates: ((variables, data) =>
|
||||||
"mutationFn"
|
invalidates(
|
||||||
>,
|
variables as TInput,
|
||||||
): UseMutationOptions<
|
data as TResponse,
|
||||||
TResponse,
|
)) satisfies InvalidatesMeta,
|
||||||
Error,
|
}
|
||||||
TInput
|
: config?.meta;
|
||||||
> => {
|
|
||||||
return {
|
return {
|
||||||
...config,
|
...config,
|
||||||
mutationFn: (
|
meta,
|
||||||
variables: TInput,
|
mutationFn: (variables: TInput): Promise<TResponse> => execute(variables),
|
||||||
): Promise<TResponse> =>
|
};
|
||||||
execute(variables),
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
call,
|
call,
|
||||||
|
|||||||
Reference in New Issue
Block a user