diff --git a/src/components/home/EmptyState.tsx b/src/components/home/EmptyState.tsx new file mode 100644 index 0000000..db2975b --- /dev/null +++ b/src/components/home/EmptyState.tsx @@ -0,0 +1,21 @@ + +import React from 'react'; + +interface EmptyStateProps { + message?: string; + subMessage?: string; +} + +const EmptyState: React.FC = ({ + message = "아직 데이터가 없습니다", + subMessage = "예산을 설정하고 지출을 추가해 보세요" +}) => { + return ( +
+

{message}

+

{subMessage}

+
+ ); +}; + +export default EmptyState; diff --git a/src/components/home/HomeContent.tsx b/src/components/home/HomeContent.tsx new file mode 100644 index 0000000..33316d3 --- /dev/null +++ b/src/components/home/HomeContent.tsx @@ -0,0 +1,86 @@ + +import React from 'react'; +import BudgetProgressCard from '@/components/BudgetProgressCard'; +import BudgetCategoriesSection from '@/components/BudgetCategoriesSection'; +import RecentTransactionsSection from '@/components/RecentTransactionsSection'; +import EmptyState from './EmptyState'; +import { BudgetPeriod } from '@/contexts/BudgetContext'; +import { formatCurrency, calculatePercentage } from '@/utils/formatters'; +import { Transaction } from '@/components/TransactionCard'; + +interface HomeContentProps { + transactions: Transaction[]; + budgetData: { + daily: { + targetAmount: number; + spentAmount: number; + remainingAmount: number; + }; + weekly: { + targetAmount: number; + spentAmount: number; + remainingAmount: number; + }; + monthly: { + targetAmount: number; + spentAmount: number; + remainingAmount: number; + }; + }; + selectedTab: string; + setSelectedTab: (value: string) => void; + handleBudgetGoalUpdate: (type: BudgetPeriod, amount: number, newCategoryBudgets?: Record) => void; + updateTransaction: (transaction: Transaction) => void; + getCategorySpending: () => Array<{ + title: string; + current: number; + total: number; + }>; +} + +const HomeContent: React.FC = ({ + transactions, + budgetData, + selectedTab, + setSelectedTab, + handleBudgetGoalUpdate, + updateTransaction, + getCategorySpending +}) => { + return ( + <> + {/* 목표 진행 상황 */} +

예산과 지출

+ + + {/* 지출 카테고리 */} + {getCategorySpending().some(cat => cat.current > 0 || cat.total > 0) ? ( + + ) : ( + + )} + + {/* 최근 지출 */} + {transactions.length > 0 ? ( + + ) : ( +
+

최근 지출

+ +
+ )} + + ); +}; + +export default HomeContent; diff --git a/src/hooks/useDataInitialization.ts b/src/hooks/useDataInitialization.ts new file mode 100644 index 0000000..05e812d --- /dev/null +++ b/src/hooks/useDataInitialization.ts @@ -0,0 +1,94 @@ + +import { useState, useEffect, useCallback } from 'react'; +import { resetAllData } from '@/contexts/budget/storageUtils'; +import { resetAllStorageData } from '@/utils/storageUtils'; + +export const useDataInitialization = (resetBudgetData?: () => void) => { + const [isInitialized, setIsInitialized] = useState(false); + + // 모든 데이터 초기화 함수 + const initializeAllData = useCallback(() => { + console.log('모든 데이터 초기화 시작'); + + // 현재 dontShowWelcome 값 백업 + const dontShowWelcomeValue = localStorage.getItem('dontShowWelcome'); + console.log('useDataInitialization - 초기화 전 dontShowWelcome 값:', dontShowWelcomeValue); + + // 여러번 초기화 실행 + for (let i = 0; i < 3; i++) { + // 모든 데이터 완전히 삭제 및 초기화 + resetAllData(); + resetAllStorageData(); + + // localStorage 직접 초기화 (추가 보호) + clearAllAnalyticsData(); + } + + // 컨텍스트 데이터 리셋 (마지막에 한번 더) + if (resetBudgetData) { + resetBudgetData(); + } + + // 초기화 후 dontShowWelcome 값 확인 + const afterResetValue = localStorage.getItem('dontShowWelcome'); + console.log('useDataInitialization - 초기화 후 dontShowWelcome 값:', afterResetValue); + + // 값이 유지되지 않았다면 복원 + if (dontShowWelcomeValue && afterResetValue !== dontShowWelcomeValue) { + console.log('useDataInitialization - dontShowWelcome 값 복원:', dontShowWelcomeValue); + localStorage.setItem('dontShowWelcome', dontShowWelcomeValue); + } + + console.log('모든 데이터 초기화 완료'); + return true; + }, [resetBudgetData]); + + // 분석 페이지 데이터 초기화 함수 + const clearAllAnalyticsData = useCallback(() => { + // 분석 관련 데이터 강제 삭제 + const analyticsKeys = [ + 'analytics', 'monthlyTotals', 'chartData', + 'expenseHistory', 'budgetHistory', 'categorySpending', + 'monthlyData', 'expenseData', 'analyticData' + ]; + + analyticsKeys.forEach(key => { + localStorage.removeItem(key); + }); + + // 모든 localStorage 순회하며 월간, 차트, 분석 관련 키워드 삭제 + for (let i = localStorage.length - 1; i >= 0; i--) { + const key = localStorage.key(i); + if (key && ( + key.includes('month') || + key.includes('chart') || + key.includes('analytics') || + key.includes('expense') || + key.includes('budget') || + key.includes('total') + )) { + console.log(`분석 데이터 삭제: ${key}`); + localStorage.removeItem(key); + } + } + + return true; + }, []); + + // 데이터 초기화 실행 + useEffect(() => { + if (!isInitialized) { + const result = initializeAllData(); + setIsInitialized(result); + } + + // 방문 기록 저장 (초기화 후에 저장) + localStorage.setItem('hasVisitedBefore', 'true'); + }, [isInitialized, initializeAllData]); + + return { + isInitialized, + initializeAllData, + clearAllAnalyticsData + }; +}; diff --git a/src/hooks/useWelcomeDialog.ts b/src/hooks/useWelcomeDialog.ts new file mode 100644 index 0000000..d183226 --- /dev/null +++ b/src/hooks/useWelcomeDialog.ts @@ -0,0 +1,60 @@ + +import { useState, useEffect, useCallback } from 'react'; + +export const useWelcomeDialog = () => { + const [showWelcome, setShowWelcome] = useState(false); + + // 환영 다이얼로그 표시 여부 확인 + const checkWelcomeDialogState = useCallback(() => { + // 현재 세션에서 이미 환영 메시지를 닫았는지 확인 + const sessionClosed = sessionStorage.getItem('welcomeClosedThisSession') === 'true'; + + if (sessionClosed) { + console.log('useWelcomeDialog - 이번 세션에서 이미 환영 메시지를 닫았습니다'); + setShowWelcome(false); + return; + } + + const dontShowWelcome = localStorage.getItem('dontShowWelcome'); + console.log('useWelcomeDialog - dontShowWelcome 값:', dontShowWelcome); + + // 명시적으로 'true' 문자열인 경우에만 숨김 처리 + if (dontShowWelcome === 'true') { + console.log('useWelcomeDialog - 환영 메시지 표시하지 않음 (저장된 설정)'); + setShowWelcome(false); + } else { + console.log('useWelcomeDialog - 환영 메시지 표시함'); + setShowWelcome(true); + } + }, []); + + // 환영 다이얼로그 닫기 핸들러 + const handleCloseWelcome = useCallback((dontShowAgain: boolean) => { + setShowWelcome(false); + + // 이번 세션에서 닫았음을 기록 + sessionStorage.setItem('welcomeClosedThisSession', 'true'); + + // 사용자가 더 이상 보지 않기를 선택한 경우 + if (dontShowAgain) { + localStorage.setItem('dontShowWelcome', 'true'); + sessionStorage.setItem('dontShowWelcome', 'true'); + console.log('useWelcomeDialog - 환영 팝업 더 이상 표시하지 않기 설정됨:', dontShowAgain); + + // 설정 확인 + const savedValue = localStorage.getItem('dontShowWelcome'); + console.log('useWelcomeDialog - 설정 후 dontShowWelcome 저장값:', savedValue); + } else { + // 체크하지 않은 경우 명시적으로 false 저장 + localStorage.setItem('dontShowWelcome', 'false'); + sessionStorage.setItem('dontShowWelcome', 'false'); + } + }, []); + + return { + showWelcome, + setShowWelcome, + checkWelcomeDialogState, + handleCloseWelcome + }; +}; diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 0edf0b8..526c6a1 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -1,17 +1,14 @@ -import React, { useState, useEffect } from 'react'; +import React, { useEffect } from 'react'; import NavBar from '@/components/NavBar'; import AddTransactionButton from '@/components/AddTransactionButton'; import Header from '@/components/Header'; -import BudgetProgressCard from '@/components/BudgetProgressCard'; -import BudgetCategoriesSection from '@/components/BudgetCategoriesSection'; -import RecentTransactionsSection from '@/components/RecentTransactionsSection'; import WelcomeDialog from '@/components/onboarding/WelcomeDialog'; -import { formatCurrency, calculatePercentage } from '@/utils/formatters'; +import HomeContent from '@/components/home/HomeContent'; import { useBudget } from '@/contexts/BudgetContext'; import { useAuth } from '@/contexts/auth'; -import { resetAllData } from '@/contexts/budget/storageUtils'; -import { resetAllStorageData } from '@/utils/storageUtils'; +import { useWelcomeDialog } from '@/hooks/useWelcomeDialog'; +import { useDataInitialization } from '@/hooks/useDataInitialization'; import { useIsMobile } from '@/hooks/use-mobile'; // 메인 컴포넌트 @@ -28,150 +25,17 @@ const Index = () => { } = useBudget(); const { user } = useAuth(); - const [showWelcome, setShowWelcome] = useState(false); - const [isInitialized, setIsInitialized] = useState(false); + const { showWelcome, checkWelcomeDialogState, handleCloseWelcome } = useWelcomeDialog(); + const { isInitialized } = useDataInitialization(resetBudgetData); const isMobile = useIsMobile(); - // 화면이 처음 로드될 때 데이터 초기화 + // 초기화 후 0.5초 후에 환영 메시지 표시 상태 확인 useEffect(() => { - // 초기화 함수 모음 - const initializeAllData = () => { - console.log('모든 데이터 초기화 시작'); - - // 현재 dontShowWelcome 값 백업 - const dontShowWelcomeValue = localStorage.getItem('dontShowWelcome'); - console.log('Index - 초기화 전 dontShowWelcome 값:', dontShowWelcomeValue); - - // 여러번 초기화 실행 - for (let i = 0; i < 3; i++) { - // 모든 데이터 완전히 삭제 및 초기화 - resetAllData(); - resetAllStorageData(); - - // localStorage 직접 초기화 (추가 보호) - clearAllAnalyticsData(); - } - - // 컨텍스트 데이터 리셋 (마지막에 한번 더) - if (resetBudgetData) { - resetBudgetData(); - } - - // 초기화 후 dontShowWelcome 값 확인 - const afterResetValue = localStorage.getItem('dontShowWelcome'); - console.log('Index - 초기화 후 dontShowWelcome 값:', afterResetValue); - - // 값이 유지되지 않았다면 복원 - if (dontShowWelcomeValue && afterResetValue !== dontShowWelcomeValue) { - console.log('Index - dontShowWelcome 값 복원:', dontShowWelcomeValue); - localStorage.setItem('dontShowWelcome', dontShowWelcomeValue); - } - - console.log('모든 데이터 초기화 완료'); - return true; - }; - - // 분석 페이지 데이터 초기화 함수 - const clearAllAnalyticsData = () => { - // 분석 관련 데이터 강제 삭제 - const analyticsKeys = [ - 'analytics', 'monthlyTotals', 'chartData', - 'expenseHistory', 'budgetHistory', 'categorySpending', - 'monthlyData', 'expenseData', 'analyticData' - ]; - - analyticsKeys.forEach(key => { - localStorage.removeItem(key); - }); - - // 모든 localStorage 순회하며 월간, 차트, 분석 관련 키워드 삭제 - for (let i = localStorage.length - 1; i >= 0; i--) { - const key = localStorage.key(i); - if (key && ( - key.includes('month') || - key.includes('chart') || - key.includes('analytics') || - key.includes('expense') || - key.includes('budget') || - key.includes('total') - )) { - console.log(`분석 데이터 삭제: ${key}`); - localStorage.removeItem(key); - } - } - - return true; - }; - - if (!isInitialized) { - // 데이터 초기화 실행 - const result = initializeAllData(); - setIsInitialized(result); + if (isInitialized) { + const timeoutId = setTimeout(checkWelcomeDialogState, 500); + return () => clearTimeout(timeoutId); } - - // 환영 다이얼로그 표시 여부 결정 (데이터 초기화 후) - const checkWelcomeDialogState = () => { - // 현재 세션에서 이미 환영 메시지를 닫았는지 확인 - const sessionClosed = sessionStorage.getItem('welcomeClosedThisSession') === 'true'; - - if (sessionClosed) { - console.log('Index - 이번 세션에서 이미 환영 메시지를 닫았습니다'); - setShowWelcome(false); - return; - } - - const dontShowWelcome = localStorage.getItem('dontShowWelcome'); - console.log('Index - 페이지 로딩 시 dontShowWelcome 값:', dontShowWelcome); - - // 명시적으로 'true' 문자열인 경우에만 숨김 처리 - if (dontShowWelcome === 'true') { - console.log('Index - 환영 메시지 표시하지 않음 (저장된 설정)'); - setShowWelcome(false); - } else { - console.log('Index - 환영 메시지 표시함'); - setShowWelcome(true); - } - }; - - // 0.5초 후 환영 메시지 표시 상태 확인 (데이터 초기화가 완료된 후) - const timeoutId = setTimeout(checkWelcomeDialogState, 500); - - // 방문 기록 저장 (초기화 후에 저장) - localStorage.setItem('hasVisitedBefore', 'true'); - - return () => clearTimeout(timeoutId); - }, [isInitialized, resetBudgetData]); - - // 환영 팝업 닫기 - const handleCloseWelcome = (dontShowAgain: boolean) => { - setShowWelcome(false); - - // 이번 세션에서 닫았음을 기록 - sessionStorage.setItem('welcomeClosedThisSession', 'true'); - - // 사용자가 더 이상 보지 않기를 선택한 경우 - if (dontShowAgain) { - localStorage.setItem('dontShowWelcome', 'true'); - sessionStorage.setItem('dontShowWelcome', 'true'); - console.log('Index - 환영 팝업 더 이상 표시하지 않기 설정됨:', dontShowAgain); - - // 설정 확인 - const savedValue = localStorage.getItem('dontShowWelcome'); - console.log('Index - 설정 후 dontShowWelcome 저장값:', savedValue); - } else { - // 체크하지 않은 경우 명시적으로 false 저장 - localStorage.setItem('dontShowWelcome', 'false'); - sessionStorage.setItem('dontShowWelcome', 'false'); - } - }; - - // 빈 데이터 상태 메시지 - const EmptyState = () => ( -
-

아직 데이터가 없습니다

-

예산을 설정하고 지출을 추가해 보세요

-
- ); + }, [isInitialized, checkWelcomeDialogState]); // 트랜잭션 변경 시 페이지 새로고침 useEffect(() => { @@ -194,36 +58,15 @@ const Index = () => {
- {/* 목표 진행 상황 */} -

예산과 지출

- - - {/* 지출 카테고리 */} - {getCategorySpending().some(cat => cat.current > 0 || cat.total > 0) ? ( - - ) : ( - - )} - - {/* 최근 지출 */} - {transactions.length > 0 ? ( - - ) : ( -
-

최근 지출

- -
- )}