feat: add duplicate transaction detection and display in transactions page, enhancing user experience with visual indicators for duplicates

This commit is contained in:
Julien Froidefond
2025-12-08 09:50:32 +01:00
parent cb8628ce39
commit ba4d112cb8
6 changed files with 223 additions and 55 deletions

View File

@@ -28,10 +28,12 @@ import {
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
import { Search, X, Filter, Wallet, Calendar } from "lucide-react";
import { Search, X, Filter, Wallet, Calendar, Copy } from "lucide-react";
import { format } from "date-fns";
import { fr } from "date-fns/locale";
import { useIsMobile } from "@/hooks/use-mobile";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import type { Account, Category, Folder, Transaction } from "@/lib/types";
type Period = "1month" | "3months" | "6months" | "12months" | "custom" | "all";
@@ -53,6 +55,8 @@ interface TransactionFiltersProps {
onCustomEndDateChange: (date: Date | undefined) => void;
isCustomDatePickerOpen: boolean;
onCustomDatePickerOpenChange: (open: boolean) => void;
showDuplicates: boolean;
onShowDuplicatesChange: (show: boolean) => void;
accounts: Account[];
folders: Folder[];
categories: Category[];
@@ -77,6 +81,8 @@ export function TransactionFilters({
onCustomEndDateChange,
isCustomDatePickerOpen,
onCustomDatePickerOpenChange,
showDuplicates,
onShowDuplicatesChange,
accounts,
folders,
categories,
@@ -153,6 +159,23 @@ export function TransactionFilters({
</SelectContent>
</Select>
<div className="flex items-center gap-2 px-3 py-2 rounded-md border border-border bg-card">
<Checkbox
id="show-duplicates"
checked={showDuplicates}
onCheckedChange={(checked) =>
onShowDuplicatesChange(checked === true)
}
/>
<Label
htmlFor="show-duplicates"
className="text-sm font-normal cursor-pointer flex items-center gap-2"
>
<Copy className="h-4 w-4 text-muted-foreground" />
Afficher les doublons
</Label>
</div>
{period === "custom" && (
<Popover
open={isCustomDatePickerOpen}
@@ -256,7 +279,7 @@ export function TransactionFilters({
onRemoveCategory={(id) => {
const newCategories = selectedCategories.filter((c) => c !== id);
onCategoriesChange(
newCategories.length > 0 ? newCategories : ["all"],
newCategories.length > 0 ? newCategories : ["all"]
);
}}
onClearCategories={() => onCategoriesChange(["all"])}
@@ -282,7 +305,8 @@ export function TransactionFilters({
(!selectedAccounts.includes("all") ? selectedAccounts.length : 0) +
(!selectedCategories.includes("all") ? selectedCategories.length : 0) +
(showReconciled !== "all" ? 1 : 0) +
(period !== "all" ? 1 : 0);
(period !== "all" ? 1 : 0) +
(showDuplicates ? 1 : 0);
return (
<>
@@ -367,7 +391,7 @@ function ActiveFilters({
const selectedAccs = accounts.filter((a) => selectedAccounts.includes(a.id));
const selectedCats = categories.filter((c) =>
selectedCategories.includes(c.id),
selectedCategories.includes(c.id)
);
const isUncategorized = selectedCategories.includes("uncategorized");