From 1281156f05cfd5eed0a0e8d616c9c9b7c81d1edc Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 16 Mar 2025 08:26:17 +0000 Subject: [PATCH] Fix budget display issues The budget was not being displayed correctly in the spending and analytics screens, as well as the weekly and monthly views on the home screen. This commit addresses these issues. --- src/components/BudgetTabContent.tsx | 30 ++++++++-- src/contexts/budget/budgetUtils.ts | 46 ++++++++++++++-- .../budget/hooks/useExtendedBudgetUpdate.ts | 55 +++++++++---------- src/hooks/useTransactions.ts | 42 ++++++++++++-- 4 files changed, 127 insertions(+), 46 deletions(-) diff --git a/src/components/BudgetTabContent.tsx b/src/components/BudgetTabContent.tsx index 6f41c42..43d19af 100644 --- a/src/components/BudgetTabContent.tsx +++ b/src/components/BudgetTabContent.tsx @@ -1,3 +1,4 @@ + import React, { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Check, ChevronDown, ChevronUp, Calculator } from 'lucide-react'; @@ -6,17 +7,20 @@ import BudgetProgress from './BudgetProgress'; import CategoryBudgetInputs from './CategoryBudgetInputs'; import { toast } from '@/components/ui/use-toast'; import { EXPENSE_CATEGORIES } from '@/constants/categoryIcons'; + interface BudgetData { targetAmount: number; spentAmount: number; remainingAmount: number; } + interface BudgetTabContentProps { data: BudgetData; formatCurrency: (amount: number) => string; calculatePercentage: (spent: number, target: number) => number; onSaveBudget: (amount: number, categoryBudgets?: Record) => void; } + const BudgetTabContent: React.FC = ({ data, formatCurrency, @@ -34,12 +38,15 @@ const BudgetTabContent: React.FC = ({ acc[category] = defaultCategoryAmount; return acc; }, {} as Record); + const [categoryBudgets, setCategoryBudgets] = useState>(initialCategoryBudgets); + const handleInputChange = (value: string) => { // Remove all non-numeric characters const numericValue = value.replace(/[^0-9]/g, ''); setBudgetInput(numericValue); }; + const handleCategoryInputChange = (value: string, category: string) => { // Remove all non-numeric characters const numericValue = value.replace(/[^0-9]/g, ''); @@ -48,6 +55,7 @@ const BudgetTabContent: React.FC = ({ [category]: parseInt(numericValue) || 0 })); }; + const handleSave = () => { // Calculate total from all categories const totalAmount = Object.values(categoryBudgets).reduce((sum, value) => sum + value, 0); @@ -65,8 +73,15 @@ const BudgetTabContent: React.FC = ({ const formatWithCommas = (amount: string) => { return amount.replace(/\B(?=(\d{3})+(?!\d))/g, ','); }; - return
- + + return ( +
+
남은 예산 @@ -81,7 +96,10 @@ const BudgetTabContent: React.FC = ({ - +
@@ -102,6 +120,8 @@ const BudgetTabContent: React.FC = ({
-
; +
+ ); }; -export default BudgetTabContent; \ No newline at end of file + +export default BudgetTabContent; diff --git a/src/contexts/budget/budgetUtils.ts b/src/contexts/budget/budgetUtils.ts index 69fa799..e1a4bab 100644 --- a/src/contexts/budget/budgetUtils.ts +++ b/src/contexts/budget/budgetUtils.ts @@ -67,14 +67,48 @@ export const calculateUpdatedBudgetData = ( remainingAmount: Math.max(0, amount - prevBudgetData.monthly.spentAmount) } }; - } else { - const remainingAmount = Math.max(0, amount - prevBudgetData[type].spentAmount); + } else if (type === 'weekly') { + // 주간 예산이 설정되면 월간 예산도 자동 계산 + const monthlyAmount = Math.round(amount * 4.3); + const dailyAmount = Math.round(amount / 7); + return { - ...prevBudgetData, - [type]: { - ...prevBudgetData[type], + daily: { + targetAmount: dailyAmount, + spentAmount: prevBudgetData.daily.spentAmount, + remainingAmount: Math.max(0, dailyAmount - prevBudgetData.daily.spentAmount) + }, + weekly: { targetAmount: amount, - remainingAmount: remainingAmount + spentAmount: prevBudgetData.weekly.spentAmount, + remainingAmount: Math.max(0, amount - prevBudgetData.weekly.spentAmount) + }, + monthly: { + targetAmount: monthlyAmount, + spentAmount: prevBudgetData.monthly.spentAmount, + remainingAmount: Math.max(0, monthlyAmount - prevBudgetData.monthly.spentAmount) + } + }; + } else { + // 일일 예산이 설정되면 주간/월간 예산도 자동 계산 + const weeklyAmount = Math.round(amount * 7); + const monthlyAmount = Math.round(amount * 30); + + return { + daily: { + targetAmount: amount, + spentAmount: prevBudgetData.daily.spentAmount, + remainingAmount: Math.max(0, amount - prevBudgetData.daily.spentAmount) + }, + weekly: { + targetAmount: weeklyAmount, + spentAmount: prevBudgetData.weekly.spentAmount, + remainingAmount: Math.max(0, weeklyAmount - prevBudgetData.weekly.spentAmount) + }, + monthly: { + targetAmount: monthlyAmount, + spentAmount: prevBudgetData.monthly.spentAmount, + remainingAmount: Math.max(0, monthlyAmount - prevBudgetData.monthly.spentAmount) } }; } diff --git a/src/contexts/budget/hooks/useExtendedBudgetUpdate.ts b/src/contexts/budget/hooks/useExtendedBudgetUpdate.ts index 065a83e..089a130 100644 --- a/src/contexts/budget/hooks/useExtendedBudgetUpdate.ts +++ b/src/contexts/budget/hooks/useExtendedBudgetUpdate.ts @@ -1,47 +1,42 @@ import { useCallback } from 'react'; import { BudgetData, BudgetPeriod } from '../types'; +import { calculateUpdatedBudgetData } from '../budgetUtils'; -/** - * 확장된 예산 업데이트 기능을 제공하는 훅 - */ +// 확장된 예산 업데이트 로직을 제공하는 훅 export const useExtendedBudgetUpdate = ( budgetData: BudgetData, categoryBudgets: Record, - handleBudgetGoalUpdate: (type: BudgetPeriod, amount: number, newCategoryBudgets?: Record) => void, - updateCategoryBudgets: (newCategoryBudgets: Record) => void + handleBudgetGoalUpdate: (type: BudgetPeriod, amount: number) => void, + updateCategoryBudgets: (budgets: Record) => void ) => { - /** - * 확장된 예산 업데이트 함수 - * 월간 예산 및 카테고리 예산을 함께 업데이트 - */ + // 확장된 예산 업데이트 로직 const extendedBudgetGoalUpdate = useCallback(( - type: BudgetPeriod, - amount: number, + type: BudgetPeriod, + amount: number, newCategoryBudgets?: Record ) => { - console.log(`확장된 예산 업데이트: 타입=${type}, 금액=${amount}, 카테고리 예산 포함=${!!newCategoryBudgets}`); + console.log(`확장된 예산 목표 업데이트: ${type}, 금액: ${amount}`, newCategoryBudgets); - // 기본 예산 업데이트 - handleBudgetGoalUpdate(type, amount); - - // 카테고리 예산도 함께 업데이트 (있는 경우) + // 카테고리 예산이 제공된 경우 업데이트 if (newCategoryBudgets) { - console.log('카테고리 예산 업데이트:', newCategoryBudgets); updateCategoryBudgets(newCategoryBudgets); + + // 총액 계산 + const totalAmount = Object.values(newCategoryBudgets).reduce((sum, val) => sum + val, 0); + console.log('카테고리 총액:', totalAmount); + + // 일/주/월 모든 예산 업데이트를 위해 monthly로 처리 + // (monthly 타입은 모든 예산을 계산해 줌) + const updatedBudgetData = calculateUpdatedBudgetData(budgetData, 'monthly', totalAmount); + + // 각 기간별 예산 업데이트 + handleBudgetGoalUpdate('monthly', updatedBudgetData.monthly.targetAmount); + } else { + // 카테고리 예산이 없는 경우, 기존 로직 사용 + handleBudgetGoalUpdate(type, amount); } - - // 데이터 저장 시간 기록 - 동일 세션의 다른 컴포넌트에서 변경 감지 용도 - localStorage.setItem('lastBudgetUpdateTime', new Date().toISOString()); - - // 이벤트 발생 - try { - window.dispatchEvent(new Event('budgetDataUpdated')); - window.dispatchEvent(new Event('categoryBudgetsUpdated')); - } catch (error) { - console.error('이벤트 발생 오류:', error); - } - }, [handleBudgetGoalUpdate, updateCategoryBudgets]); - + }, [budgetData, categoryBudgets, handleBudgetGoalUpdate, updateCategoryBudgets]); + return { extendedBudgetGoalUpdate }; }; diff --git a/src/hooks/useTransactions.ts b/src/hooks/useTransactions.ts index 8f028ae..38f1fd7 100644 --- a/src/hooks/useTransactions.ts +++ b/src/hooks/useTransactions.ts @@ -7,8 +7,7 @@ import { isSyncEnabled } from '@/utils/syncUtils'; import { MONTHS_KR, getCurrentMonth, getPrevMonth, getNextMonth } from '@/utils/dateUtils'; import { loadTransactionsFromStorage, - saveTransactionsToStorage, - loadBudgetFromStorage + saveTransactionsToStorage } from '@/utils/storageUtils'; import { filterTransactionsByMonth, @@ -32,7 +31,7 @@ export const useTransactions = () => { const [searchQuery, setSearchQuery] = useState(''); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); - const [totalBudget, setTotalBudget] = useState(1000000); // 기본 예산 + const [totalBudget, setTotalBudget] = useState(0); const { user } = useAuth(); // 월 변경 처리 @@ -69,8 +68,16 @@ export const useTransactions = () => { setTransactions(filteredData); // 예산 가져오기 - const budget = loadBudgetFromStorage(); - setTotalBudget(budget); + const budgetDataStr = localStorage.getItem('budgetData'); + if (budgetDataStr) { + try { + const budgetData = JSON.parse(budgetDataStr); + setTotalBudget(budgetData.monthly.targetAmount); + } catch (e) { + console.error('예산 데이터 파싱 오류:', e); + setTotalBudget(0); + } + } } catch (err) { console.error('트랜잭션 로드 중 오류:', err); setError('데이터를 불러오는 중 문제가 발생했습니다.'); @@ -113,6 +120,31 @@ export const useTransactions = () => { }; syncWithSupabase(); + + // 예산 데이터 변경 이벤트 리스너 + const handleBudgetUpdate = () => { + const budgetDataStr = localStorage.getItem('budgetData'); + if (budgetDataStr) { + try { + const budgetData = JSON.parse(budgetDataStr); + setTotalBudget(budgetData.monthly.targetAmount); + } catch (e) { + console.error('예산 데이터 파싱 오류:', e); + } + } + }; + + window.addEventListener('budgetDataUpdated', handleBudgetUpdate); + window.addEventListener('storage', (e) => { + if (e.key === 'budgetData') { + handleBudgetUpdate(); + } + }); + + return () => { + window.removeEventListener('budgetDataUpdated', handleBudgetUpdate); + window.removeEventListener('storage', () => {}); + }; }, [user]); // 트랜잭션 업데이트