refactor(structure): move to 7project dir

This commit is contained in:
2025-10-05 01:30:55 +02:00
parent 291305c2e5
commit d58d553945
111 changed files with 6638 additions and 36 deletions

View File

@@ -0,0 +1,131 @@
import { useState, useEffect } from 'react';
import { Transaction, Category, TransactionSummary } from '../types';
import { apiClient } from '../utils/api';
import { API_ENDPOINTS } from '../config/api';
export const useTransactions = () => {
const [transactions, setTransactions] = useState<Transaction[]>([]);
const [categories, setCategories] = useState<Category[]>([]);
const [loading, setLoading] = useState(false);
const [summary, setSummary] = useState<TransactionSummary>({
totalIncome: 0,
totalExpenses: 0,
balance: 0,
categoryBreakdown: [],
});
const fetchTransactions = async () => {
setLoading(true);
try {
const data = await apiClient.get<Transaction[]>(API_ENDPOINTS.transactions.list);
setTransactions(data);
calculateSummary(data);
} catch (error) {
console.error('Failed to fetch transactions:', error);
} finally {
setLoading(false);
}
};
const fetchCategories = async () => {
try {
const data = await apiClient.get<Category[]>(API_ENDPOINTS.categories.list);
setCategories(data);
} catch (error) {
console.error('Failed to fetch categories:', error);
}
};
const createTransaction = async (transaction: Omit<Transaction, 'id' | 'user_id' | 'created_at' | 'updated_at'>) => {
try {
const newTransaction = await apiClient.post<Transaction>(
API_ENDPOINTS.transactions.create,
transaction
);
setTransactions(prev => [newTransaction, ...prev]);
calculateSummary([newTransaction, ...transactions]);
return newTransaction;
} catch (error) {
throw new Error('Failed to create transaction');
}
};
const updateTransaction = async (id: string, updates: Partial<Transaction>) => {
try {
const updatedTransaction = await apiClient.put<Transaction>(
API_ENDPOINTS.transactions.update(id),
updates
);
setTransactions(prev =>
prev.map(t => (t.id === id ? updatedTransaction : t))
);
const newTransactions = transactions.map(t => (t.id === id ? updatedTransaction : t));
calculateSummary(newTransactions);
return updatedTransaction;
} catch (error) {
throw new Error('Failed to update transaction');
}
};
const deleteTransaction = async (id: string) => {
try {
await apiClient.delete(API_ENDPOINTS.transactions.delete(id));
setTransactions(prev => prev.filter(t => t.id !== id));
const newTransactions = transactions.filter(t => t.id !== id);
calculateSummary(newTransactions);
} catch (error) {
throw new Error('Failed to delete transaction');
}
};
const calculateSummary = (transactionList: Transaction[]) => {
const totalIncome = transactionList
.filter(t => t.type === 'income')
.reduce((sum, t) => sum + t.amount, 0);
const totalExpenses = transactionList
.filter(t => t.type === 'expense')
.reduce((sum, t) => sum + t.amount, 0);
const balance = totalIncome - totalExpenses;
const categoryTotals = transactionList.reduce((acc, transaction) => {
const categoryName = transaction.category?.name || 'Uncategorized';
acc[categoryName] = (acc[categoryName] || 0) + Math.abs(transaction.amount);
return acc;
}, {} as Record<string, number>);
const totalAmount = Object.values(categoryTotals).reduce((sum, amount) => sum + amount, 0);
const categoryBreakdown = Object.entries(categoryTotals)
.map(([category, amount]) => ({
category,
amount,
percentage: totalAmount > 0 ? (amount / totalAmount) * 100 : 0,
}))
.sort((a, b) => b.amount - a.amount);
setSummary({
totalIncome,
totalExpenses,
balance,
categoryBreakdown,
});
};
useEffect(() => {
fetchTransactions();
fetchCategories();
}, []);
return {
transactions,
categories,
loading,
summary,
createTransaction,
updateTransaction,
deleteTransaction,
refreshTransactions: fetchTransactions,
refreshCategories: fetchCategories,
};
};