117 lines
3.2 KiB
TypeScript
117 lines
3.2 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useMemo, useCallback } from "react";
|
|
import { useQueryClient } from "@tanstack/react-query";
|
|
import type { Transaction, Category } from "@/lib/types";
|
|
import { updateCategory } from "@/lib/store-db";
|
|
import {
|
|
normalizeDescription,
|
|
suggestKeyword,
|
|
} from "@/components/rules/constants";
|
|
import {
|
|
invalidateAllTransactionQueries,
|
|
invalidateAllCategoryQueries,
|
|
} from "@/lib/cache-utils";
|
|
|
|
interface UseTransactionRulesProps {
|
|
transactionsData: { transactions: Transaction[] } | undefined;
|
|
metadata: {
|
|
categories: Category[];
|
|
} | null;
|
|
}
|
|
|
|
export function useTransactionRules({
|
|
transactionsData,
|
|
metadata,
|
|
}: UseTransactionRulesProps) {
|
|
const queryClient = useQueryClient();
|
|
const [ruleDialogOpen, setRuleDialogOpen] = useState(false);
|
|
const [ruleTransaction, setRuleTransaction] = useState<Transaction | null>(
|
|
null,
|
|
);
|
|
|
|
const handleCreateRule = useCallback((transaction: Transaction) => {
|
|
setRuleTransaction(transaction);
|
|
setRuleDialogOpen(true);
|
|
}, []);
|
|
|
|
const ruleGroup = useMemo(() => {
|
|
if (!ruleTransaction || !transactionsData) return null;
|
|
|
|
const normalizedDesc = normalizeDescription(ruleTransaction.description);
|
|
const similarTransactions = transactionsData.transactions.filter(
|
|
(t) => normalizeDescription(t.description) === normalizedDesc,
|
|
);
|
|
|
|
if (similarTransactions.length === 0) return null;
|
|
|
|
return {
|
|
key: normalizedDesc,
|
|
displayName: ruleTransaction.description,
|
|
transactions: similarTransactions,
|
|
totalAmount: similarTransactions.reduce((sum, t) => sum + t.amount, 0),
|
|
suggestedKeyword: suggestKeyword(
|
|
similarTransactions.map((t) => t.description),
|
|
),
|
|
};
|
|
}, [ruleTransaction, transactionsData]);
|
|
|
|
const handleSaveRule = useCallback(
|
|
async (ruleData: {
|
|
keyword: string;
|
|
categoryId: string;
|
|
applyToExisting: boolean;
|
|
transactionIds: string[];
|
|
}) => {
|
|
if (!metadata) return;
|
|
|
|
// Add keyword to category
|
|
const category = metadata.categories.find(
|
|
(c) => c.id === ruleData.categoryId,
|
|
);
|
|
if (!category) {
|
|
throw new Error("Category not found");
|
|
}
|
|
|
|
// Check if keyword already exists
|
|
const keywordExists = category.keywords.some(
|
|
(k: string) => k.toLowerCase() === ruleData.keyword.toLowerCase(),
|
|
);
|
|
|
|
if (!keywordExists) {
|
|
await updateCategory({
|
|
...category,
|
|
keywords: [...category.keywords, ruleData.keyword],
|
|
});
|
|
}
|
|
|
|
// Apply to existing transactions if requested
|
|
if (ruleData.applyToExisting) {
|
|
await Promise.all(
|
|
ruleData.transactionIds.map((id) =>
|
|
fetch("/api/banking/transactions", {
|
|
method: "PUT",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ id, categoryId: ruleData.categoryId }),
|
|
}),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Invalider toutes les queries liées
|
|
invalidateAllTransactionQueries(queryClient);
|
|
invalidateAllCategoryQueries(queryClient);
|
|
setRuleDialogOpen(false);
|
|
},
|
|
[metadata, queryClient],
|
|
);
|
|
|
|
return {
|
|
ruleDialogOpen,
|
|
setRuleDialogOpen,
|
|
ruleGroup,
|
|
handleCreateRule,
|
|
handleSaveRule,
|
|
};
|
|
}
|