// services/trip.service.ts // All API calls for the Trip module. // Endpoints extracted from: trip_api_reference.html → /api/v1/trips/... // Follows the exact same pattern as services/driver.service.ts. import { get, post, patch, del } from "./api"; import type { Trip, TripListResponse, TripDetailResponse, TripReportResponse, CreateTripPayload, UpdateTripPayload, TripListParams, } from "@/types/trip"; /** Build a query string for list endpoints */ function buildQuery( params: Record, ): string { const entries = Object.entries(params).filter( ([, v]) => v !== undefined && v !== "", ); if (!entries.length) return ""; return ( "?" + entries .map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`) .join("&") ); } export const tripService = { /** * GET /trips * Fetch paginated + filterable + searchable trip list. * Requires: "read-trip" permission */ getAll: (params: TripListParams = {}, token: string | null) => get(`trips${buildQuery({ ...params })}`, token), /** * GET /trips/archived * Fetch soft-deleted (archived) trips. Same filters as getAll. * Requires: "read-deleted-trip" permission */ getArchived: (params: TripListParams = {}, token: string | null) => get(`trips/archived${buildQuery({ ...params })}`, token), /** * GET /trips/archived/:id * Fetch a single archived trip with full details. * Requires: "read-deleted-trip" permission */ getArchivedById: (id: string, token: string | null) => get(`trips/archived/${id}`, token), /** * GET /trips/:id * Fetch a single trip with full driver/car details. * Requires: "read-trip" permission */ getById: (id: string, token: string | null) => get(`trips/${id}`, token), /** * POST /trips * Create a new trip. * Side effect: driver & car flip to status "InTrip" automatically. * Requires: "create-trip" permission */ create: (payload: CreateTripPayload, token: string | null) => post<{ data: Trip }>("trips", payload, token), /** * PATCH /trips/:id * Update trip data / status / reassign driver or car. * Side effects: * - changing driverId: old driver -> Active, new driver -> InTrip * - changing carId: same logic for cars * - status Completed/Cancelled: driver & car both -> Active * Requires: "update-trip" permission */ update: (id: string, payload: UpdateTripPayload, token: string | null) => patch<{ data: Trip }>(`trips/${id}`, payload, token), /** * DELETE /trips/:id * Soft-delete a trip (isDeleted=true, deletedAt=now()). 204 No Content. * Requires: "delete-trip" permission */ delete: (id: string, token: string | null) => del(`trips/${id}`, token), // ── Reports ─────────────────────────────────────────────────────────────── /** * GET /trips/:id/reports * Generate the Trip Manifest report (HTML, saved server-side). * Returns { reportUrl } * Requires: "generate-trip-report" permission */ getReport: (id: string, token: string | null) => get(`trips/${id}/reports`, token), /** * GET /trips/:id/reports/client/:clientId * Generate a client-filtered version of the trip report. * Returns { reportUrl } * Requires: "generate-trip-report" permission */ getClientReport: (id: string, clientId: string, token: string | null) => get(`trips/${id}/reports/client/${clientId}`, token), };