refactor(bookings): Streamline new booking process, integrate useAuth for customer data, and simplify API payloads

This commit is contained in:
ghost2023
2026-05-28 16:27:22 +03:00
parent 3e77f27a96
commit 240fb505ec
6 changed files with 24 additions and 29 deletions

View File

@@ -13,7 +13,6 @@ import {
Truck,
} from "lucide-react";
import Breadcrumbs from "@/components/Breadcrumbs";
import DeleteBookingDialog from "./DeleteBookingDialog";
import { getMyBookings } from "@/lib/currentCustomer";
import { deleteBooking, type Booking, type BookingStatus } from "./bookings.mock";
@@ -183,8 +182,6 @@ export default function MyBookings() {
return (
<div className="min-h-screen p-6">
<div className="space-y-6">
<Breadcrumbs items={[{ label: "My Bookings" }]} />
{/* Header Section Card */}
<Card className="p-6 flex-row justify-between">
<div>

View File

@@ -1,12 +1,11 @@
import { useEffect, useMemo, useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { CheckCircle2, ChevronLeft, ChevronRight } from "lucide-react";
import { Button } from "@edr/ui-common";
import Breadcrumbs from "@/components/Breadcrumbs";
import { getCurrentCustomer } from "@/lib/currentCustomer";
import { api } from "@/services/api";
import type { CreateBookingPayload } from "@/services/bookings.service";
import {
@@ -30,6 +29,7 @@ import {
Step7Documents,
Step8Review,
} from "./new-booking-form/steps";
import useAuth from "@/hooks/useAuth";
export default function NewBookingPage() {
const navigate = useNavigate();
@@ -37,6 +37,7 @@ export default function NewBookingPage() {
const [step, setStep] = useState(1);
const [renewalValidating, setRenewalValidating] = useState(false);
const [renewalValid, setRenewalValid] = useState<boolean | null>(null);
const { customer } = useAuth();
const createMutation = useMutation({
mutationFn: (payload: CreateBookingPayload) =>
api.bookings.create.call(payload),
@@ -129,7 +130,6 @@ export default function NewBookingPage() {
return;
}
const me = getCurrentCustomer();
const reference = data.previousContractRef;
const totalWeight =
@@ -142,7 +142,7 @@ export default function NewBookingPage() {
const apiPayload = {
reference,
customerId: String(me.id),
customerId: customer!.id,
scheduledDate: new Date().toISOString().slice(0, 10),
totalAmount: 0,
contractType:
@@ -194,7 +194,7 @@ export default function NewBookingPage() {
createMutation.mutate(apiPayload);
});
if (createMutation.isSuccess && createMutation.data) {
if (createMutation.isSuccess) {
return (
<div className="flex min-h-screen items-center justify-center p-6">
<div className="w-full max-w-sm rounded-2xl border border-border bg-card p-10 text-center shadow-sm">
@@ -207,7 +207,7 @@ export default function NewBookingPage() {
notified once approved.
</p>
<p className="mt-4 font-mono text-sm font-semibold text-primary">
{createMutation.data.reference}
{createMutation.data?.reference}
</p>
</div>
</div>

View File

@@ -161,7 +161,7 @@ export const bookingFormSchema = z
destinationYard: z.string(),
cargoType: z.enum(["container", "bulk"], "Select a cargo type."),
cargoWeight: z.string(),
freightType: z.enum(["bulk", "break_bulk"]),
freightType: z.enum(["bulk", "break_bulk"]).optional(),
bulkCommodity: z.string(),
bulkCommodityOther: z.string(),
breakBulkType: z.string(),

View File

@@ -2,7 +2,13 @@ import { Controller, type UseFormReturn } from "react-hook-form";
import { Flame, MapPin, Snowflake } from "lucide-react";
import { Field, SelectItem, Separator, Switch } from "@edr/ui-common";
import { type BookingFormValues, getRouteDirection, STATIONS } from "./schema";
import { SelectField, SelectOptions, StepHeader, StepLabel } from "./shared";
import {
AlertBox,
SelectField,
SelectOptions,
StepHeader,
StepLabel,
} from "./shared";
import { useDropdownSettingByCode } from "@/hooks/useDropdownSettings";
import { DropdownOption } from "@/types/dropdownSettings";
@@ -145,12 +151,10 @@ export function Step4Route({ form }: { form: BookingForm }) {
);
}
function getStationOptions(options?: DropdownOption[]): DropdownOption[] {
return [...(options ?? [])].sort((a, b) => a.order - b.order);
}
function StationSelectOptions({
options,
excludeValue,
@@ -193,4 +197,4 @@ function StationSelectOptions({
))}
</>
);
}
}

View File

@@ -78,7 +78,9 @@ export function Step5CargoDetails({
selected={cargoType === "container"}
onClick={() => {
field.onChange("container");
form.setValue("freightType", "", { shouldDirty: true });
form.setValue("freightType", undefined, {
shouldDirty: true,
});
form.setValue("cargoWeight", "", { shouldDirty: true });
}}
>

View File

@@ -1,31 +1,23 @@
import type { Freight, PaginatedResponse } from "@edr/types";
import { client as api } from "@/utils/api";
import { client } from "../utils/api";
export type CreateBookingPayload = Freight.CreateBookingDto;
export const bookingsService = {
list: async (): Promise<PaginatedResponse<Freight.IBooking>> => {
const { data } = await api.get("/bookings");
const { data } = await client.get("/bookings");
return data.data;
},
get: async (id: string): Promise<Freight.IBooking> => {
const { data } = await api.get(`/bookings/${id}`);
const { data } = await client.get(`/bookings/${id}`);
return data.data;
},
create: async (payload: CreateBookingPayload): Promise<Freight.IBooking> => {
const fd = new FormData();
for (const [key, value] of Object.entries(payload)) {
if (value === undefined || value === null) continue;
if (Array.isArray(value) || typeof value === "object") {
fd.append(key, JSON.stringify(value));
} else {
fd.append(key, String(value));
}
}
const { data } = await api.post("/api/bookings", fd);
const { data } = await client.post("/api/bookings", payload);
return data.data;
},
remove: async (id: string): Promise<void> => {
await api.delete(`/bookings/${id}`);
await client.delete(`/bookings/${id}`);
},
};