From c2edd36ccc1b257a10806f265b029d202b426862 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Mon, 8 Sep 2025 20:46:12 +0000 Subject: [PATCH] Add a tabbed interface to organize and filter financial records Integrates a tabbed navigation system into the Avoirs page, allowing users to easily switch between "pending" and "completed" financial records, with enhanced filtering and search capabilities. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9fcf4b21-eb0c-4e53-a567-e2ce4a6ad869 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/9fcf4b21-eb0c-4e53-a567-e2ce4a6ad869/7eY9Hl8 --- client/src/pages/Avoirs.tsx | 682 +++++++++++++++++++++++++++-- client/src/pages/Avoirs_backup.tsx | 1 + 2 files changed, 646 insertions(+), 37 deletions(-) create mode 100644 client/src/pages/Avoirs_backup.tsx diff --git a/client/src/pages/Avoirs.tsx b/client/src/pages/Avoirs.tsx index 9516c49..8871368 100644 --- a/client/src/pages/Avoirs.tsx +++ b/client/src/pages/Avoirs.tsx @@ -1,11 +1,12 @@ import { useState, useEffect } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; -import { Plus, Search, FileText, CheckCircle, AlertCircle, Clock, Edit, Trash2, UserCheck, Send, Upload, XCircle, MessageSquare } from "lucide-react"; +import { Plus, Search, FileText, CheckCircle, AlertCircle, Clock, Edit, Trash2, UserCheck, Send, Upload, XCircle, MessageSquare, Settings } from "lucide-react"; import { useStore } from "@/components/Layout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from "@/components/ui/dialog"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { Label } from "@/components/ui/label"; @@ -108,6 +109,7 @@ type AvoirUpdateData = AvoirFormData & { }; export default function Avoirs() { + const [activeTab, setActiveTab] = useState("pending"); const [searchTerm, setSearchTerm] = useState(""); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); @@ -872,45 +874,364 @@ export default function Avoirs() { } }; + // Séparer les avoirs par statut + const pendingAvoirs = avoirs.filter(avoir => avoir.status !== 'Reçu'); + const completedAvoirs = avoirs.filter(avoir => avoir.status === 'Reçu'); + + // Filtrage par recherche + const filterAvoirs = (avoirsList: Avoir[]) => { + return avoirsList.filter((avoir) => { + const searchLower = searchTerm.toLowerCase(); + return ( + avoir.supplier?.name?.toLowerCase().includes(searchLower) || + avoir.invoiceReference?.toLowerCase().includes(searchLower) || + avoir.comment?.toLowerCase().includes(searchLower) + ); + }); + }; + + const filteredPendingAvoirs = filterAvoirs(pendingAvoirs); + const filteredCompletedAvoirs = filterAvoirs(completedAvoirs); + + const canEditDelete = ['admin', 'directeur'].includes((user as any)?.role); + + // Fonction pour rendre le tableau d'avoirs + const renderAvoirTable = (avoirsList: Avoir[]) => { + if (isLoading) { + return ( +
+ {searchTerm ? "Aucun avoir ne correspond à votre recherche." : "Aucun avoir dans cette catégorie."} +
+| + Fournisseur + | ++ Statut + | ++ Référence + | ++ Magasin + | ++ Montant + | ++ Créé le + | ++ Vérification + | ++ Actions + | +
|---|---|---|---|---|---|---|---|
| + {avoir.supplier?.name || 'Fournisseur non défini'} + | ++ + | ++ #{avoir.invoiceReference || 'Sans référence'} + | +
+
+
+ {avoir.group?.name || 'Magasin non défini'}
+
+ |
+
+
+ {avoir.amount !== null && avoir.amount !== undefined ? `${Number(avoir.amount).toFixed(2)} €` : 'Non spécifié'}
+ {avoir.commercialProcessed && (
+
+ |
+ + {format(new Date(avoir.createdAt), 'dd/MM/yyyy HH:mm', { locale: fr })} + | +
+ {(avoirVerificationResults[avoir.id]?.exists === true || avoir.nocodbVerified) ? (
+
+
+ ) : avoir.invoiceReference && avoir.invoiceReference.trim() !== '' ? (
+
+ {verifyingAvoirs.has(avoir.id) ? (
+
+ ) : (
+
+ )}
+
+ ) : (
+ Sans réf.
+ )}
+ |
+
+
+ {/* Upload pour avoirs "Reçu" */}
+ {avoir?.status === 'Reçu' && (
+
+ )}
+
+ {/* Bouton Valider */}
+ {avoirVerificationResults[avoir.id]?.exists === true && !avoir.nocodbVerified && (
+
+ )}
+
+ {/* Bouton Dévalider */}
+ {avoir.nocodbVerified && canEditDelete && (
+
+ )}
+
+ {/* Bouton Commentaire */}
+ {avoir.comment && avoir.comment.trim() !== '' && (
+
+ )}
+
+ {canEditDelete && (
+ <>
+
+
+ >
+ )}
+ {!canEditDelete && avoir?.status !== 'Reçu' && (
+ Lecture seule
+ )}
+
+ |
+
- Gestion des demandes d'avoirs et de remboursements -
-