xpeditis2.0/apps/frontend/app/carrier/accept/[token]/page.tsx
2025-12-15 15:03:59 +01:00

153 lines
5.2 KiB
TypeScript

'use client';
import { useEffect, useState, useRef } from 'react';
import { useParams, useRouter } from 'next/navigation';
import { CheckCircle, Loader2, XCircle } from 'lucide-react';
export default function CarrierAcceptPage() {
const params = useParams();
const router = useRouter();
const token = params.token as string;
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [countdown, setCountdown] = useState(5);
// Prevent double API calls (React 18 StrictMode issue)
const hasCalledApi = useRef(false);
useEffect(() => {
const acceptBooking = async () => {
// Protection contre les doubles appels
if (hasCalledApi.current) {
return;
}
hasCalledApi.current = true;
if (!token) {
setError('Token manquant');
setLoading(false);
return;
}
try {
// Appeler l'API backend pour accepter le booking
const response = await fetch(`http://localhost:4000/api/v1/csv-booking-actions/accept/${token}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
let errorData;
try {
errorData = await response.json();
} catch (e) {
errorData = { message: `Erreur HTTP ${response.status}` };
}
let errorMessage = errorData.message || 'Erreur lors de l\'acceptation du booking';
if (errorMessage.includes('status ACCEPTED') || errorMessage.includes('ACCEPTED')) {
errorMessage = 'Ce booking a déjà été accepté.';
} else if (errorMessage.includes('status REJECTED')) {
errorMessage = 'Ce booking a déjà été refusé.';
} else if (errorMessage.includes('not found') || errorMessage.includes('Booking not found')) {
errorMessage = 'Booking introuvable. Le lien peut avoir expiré.';
}
throw new Error(errorMessage);
}
setLoading(false);
// Démarrer le compte à rebours
const timer = setInterval(() => {
setCountdown((prev) => {
if (prev <= 1) {
clearInterval(timer);
router.push('/');
return 0;
}
return prev - 1;
});
}, 1000);
return () => clearInterval(timer);
} catch (err) {
console.error('Error accepting booking:', err);
setError(err instanceof Error ? err.message : 'Erreur lors de l\'acceptation');
setLoading(false);
}
};
acceptBooking();
}, [token, router]);
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-green-50 to-blue-50">
<div className="bg-white p-8 rounded-lg shadow-lg max-w-md w-full text-center">
<Loader2 className="w-16 h-16 text-green-600 mx-auto mb-4 animate-spin" />
<h1 className="text-2xl font-bold text-gray-900 mb-4">
Traitement en cours...
</h1>
<p className="text-gray-600">
Nous traitons votre acceptation.
</p>
</div>
</div>
);
}
if (error) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-red-50 to-orange-50">
<div className="bg-white p-8 rounded-lg shadow-lg max-w-md w-full text-center">
<XCircle className="w-16 h-16 text-red-500 mx-auto mb-4" />
<h1 className="text-2xl font-bold text-gray-900 mb-4">Erreur</h1>
<p className="text-gray-600 mb-6">{error}</p>
<button
onClick={() => router.push('/')}
className="w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
Retour à l'accueil
</button>
</div>
</div>
);
}
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-green-50 to-blue-50">
<div className="bg-white p-8 rounded-lg shadow-lg max-w-md w-full text-center">
<CheckCircle className="w-20 h-20 text-green-500 mx-auto mb-6" />
<h1 className="text-3xl font-bold text-gray-900 mb-4">
Merci !
</h1>
<div className="bg-green-50 border-2 border-green-200 rounded-lg p-6 mb-6">
<p className="text-green-800 font-medium text-lg mb-2">
✅ Votre acceptation a bien été prise en compte
</p>
<p className="text-green-700 text-sm">
Nous vous remercions d'avoir accepté cette demande de transport.
</p>
</div>
<p className="text-gray-500 text-sm mb-4">
Redirection vers la page d'accueil dans {countdown} seconde{countdown > 1 ? 's' : ''}...
</p>
<button
onClick={() => router.push('/')}
className="w-full px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 font-semibold transition-colors"
>
Retour à l'accueil
</button>
</div>
</div>
);
}