feat(bookings): Integrate booking list and detail pages with backend API

This commit is contained in:
ghost2023
2026-06-02 16:04:47 +03:00
parent 34bf4ade48
commit dab72217e1
6 changed files with 189 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
import { useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useQuery } from "@tanstack/react-query";
import {
AlertCircle,
AlertTriangle,
@@ -27,14 +27,9 @@ import {
import Breadcrumbs from "@/components/ui/Breadcrumbs";
import { cn } from "@/lib/utils";
import {
getBookingRequestById,
getBookingRequests,
saveBookingRequestsToStorage,
updateBookingRequestStatus,
BOOKING_STATUSES,
type BookingRequest,
} from "./booking-requests.mock";
import { api } from "@/services/api";
import { useUpdateBookingStatus } from "@/hooks/useBookings";
import { mapBookingToRequest, BOOKING_STATUSES } from "./booking-requests.mock";
import {
Badge,
Button,
@@ -233,9 +228,16 @@ const STATUS_CONFIG: Record<
export default function BookingRequestDetailPage() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const [booking, setBooking] = useState<BookingRequest | undefined>(
id ? getBookingRequestById(id) : undefined,
const { data: bookingData } = useQuery(
api.bookings.getById.queryOptions({
input: { id: id ?? "" },
enabled: Boolean(id),
}),
);
const updateStatus = useUpdateBookingStatus();
const booking = bookingData ? mapBookingToRequest(bookingData) : undefined;
if (!booking) {
return (
@@ -270,20 +272,20 @@ export default function BookingRequestDetailPage() {
booking.status,
);
const isPending = updateStatus.isPending;
function handleApprove() {
if (!booking) return;
const nextStatus =
const action =
booking.status === "RFQ_SUBMITTED"
? ("QUOTATION_SENT" as const)
: ("APPROVED" as const);
updateBookingRequestStatus(booking.id, nextStatus);
setBooking(getBookingRequestById(booking.id));
? "SEND_QUOTATION"
: "APPROVE";
updateStatus.mutate({ id: booking.id, action });
}
function handleReject() {
if (!booking) return;
updateBookingRequestStatus(booking.id, "CANCELLED");
setBooking(getBookingRequestById(booking.id));
updateStatus.mutate({ id: booking.id, action: "CANCEL", reason: "Cancelled by backoffice" });
}
return (

View File

@@ -1,5 +1,6 @@
import { useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useQuery } from "@tanstack/react-query";
import {
AlertCircle,
ArrowRight,
@@ -18,10 +19,11 @@ import {
import Breadcrumbs from "@/components/ui/Breadcrumbs";
import { cn } from "@/lib/utils";
import { api } from "@/services/api";
import {
getBookingRequests,
BOOKING_STATUSES,
type BookingRequest,
mapBookingToRequest,
} from "./booking-requests.mock";
import {
DataTable,
@@ -153,7 +155,13 @@ export default function BookingRequestsPage() {
const [query, setQuery] = useState("");
const [statusFilter, setStatusFilter] = useState<string | null>(null);
const bookingRequests = useMemo(() => getBookingRequests(), []);
const { data: bookingData } = useQuery(
api.bookings.list.queryOptions({ input: { filter: { page: pagination.pageIndex + 1, pageSize: pagination.pageSize } } }),
);
const bookingRequests = useMemo(
() => (bookingData?.items ?? []).map(mapBookingToRequest),
[bookingData],
);
const filtered = useMemo(() => {
const q = query.trim().toLowerCase();

View File

@@ -1,3 +1,5 @@
import type { Freight } from "@edr/types";
export interface BookingRequest {
id: string;
reference: string;
@@ -131,6 +133,36 @@ export function updateBookingRequestStatus(id: string, newStatus: (typeof BOOKIN
saveBookingRequestsToStorage(requests);
}
export function mapBookingToRequest(booking: Freight.IBooking): BookingRequest {
return {
id: booking.id,
reference: booking.reference,
customer: booking.customerId,
status: booking.status as BookingRequest["status"],
scheduledDate: booking.scheduledDate,
totalAmount: booking.totalAmount,
paymentStatus: booking.paymentStatus,
contractType: booking.contractType,
serviceType:
booking.serviceType === "RAIL_ONLY" ? "RAIL" : (booking.serviceType as string),
tradeDirection: booking.tradeDirection as string,
originYard: booking.originStation,
destinationYard: booking.destinationStation,
cargoType: booking.freightType ?? booking.freightSubtype ?? "",
cargoTotalWeightVgm: booking.cargoTotalWeightVgm,
isHazardous: booking.isHazardous,
paymentCurrency: booking.paymentCurrency,
priorityScore: booking.priorityScore,
firstMilePickupAddress: booking.firstMilePickupAddress ?? null,
lastMileDeliveryAddress: booking.lastMileDeliveryAddress ?? null,
shippingLine: null,
pnrCode: null,
createdBy: booking.customerId,
createdAt: booking.createdAt,
updatedAt: booking.updatedAt,
};
}
export function getBookingRequests(): BookingRequest[] {
if (typeof window === "undefined" || !window.localStorage) {
return INITIAL_REQUESTS;