import { api as client } from "../auth/http"; import { unwrap } from "@/utils/endpoint"; import { URL_CONSTANTS } from "@/constants/URLS"; import type { BookingDetail } from "@/types/booking"; const B = URL_CONSTANTS.BOOKINGS; export interface BookingListFilter { status?: string; // customerId?: string; companyId?: string; freightType?: string; tradeDirection?: string; paymentCurrency?: string; page?: number; pageSize?: number; sortBy?: string; sortOrder?: "ASC" | "DESC"; } export interface PaginatedBookings { items: BookingDetail[]; total: number; } export interface ApproveStepPayload { id: string; stepId: string; requiredRole: string; } export interface RejectStepPayload { id: string; stepId: string; reason: string; } export interface ContractView { bookingId: string; reference: string; status: string; templateKey: string; title: string; html: string; canSignCustomer: boolean; canSignStaff: boolean; hasContractDocument: boolean; signatures: Array<{ role: string; signerDisplayName: string; signedAt: string; signatureImageUrl?: string | null; }>; } export interface SignContractPayload { role: "CUSTOMER" | "STAFF"; signatureImageBase64: string; signerDisplayName: string; consentText?: string; } async function postBooking(url: string, body?: unknown): Promise { const response = await client.post(url, body ?? {}); return unwrap(response.data); } export const bookingsService = { list: async (filter?: BookingListFilter): Promise => { const response = await client.get(B.BASE, { params: filter, }); const data = unwrap(response.data); return { items: (data.items ?? []) as BookingDetail[], total: data.total ?? 0, }; }, getById: async (id: string): Promise => { const response = await client.get(B.BY_ID(id)); return unwrap(response.data) as BookingDetail; }, remove: async (id: string): Promise => { await client.delete(B.BY_ID(id)); }, staffAccept: (id: string) => postBooking(B.STAFF_ACCEPT(id)), requestChanges: (id: string, note: string) => postBooking(B.STAFF_REQUEST_CHANGES(id), { note }), staffReject: (id: string, reason: string) => postBooking(B.STAFF_REJECT(id), { reason }), approveStep: ({ id, stepId, requiredRole }: ApproveStepPayload) => postBooking(B.APPROVE_STEP(id, stepId), { requiredRole }), rejectStep: ({ id, stepId, reason }: RejectStepPayload) => postBooking(B.REJECT_STEP(id, stepId), { reason }), generateContract: (id: string) => postBooking(B.CONTRACT_GENERATE(id)), getContractView: async (id: string): Promise => { const response = await client.get(B.CONTRACT_VIEW(id)); return unwrap(response.data) as ContractView; }, downloadContract: async (id: string): Promise => { const response = await client.get(B.CONTRACT_DOWNLOAD(id), { responseType: "blob", }); return response.data as Blob; }, downloadContractDocument: async (id: string): Promise => { const response = await client.get(B.CONTRACT_DOCUMENT(id), { responseType: "blob", }); return response.data as Blob; }, signContract: (id: string, payload: SignContractPayload) => postBooking(B.CONTRACT_SIGN(id), payload), getSummary: async (id: string): Promise<{ summary: string }> => { const response = await client.get<{ summary: string }>(B.SUMMARY(id)); return unwrap(response.data); }, customerSign: (id: string, payload: SignContractPayload) => postBooking(B.CUSTOMER_SIGN(id), { ...payload, role: "CUSTOMER", }), marketingApprove: (id: string, payload: SignContractPayload) => postBooking(B.MARKETING_APPROVE(id), { ...payload, role: "STAFF", }), generatePnr: (id: string) => postBooking(B.PAYMENT_PNR(id)), submitPaymentProof: async (id: string, file: File): Promise => { const form = new FormData(); form.append("file", file); const response = await client.post(B.PAYMENT_PROOF(id), form, { headers: { "Content-Type": "multipart/form-data" }, }); return unwrap(response.data) as BookingDetail; }, verifyPayment: (id: string) => postBooking(B.PAYMENT_VERIFY(id)), downloadPaymentRequestLetter: async (id: string): Promise => { const response = await client.get(B.PAYMENT_REQUEST_LETTER(id), { responseType: "blob", }); return response.data as Blob; }, startTransit: (id: string) => postBooking(B.START_TRANSIT(id)), complete: (id: string) => postBooking(B.COMPLETE(id)), cancel: (id: string, reason: string) => postBooking(B.CANCEL(id), { reason }), };