217 lines
5.5 KiB
TypeScript
217 lines
5.5 KiB
TypeScript
"use client";
|
|
|
|
import type {
|
|
BankingData,
|
|
Account,
|
|
Transaction,
|
|
Folder,
|
|
Category,
|
|
} from "./types";
|
|
import { defaultCategories, defaultRootFolder } from "./defaults";
|
|
|
|
const STORAGE_KEY = "banking-app-data";
|
|
|
|
// Convertir les CategoryDefinition en Category pour le localStorage
|
|
function buildCategoriesFromDefaults(): Category[] {
|
|
const slugToId = new Map<string, string>();
|
|
const categories: Category[] = [];
|
|
|
|
// D'abord les parents
|
|
const parents = defaultCategories.filter((c) => c.parentSlug === null);
|
|
parents.forEach((cat, index) => {
|
|
const id = `cat-${index + 1}`;
|
|
slugToId.set(cat.slug, id);
|
|
categories.push({
|
|
id,
|
|
name: cat.name,
|
|
color: cat.color,
|
|
icon: cat.icon,
|
|
keywords: cat.keywords,
|
|
parentId: null,
|
|
});
|
|
});
|
|
|
|
// Puis les enfants
|
|
const children = defaultCategories.filter((c) => c.parentSlug !== null);
|
|
children.forEach((cat, index) => {
|
|
const id = `cat-${parents.length + index + 1}`;
|
|
slugToId.set(cat.slug, id);
|
|
categories.push({
|
|
id,
|
|
name: cat.name,
|
|
color: cat.color,
|
|
icon: cat.icon,
|
|
keywords: cat.keywords,
|
|
parentId: cat.parentSlug ? slugToId.get(cat.parentSlug) || null : null,
|
|
});
|
|
});
|
|
|
|
return categories;
|
|
}
|
|
|
|
const defaultData: BankingData = {
|
|
accounts: [],
|
|
transactions: [],
|
|
folders: [defaultRootFolder],
|
|
categories: buildCategoriesFromDefaults(),
|
|
};
|
|
|
|
export function loadData(): BankingData {
|
|
if (typeof window === "undefined") return defaultData;
|
|
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
if (!stored) {
|
|
saveData(defaultData);
|
|
return defaultData;
|
|
}
|
|
|
|
try {
|
|
return JSON.parse(stored);
|
|
} catch {
|
|
return defaultData;
|
|
}
|
|
}
|
|
|
|
export function saveData(data: BankingData): void {
|
|
if (typeof window === "undefined") return;
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
}
|
|
|
|
export function addAccount(account: Account): BankingData {
|
|
const data = loadData();
|
|
data.accounts.push(account);
|
|
saveData(data);
|
|
return data;
|
|
}
|
|
|
|
export function updateAccount(account: Account): BankingData {
|
|
const data = loadData();
|
|
const index = data.accounts.findIndex((a) => a.id === account.id);
|
|
if (index !== -1) {
|
|
data.accounts[index] = account;
|
|
saveData(data);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
export function deleteAccount(accountId: string): BankingData {
|
|
const data = loadData();
|
|
data.accounts = data.accounts.filter((a) => a.id !== accountId);
|
|
data.transactions = data.transactions.filter(
|
|
(t) => t.accountId !== accountId,
|
|
);
|
|
saveData(data);
|
|
return data;
|
|
}
|
|
|
|
export function addTransactions(transactions: Transaction[]): BankingData {
|
|
const data = loadData();
|
|
|
|
// Filter out duplicates based on fitId
|
|
const existingFitIds = new Set(
|
|
data.transactions.map((t) => `${t.accountId}-${t.fitId}`),
|
|
);
|
|
const newTransactions = transactions.filter(
|
|
(t) => !existingFitIds.has(`${t.accountId}-${t.fitId}`),
|
|
);
|
|
|
|
data.transactions.push(...newTransactions);
|
|
saveData(data);
|
|
return data;
|
|
}
|
|
|
|
export function updateTransaction(transaction: Transaction): BankingData {
|
|
const data = loadData();
|
|
const index = data.transactions.findIndex((t) => t.id === transaction.id);
|
|
if (index !== -1) {
|
|
data.transactions[index] = transaction;
|
|
saveData(data);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
export function addFolder(folder: Folder): BankingData {
|
|
const data = loadData();
|
|
data.folders.push(folder);
|
|
saveData(data);
|
|
return data;
|
|
}
|
|
|
|
export function updateFolder(folder: Folder): BankingData {
|
|
const data = loadData();
|
|
const index = data.folders.findIndex((f) => f.id === folder.id);
|
|
if (index !== -1) {
|
|
data.folders[index] = folder;
|
|
saveData(data);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
export function deleteFolder(folderId: string): BankingData {
|
|
const data = loadData();
|
|
// Move accounts to root
|
|
data.accounts = data.accounts.map((a) =>
|
|
a.folderId === folderId ? { ...a, folderId: "folder-root" } : a,
|
|
);
|
|
// Move subfolders to parent
|
|
const folder = data.folders.find((f) => f.id === folderId);
|
|
if (folder) {
|
|
data.folders = data.folders.map((f) =>
|
|
f.parentId === folderId ? { ...f, parentId: folder.parentId } : f,
|
|
);
|
|
}
|
|
data.folders = data.folders.filter((f) => f.id !== folderId);
|
|
saveData(data);
|
|
return data;
|
|
}
|
|
|
|
export function addCategory(category: Category): BankingData {
|
|
const data = loadData();
|
|
data.categories.push(category);
|
|
saveData(data);
|
|
return data;
|
|
}
|
|
|
|
export function updateCategory(category: Category): BankingData {
|
|
const data = loadData();
|
|
const index = data.categories.findIndex((c) => c.id === category.id);
|
|
if (index !== -1) {
|
|
data.categories[index] = category;
|
|
saveData(data);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
export function deleteCategory(categoryId: string): BankingData {
|
|
const data = loadData();
|
|
data.categories = data.categories.filter((c) => c.id !== categoryId);
|
|
// Remove category from transactions
|
|
data.transactions = data.transactions.map((t) =>
|
|
t.categoryId === categoryId ? { ...t, categoryId: null } : t,
|
|
);
|
|
saveData(data);
|
|
return data;
|
|
}
|
|
|
|
// Auto-categorize a transaction based on keywords
|
|
export function autoCategorize(
|
|
description: string,
|
|
categories: Category[],
|
|
): string | null {
|
|
const lowerDesc = description.toLowerCase();
|
|
|
|
for (const category of categories) {
|
|
for (const keyword of category.keywords) {
|
|
if (lowerDesc.includes(keyword.toLowerCase())) {
|
|
return category.id;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function generateId(): string {
|
|
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
}
|