Fix: App crashing on launch

Investigate and resolve the issue causing the application to crash during startup.
This commit is contained in:
gpt-engineer-app[bot]
2025-04-05 05:04:27 +00:00
parent 9f9c49c588
commit af51ba2d52
5 changed files with 220 additions and 164 deletions

View File

@@ -1,3 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { isAndroidPlatform, isIOSPlatform } from '@/utils/platform'; import { isAndroidPlatform, isIOSPlatform } from '@/utils/platform';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';

View File

@@ -21,7 +21,7 @@ export const useBudgetDataLoad = (
console.log('예산 데이터 로드 시도 중...'); console.log('예산 데이터 로드 시도 중...');
// 비동기 작업을 마이크로태스크로 지연 // 비동기 작업을 마이크로태스크로 지연
await new Promise<void>(resolve => queueMicrotask(() => resolve())); await new Promise<void>(resolve => setTimeout(() => resolve(), 0));
// 안전하게 데이터 로드 // 안전하게 데이터 로드
const loadedData = safelyLoadBudgetData(); const loadedData = safelyLoadBudgetData();
@@ -40,6 +40,8 @@ export const useBudgetDataLoad = (
} }
} catch (error) { } catch (error) {
console.error('예산 데이터 로드 중 오류:', error); console.error('예산 데이터 로드 중 오류:', error);
// 오류가 발생해도 앱을 사용할 수 있도록 기본 데이터 설정
setIsInitialized(true);
} }
}; };
@@ -52,12 +54,17 @@ export const useBudgetDataLoad = (
// 로드 함수 반환 (외부에서 필요할 때 호출 가능) // 로드 함수 반환 (외부에서 필요할 때 호출 가능)
return { return {
loadBudgetData: async () => { loadBudgetData: async () => {
try {
const loadedData = safelyLoadBudgetData(); const loadedData = safelyLoadBudgetData();
if (JSON.stringify(loadedData) !== JSON.stringify(budgetData)) { if (JSON.stringify(loadedData) !== JSON.stringify(budgetData)) {
setBudgetData(loadedData); setBudgetData(loadedData);
setLastUpdateTime(Date.now()); setLastUpdateTime(Date.now());
} }
return loadedData; return loadedData;
} catch (error) {
console.error('loadBudgetData 호출 중 오류:', error);
return budgetData; // 오류 발생 시 현재 데이터 유지
}
} }
}; };
}; };

View File

@@ -16,8 +16,8 @@ export const useTransactionState = () => {
useEffect(() => { useEffect(() => {
try { try {
const storedTransactions = loadTransactionsFromStorage(); const storedTransactions = loadTransactionsFromStorage();
console.log('로컬 스토리지에서 트랜잭션 로드:', storedTransactions.length); console.log('로컬 스토리지에서 트랜잭션 로드:', storedTransactions?.length || 0);
setTransactions(storedTransactions); setTransactions(storedTransactions || []);
} catch (error) { } catch (error) {
console.error('트랜잭션 로드 중 오류 발생:', error); console.error('트랜잭션 로드 중 오류 발생:', error);
// 오류 발생 시 빈 배열로 초기화 // 오류 발생 시 빈 배열로 초기화
@@ -27,41 +27,57 @@ export const useTransactionState = () => {
// 트랜잭션 변경 시 로컬 스토리지에 저장 // 트랜잭션 변경 시 로컬 스토리지에 저장
useEffect(() => { useEffect(() => {
if (transactions.length > 0) { try {
if (transactions && transactions.length > 0) {
console.log('트랜잭션 저장 중:', transactions.length); console.log('트랜잭션 저장 중:', transactions.length);
saveTransactionsToStorage(transactions); saveTransactionsToStorage(transactions);
} }
} catch (error) {
console.error('트랜잭션 저장 중 오류 발생:', error);
}
}, [transactions]); }, [transactions]);
// 트랜잭션 추가 // 트랜잭션 추가
const addTransaction = (transaction: Transaction) => { const addTransaction = (transaction: Transaction) => {
try {
const newTransaction = { const newTransaction = {
...transaction, ...transaction,
id: transaction.id || uuidv4(), id: transaction.id || uuidv4(),
localTimestamp: new Date().toISOString() localTimestamp: new Date().toISOString()
}; };
setTransactions(prevTransactions => [...prevTransactions, newTransaction]); setTransactions(prevTransactions => [...(prevTransactions || []), newTransaction]);
console.log('트랜잭션 추가됨:', newTransaction); console.log('트랜잭션 추가됨:', newTransaction);
} catch (error) {
console.error('트랜잭션 추가 중 오류 발생:', error);
}
}; };
// 트랜잭션 업데이트 // 트랜잭션 업데이트
const updateTransaction = (updatedTransaction: Transaction) => { const updateTransaction = (updatedTransaction: Transaction) => {
try {
setTransactions(prevTransactions => setTransactions(prevTransactions =>
prevTransactions.map(transaction => (prevTransactions || []).map(transaction =>
transaction.id === updatedTransaction.id transaction.id === updatedTransaction.id
? { ...updatedTransaction, localTimestamp: new Date().toISOString() } ? { ...updatedTransaction, localTimestamp: new Date().toISOString() }
: transaction : transaction
) )
); );
console.log('트랜잭션 업데이트됨:', updatedTransaction.id); console.log('트랜잭션 업데이트됨:', updatedTransaction.id);
} catch (error) {
console.error('트랜잭션 업데이트 중 오류 발생:', error);
}
}; };
// 트랜잭션 삭제 // 트랜잭션 삭제
const deleteTransaction = (id: string) => { const deleteTransaction = (id: string) => {
try {
setTransactions(prevTransactions => setTransactions(prevTransactions =>
prevTransactions.filter(transaction => transaction.id !== id) (prevTransactions || []).filter(transaction => transaction.id !== id)
); );
console.log('트랜잭션 삭제됨:', id); console.log('트랜잭션 삭제됨:', id);
} catch (error) {
console.error('트랜잭션 삭제 중 오류 발생:', error);
}
}; };
return { return {

View File

@@ -11,6 +11,7 @@ export const useDataInitialization = (resetBudgetData?: () => void) => {
// 모든 데이터 초기화 함수 // 모든 데이터 초기화 함수
const initializeAllData = useCallback(async () => { const initializeAllData = useCallback(async () => {
try {
// 중요: 이미 방문한 적이 있으면 절대 초기화하지 않음 // 중요: 이미 방문한 적이 있으면 절대 초기화하지 않음
const hasVisitedBefore = localStorage.getItem('hasVisitedBefore') === 'true'; const hasVisitedBefore = localStorage.getItem('hasVisitedBefore') === 'true';
if (hasVisitedBefore) { if (hasVisitedBefore) {
@@ -57,6 +58,11 @@ export const useDataInitialization = (resetBudgetData?: () => void) => {
console.error('데이터 초기화 중 오류 발생:', error); console.error('데이터 초기화 중 오류 발생:', error);
return false; return false;
} }
} catch (error) {
console.error('initializeAllData 함수 실행 중 오류:', error);
setIsInitialized(true); // 오류가 발생해도 앱을 사용할 수 있도록 초기화 완료로 설정
return false;
}
}, [resetBudgetData, user]); }, [resetBudgetData, user]);
// 분석 페이지 데이터 초기화 함수 // 분석 페이지 데이터 초기화 함수
@@ -102,6 +108,7 @@ export const useDataInitialization = (resetBudgetData?: () => void) => {
// 데이터 초기화 실행 - 첫 방문시에만 // 데이터 초기화 실행 - 첫 방문시에만
useEffect(() => { useEffect(() => {
try {
if (!isInitialized) { if (!isInitialized) {
// 이미 방문한 적이 있는지 체크 (이미 있다면 초기화하지 않음) // 이미 방문한 적이 있는지 체크 (이미 있다면 초기화하지 않음)
const hasVisitedBefore = localStorage.getItem('hasVisitedBefore') === 'true'; const hasVisitedBefore = localStorage.getItem('hasVisitedBefore') === 'true';
@@ -117,6 +124,10 @@ export const useDataInitialization = (resetBudgetData?: () => void) => {
// 첫 방문 여부 체크용 키 설정 (항상 true로 설정) // 첫 방문 여부 체크용 키 설정 (항상 true로 설정)
localStorage.setItem('hasVisitedBefore', 'true'); localStorage.setItem('hasVisitedBefore', 'true');
} catch (error) {
console.error('데이터 초기화 useEffect 내 오류:', error);
setIsInitialized(true); // 오류 발생해도 앱을 사용할 수 있도록 초기화 완료로 설정
}
}, [isInitialized, initializeAllData]); }, [isInitialized, initializeAllData]);
return { return {

View File

@@ -1,3 +1,4 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import NavBar from '@/components/NavBar'; import NavBar from '@/components/NavBar';
import AddTransactionButton from '@/components/AddTransactionButton'; import AddTransactionButton from '@/components/AddTransactionButton';
@@ -41,6 +42,7 @@ const Index = () => {
// 앱 시작시 예시 알림 추가 (실제 앱에서는 필요한 이벤트에 따라 알림 추가) // 앱 시작시 예시 알림 추가 (실제 앱에서는 필요한 이벤트에 따라 알림 추가)
useEffect(() => { useEffect(() => {
try {
// 환영 메시지가 이미 표시되었는지 확인하는 키 // 환영 메시지가 이미 표시되었는지 확인하는 키
const welcomeNotificationSent = sessionStorage.getItem('welcomeNotificationSent'); const welcomeNotificationSent = sessionStorage.getItem('welcomeNotificationSent');
@@ -57,12 +59,16 @@ const Index = () => {
return () => clearTimeout(timeoutId); return () => clearTimeout(timeoutId);
} }
} catch (error) {
console.error('환영 메시지 알림 표시 중 오류:', error);
}
}, [isInitialized, user, addNotification]); }, [isInitialized, user, addNotification]);
// 페이지가 처음 로드될 때 데이터 로딩 확인 // 페이지가 처음 로드될 때 데이터 로딩 확인 - 에러 방지를 위해 try/catch 추가
useEffect(() => { useEffect(() => {
try {
console.log('Index 페이지 마운트, 현재 데이터 상태:'); console.log('Index 페이지 마운트, 현재 데이터 상태:');
console.log('트랜잭션:', transactions.length); console.log('트랜잭션:', transactions?.length || 0);
console.log('예산 데이터:', budgetData); console.log('예산 데이터:', budgetData);
// 페이지 첫 마운트 시에만 실행되는 로직으로 수정 // 페이지 첫 마운트 시에만 실행되는 로직으로 수정
@@ -106,11 +112,15 @@ const Index = () => {
console.error('백업 복구 시도 중 오류:', error); console.error('백업 복구 시도 중 오류:', error);
} }
} }
} catch (error) {
console.error('Index 페이지 초기화 중 오류:', error);
}
}, []); // 의존성 배열 비움 - 컴포넌트 마운트 시 한 번만 실행 }, []); // 의존성 배열 비움 - 컴포넌트 마운트 시 한 번만 실행
// 앱이 포커스를 얻었을 때 데이터를 새로고침 // 앱이 포커스를 얻었을 때 데이터를 새로고침
useEffect(() => { useEffect(() => {
const handleFocus = () => { const handleFocus = () => {
try {
console.log('창이 포커스를 얻음 - 데이터 새로고침'); console.log('창이 포커스를 얻음 - 데이터 새로고침');
// 이미 리프레시 중인지 확인하는 플래그 // 이미 리프레시 중인지 확인하는 플래그
if (sessionStorage.getItem('isRefreshing') === 'true') { if (sessionStorage.getItem('isRefreshing') === 'true') {
@@ -135,6 +145,9 @@ const Index = () => {
console.error('이벤트 발생 오류:', e); console.error('이벤트 발생 오류:', e);
sessionStorage.setItem('isRefreshing', 'false'); sessionStorage.setItem('isRefreshing', 'false');
} }
} catch (error) {
console.error('포커스 이벤트 처리 중 오류:', error);
}
}; };
// 포커스 이벤트 // 포커스 이벤트
@@ -142,21 +155,29 @@ const Index = () => {
// 가시성 변경 이벤트 (백그라운드에서 전경으로 돌아올 때) // 가시성 변경 이벤트 (백그라운드에서 전경으로 돌아올 때)
const handleVisibilityChange = () => { const handleVisibilityChange = () => {
try {
if (document.visibilityState === 'visible') { if (document.visibilityState === 'visible') {
console.log('페이지가 다시 보임 - 데이터 새로고침'); console.log('페이지가 다시 보임 - 데이터 새로고침');
handleFocus(); handleFocus();
} }
} catch (error) {
console.error('가시성 이벤트 처리 중 오류:', error);
}
}; };
document.addEventListener('visibilitychange', handleVisibilityChange); document.addEventListener('visibilitychange', handleVisibilityChange);
// 정기적인 데이터 새로고침 (60초마다로 변경 - 너무 빈번한 리프레시 방지) // 정기적인 데이터 새로고침 (60초마다로 변경 - 너무 빈번한 리프레시 방지)
const refreshInterval = setInterval(() => { const refreshInterval = setInterval(() => {
try {
if (document.visibilityState === 'visible' && if (document.visibilityState === 'visible' &&
sessionStorage.getItem('isRefreshing') !== 'true') { sessionStorage.getItem('isRefreshing') !== 'true') {
console.log('정기 새로고침 - 데이터 업데이트'); console.log('정기 새로고침 - 데이터 업데이트');
handleFocus(); handleFocus();
} }
} catch (error) {
console.error('정기 새로고침 처리 중 오류:', error);
}
}, 60000); // 10초에서 60초로 변경 }, 60000); // 10초에서 60초로 변경
return () => { return () => {
@@ -172,8 +193,8 @@ const Index = () => {
<Header /> <Header />
<HomeContent <HomeContent
transactions={transactions} transactions={transactions || []}
budgetData={budgetData} budgetData={budgetData || {}}
selectedTab={selectedTab} selectedTab={selectedTab}
setSelectedTab={setSelectedTab} setSelectedTab={setSelectedTab}
handleBudgetGoalUpdate={handleBudgetGoalUpdate} handleBudgetGoalUpdate={handleBudgetGoalUpdate}