diff --git a/src/components/BudgetProgressCard.tsx b/src/components/BudgetProgressCard.tsx index 1263715..e23ccf3 100644 --- a/src/components/BudgetProgressCard.tsx +++ b/src/components/BudgetProgressCard.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import BudgetTabContent from './BudgetTabContent'; -import { BudgetPeriod, BudgetData } from '@/contexts/budget/BudgetContext'; +import { BudgetPeriod, BudgetData } from '@/contexts/budget/types'; interface BudgetProgressCardProps { budgetData: BudgetData; diff --git a/src/components/home/HomeContent.tsx b/src/components/home/HomeContent.tsx index a2b10f3..2440378 100644 --- a/src/components/home/HomeContent.tsx +++ b/src/components/home/HomeContent.tsx @@ -4,9 +4,9 @@ import BudgetProgressCard from '@/components/BudgetProgressCard'; import BudgetCategoriesSection from '@/components/BudgetCategoriesSection'; import RecentTransactionsSection from '@/components/RecentTransactionsSection'; import EmptyState from './EmptyState'; -import { BudgetPeriod, BudgetData } from '@/contexts/budget/BudgetContext'; +import { BudgetPeriod } from '@/contexts/budget/BudgetContext'; import { formatCurrency, calculatePercentage } from '@/utils/formatters'; -import { Transaction } from '@/contexts/budget/types'; +import { Transaction, BudgetData } from '@/contexts/budget/types'; interface HomeContentProps { transactions: Transaction[]; diff --git a/src/contexts/budget/budgetUtils.ts b/src/contexts/budget/budgetUtils.ts index 6458d24..07cb20f 100644 --- a/src/contexts/budget/budgetUtils.ts +++ b/src/contexts/budget/budgetUtils.ts @@ -1,24 +1,154 @@ -// 분리된 유틸리티 파일들에서 함수와 상수를 재내보내기 -export { - DEFAULT_CATEGORY_BUDGETS, - DEFAULT_MONTHLY_BUDGET, - getInitialBudgetData -} from './utils/constants'; +import { BudgetData, Transaction } from './types'; +import { format } from 'date-fns'; -export { - calculateCategorySpending -} from './utils/categoryUtils'; +// 기본 예산 데이터 +export const getInitialBudgetData = (): BudgetData => ({ + daily: { + targetAmount: 0, + spentAmount: 0, + remainingAmount: 0 + }, + weekly: { + targetAmount: 0, + spentAmount: 0, + remainingAmount: 0 + }, + monthly: { + targetAmount: 0, + spentAmount: 0, + remainingAmount: 0 + } +}); -export { - calculateUpdatedBudgetData -} from './utils/budgetCalculation'; +// 예산 데이터 스토리지에서 로드 +export const safelyLoadBudgetData = (): BudgetData => { + try { + const budgetDataStr = localStorage.getItem('budgetData'); + + if (budgetDataStr) { + const parsedData = JSON.parse(budgetDataStr); + + // 데이터 구조 검증 (필요한 키가 있는지 확인) + if (parsedData && + typeof parsedData === 'object' && + 'daily' in parsedData && + 'weekly' in parsedData && + 'monthly' in parsedData) { + return parsedData; + } else { + console.warn('저장된 예산 데이터 구조가 유효하지 않습니다. 기본값을 반환합니다.'); + } + } + } catch (error) { + console.error('예산 데이터 로드 중 오류:', error); + } + + // 오류 발생 또는 유효하지 않은 데이터인 경우 기본값 반환 + return getInitialBudgetData(); +}; -export { - calculateSpentAmounts -} from './utils/spendingCalculation'; +// 지출 금액 계산 함수 +export const calculateSpentAmounts = (transactions: Transaction[], budgetData: BudgetData): BudgetData => { + // 기존 예산 데이터 복사 + const newBudgetData = JSON.parse(JSON.stringify(budgetData)); + + // 지출 트랜잭션만 필터링 + const expenseTransactions = transactions.filter(t => t.type === 'expense'); + + // 현재 날짜 정보 + const now = new Date(); + const currentDay = now.getDate(); + const currentMonth = now.getMonth(); + const currentYear = now.getFullYear(); + const todayStr = format(now, 'yyyy-MM-dd'); + + // 월간 지출 합계 (현재 월의 모든 지출) + const monthlyExpenses = expenseTransactions.filter(t => { + try { + const transactionDate = new Date(t.date); + return ( + transactionDate.getMonth() === currentMonth && + transactionDate.getFullYear() === currentYear + ); + } catch (e) { + return false; // 날짜 파싱 오류 시 포함하지 않음 + } + }); + + // 주간 지출 합계 (최근 7일) + const weeklyExpenses = expenseTransactions.filter(t => { + try { + const transactionDate = new Date(t.date); + const diffTime = now.getTime() - transactionDate.getTime(); + const diffDays = diffTime / (1000 * 3600 * 24); + return diffDays <= 7; + } catch (e) { + return false; + } + }); + + // 일일 지출 합계 (오늘) + const dailyExpenses = expenseTransactions.filter(t => { + try { + const transactionDateStr = format(new Date(t.date), 'yyyy-MM-dd'); + return transactionDateStr === todayStr; + } catch (e) { + return false; + } + }); + + // 계산된 지출 금액 + const dailyTotal = dailyExpenses.reduce((sum, t) => sum + t.amount, 0); + const weeklyTotal = weeklyExpenses.reduce((sum, t) => sum + t.amount, 0); + const monthlyTotal = monthlyExpenses.reduce((sum, t) => sum + t.amount, 0); + + // 예산 데이터에 적용 + newBudgetData.daily.spentAmount = dailyTotal; + newBudgetData.daily.remainingAmount = Math.max(0, newBudgetData.daily.targetAmount - dailyTotal); + + newBudgetData.weekly.spentAmount = weeklyTotal; + newBudgetData.weekly.remainingAmount = Math.max(0, newBudgetData.weekly.targetAmount - weeklyTotal); + + newBudgetData.monthly.spentAmount = monthlyTotal; + newBudgetData.monthly.remainingAmount = Math.max(0, newBudgetData.monthly.targetAmount - monthlyTotal); + + return newBudgetData; +}; -export { - safelyLoadBudgetData, - safeStorage -} from './utils/storageUtils'; +// 예산 목표 업데이트 함수 +export const calculateUpdatedBudgetData = ( + budgetData: BudgetData, + type: 'daily' | 'weekly' | 'monthly', + amount: number +): BudgetData => { + const newBudgetData = JSON.parse(JSON.stringify(budgetData)); + + // 새로운 예산 목표 설정 및 남은 금액 계산 + newBudgetData[type].targetAmount = amount; + newBudgetData[type].remainingAmount = Math.max(0, amount - newBudgetData[type].spentAmount); + + // 월간 예산 기준으로 일일/주간 예산 자동 계산 (월간 예산이 설정된 경우만) + if (type === 'monthly' && amount > 0) { + // 현재 날짜 기준으로 이번 달 남은 일수 계산 + const today = new Date(); + const lastDayOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0).getDate(); + const remainingDays = lastDayOfMonth - today.getDate() + 1; + + // 일일 예산 계산 (남은 금액 / 남은 일수) + if (newBudgetData.daily.targetAmount === 0) { + const dailyBudget = Math.round(amount / lastDayOfMonth); + newBudgetData.daily.targetAmount = dailyBudget; + newBudgetData.daily.remainingAmount = Math.max(0, dailyBudget - newBudgetData.daily.spentAmount); + } + + // 주간 예산 계산 (월간 예산 / 4.3주) + if (newBudgetData.weekly.targetAmount === 0) { + const weeklyBudget = Math.round(amount / 4.3); + newBudgetData.weekly.targetAmount = weeklyBudget; + newBudgetData.weekly.remainingAmount = Math.max(0, weeklyBudget - newBudgetData.weekly.spentAmount); + } + } + + return newBudgetData; +};