diff --git a/client/src/pages/SavTickets.tsx b/client/src/pages/SavTickets.tsx
index b74b162..e631de6 100644
--- a/client/src/pages/SavTickets.tsx
+++ b/client/src/pages/SavTickets.tsx
@@ -190,6 +190,38 @@ export default function SavTickets() {
},
});
+ // Update ticket status/priority mutation
+ const updateTicketMutation = useMutation({
+ mutationFn: async (data: { ticketId: number; status?: string; priority?: string; resolutionDescription?: string }) => {
+ const response = await apiRequest(`/api/sav/tickets/${data.ticketId}`, "PATCH", {
+ status: data.status,
+ priority: data.priority,
+ resolutionDescription: data.resolutionDescription,
+ });
+ return response;
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['/api/sav/tickets'] });
+ queryClient.invalidateQueries({ queryKey: ['/api/sav/stats'] });
+ if (selectedTicket) {
+ queryClient.invalidateQueries({ queryKey: [`/api/sav/tickets/${selectedTicket.id}`] });
+ }
+ setTempStatus("");
+ setTempPriority("");
+ toast({
+ title: "Ticket mis à jour",
+ description: "Le statut du ticket a été modifié avec succès.",
+ });
+ },
+ onError: (error: any) => {
+ toast({
+ title: "Erreur",
+ description: error?.message || "Impossible de modifier le ticket.",
+ variant: "destructive",
+ });
+ },
+ });
+
// Delete ticket mutation
const deleteTicketMutation = useMutation({
mutationFn: async (ticketId: number) => {
@@ -263,7 +295,7 @@ export default function SavTickets() {
problemDescription: formData.problemDescription,
priority: formData.priority as "faible" | "normale" | "haute" | "critique",
status: "nouveau" as const,
- createdBy: 1, // Will be set by the backend from session
+ createdBy: "1", // Will be set by the backend from session
clientName: formData.clientName || undefined,
clientPhone: formData.clientPhone || undefined,
};
@@ -285,6 +317,20 @@ export default function SavTickets() {
staleTime: 0, // Toujours récupérer les derniers commentaires
});
+ // Function to check if ticket has recent comments (last 24h)
+ const hasRecentComments = (ticket: SavTicketWithRelations) => {
+ if (!ticket.history || ticket.history.length === 0) return false;
+
+ const oneDayAgo = new Date();
+ oneDayAgo.setDate(oneDayAgo.getDate() - 1);
+
+ return ticket.history.some(entry =>
+ entry.action === 'comment' &&
+ entry.createdAt &&
+ new Date(entry.createdAt) > oneDayAgo
+ );
+ };
+
// Handle editing ticket
const handleEditTicket = (ticket: SavTicketWithRelations) => {
setSelectedTicket(ticket);
@@ -370,160 +416,200 @@ export default function SavTickets() {
-
- {/* Informations produit */}
-
-
Informations produit
-
-
-
- setFormData({...formData, productGencode: e.target.value})}
- placeholder="Code-barres du produit"
- />
-
-
-
-
- setFormData({...formData, productReference: e.target.value})}
- placeholder="Référence du produit"
- />
-
-
-
-
- setFormData({...formData, productDesignation: e.target.value})}
- placeholder="Nom/désignation du produit"
- />
-
-
-
-
-
-
-
- {availableGroups.length > 1 && (
-
-
-
-
- )}
-
- {availableGroups.length === 1 && (
-
-
-
-
-
{availableGroups[0].name}
+
+ {/* Section Informations Produit */}
+
+
+
+
+ Informations Produit
+
+
+ Détails du produit concerné par le SAV
+
+
+
+
- )}
-
- {availableGroups.length === 0 && (
+
-
-
- Aucun magasin assigné. Contactez un administrateur.
-
+
+
setFormData({...formData, productDesignation: e.target.value})}
+ placeholder="Nom/désignation du produit"
+ />
- )}
-
+
+
+
+
+
+
+
+ {availableGroups.length > 1 && (
+
+
+
+
+ )}
+
+
+ {availableGroups.length === 1 && (
+
+
+
+
+ {availableGroups[0].name}
+
+
+ )}
+
+ {availableGroups.length === 0 && (
+
+
+
+ Aucun magasin assigné. Contactez un administrateur.
+
+
+ )}
+
+
- {/* Informations problème et client */}
-
-
Problème et client
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- setFormData({...formData, clientName: e.target.value})}
- placeholder="Nom du client"
- />
-
-
-
-
- setFormData({...formData, clientPhone: e.target.value})}
- placeholder="Numéro de téléphone"
- />
-
-
+ {/* Section Informations Client */}
+
+
+
+
+ Informations Client
+
+
+ Informations de contact du client (optionnel)
+
+
+
+
+
+
+
+ {/* Section Problème et Priorité */}
+
+
+
+
+ Problème et Priorité
+
+
+ Description du problème rencontré
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -719,9 +805,15 @@ export default function SavTickets() {
-
+
{ticket.ticketNumber}
+ {hasRecentComments(ticket) && (
+
+
+ Nouveau
+
+ )}
|
@@ -822,10 +914,15 @@ export default function SavTickets() {
{/* Colonne de gauche - Détails et Actions */}
- {/* Product Info */}
-
- Informations produit
-
+ {/* Section Informations Produit */}
+
+
+
+
+ Informations Produit
+
+
+
Code-barres:
{selectedTicket.productGencode}
@@ -838,35 +935,19 @@ export default function SavTickets() {
Désignation:
{selectedTicket.productDesignation}
-
-
+
+
- {/* Problem Info */}
-
- Problème
-
-
- Type:
- {selectedTicket.problemType}
-
-
- Priorité:
-
- {priorityConfig[selectedTicket.priority as keyof typeof priorityConfig]?.label}
-
-
-
- Description:
- {selectedTicket.problemDescription}
-
-
-
-
- {/* Client Info */}
+ {/* Section Informations Client */}
{(selectedTicket.clientName || selectedTicket.clientPhone) && (
-
- Client
-
+
+
+
+
+ Informations Client
+
+
+
Nom:
{selectedTicket.clientName || "Non renseigné"}
@@ -875,14 +956,47 @@ export default function SavTickets() {
Téléphone:
{selectedTicket.clientPhone || "Non renseigné"}
-
-
+
+
)}
- {/* Ticket Info */}
-
- Informations ticket
-
+ {/* Section Problème */}
+
+
+
+
+ Problème
+
+
+
+
+
+ Type:
+ {selectedTicket.problemType}
+
+
+ Priorité:
+
+ {priorityConfig[selectedTicket.priority as keyof typeof priorityConfig]?.label}
+
+
+
+
+ Description:
+ {selectedTicket.problemDescription}
+
+
+
+
+ {/* Section Informations Ticket */}
+
+
+
+
+ Informations Ticket
+
+
+
Statut:
@@ -901,8 +1015,8 @@ export default function SavTickets() {
Créé le:
{safeFormat(selectedTicket.createdAt, 'dd/MM/yyyy HH:mm')}
-
-
+
+
{/* Actions rapides */}
{canModify && (
@@ -911,11 +1025,11 @@ export default function SavTickets() {
- |