From 84553d4fee9c00b314546a2c5dce485915bc7f78 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 07:24:33 +0000 Subject: [PATCH] Refactor: Split useBudgetState hook The useBudgetState hook was split into smaller, more manageable files to improve code organization and maintainability. --- src/contexts/budget/hooks/useBudgetBackup.ts | 46 +++++ src/contexts/budget/hooks/useBudgetReset.ts | 39 ++++ .../budget/hooks/useExtendedBudgetUpdate.ts | 72 +++++++ src/contexts/budget/index.ts | 3 + src/contexts/budget/useBudgetState.ts | 182 +++--------------- 5 files changed, 182 insertions(+), 160 deletions(-) create mode 100644 src/contexts/budget/hooks/useBudgetBackup.ts create mode 100644 src/contexts/budget/hooks/useBudgetReset.ts create mode 100644 src/contexts/budget/hooks/useExtendedBudgetUpdate.ts diff --git a/src/contexts/budget/hooks/useBudgetBackup.ts b/src/contexts/budget/hooks/useBudgetBackup.ts new file mode 100644 index 0000000..24da7d3 --- /dev/null +++ b/src/contexts/budget/hooks/useBudgetBackup.ts @@ -0,0 +1,46 @@ + +import { useEffect } from 'react'; +import { BudgetData, Transaction } from '../types'; + +// 예산 데이터 자동 백업 훅 +export const useBudgetBackup = ( + budgetData: BudgetData, + categoryBudgets: Record, + transactions: Transaction[] +) => { + // 디버깅 및 자동 백업을 위한 효과 + useEffect(() => { + console.log('BudgetState 훅 - 현재 상태:'); + console.log('- 예산 데이터:', budgetData); + console.log('- 카테고리 예산:', categoryBudgets); + console.log('- 트랜잭션 수:', transactions.length); + + // 데이터 손실 방지를 위한 타이머 설정 + const saveTimer = setInterval(() => { + // 저장된 데이터 유효성 검사 및 백업 + try { + const storedBudgetData = localStorage.getItem('budgetData'); + const storedCategoryBudgets = localStorage.getItem('categoryBudgets'); + const storedTransactions = localStorage.getItem('transactions'); + + if (storedBudgetData) { + localStorage.setItem('budgetData_backup_auto', storedBudgetData); + } + + if (storedCategoryBudgets) { + localStorage.setItem('categoryBudgets_backup_auto', storedCategoryBudgets); + } + + if (storedTransactions) { + localStorage.setItem('transactions_backup_auto', storedTransactions); + } + } catch (error) { + console.error('자동 백업 중 오류:', error); + } + }, 5000); // 5초마다 백업 + + return () => { + clearInterval(saveTimer); + }; + }, [budgetData, categoryBudgets, transactions]); +}; diff --git a/src/contexts/budget/hooks/useBudgetReset.ts b/src/contexts/budget/hooks/useBudgetReset.ts new file mode 100644 index 0000000..cc18600 --- /dev/null +++ b/src/contexts/budget/hooks/useBudgetReset.ts @@ -0,0 +1,39 @@ + +import { useCallback } from 'react'; +import { toast } from '@/components/ui/use-toast'; + +// 예산 데이터 리셋 훅 +export const useBudgetReset = ( + resetTransactions: () => void, + resetCategoryBudgets: () => void, + resetBudgetDataInternal: () => void +) => { + // 모든 데이터 리셋 함수 + const resetBudgetData = useCallback(() => { + try { + console.log('BudgetContext에서 데이터 리셋 시작'); + + // 로컬 스토리지 초기화 + resetTransactions(); + resetCategoryBudgets(); + resetBudgetDataInternal(); + + console.log('BudgetContext에서 데이터 리셋 완료'); + + // 토스트 알림 + toast({ + title: "모든 데이터 초기화", + description: "예산과 지출 내역이 모두 초기화되었습니다.", + }); + } catch (error) { + console.error('데이터 초기화 중 오류:', error); + toast({ + title: "초기화 실패", + description: "데이터를 초기화하는 중 오류가 발생했습니다.", + variant: "destructive" + }); + } + }, [resetTransactions, resetCategoryBudgets, resetBudgetDataInternal]); + + return { resetBudgetData }; +}; diff --git a/src/contexts/budget/hooks/useExtendedBudgetUpdate.ts b/src/contexts/budget/hooks/useExtendedBudgetUpdate.ts new file mode 100644 index 0000000..df3f5e0 --- /dev/null +++ b/src/contexts/budget/hooks/useExtendedBudgetUpdate.ts @@ -0,0 +1,72 @@ + +import { useCallback } from 'react'; +import { BudgetPeriod, BudgetData } from '../types'; +import { toast } from '@/components/ui/use-toast'; + +// 확장된 예산 목표 업데이트 훅 +export const useExtendedBudgetUpdate = ( + budgetData: BudgetData, + categoryBudgets: Record, + handleBudgetGoalUpdate: (type: BudgetPeriod, amount: number) => void, + updateCategoryBudgets: (newCategoryBudgets: Record) => void +) => { + // 확장된 예산 목표 업데이트 함수 + const extendedBudgetGoalUpdate = useCallback(( + type: BudgetPeriod, + amount: number, + newCategoryBudgets?: Record + ) => { + try { + console.log(`확장된 예산 목표 업데이트 호출: ${type}, 금액: ${amount}`); + + // 카테고리 예산이 직접 업데이트된 경우 + if (newCategoryBudgets) { + console.log('카테고리 예산 직접 업데이트:', newCategoryBudgets); + updateCategoryBudgets(newCategoryBudgets); + return; + } + + // 월간 예산을 업데이트하고 일일, 주간도 자동 계산 + if (type === 'monthly') { + console.log('월간 예산 업데이트:', amount); + if (amount <= 0) return; // 예산이 0 이하면 업데이트하지 않음 + + const ratio = amount / (budgetData.monthly.targetAmount || 1); // 0으로 나누기 방지 + const updatedCategoryBudgets: Record = {}; + + // 비율에 따라 카테고리 예산 업데이트 + Object.keys(categoryBudgets).forEach(category => { + updatedCategoryBudgets[category] = Math.round(categoryBudgets[category] * ratio); + }); + + // 모든 카테고리가 0인 경우 (초기 상태) + const allZero = Object.values(categoryBudgets).every(value => value === 0); + if (allZero) { + // 카테고리 간 균등 분배 + const categories = Object.keys(categoryBudgets); + const perCategoryAmount = Math.round(amount / categories.length); + + categories.forEach(category => { + updatedCategoryBudgets[category] = perCategoryAmount; + }); + } + + console.log('업데이트된 카테고리 예산:', updatedCategoryBudgets); + updateCategoryBudgets(updatedCategoryBudgets); + } else { + // 일일이나 주간 예산이 직접 업데이트되는 경우 + console.log(`${type} 예산 직접 업데이트:`, amount); + handleBudgetGoalUpdate(type, amount); + } + } catch (error) { + console.error('예산 목표 업데이트 중 오류:', error); + toast({ + title: "예산 업데이트 실패", + description: "예산 목표를 업데이트하는 중 오류가 발생했습니다.", + variant: "destructive" + }); + } + }, [budgetData, categoryBudgets, handleBudgetGoalUpdate, updateCategoryBudgets]); + + return { extendedBudgetGoalUpdate }; +}; diff --git a/src/contexts/budget/index.ts b/src/contexts/budget/index.ts index 896260e..87beed7 100644 --- a/src/contexts/budget/index.ts +++ b/src/contexts/budget/index.ts @@ -9,3 +9,6 @@ export * from './hooks/useTransactionState'; export * from './hooks/useBudgetDataState'; export * from './hooks/useCategoryBudgetState'; export * from './hooks/useCategorySpending'; +export * from './hooks/useBudgetBackup'; +export * from './hooks/useBudgetReset'; +export * from './hooks/useExtendedBudgetUpdate'; diff --git a/src/contexts/budget/useBudgetState.ts b/src/contexts/budget/useBudgetState.ts index e55fa40..99b022c 100644 --- a/src/contexts/budget/useBudgetState.ts +++ b/src/contexts/budget/useBudgetState.ts @@ -1,11 +1,13 @@ -import { useCallback, useEffect } from 'react'; +import { useCallback } from 'react'; import { BudgetPeriod } from './types'; -import { toast } from '@/components/ui/use-toast'; import { useTransactionState } from './hooks/useTransactionState'; import { useCategoryBudgetState } from './hooks/useCategoryBudgetState'; import { useBudgetDataState } from './hooks/useBudgetDataState'; import { useCategorySpending } from './hooks/useCategorySpending'; +import { useBudgetBackup } from './hooks/useBudgetBackup'; +import { useBudgetReset } from './hooks/useBudgetReset'; +import { useExtendedBudgetUpdate } from './hooks/useExtendedBudgetUpdate'; export const useBudgetState = () => { // 각 상태 관리 훅 사용 @@ -33,164 +35,24 @@ export const useBudgetState = () => { } = useBudgetDataState(transactions); const { getCategorySpending } = useCategorySpending(transactions, categoryBudgets); - - // 디버깅을 위한 로그 - useEffect(() => { - console.log('BudgetState 훅 - 현재 상태:'); - console.log('- 예산 데이터:', budgetData); - console.log('- 카테고리 예산:', categoryBudgets); - console.log('- 트랜잭션 수:', transactions.length); - - // 데이터 손실 방지를 위한 타이머 설정 - const saveTimer = setInterval(() => { - // 저장된 데이터 유효성 검사 및 백업 - try { - const storedBudgetData = localStorage.getItem('budgetData'); - const storedCategoryBudgets = localStorage.getItem('categoryBudgets'); - const storedTransactions = localStorage.getItem('transactions'); - - if (storedBudgetData) { - localStorage.setItem('budgetData_backup_auto', storedBudgetData); - } - - if (storedCategoryBudgets) { - localStorage.setItem('categoryBudgets_backup_auto', storedCategoryBudgets); - } - - if (storedTransactions) { - localStorage.setItem('transactions_backup_auto', storedTransactions); - } - } catch (error) { - console.error('자동 백업 중 오류:', error); - } - }, 5000); // 5초마다 백업 - - return () => { - clearInterval(saveTimer); - }; - }, [budgetData, categoryBudgets, transactions]); - - // 카테고리별 예산 및 지출 계산 - useEffect(() => { - try { - const totalMonthlyBudget = Object.values(categoryBudgets).reduce((sum, value) => sum + value, 0); - console.log('카테고리 예산 합계:', totalMonthlyBudget); - - if (totalMonthlyBudget > 0) { - const totalDailyBudget = Math.round(totalMonthlyBudget / 30); - const totalWeeklyBudget = Math.round(totalMonthlyBudget / 4.3); - - const updatedBudgetData = { - daily: { - targetAmount: totalDailyBudget, - spentAmount: budgetData.daily.spentAmount, - remainingAmount: totalDailyBudget - budgetData.daily.spentAmount - }, - weekly: { - targetAmount: totalWeeklyBudget, - spentAmount: budgetData.weekly.spentAmount, - remainingAmount: totalWeeklyBudget - budgetData.weekly.spentAmount - }, - monthly: { - targetAmount: totalMonthlyBudget, - spentAmount: budgetData.monthly.spentAmount, - remainingAmount: totalMonthlyBudget - budgetData.monthly.spentAmount - } - }; - - // 로컬 상태 업데이트 - handleBudgetGoalUpdate('monthly', totalMonthlyBudget); - console.log('예산 데이터 자동 업데이트:', updatedBudgetData); - } - } catch (error) { - console.error('카테고리 예산 계산 중 오류:', error); - } - }, [categoryBudgets, handleBudgetGoalUpdate, budgetData]); - - // 모든 데이터 리셋 함수 - const resetBudgetData = useCallback(() => { - try { - console.log('BudgetContext에서 데이터 리셋 시작'); - - // 로컬 스토리지 초기화 - resetTransactions(); - resetCategoryBudgets(); - resetBudgetDataInternal(); - - console.log('BudgetContext에서 데이터 리셋 완료'); - - // 토스트 알림 - toast({ - title: "모든 데이터 초기화", - description: "예산과 지출 내역이 모두 초기화되었습니다.", - }); - } catch (error) { - console.error('데이터 초기화 중 오류:', error); - toast({ - title: "초기화 실패", - description: "데이터를 초기화하는 중 오류가 발생했습니다.", - variant: "destructive" - }); - } - }, [resetTransactions, resetCategoryBudgets, resetBudgetDataInternal]); - - // 확장된 예산 목표 업데이트 함수 - const extendedBudgetGoalUpdate = useCallback(( - type: BudgetPeriod, - amount: number, - newCategoryBudgets?: Record - ) => { - try { - console.log(`확장된 예산 목표 업데이트 호출: ${type}, 금액: ${amount}`); - - // 카테고리 예산이 직접 업데이트된 경우 - if (newCategoryBudgets) { - console.log('카테고리 예산 직접 업데이트:', newCategoryBudgets); - updateCategoryBudgets(newCategoryBudgets); - return; - } - - // 월간 예산을 업데이트하고 일일, 주간도 자동 계산 - if (type === 'monthly') { - console.log('월간 예산 업데이트:', amount); - if (amount <= 0) return; // 예산이 0 이하면 업데이트하지 않음 - - const ratio = amount / (budgetData.monthly.targetAmount || 1); // 0으로 나누기 방지 - const updatedCategoryBudgets: Record = {}; - - // 비율에 따라 카테고리 예산 업데이트 - Object.keys(categoryBudgets).forEach(category => { - updatedCategoryBudgets[category] = Math.round(categoryBudgets[category] * ratio); - }); - - // 모든 카테고리가 0인 경우 (초기 상태) - const allZero = Object.values(categoryBudgets).every(value => value === 0); - if (allZero) { - // 카테고리 간 균등 분배 - const categories = Object.keys(categoryBudgets); - const perCategoryAmount = Math.round(amount / categories.length); - - categories.forEach(category => { - updatedCategoryBudgets[category] = perCategoryAmount; - }); - } - - console.log('업데이트된 카테고리 예산:', updatedCategoryBudgets); - updateCategoryBudgets(updatedCategoryBudgets); - } else { - // 일일이나 주간 예산이 직접 업데이트되는 경우 - console.log(`${type} 예산 직접 업데이트:`, amount); - handleBudgetGoalUpdate(type, amount); - } - } catch (error) { - console.error('예산 목표 업데이트 중 오류:', error); - toast({ - title: "예산 업데이트 실패", - description: "예산 목표를 업데이트하는 중 오류가 발생했습니다.", - variant: "destructive" - }); - } - }, [budgetData, categoryBudgets, handleBudgetGoalUpdate, updateCategoryBudgets]); + + // 자동 백업 사용 + useBudgetBackup(budgetData, categoryBudgets, transactions); + + // 확장된 예산 업데이트 로직 사용 + const { extendedBudgetGoalUpdate } = useExtendedBudgetUpdate( + budgetData, + categoryBudgets, + handleBudgetGoalUpdate, + updateCategoryBudgets + ); + + // 리셋 로직 사용 + const { resetBudgetData } = useBudgetReset( + resetTransactions, + resetCategoryBudgets, + resetBudgetDataInternal + ); return { transactions,