prevent booking when no car added

This commit is contained in:
root
2026-06-11 12:30:41 -04:00
parent 919f583677
commit 6eeba99c45
2 changed files with 182 additions and 99 deletions
@@ -2,6 +2,7 @@
import { useEffect, useState } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { formatCurrency } from '@rentaldrivego/types'
import { apiFetch } from '@/lib/api'
import { useDashboardI18n } from '@/components/I18nProvider'
@@ -25,18 +26,26 @@ interface ReservationRow {
customer: { firstName: string; lastName: string; email: string }
}
interface VehicleRow {
id: string
}
export default function ReservationsPage() {
const { dict, language } = useDashboardI18n()
const router = useRouter()
const r = dict.reservations
const localeCode = language === 'fr' ? 'fr-FR' : language === 'ar' ? 'ar-MA' : 'en-US'
const [rows, setRows] = useState<ReservationRow[]>([])
const [error, setError] = useState<string | null>(null)
const [loadError, setLoadError] = useState<string | null>(null)
const [actionError, setActionError] = useState<string | null>(null)
const [checkingNewReservation, setCheckingNewReservation] = useState(false)
const [showNoVehiclesModal, setShowNoVehiclesModal] = useState(false)
useEffect(() => {
apiFetch<ReservationRow[]>('/reservations?pageSize=100')
.then((result) => setRows(result ?? []))
.catch((err) => setError(err.message))
.catch((err) => setLoadError(err.message))
}, [])
const formatDate = (iso: string) =>
@@ -52,6 +61,40 @@ export default function ReservationsPage() {
}
return language === 'fr' ? 'Voir la réservation' : language === 'ar' ? 'عرض الحجز' : 'View reservation'
}
const noVehiclesMessage =
language === 'fr'
? 'Ajoutez au moins un véhicule à votre flotte avant de créer une réservation.'
: language === 'ar'
? 'أضف مركبة واحدة على الأقل إلى الأسطول قبل إنشاء حجز.'
: 'Add at least one vehicle to your fleet before creating a reservation.'
async function handleNewReservationClick() {
setActionError(null)
setCheckingNewReservation(true)
try {
const vehicles = await apiFetch<VehicleRow[]>('/vehicles?pageSize=1')
if (!vehicles || vehicles.length === 0) {
setShowNoVehiclesModal(true)
return
}
router.push('/reservations/new')
} catch (err: any) {
setActionError(err.message ?? (
language === 'fr'
? 'Impossible de vérifier la flotte avant de créer la réservation.'
: language === 'ar'
? 'تعذر التحقق من الأسطول قبل إنشاء الحجز.'
: 'Failed to verify fleet before creating the reservation.'
))
} finally {
setCheckingNewReservation(false)
}
}
function handleAddCar() {
setShowNoVehiclesModal(false)
router.push('/fleet?modal=add-car')
}
return (
<div className="space-y-6">
@@ -60,13 +103,29 @@ export default function ReservationsPage() {
<h2 className="text-xl font-semibold text-slate-900">{r.heading}</h2>
<p className="text-sm text-slate-500 mt-1">{r.subtitle}</p>
</div>
<Link href="/reservations/new" className="btn-primary whitespace-nowrap">
{language === 'fr' ? 'Réserver une voiture' : language === 'ar' ? 'حجز سيارة' : 'Book car'}
</Link>
<button
type="button"
className="btn-primary whitespace-nowrap"
onClick={handleNewReservationClick}
disabled={checkingNewReservation}
>
{checkingNewReservation
? language === 'fr'
? 'Vérification…'
: language === 'ar'
? 'جارٍ التحقق…'
: 'Checking…'
: language === 'fr'
? 'Réserver une voiture'
: language === 'ar'
? 'حجز سيارة'
: 'Book car'}
</button>
</div>
{actionError ? <div className="card p-4 text-sm text-red-600">{actionError}</div> : null}
<div className="card overflow-hidden">
{error ? (
<div className="p-8 text-sm text-red-600">{error}</div>
{loadError ? (
<div className="p-8 text-sm text-red-600">{loadError}</div>
) : (
<div className="overflow-x-auto">
<table className="w-full">
@@ -109,6 +168,29 @@ export default function ReservationsPage() {
</div>
)}
</div>
{showNoVehiclesModal ? (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-blue-950/40 p-4"
onClick={(event) => {
if (event.target === event.currentTarget) setShowNoVehiclesModal(false)
}}
>
<div className="w-full max-w-md rounded-2xl bg-white p-6 shadow-xl">
<h3 className="text-lg font-semibold text-slate-900">
{language === 'fr' ? 'Ajouter un véhicule' : language === 'ar' ? 'أضف مركبة' : 'Add a car'}
</h3>
<p className="mt-2 text-sm text-slate-600">{noVehiclesMessage}</p>
<div className="mt-6 flex gap-3">
<button type="button" className="btn-primary flex-1" onClick={handleAddCar}>
{language === 'fr' ? 'Ajouter une voiture' : language === 'ar' ? 'إضافة مركبة' : 'Add car'}
</button>
<button type="button" className="btn-secondary flex-1" onClick={() => setShowNoVehiclesModal(false)}>
{language === 'fr' ? 'Annuler' : language === 'ar' ? 'إلغاء' : 'Cancel'}
</button>
</div>
</div>
</div>
) : null}
</div>
)
}