Added Chat Page

This commit is contained in:
2026-01-21 18:13:35 +01:00
parent 0ca8ce8b52
commit 3eed79ca93
37 changed files with 3966 additions and 64 deletions

View File

@@ -3,6 +3,8 @@
import { useState } from 'react';
import TrajetForm from './TrajetForm';
import ValidationModal from './ValidationModal';
import ConfirmModal from './ConfirmModal';
import { useNotification } from './NotificationProvider';
interface Trajet {
id: string;
@@ -33,8 +35,11 @@ interface TrajetDetailModalProps {
}
export default function TrajetDetailModal({ trajet, onClose, onUpdate }: TrajetDetailModalProps) {
const { showNotification } = useNotification();
const [showEditForm, setShowEditForm] = useState(false);
const [showValidationModal, setShowValidationModal] = useState(false);
const [showCancelConfirm, setShowCancelConfirm] = useState(false);
const [showArchiveConfirm, setShowArchiveConfirm] = useState(false);
const [loading, setLoading] = useState(false);
const formatDate = (dateString: string) => {
@@ -52,11 +57,12 @@ export default function TrajetDetailModal({ trajet, onClose, onUpdate }: TrajetD
return date.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' });
};
const handleCancel = async () => {
if (!confirm('Êtes-vous sûr de vouloir annuler ce trajet ?')) {
return;
}
const handleCancelClick = () => {
setShowCancelConfirm(true);
};
const handleCancel = async () => {
setShowCancelConfirm(false);
setLoading(true);
try {
const response = await fetch(`/api/trajets/${trajet.id}`, {
@@ -70,15 +76,47 @@ export default function TrajetDetailModal({ trajet, onClose, onUpdate }: TrajetD
});
if (response.ok) {
showNotification('info', 'Trajet annulé avec succès');
onUpdate();
onClose();
} else {
const error = await response.json();
alert(error.error || 'Erreur lors de l\'annulation du trajet');
showNotification('error', error.error || 'Erreur lors de l\'annulation du trajet');
}
} catch (error) {
console.error('Erreur lors de l\'annulation:', error);
alert('Erreur lors de l\'annulation du trajet');
showNotification('error', 'Erreur lors de l\'annulation du trajet');
} finally {
setLoading(false);
}
};
const handleArchiveClick = () => {
setShowArchiveConfirm(true);
};
const handleArchive = async () => {
setShowArchiveConfirm(false);
setLoading(true);
try {
const response = await fetch(`/api/trajets/${trajet.id}/archive`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
if (response.ok) {
showNotification('info', 'Trajet archivé avec succès');
onUpdate();
onClose();
} else {
const error = await response.json();
showNotification('error', error.error || 'Erreur lors de l\'archivage du trajet');
}
} catch (error) {
console.error('Erreur lors de l\'archivage:', error);
showNotification('error', 'Erreur lors de l\'archivage du trajet');
} finally {
setLoading(false);
}
@@ -274,7 +312,7 @@ export default function TrajetDetailModal({ trajet, onClose, onUpdate }: TrajetD
<div className="flex justify-between gap-3">
<button
type="button"
onClick={handleCancel}
onClick={handleCancelClick}
disabled={loading || trajet.statut === 'Validé' || trajet.statut === 'Terminé' || trajet.statut === 'Annulé'}
className="px-4 py-2 text-sm font-medium text-red-600 hover:text-red-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
>
@@ -287,7 +325,7 @@ export default function TrajetDetailModal({ trajet, onClose, onUpdate }: TrajetD
<button
type="button"
onClick={() => setShowEditForm(true)}
disabled={trajet.statut === 'Validé' || trajet.statut === 'Terminé'}
disabled={trajet.statut === 'Validé' || trajet.statut === 'Terminé' || trajet.statut === 'Annulé'}
className="px-4 py-2 text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -295,6 +333,17 @@ export default function TrajetDetailModal({ trajet, onClose, onUpdate }: TrajetD
</svg>
Modifier
</button>
<button
type="button"
onClick={handleArchiveClick}
disabled={loading}
className="px-4 py-2 text-sm font-medium text-orange-600 hover:text-orange-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
</svg>
Archiver
</button>
{trajet.chauffeur && trajet.statut === 'Planifié' && (
<button
type="button"
@@ -310,6 +359,27 @@ export default function TrajetDetailModal({ trajet, onClose, onUpdate }: TrajetD
</div>
</div>
</div>
<ConfirmModal
isOpen={showCancelConfirm}
title="Annuler le trajet"
message="Êtes-vous sûr de vouloir annuler ce trajet ?"
confirmText="Annuler le trajet"
cancelText="Retour"
confirmColor="danger"
onConfirm={handleCancel}
onCancel={() => setShowCancelConfirm(false)}
/>
<ConfirmModal
isOpen={showArchiveConfirm}
title="Archiver le trajet"
message="Êtes-vous sûr de vouloir archiver ce trajet ? Il ne sera plus visible dans le calendrier."
confirmText="Archiver"
cancelText="Annuler"
confirmColor="warning"
onConfirm={handleArchive}
onCancel={() => setShowArchiveConfirm(false)}
/>
</div>
</div>
);