'use client' import { useRouter, useSearchParams } from 'next/navigation' import { useEffect, useState } from 'react' import { DEFAULT_COMPANY_SLUG } from '@/lib/api' import { getPublicSiteDictionary, type PublicSiteLanguage } from '@/lib/i18n' interface VehicleDetail { id: string make: string model: string year: number category: string dailyRate: number seats: number transmission: string photos: string[] } interface PromoOffer { id: string title: string discountValue: number } interface InsurancePolicy { id: string name: string type: string chargeType: 'PER_DAY' | 'PER_RENTAL' | 'PERCENTAGE_OF_RENTAL' chargeValue: number isRequired: boolean } interface ContractSettings { fuelPolicyType: string fuelPolicyNote: string | null additionalDriverCharge: 'FREE' | 'PER_DAY' | 'FLAT' additionalDriverDailyRate: number additionalDriverFlatRate: number } interface BookingOptions { insurancePolicies: InsurancePolicy[] contractSettings: ContractSettings | null } interface Step1 { startDate: string endDate: string } interface Step2 { firstName: string lastName: string email: string phone: string driverLicense: string dateOfBirth: string licenseExpiry: string licenseIssuedAt: string nationality: string promoCode: string } interface AdditionalDriverForm { firstName: string lastName: string email: string phone: string driverLicense: string dateOfBirth: string licenseExpiry: string licenseIssuedAt: string nationality: string } const API_BASE = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000/api/v1' function diffDays(start: string, end: string): number { if (!start || !end) return 0 const ms = new Date(end).getTime() - new Date(start).getTime() return Math.max(1, Math.ceil(ms / 86400000)) } function fmt(n: number) { return n.toLocaleString('fr-MA', { style: 'currency', currency: 'MAD', maximumFractionDigits: 0 }) } function inputClass(error?: string) { return [ 'w-full rounded-xl border px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-sky-500', error ? 'border-red-400 bg-red-50' : 'border-slate-300 bg-white', ].join(' ') } function insuranceCharge(policy: InsurancePolicy, days: number, baseTotal: number) { if (policy.chargeType === 'PER_DAY') return policy.chargeValue * days if (policy.chargeType === 'PERCENTAGE_OF_RENTAL') return Math.round(baseTotal * policy.chargeValue / 100) return policy.chargeValue } function additionalDriverCharge(settings: ContractSettings | null, count: number, days: number) { if (!settings || count === 0) return 0 if (settings.additionalDriverCharge === 'PER_DAY') return settings.additionalDriverDailyRate * count * days if (settings.additionalDriverCharge === 'FLAT') return settings.additionalDriverFlatRate * count return 0 } function getDayLabel(language: PublicSiteLanguage, days: number) { if (language === 'fr') return days === 1 ? 'jour' : 'jours' if (language === 'ar') return days === 1 ? 'يوم' : 'أيام' return days === 1 ? 'day' : 'days' } function StepDots({ step, steps, }: { step: number steps: { selectDates: string driverDetails: string reviewBooking: string payment: string } }) { return (
{dict.booking.eyebrow}
{vehicle.make} {vehicle.model} ({vehicle.year})
{vehicle.category} · {vehicle.transmission} · {dict.vehicles.seats(vehicle.seats)}
{fmt(vehicle.dailyRate)} {dict.vehicles.detail.perDay}
{step1Errors.startDate}
}{step1Errors.endDate}
}{step2Errors.firstName}
}{step2Errors.lastName}
}{step2Errors.email}
}{step2Errors.driverLicense}
}{step2Errors.dateOfBirth}
}{step2Errors.licenseIssuedAt}
}{step2Errors.licenseExpiry}
}{dict.booking.insuranceAndPickupPolicies}
{bookingOptions.contractSettings?.fuelPolicyNote || dict.booking.insuranceHint}
{dict.booking.noOptionalInsurance}
)}{step2Errors.additionalDriverFirstName}
}{step2Errors.additionalDriverLastName}
}{step2Errors.additionalDriverLicense}
}{promoError}
} {promoApplied &&{dict.booking.appliedPromo(promoApplied.title, promoApplied.discountValue)}
}{dict.booking.currency}
{dict.booking.paymentMethod}