diff --git a/src/components/CategoryBudgetInputs.tsx b/src/components/CategoryBudgetInputs.tsx index 42f6d3d..c03a5da 100644 --- a/src/components/CategoryBudgetInputs.tsx +++ b/src/components/CategoryBudgetInputs.tsx @@ -1,5 +1,5 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { Input } from '@/components/ui/input'; import { EXPENSE_CATEGORIES } from '@/constants/categoryIcons'; import { useIsMobile } from '@/hooks/use-mobile'; @@ -28,6 +28,22 @@ const CategoryBudgetInputs: React.FC = ({ handleCategoryInputChange(numericValue, category); }; + // 컴포넌트가 마운트될 때 categoryBudgets가 로컬 스토리지에서 다시 로드되도록 이벤트 리스너 설정 + useEffect(() => { + const handleStorageChange = () => { + // 부모 컴포넌트에서 데이터가 업데이트되므로 별도 처리 필요 없음 + console.log('카테고리 예산 데이터 변경 감지됨'); + }; + + window.addEventListener('categoryBudgetsUpdated', handleStorageChange); + window.addEventListener('storage', handleStorageChange); + + return () => { + window.removeEventListener('categoryBudgetsUpdated', handleStorageChange); + window.removeEventListener('storage', handleStorageChange); + }; + }, []); + return (
{EXPENSE_CATEGORIES.map(category => ( diff --git a/src/contexts/budget/hooks/useBudgetDataState.ts b/src/contexts/budget/hooks/useBudgetDataState.ts index e25239f..5a811cc 100644 --- a/src/contexts/budget/hooks/useBudgetDataState.ts +++ b/src/contexts/budget/hooks/useBudgetDataState.ts @@ -5,7 +5,7 @@ import { loadBudgetDataFromStorage, saveBudgetDataToStorage, clearAllBudgetData -} from '../storageUtils'; +} from '../storage'; import { toast } from '@/components/ui/use-toast'; import { calculateUpdatedBudgetData, @@ -17,21 +17,56 @@ export const useBudgetDataState = (transactions: any[]) => { const [budgetData, setBudgetData] = useState(loadBudgetDataFromStorage()); const [selectedTab, setSelectedTab] = useState("daily"); - // 지출 금액 업데이트 + // 지출 금액 업데이트 - 트랜잭션이 변경될 때마다 실행 useEffect(() => { - // 스토리지에서 데이터 로드 - const loadedBudgetData = loadBudgetDataFromStorage(); - // 지출 금액 업데이트 - const updatedBudgetData = calculateSpentAmounts(transactions, loadedBudgetData); + const updatedBudgetData = calculateSpentAmounts(transactions, budgetData); // 상태 및 스토리지 모두 업데이트 setBudgetData(updatedBudgetData); saveBudgetDataToStorage(updatedBudgetData); + }, [transactions, budgetData]); + + // 이벤트 리스너 설정 + useEffect(() => { + const handleBudgetUpdate = () => { + const loadedBudgetData = loadBudgetDataFromStorage(); + setBudgetData(prevData => { + // 예산 목표는 로드된 데이터에서 가져오고, 지출 금액은 유지 + const updatedData = { + daily: { + ...loadedBudgetData.daily, + spentAmount: prevData.daily.spentAmount, + }, + weekly: { + ...loadedBudgetData.weekly, + spentAmount: prevData.weekly.spentAmount, + }, + monthly: { + ...loadedBudgetData.monthly, + spentAmount: prevData.monthly.spentAmount, + } + }; + + // 남은 금액 재계산 + updatedData.daily.remainingAmount = updatedData.daily.targetAmount - updatedData.daily.spentAmount; + updatedData.weekly.remainingAmount = updatedData.weekly.targetAmount - updatedData.weekly.spentAmount; + updatedData.monthly.remainingAmount = updatedData.monthly.targetAmount - updatedData.monthly.spentAmount; + + return updatedData; + }); + }; - // 로컬 이벤트 발생 (다른 컴포넌트에서 변경 감지하도록) - window.dispatchEvent(new Event('budgetDataUpdated')); - }, [transactions]); + window.addEventListener('budgetDataUpdated', handleBudgetUpdate); + window.addEventListener('categoryBudgetsUpdated', handleBudgetUpdate); + window.addEventListener('storage', handleBudgetUpdate); + + return () => { + window.removeEventListener('budgetDataUpdated', handleBudgetUpdate); + window.removeEventListener('categoryBudgetsUpdated', handleBudgetUpdate); + window.removeEventListener('storage', handleBudgetUpdate); + }; + }, []); // 예산 목표 업데이트 함수 const handleBudgetGoalUpdate = useCallback(( @@ -45,6 +80,9 @@ export const useBudgetDataState = (transactions: any[]) => { setBudgetData(updatedBudgetData); saveBudgetDataToStorage(updatedBudgetData); + // 이벤트 발생시키기 + window.dispatchEvent(new Event('budgetDataUpdated')); + toast({ title: "목표 업데이트 완료", description: `${type === 'daily' ? '일일' : type === 'weekly' ? '주간' : '월간'} 목표가 ${amount.toLocaleString()}원으로 설정되었습니다.` diff --git a/src/contexts/budget/hooks/useCategoryBudgetState.ts b/src/contexts/budget/hooks/useCategoryBudgetState.ts index 79d6c40..6178ba4 100644 --- a/src/contexts/budget/hooks/useCategoryBudgetState.ts +++ b/src/contexts/budget/hooks/useCategoryBudgetState.ts @@ -4,7 +4,7 @@ import { loadCategoryBudgetsFromStorage, saveCategoryBudgetsToStorage, clearAllCategoryBudgets -} from '../storage/categoryStorage'; +} from '../storage'; // 카테고리 예산 상태 관리 훅 export const useCategoryBudgetState = () => { @@ -12,6 +12,21 @@ export const useCategoryBudgetState = () => { loadCategoryBudgetsFromStorage() ); + // 이벤트 리스너 설정 + useEffect(() => { + const handleCategoryUpdate = () => { + setCategoryBudgets(loadCategoryBudgetsFromStorage()); + }; + + window.addEventListener('categoryBudgetsUpdated', handleCategoryUpdate); + window.addEventListener('storage', handleCategoryUpdate); + + return () => { + window.removeEventListener('categoryBudgetsUpdated', handleCategoryUpdate); + window.removeEventListener('storage', handleCategoryUpdate); + }; + }, []); + // 카테고리 예산 업데이트 함수 const updateCategoryBudgets = useCallback((newCategoryBudgets: Record) => { setCategoryBudgets(newCategoryBudgets); diff --git a/src/contexts/budget/hooks/useTransactionState.ts b/src/contexts/budget/hooks/useTransactionState.ts index 31cce47..a85377f 100644 --- a/src/contexts/budget/hooks/useTransactionState.ts +++ b/src/contexts/budget/hooks/useTransactionState.ts @@ -5,7 +5,7 @@ import { loadTransactionsFromStorage, saveTransactionsToStorage, clearAllTransactions -} from '../storageUtils'; +} from '../storage'; import { toast } from '@/components/ui/use-toast'; // 트랜잭션 상태 관리 훅 @@ -22,9 +22,17 @@ export const useTransactionState = () => { loadTransactions(); // 이벤트 리스너를 추가하여 다른 컴포넌트에서 변경 시 업데이트 - window.addEventListener('storage', loadTransactions); + const handleTransactionUpdate = () => loadTransactions(); + window.addEventListener('transactionUpdated', handleTransactionUpdate); + window.addEventListener('transactionDeleted', handleTransactionUpdate); + window.addEventListener('transactionAdded', handleTransactionUpdate); + window.addEventListener('storage', handleTransactionUpdate); + return () => { - window.removeEventListener('storage', loadTransactions); + window.removeEventListener('transactionUpdated', handleTransactionUpdate); + window.removeEventListener('transactionDeleted', handleTransactionUpdate); + window.removeEventListener('transactionAdded', handleTransactionUpdate); + window.removeEventListener('storage', handleTransactionUpdate); }; }, []); @@ -33,6 +41,10 @@ export const useTransactionState = () => { setTransactions(prev => { const updated = [newTransaction, ...prev]; saveTransactionsToStorage(updated); + + // 이벤트 발생시키기 + window.dispatchEvent(new Event('transactionAdded')); + return updated; }); }, []); @@ -44,11 +56,12 @@ export const useTransactionState = () => { transaction.id === updatedTransaction.id ? updatedTransaction : transaction ); saveTransactionsToStorage(updated); + + // 이벤트 발생시키기 + window.dispatchEvent(new Event('transactionUpdated')); + return updated; }); - - // 로컬 이벤트 발생 (다른 컴포넌트에서 변경 감지하도록) - window.dispatchEvent(new Event('transactionUpdated')); }, []); // 트랜잭션 삭제 함수 @@ -56,16 +69,17 @@ export const useTransactionState = () => { setTransactions(prev => { const updated = prev.filter(transaction => transaction.id !== transactionId); saveTransactionsToStorage(updated); + + // 이벤트 발생시키기 + window.dispatchEvent(new Event('transactionDeleted')); + + toast({ + title: "지출이 삭제되었습니다", + description: "지출 항목이 성공적으로 삭제되었습니다.", + }); + return updated; }); - - toast({ - title: "지출이 삭제되었습니다", - description: "지출 항목이 성공적으로 삭제되었습니다.", - }); - - // 로컬 이벤트 발생 (다른 컴포넌트에서 변경 감지하도록) - window.dispatchEvent(new Event('transactionDeleted')); }, []); // 트랜잭션 초기화 함수 diff --git a/src/contexts/budget/storage/budgetStorage.ts b/src/contexts/budget/storage/budgetStorage.ts index 0fd33ca..2f911ee 100644 --- a/src/contexts/budget/storage/budgetStorage.ts +++ b/src/contexts/budget/storage/budgetStorage.ts @@ -31,6 +31,11 @@ export const saveBudgetDataToStorage = (budgetData: BudgetData): void => { try { localStorage.setItem('budgetData', JSON.stringify(budgetData)); console.log('예산 데이터 저장 완료'); + + // 스토리지 이벤트 수동 트리거 (동일 창에서도 감지하기 위함) + window.dispatchEvent(new StorageEvent('storage', { + key: 'budgetData' + })); } catch (error) { console.error('예산 데이터 저장 오류:', error); } diff --git a/src/contexts/budget/storage/categoryStorage.ts b/src/contexts/budget/storage/categoryStorage.ts index 566487d..8a8f22b 100644 --- a/src/contexts/budget/storage/categoryStorage.ts +++ b/src/contexts/budget/storage/categoryStorage.ts @@ -29,6 +29,11 @@ export const saveCategoryBudgetsToStorage = (categoryBudgets: Record try { localStorage.setItem('transactions', JSON.stringify(transactions)); console.log('트랜잭션 저장 완료, 항목 수:', transactions.length); + + // 스토리지 이벤트 수동 트리거 (동일 창에서도 감지하기 위함) + window.dispatchEvent(new StorageEvent('storage', { + key: 'transactions' + })); } catch (error) { console.error('트랜잭션 저장 오류:', error); } @@ -37,6 +42,11 @@ export const clearAllTransactions = (): void => { // 빈 배열을 저장하여 확실히 초기화 localStorage.setItem('transactions', JSON.stringify([])); console.log('모든 트랜잭션이 삭제되었습니다.'); + + // 스토리지 이벤트 수동 트리거 + window.dispatchEvent(new StorageEvent('storage', { + key: 'transactions' + })); } catch (error) { console.error('트랜잭션 삭제 오류:', error); } diff --git a/src/contexts/budget/useBudgetState.ts b/src/contexts/budget/useBudgetState.ts index 434b149..12bac76 100644 --- a/src/contexts/budget/useBudgetState.ts +++ b/src/contexts/budget/useBudgetState.ts @@ -64,7 +64,7 @@ export const useBudgetState = () => { }; // 로컬 이벤트 발생 (다른 컴포넌트에서 변경 감지하도록) - window.dispatchEvent(new Event('categoryBudgetsUpdated')); + window.dispatchEvent(new Event('budgetDataUpdated')); }, [categoryBudgets, budgetData]); // 모든 데이터 리셋 함수 diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 526c6a1..b79a102 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -37,20 +37,15 @@ const Index = () => { } }, [isInitialized, checkWelcomeDialogState]); - // 트랜잭션 변경 시 페이지 새로고침 + // 앱이 포커스를 얻었을 때 데이터를 새로고침 useEffect(() => { - const handleTransactionAdded = () => { - console.log('트랜잭션이 추가되었습니다. 페이지를 새로고침합니다.'); - // 컨텍스트에서 최신 데이터 가져오기 + const handleFocus = () => { + // 이벤트 발생시켜 데이터 새로고침 + window.dispatchEvent(new Event('storage')); }; - window.addEventListener('transactionAdded', handleTransactionAdded); - window.addEventListener('budgetDataUpdated', handleTransactionAdded); - - return () => { - window.removeEventListener('transactionAdded', handleTransactionAdded); - window.removeEventListener('budgetDataUpdated', handleTransactionAdded); - }; + window.addEventListener('focus', handleFocus); + return () => window.removeEventListener('focus', handleFocus); }, []); return (