finsh user,car,driver pages also add validator layer to app build trip page
This commit is contained in:
86
types/car.ts
86
types/car.ts
@@ -6,7 +6,54 @@ export type InsuranceStatus = "Valid" | "Expired" | "NotInsured";
|
||||
export type ImpoundStatus = "None" | string;
|
||||
export type ImageStage = "BEFORE" | "AFTER" | "GENERAL";
|
||||
|
||||
// ── Core Car ────────────────────────────────────────────────────────────────
|
||||
// ── Status display config ────────────────────────────────────────────────────
|
||||
// Used by page.tsx (CarCard) and CarDetailPanel
|
||||
export const STATUS_MAP: Record<
|
||||
CarStatus,
|
||||
{ label: string; color: string; bg: string; border: string; dot: string }
|
||||
> = {
|
||||
Active: { label: "نشط", color: "#166534", bg: "#DCFCE7", border: "#BBF7D0", dot: "#16A34A" },
|
||||
InMaintenance: { label: "صيانة", color: "#854D0E", bg: "#FFFBEB", border: "#FDE68A", dot: "#D97706" },
|
||||
InTrip: { label: "في رحلة", color: "#1E40AF", bg: "#EFF6FF", border: "#BFDBFE", dot: "#3B82F6" },
|
||||
Inactive: { label: "غير نشط", color: "#64748B", bg: "#F1F5F9", border: "#E2E8F0", dot: "#94A3B8" },
|
||||
};
|
||||
|
||||
export const INS_MAP: Record<InsuranceStatus, { label: string; color: string }> = {
|
||||
Valid: { label: "سارٍ", color: "#16A34A" },
|
||||
Expired: { label: "منتهي", color: "#DC2626" },
|
||||
NotInsured: { label: "غير مؤمَّن", color: "#D97706" },
|
||||
};
|
||||
|
||||
// ── Stage display config ─────────────────────────────────────────────────────
|
||||
// Used by CarImageGallery
|
||||
export const STAGE_MAP: Record<ImageStage, { label: string; color: string; bg: string }> = {
|
||||
BEFORE: { label: "قبل", color: "#854D0E", bg: "#FFFBEB" },
|
||||
AFTER: { label: "بعد", color: "#166534", bg: "#DCFCE7" },
|
||||
GENERAL: { label: "عام", color: "#1E40AF", bg: "#EFF6FF" },
|
||||
};
|
||||
|
||||
// ── Shared date helpers ───────────────────────────────────────────────────────
|
||||
export function fmtDate(iso?: string | null): string {
|
||||
if (!iso) return "—";
|
||||
return new Date(iso).toLocaleDateString("ar-SA", {
|
||||
year: "numeric", month: "long", day: "numeric",
|
||||
});
|
||||
}
|
||||
|
||||
export function fmtDateShort(iso?: string | null): string {
|
||||
if (!iso) return "—";
|
||||
return new Date(iso).toLocaleDateString("ar-SA", {
|
||||
year: "numeric", month: "short", day: "numeric",
|
||||
});
|
||||
}
|
||||
|
||||
/** Returns true if the date is within 90 days in the future (or already past) */
|
||||
export function isExpiringSoon(iso?: string | null): boolean {
|
||||
if (!iso) return false;
|
||||
return (new Date(iso).getTime() - Date.now()) / 86_400_000 <= 90;
|
||||
}
|
||||
|
||||
// ── Core Car ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface Car {
|
||||
id: string;
|
||||
@@ -66,7 +113,7 @@ export interface CarStatusHistoryEntry {
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
// ── Car Image ────────────────────────────────────────────────────────────────
|
||||
// ── Car Image ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface CarImage {
|
||||
id: string;
|
||||
@@ -82,7 +129,7 @@ export interface CarImage {
|
||||
isDeleted: boolean;
|
||||
}
|
||||
|
||||
// ── Payloads ────────────────────────────────────────────────────────────────
|
||||
// ── Payloads ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface CreateCarPayload {
|
||||
manufacturer: string;
|
||||
@@ -118,7 +165,7 @@ export interface CreateCarPayload {
|
||||
|
||||
export type UpdateCarPayload = Partial<CreateCarPayload> & { isActive?: boolean };
|
||||
|
||||
// ── API Responses ────────────────────────────────────────────────────────────
|
||||
// ── API Responses ─────────────────────────────────────────────────────────────
|
||||
|
||||
export interface CarListResponse {
|
||||
data: {
|
||||
@@ -136,7 +183,7 @@ export interface CarImageListResponse {
|
||||
data: CarImage[];
|
||||
}
|
||||
|
||||
// ── Form state ───────────────────────────────────────────────────────────────
|
||||
// ── Form state ────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface CarFormErrors {
|
||||
manufacturer?: string;
|
||||
@@ -146,4 +193,33 @@ export interface CarFormErrors {
|
||||
plateLetters?: string;
|
||||
registrationNumber?: string;
|
||||
vinNumber?: string;
|
||||
}
|
||||
|
||||
// ── Toast ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface ToastMsg {
|
||||
type: "success" | "error";
|
||||
message: string;
|
||||
}
|
||||
// — CarFormErrors ──────────────────────────────────
|
||||
|
||||
export interface CarFormErrors {
|
||||
manufacturer?: string;
|
||||
model?: string;
|
||||
year?: string;
|
||||
color?: string;
|
||||
plateNumber?: string;
|
||||
plateLetters?: string;
|
||||
plateType?: string;
|
||||
registrationNumber?: string;
|
||||
vinNumber?: string;
|
||||
branchId?: string;
|
||||
currentStatus?: string;
|
||||
insuranceStatus?: string;
|
||||
registrationExpiryDate?: string;
|
||||
insuranceExpiryDate?: string;
|
||||
inspectionExpiryDate?: string;
|
||||
gpsDeviceId?: string;
|
||||
capacity?: string;
|
||||
weight?: string;
|
||||
}
|
||||
@@ -34,6 +34,9 @@ export interface Driver {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
isDeleted?: boolean;
|
||||
photoUrl?: string | null;
|
||||
nationalPhotoUrl?: string | null;
|
||||
driverCardPhotoUrl?: string | null;
|
||||
}
|
||||
|
||||
export interface DriverStatusHistoryEntry {
|
||||
|
||||
160
types/trip.ts
Normal file
160
types/trip.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
// types/trip.ts
|
||||
// Mirrors the structure of types/driver.ts.
|
||||
// Source of truth for endpoint shapes: trip_api_reference.html (/api/v1/trips)
|
||||
|
||||
export type TripStatus = "Scheduled" | "InProgress" | "Completed" | "Cancelled";
|
||||
|
||||
// ── Embedded summaries returned inside Trip responses ───────────────────────
|
||||
// NOTE: Car has no dedicated types/car.ts in this handoff — these summaries
|
||||
// are inferred from the response field list in trip_api_reference.html.
|
||||
// If a real types/car.ts already exists in the project, prefer importing
|
||||
// from there instead of duplicating this shape.
|
||||
|
||||
export interface TripDriverSummary {
|
||||
id?: string;
|
||||
name: string;
|
||||
userName?: string | null;
|
||||
email?: string | null;
|
||||
address?: string | null;
|
||||
nationality?: string | null;
|
||||
nationalId?: string | null;
|
||||
gosiNumber?: string | null;
|
||||
phone: string;
|
||||
licenseNumber?: string | null;
|
||||
driverCardNumber?: string | null;
|
||||
}
|
||||
|
||||
export interface TripCarSummary {
|
||||
id?: string;
|
||||
manufacturer: string;
|
||||
model: string;
|
||||
year?: number | null;
|
||||
color?: string | null;
|
||||
plateNumber: string;
|
||||
plateLetters?: string | null;
|
||||
plateType?: string | null;
|
||||
registrationNumber?: string | null;
|
||||
ownerNationalId?: string | null;
|
||||
}
|
||||
|
||||
export interface TripBranchSummary {
|
||||
id?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
// ── Core Trip ─────────────────────────────────────────────────────────────
|
||||
|
||||
export interface Trip {
|
||||
id: string;
|
||||
tripNumber: string;
|
||||
title: string;
|
||||
startTime?: string | null;
|
||||
endTime?: string | null;
|
||||
status: TripStatus;
|
||||
collectedCount: number;
|
||||
deliveredCount: number;
|
||||
returnedCount: number;
|
||||
totalCashCollected?: number | string | null;
|
||||
notes?: string | null;
|
||||
endReason?: string | null;
|
||||
isDeleted?: boolean;
|
||||
deletedAt?: string | null;
|
||||
|
||||
driverId?: string;
|
||||
carId?: string;
|
||||
branchId?: string | null;
|
||||
|
||||
driver?: TripDriverSummary | null;
|
||||
car?: TripCarSummary | null;
|
||||
branch?: TripBranchSummary | null;
|
||||
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
// ── Payloads ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface CreateTripPayload {
|
||||
title: string;
|
||||
driverId: string;
|
||||
carId: string;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
branchId?: string;
|
||||
status?: TripStatus;
|
||||
collectedCount?: number;
|
||||
deliveredCount?: number;
|
||||
returnedCount?: number;
|
||||
totalCashCollected?: number | string;
|
||||
notes?: string;
|
||||
endReason?: string;
|
||||
}
|
||||
|
||||
export type UpdateTripPayload = Partial<CreateTripPayload> & {
|
||||
/** Reason for changing driverId/carId — recorded in history. Update-only field. */
|
||||
reason?: string;
|
||||
};
|
||||
|
||||
// ── List query params (GET /trips) ───────────────────────────────────────────
|
||||
|
||||
export interface TripListParams {
|
||||
status?: TripStatus;
|
||||
driverId?: string;
|
||||
carId?: string;
|
||||
branchId?: string;
|
||||
/** Searches across tripNumber, status, title, carId, driverId */
|
||||
search?: string;
|
||||
sort?: "createdAt" | "tripNumber" | "status" | "startTime" | "endTime";
|
||||
page?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
// ── API Responses ─────────────────────────────────────────────────────────────
|
||||
|
||||
export interface TripListResponse {
|
||||
data: {
|
||||
data: Trip[];
|
||||
pagination: { total: number; page: number; limit: number; totalPages: number };
|
||||
};
|
||||
}
|
||||
|
||||
export interface TripDetailResponse {
|
||||
data: Trip;
|
||||
}
|
||||
|
||||
export interface TripReportResponse {
|
||||
data: {
|
||||
reportUrl: string;
|
||||
};
|
||||
}
|
||||
|
||||
// ── Form state ────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface TripFormErrors {
|
||||
title?: string;
|
||||
driverId?: string;
|
||||
carId?: string;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
branchId?: string;
|
||||
status?: string;
|
||||
collectedCount?: string;
|
||||
deliveredCount?: string;
|
||||
returnedCount?: string;
|
||||
totalCashCollected?: string;
|
||||
notes?: string;
|
||||
endReason?: string;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
// ── Status display config (mirrors DRIVER_STATUS_MAP) ───────────────────────
|
||||
|
||||
export const TRIP_STATUS_MAP: Record<
|
||||
TripStatus,
|
||||
{ label: string; color: string; bg: string; border: string; dot: string }
|
||||
> = {
|
||||
Scheduled: { label: "مجدولة", color: "#1E40AF", bg: "#EFF6FF", border: "#BFDBFE", dot: "#3B82F6" },
|
||||
InProgress: { label: "جارية", color: "#92400E", bg: "#FFFBEB", border: "#FDE68A", dot: "#D97706" },
|
||||
Completed: { label: "مكتملة", color: "#166534", bg: "#DCFCE7", border: "#BBF7D0", dot: "#16A34A" },
|
||||
Cancelled: { label: "ملغاة", color: "#991B1B", bg: "#FEF2F2", border: "#FECACA", dot: "#DC2626" },
|
||||
};
|
||||
Reference in New Issue
Block a user