mirror of
https://github.com/dat515-2025/Group-8.git
synced 2026-03-22 06:57:47 +01:00
131 lines
4.0 KiB
TypeScript
131 lines
4.0 KiB
TypeScript
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,
|
|
};
|
|
}; |