"use client" import { useState, useMemo } from "react" import { Sidebar } from "@/components/dashboard/sidebar" import { useBankingData } from "@/lib/hooks" import { Button } from "@/components/ui/button" import { Card, CardContent } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Badge } from "@/components/ui/badge" import { Checkbox } from "@/components/ui/checkbox" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator, } from "@/components/ui/dropdown-menu" import { OFXImportDialog } from "@/components/import/ofx-import-dialog" import { CategoryIcon } from "@/components/ui/category-icon" import { Search, CheckCircle2, Circle, MoreVertical, Tags, Upload, RefreshCw, ArrowUpDown, Check } from "lucide-react" import { cn } from "@/lib/utils" type SortField = "date" | "amount" | "description" type SortOrder = "asc" | "desc" export default function TransactionsPage() { const { data, isLoading, refresh, update } = useBankingData() const [searchQuery, setSearchQuery] = useState("") const [selectedAccount, setSelectedAccount] = useState("all") const [selectedCategory, setSelectedCategory] = useState("all") const [showReconciled, setShowReconciled] = useState("all") const [sortField, setSortField] = useState("date") const [sortOrder, setSortOrder] = useState("desc") const [selectedTransactions, setSelectedTransactions] = useState>(new Set()) const filteredTransactions = useMemo(() => { if (!data) return [] let transactions = [...data.transactions] // Filter by search if (searchQuery) { const query = searchQuery.toLowerCase() transactions = transactions.filter( (t) => t.description.toLowerCase().includes(query) || t.memo?.toLowerCase().includes(query), ) } // Filter by account if (selectedAccount !== "all") { transactions = transactions.filter((t) => t.accountId === selectedAccount) } // Filter by category if (selectedCategory !== "all") { if (selectedCategory === "uncategorized") { transactions = transactions.filter((t) => !t.categoryId) } else { transactions = transactions.filter((t) => t.categoryId === selectedCategory) } } // Filter by reconciliation status if (showReconciled !== "all") { const isReconciled = showReconciled === "reconciled" transactions = transactions.filter((t) => t.isReconciled === isReconciled) } // Sort transactions.sort((a, b) => { let comparison = 0 switch (sortField) { case "date": comparison = new Date(a.date).getTime() - new Date(b.date).getTime() break case "amount": comparison = a.amount - b.amount break case "description": comparison = a.description.localeCompare(b.description) break } return sortOrder === "asc" ? comparison : -comparison }) return transactions }, [data, searchQuery, selectedAccount, selectedCategory, showReconciled, sortField, sortOrder]) if (isLoading || !data) { return (
) } const formatCurrency = (amount: number) => { return new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR", }).format(amount) } const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleDateString("fr-FR", { day: "2-digit", month: "short", year: "numeric", }) } const toggleReconciled = (transactionId: string) => { const updatedTransactions = data.transactions.map((t) => t.id === transactionId ? { ...t, isReconciled: !t.isReconciled } : t, ) update({ ...data, transactions: updatedTransactions }) } const setCategory = (transactionId: string, categoryId: string | null) => { const updatedTransactions = data.transactions.map((t) => (t.id === transactionId ? { ...t, categoryId } : t)) update({ ...data, transactions: updatedTransactions }) } const bulkReconcile = (reconciled: boolean) => { const updatedTransactions = data.transactions.map((t) => selectedTransactions.has(t.id) ? { ...t, isReconciled: reconciled } : t, ) update({ ...data, transactions: updatedTransactions }) setSelectedTransactions(new Set()) } const bulkSetCategory = (categoryId: string | null) => { const updatedTransactions = data.transactions.map((t) => selectedTransactions.has(t.id) ? { ...t, categoryId } : t, ) update({ ...data, transactions: updatedTransactions }) setSelectedTransactions(new Set()) } const toggleSelectAll = () => { if (selectedTransactions.size === filteredTransactions.length) { setSelectedTransactions(new Set()) } else { setSelectedTransactions(new Set(filteredTransactions.map((t) => t.id))) } } const toggleSelectTransaction = (id: string) => { const newSelected = new Set(selectedTransactions) if (newSelected.has(id)) { newSelected.delete(id) } else { newSelected.add(id) } setSelectedTransactions(newSelected) } const getCategory = (categoryId: string | null) => { if (!categoryId) return null return data.categories.find((c) => c.id === categoryId) } const getAccount = (accountId: string) => { return data.accounts.find((a) => a.id === accountId) } return (

Transactions

{filteredTransactions.length} transaction{filteredTransactions.length > 1 ? "s" : ""}

{/* Filters */}
setSearchQuery(e.target.value)} className="pl-9" />
{/* Bulk actions */} {selectedTransactions.size > 0 && (
{selectedTransactions.size} sélectionnée{selectedTransactions.size > 1 ? "s" : ""} bulkSetCategory(null)}>Aucune catégorie {data.categories.map((cat) => ( bulkSetCategory(cat.id)}> {cat.name} ))}
)} {/* Transactions list */} {filteredTransactions.length === 0 ? (

Aucune transaction trouvée

) : (
{filteredTransactions.map((transaction) => { const category = getCategory(transaction.categoryId) const account = getAccount(transaction.accountId) return ( ) })}
0 } onCheckedChange={toggleSelectAll} /> Compte Catégorie Pointé
toggleSelectTransaction(transaction.id)} /> {formatDate(transaction.date)}

{transaction.description}

{transaction.memo && (

{transaction.memo}

)}
{account?.name || "-"} setCategory(transaction.id, null)}> Aucune catégorie {data.categories.map((cat) => ( setCategory(transaction.id, cat.id)}> {cat.name} {transaction.categoryId === cat.id && } ))} = 0 ? "text-emerald-600" : "text-red-600", )} > {transaction.amount >= 0 ? "+" : ""} {formatCurrency(transaction.amount)} toggleReconciled(transaction.id)}> {transaction.isReconciled ? "Dépointer" : "Pointer"}
)}
) }