import React, { useState, useEffect } from 'react';
import axios from 'axios';
import numberToWords from '../utils/numberToWords';
function Expenses() {
const [amount, setAmount] = useState('');
const [category, setCategory] = useState('');
const [date, setDate] = useState('');
const [purpose, setPurpose] = useState('');
const [location, setLocation] = useState('');
const [initialBudget, setInitialBudget] = useState(null);
const [newBudget, setNewBudget] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [allocations, setAllocations] = useState({
essentials: 0,
savings: 0,
selfInvestment: 0,
charity: 0,
emergency: 0,
});
const [expenses, setExpenses] = useState([]);
const [error, setError] = useState('');
const [isDarkMode, setIsDarkMode] = useState(false);
const token = localStorage.getItem('token');
const categories = [
'Tiêu dùng thiết yếu',
'Tiết kiệm bắt buộc',
'Đầu tư bản thân',
'Từ thiện',
'Dự phòng linh hoạt',
];
useEffect(() => {
const fetchData = async () => {
try {
const [budgetRes, expensesRes, allocationsRes] = await Promise.all([
axios.get('https://backend-rockefeller-finance.onrender.com/api/initial-budget', {
headers: { Authorization: `Bearer ${token}` },
}),
axios.get('https://backend-rockefeller-finance.onrender.com/api/expenses', {
headers: { Authorization: `Bearer ${token}` },
}),
axios.get('https://backend-rockefeller-finance.onrender.com/api/allocations', {
headers: { Authorization: `Bearer ${token}` },
}),
]);
setInitialBudget(budgetRes.data.initialBudget);
setExpenses(expensesRes.data);
setAllocations(allocationsRes.data);
} catch (err) {
setError(err.response?.data?.error || 'Lỗi lấy dữ liệu');
}
};
if (token) fetchData();
}, [token]);
const handleBudgetSubmit = async (e) => {
e.preventDefault();
const parsedBudget = parseFloat(newBudget);
if (parsedBudget <= 0) {
setError('Vui lòng nhập số tiền hợp lệ!');
return;
}
setIsSubmitting(true);
try {
const response = await axios.post(
'https://backend-rockefeller-finance.onrender.com/api/initial-budget',
{ initialBudget: parsedBudget },
{ headers: { Authorization: `Bearer ${token}` } }
);
setInitialBudget(response.data.initialBudget);
setAllocations(response.data.allocations);
setNewBudget('');
setError('');
} catch (err) {
setError(err.response?.data?.error || 'Lỗi lưu ngân sách');
} finally {
setIsSubmitting(false);
}
};
const handleExpenseSubmit = async (e) => {
e.preventDefault();
const parsedAmount = parseFloat(amount);
if (parsedAmount <= 0) {
setError('Vui lòng nhập số tiền hợp lệ!');
return;
}
if (!purpose || !location) {
setError('Vui lòng nhập mục đích và vị trí!');
return;
}
setIsSubmitting(true);
try {
const response = await axios.post(
'https://backend-rockefeller-finance.onrender.com/api/expenses',
{ amount: parsedAmount, category, purpose, location, date: date || new Date().toLocaleDateString('vi-VN') },
{ headers: { Authorization: `Bearer ${token}` } }
);
setExpenses(response.data);
// Cập nhật allocations và initialBudget
const budgetRes = await axios.get('https://backend-rockefeller-finance.onrender.com/api/initial-budget', {
headers: { Authorization: `Bearer ${token}` },
});
const allocRes = await axios.get('https://backend-rockefeller-finance.onrender.com/api/allocations', {
headers: { Authorization: `Bearer ${token}` },
});
setInitialBudget(budgetRes.data.initialBudget);
setAllocations(allocRes.data);
setAmount('');
setCategory('');
setPurpose('');
setLocation('');
setDate('');
setError('');
} catch (err) {
setError(err.response?.data?.error || 'Lỗi thêm chi tiêu');
} finally {
setIsSubmitting(false);
}
};
const handleDeleteExpense = async (index) => {
try {
const response = await axios.delete(
`https://backend-rockefeller-finance.onrender.com/api/expenses/${index}`,
{ headers: { Authorization: `Bearer ${token}` } }
);
setExpenses(response.data);
// Cập nhật initialBudget và allocations
const budgetRes = await axios.get('https://backend-rockefeller-finance.onrender.com/api/initial-budget', {
headers: { Authorization: `Bearer ${token}` },
});
const allocRes = await axios.get('https://backend-rockefeller-finance.onrender.com/api/allocations', {
headers: { Authorization: `Bearer ${token}` },
});
setInitialBudget(budgetRes.data.initialBudget);
setAllocations(allocRes.data);
} catch (err) {
setError(err.response?.data?.error || 'Lỗi xóa chi tiêu');
}
};
const toggleDarkMode = () => {
setIsDarkMode(!isDarkMode);
};
const formatVND = (value) => {
return new Intl.NumberFormat('vi-VN', { style: 'currency', currency: 'VND' }).format(value);
};
const totalAmount =
parseFloat(allocations.essentials) +
parseFloat(allocations.savings) +
parseFloat(allocations.selfInvestment) +
parseFloat(allocations.charity) +
parseFloat(allocations.emergency);
return (
{error &&
) : (
<>
{totalAmount > 0 && (
)}
>
)}
);
}
export default Expenses;
Quản lý chi tiêu
{error}
} {initialBudget === null || initialBudget === 0 ? (Nhập ngân sách ban đầu
Nạp thêm ngân sách
Số dư ngân sách
{formatVND(initialBudget)}
Thêm chi tiêu
Lịch sử chi tiêu
Ngày | Danh mục | Số tiền (VND) | Mục đích | Vị trí | Hành động |
---|---|---|---|---|---|
{expense.date} | {expense.category} | {formatVND(expense.amount)} | {expense.purpose} | {expense.location} |
Phân bổ ngân sách
Tiêu dùng thiết yếu (50%)
{formatVND(allocations.essentials)}
Tiết kiệm bắt buộc (20%)
{formatVND(allocations.savings)}
Đầu tư bản thân (15%)
{formatVND(allocations.selfInvestment)}
Từ thiện (5%)
{formatVND(allocations.charity)}
Dự phòng linh hoạt (10%)
{formatVND(allocations.emergency)}
Tổng số tiền phân bổ
{formatVND(totalAmount)}
{numberToWords(totalAmount)}