mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-11 17:27:31 +02:00
Fix buttons for adding comments and deleting service tickets
Implement mutations for adding comments and deleting service tickets, and add event handlers for these actions in the SavTickets page. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 31f9bd88-0285-4787-81b3-31ceeea5a08b Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/31f9bd88-0285-4787-81b3-31ceeea5a08b/yN3F32y
This commit is contained in:
1 parent
fb4a4733f1
commit
f58c2ca448
2 files changed
+156
-2
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -59,7 +59,10 @@ export default function SavTickets() {
|
||||
const [showCreateModal, setShowCreateModal] = useState(false);
|
||||
const [showDetailModal, setShowDetailModal] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [showCommentModal, setShowCommentModal] = useState(false);
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [selectedTicket, setSelectedTicket] = useState<SavTicketWithRelations | null>(null);
|
||||
const [newComment, setNewComment] = useState("");
|
||||
const [formData, setFormData] = useState({
|
||||
supplierId: "",
|
||||
groupId: "",
|
||||
@@ -156,6 +159,56 @@ export default function SavTickets() {
|
||||
},
|
||||
});
|
||||
|
||||
// Add comment mutation
|
||||
const addCommentMutation = useMutation({
|
||||
mutationFn: async (data: { ticketId: number; comment: string }) => {
|
||||
const response = await apiRequest(`/api/sav-tickets/${data.ticketId}/comments`, "POST", {
|
||||
comment: data.comment
|
||||
});
|
||||
return response;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['/api/sav/tickets'] });
|
||||
setShowCommentModal(false);
|
||||
setNewComment("");
|
||||
toast({
|
||||
title: "Commentaire ajouté",
|
||||
description: "Le commentaire a été ajouté avec succès.",
|
||||
});
|
||||
},
|
||||
onError: (error: any) => {
|
||||
toast({
|
||||
title: "Erreur",
|
||||
description: error?.message || "Impossible d'ajouter le commentaire.",
|
||||
variant: "destructive",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Delete ticket mutation
|
||||
const deleteTicketMutation = useMutation({
|
||||
mutationFn: async (ticketId: number) => {
|
||||
const response = await apiRequest(`/api/sav-tickets/${ticketId}`, "DELETE");
|
||||
return response;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['/api/sav/tickets'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['/api/sav/stats'] });
|
||||
setShowDeleteModal(false);
|
||||
toast({
|
||||
title: "Ticket supprimé",
|
||||
description: "Le ticket a été supprimé avec succès.",
|
||||
});
|
||||
},
|
||||
onError: (error: any) => {
|
||||
toast({
|
||||
title: "Erreur",
|
||||
description: error?.message || "Impossible de supprimer le ticket.",
|
||||
variant: "destructive",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Check permissions AFTER all hooks are called
|
||||
const canView = ['admin', 'directeur', 'manager', 'employee'].includes(user?.role || '');
|
||||
const canModify = ['admin', 'directeur', 'manager'].includes(user?.role || '');
|
||||
@@ -237,6 +290,19 @@ export default function SavTickets() {
|
||||
setShowEditModal(true);
|
||||
};
|
||||
|
||||
// Handle commenting on ticket
|
||||
const handleCommentTicket = (ticket: SavTicketWithRelations) => {
|
||||
setSelectedTicket(ticket);
|
||||
setNewComment("");
|
||||
setShowCommentModal(true);
|
||||
};
|
||||
|
||||
// Handle deleting ticket
|
||||
const handleDeleteTicket = (ticket: SavTicketWithRelations) => {
|
||||
setSelectedTicket(ticket);
|
||||
setShowDeleteModal(true);
|
||||
};
|
||||
|
||||
// Handle permission check without early return
|
||||
if (!canView) {
|
||||
return (
|
||||
@@ -717,13 +783,13 @@ export default function SavTickets() {
|
||||
<Button variant="ghost" size="sm" onClick={() => handleEditTicket(ticket)}>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Button variant="ghost" size="sm" onClick={() => handleCommentTicket(ticket)}>
|
||||
<MessageCircle className="h-4 w-4" />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{canDelete && (
|
||||
<Button variant="ghost" size="sm" className="text-red-600 hover:text-red-900">
|
||||
<Button variant="ghost" size="sm" className="text-red-600 hover:text-red-900" onClick={() => handleDeleteTicket(ticket)}>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
@@ -971,6 +1037,94 @@ export default function SavTickets() {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
|
||||
{/* Comment Modal */}
|
||||
{selectedTicket && (
|
||||
<Dialog open={showCommentModal} onOpenChange={setShowCommentModal}>
|
||||
<DialogContent className="max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Ajouter un commentaire</DialogTitle>
|
||||
<DialogDescription>
|
||||
Ajouter un commentaire au ticket {selectedTicket.ticketNumber}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="comment">Commentaire</Label>
|
||||
<Textarea
|
||||
id="comment"
|
||||
value={newComment}
|
||||
onChange={(e) => setNewComment(e.target.value)}
|
||||
placeholder="Entrez votre commentaire..."
|
||||
rows={4}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end space-x-2">
|
||||
<Button variant="outline" onClick={() => setShowCommentModal(false)}>
|
||||
Annuler
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!newComment.trim()) {
|
||||
toast({
|
||||
title: "Erreur",
|
||||
description: "Le commentaire ne peut pas être vide.",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
addCommentMutation.mutate({ ticketId: selectedTicket.id, comment: newComment.trim() });
|
||||
}}
|
||||
disabled={addCommentMutation.isPending}
|
||||
>
|
||||
{addCommentMutation.isPending ? "Ajout..." : "Ajouter"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
|
||||
{/* Delete Confirmation Modal */}
|
||||
{selectedTicket && (
|
||||
<Dialog open={showDeleteModal} onOpenChange={setShowDeleteModal}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Confirmer la suppression</DialogTitle>
|
||||
<DialogDescription>
|
||||
Êtes-vous sûr de vouloir supprimer le ticket {selectedTicket.ticketNumber} ? Cette action est irréversible.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
|
||||
<div className="flex">
|
||||
<AlertTriangle className="h-5 w-5 text-red-400 mt-0.5 mr-3" />
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-red-800">Attention</h4>
|
||||
<p className="mt-1 text-sm text-red-700">
|
||||
Toutes les données du ticket seront définitivement supprimées.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end space-x-2">
|
||||
<Button variant="outline" onClick={() => setShowDeleteModal(false)}>
|
||||
Annuler
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => deleteTicketMutation.mutate(selectedTicket.id)}
|
||||
disabled={deleteTicketMutation.isPending}
|
||||
>
|
||||
{deleteTicketMutation.isPending ? "Suppression..." : "Supprimer"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user