diff --git a/src/hooks/sync/useSyncToggle.ts b/src/hooks/sync/useSyncToggle.ts index 77d7ddc..e29b1df 100644 --- a/src/hooks/sync/useSyncToggle.ts +++ b/src/hooks/sync/useSyncToggle.ts @@ -77,92 +77,127 @@ export const useSyncToggle = () => { return; } - // 네트워크 상태 확인 - const isOnline = await checkNetworkStatus(); - if (checked && !isOnline) { - toast({ - title: "네트워크 연결 필요", - description: "동기화를 위해 인터넷 연결이 필요합니다.", - variant: "destructive" - }); + try { + // 네트워크 상태 확인 - navigator.onLine 우선 사용 + const navigatorOnline = navigator.onLine; + console.log(`[동기화] 기본 네트워크 상태 확인: ${navigatorOnline ? '온라인' : '오프라인'}`); - addNotification( - "네트워크 연결 필요", - "동기화를 위해 인터넷 연결이 필요합니다." - ); - return; - } - - // 현재 로컬 데이터 백업 - const budgetDataBackup = localStorage.getItem('budgetData'); - const categoryBudgetsBackup = localStorage.getItem('categoryBudgets'); - const transactionsBackup = localStorage.getItem('transactions'); - - console.log('동기화 설정 변경 전 로컬 데이터 백업:', { - budgetData: budgetDataBackup ? '있음' : '없음', - categoryBudgets: categoryBudgetsBackup ? '있음' : '없음', - transactions: transactionsBackup ? '있음' : '없음' - }); - - // 동기화 설정 변경 - setEnabled(checked); - setSyncEnabled(checked); - - // 실패 카운터 초기화 - resetSyncFailureCount(); - - // 동기화 활성화/비활성화 알림 추가 - addNotification( - checked ? "동기화 활성화" : "동기화 비활성화", - checked - ? "데이터가 클라우드와 동기화됩니다." - : "클라우드 동기화가 중지되었습니다." - ); - - // 이벤트 트리거 - window.dispatchEvent(new Event('auth-state-changed')); - - if (checked && user) { - try { - // 동기화 수행 - const result = await performSync(user.id); - - // 동기화 성공 시 마지막 동기화 시간 업데이트 - if (result && result.success) { - const currentTime = new Date().toISOString(); - console.log('동기화 활성화 후 첫 동기화 성공, 시간 업데이트:', currentTime); - setLastSyncTime(currentTime); - } - } catch (error) { - console.error('동기화 중 오류, 로컬 데이터 복원 시도:', error); - - // 오류 발생 시 백업 데이터 복원 - if (budgetDataBackup) { - localStorage.setItem('budgetData', budgetDataBackup); - } - if (categoryBudgetsBackup) { - localStorage.setItem('categoryBudgets', categoryBudgetsBackup); - } - if (transactionsBackup) { - localStorage.setItem('transactions', transactionsBackup); - } - - // 이벤트 발생시켜 UI 업데이트 - window.dispatchEvent(new Event('budgetDataUpdated')); - window.dispatchEvent(new Event('categoryBudgetsUpdated')); - window.dispatchEvent(new Event('transactionUpdated')); - + if (checked && !navigatorOnline) { toast({ - title: "동기화 오류", - description: "동기화 중 문제가 발생하여 로컬 데이터가 복원되었습니다.", + title: "네트워크 연결 필요", + description: "동기화를 위해 인터넷 연결이 필요합니다.", variant: "destructive" }); addNotification( - "동기화 오류", - "동기화 중 문제가 발생하여 로컬 데이터가 복원되었습니다." + "네트워크 연결 필요", + "동기화를 위해 인터넷 연결이 필요합니다." ); + return; } + + // 강화된 네트워크 확인 시도 (실패해도 계속 진행) + try { + const isOnline = await checkNetworkStatus(); + console.log(`[동기화] 강화된 네트워크 확인 결과: ${isOnline ? '온라인' : '오프라인'}`); + + // 두 번째 확인에서도 오프라인이면 중단 + if (checked && !isOnline) { + toast({ + title: "네트워크 연결 필요", + description: "동기화를 위해 인터넷 연결이 필요합니다.", + variant: "destructive" + }); + + addNotification( + "네트워크 연결 필요", + "동기화를 위해 인터넷 연결이 필요합니다." + ); + return; + } + } catch (error) { + // 네트워크 확인 실패해도 navigator.onLine이 true면 진행 + console.warn('[동기화] 강화된 네트워크 확인 실패, 기본 상태 사용:', error); + } + + // 현재 로컬 데이터 백업 + const budgetDataBackup = localStorage.getItem('budgetData'); + const categoryBudgetsBackup = localStorage.getItem('categoryBudgets'); + const transactionsBackup = localStorage.getItem('transactions'); + + console.log('동기화 설정 변경 전 로컬 데이터 백업:', { + budgetData: budgetDataBackup ? '있음' : '없음', + categoryBudgets: categoryBudgetsBackup ? '있음' : '없음', + transactions: transactionsBackup ? '있음' : '없음' + }); + + // 동기화 설정 변경 + setEnabled(checked); + setSyncEnabled(checked); + + // 실패 카운터 초기화 + resetSyncFailureCount(); + + // 동기화 활성화/비활성화 알림 추가 + addNotification( + checked ? "동기화 활성화" : "동기화 비활성화", + checked + ? "데이터가 클라우드와 동기화됩니다." + : "클라우드 동기화가 중지되었습니다." + ); + + // 이벤트 트리거 + window.dispatchEvent(new Event('auth-state-changed')); + + if (checked && user) { + try { + // 동기화 수행 + const result = await performSync(user.id); + + // 동기화 성공 시 마지막 동기화 시간 업데이트 + if (result && result.success) { + const currentTime = new Date().toISOString(); + console.log('동기화 활성화 후 첫 동기화 성공, 시간 업데이트:', currentTime); + setLastSyncTime(currentTime); + } + } catch (error) { + console.error('동기화 중 오류, 로컬 데이터 복원 시도:', error); + + // 오류 발생 시 백업 데이터 복원 + if (budgetDataBackup) { + localStorage.setItem('budgetData', budgetDataBackup); + } + if (categoryBudgetsBackup) { + localStorage.setItem('categoryBudgets', categoryBudgetsBackup); + } + if (transactionsBackup) { + localStorage.setItem('transactions', transactionsBackup); + } + + // 이벤트 발생시켜 UI 업데이트 + window.dispatchEvent(new Event('budgetDataUpdated')); + window.dispatchEvent(new Event('categoryBudgetsUpdated')); + window.dispatchEvent(new Event('transactionUpdated')); + + toast({ + title: "동기화 오류", + description: "동기화 중 문제가 발생하여 로컬 데이터가 복원되었습니다.", + variant: "destructive" + }); + + addNotification( + "동기화 오류", + "동기화 중 문제가 발생하여 로컬 데이터가 복원되었습니다." + ); + } + } + } catch (error) { + console.error('동기화 설정 변경 중 예상치 못한 오류:', error); + toast({ + title: "동기화 설정 오류", + description: "설정 변경 중 문제가 발생했습니다. 다시 시도해 주세요.", + variant: "destructive" + }); } }; @@ -181,9 +216,8 @@ const performSync = async (userId: string) => { attempts++; console.log(`동기화 시도 ${attempts}/${maxAttempts}`); - // 네트워크 상태 확인 - const isOnline = await checkNetworkStatus(); - if (!isOnline) { + // 네트워크 상태 확인 - 기본 navigator.onLine 사용 + if (!navigator.onLine) { console.log('네트워크 연결 없음, 동기화 건너뜀'); throw new Error('네트워크 연결 필요'); } diff --git a/src/utils/network/checker.ts b/src/utils/network/checker.ts index 1ed8ea4..1946f7c 100644 --- a/src/utils/network/checker.ts +++ b/src/utils/network/checker.ts @@ -9,15 +9,27 @@ import { setNetworkStatus } from './status'; */ export const checkNetworkStatus = async (): Promise => { try { + // 먼저 navigator.onLine으로 기본 확인 + if (navigator.onLine) { + console.log('[네트워크] 기본 온라인 상태 확인: 온라인'); + setNetworkStatus('online'); + return true; + } + + console.log('[네트워크] 기본 온라인 상태 확인: 오프라인, 추가 확인 시도...'); + // 더 빠른 타임아웃 설정 (2초) const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 2000); - // 실패 방지를 위해 작은 이미지 요청으로 변경 - const timestamp = new Date().getTime(); - const url = `https://www.google.com/favicon.ico?t=${timestamp}`; - + // 신뢰성 있는 확인을 위해 로컬 리소스 요청 + // CORS 이슈와 실패 방지를 위해 자체 페이지 내 리소스 확인 try { + // 타임스탬프로 캐시 방지 + const timestamp = new Date().getTime(); + // 자체 파비콘이나 작은 리소스 확인 + const url = `/favicon.ico?t=${timestamp}`; + const response = await fetch(url, { method: 'HEAD', signal: controller.signal, @@ -27,22 +39,31 @@ export const checkNetworkStatus = async (): Promise => { clearTimeout(timeoutId); if (response.ok) { + console.log('[네트워크] 로컬 리소스 확인 성공'); setNetworkStatus('online'); return true; } else { - console.log(`[네트워크] 상태 확인 실패: ${response.status}`); - setNetworkStatus('offline'); - return false; + console.log(`[네트워크] 로컬 리소스 확인 실패: ${response.status}`); + // 여전히 온라인일 수 있으므로 navigator.onLine 신뢰 + const isOnline = navigator.onLine; + setNetworkStatus(isOnline ? 'online' : 'offline'); + return isOnline; } } catch (error) { clearTimeout(timeoutId); - console.error('[네트워크] 네트워크 연결 확인 실패:', error); - setNetworkStatus('offline'); - return false; + console.warn('[네트워크] 로컬 리소스 확인 중 오류:', error); + + // 여전히 온라인일 수 있으므로 navigator.onLine 신뢰 + const isOnline = navigator.onLine; + console.log(`[네트워크] navigator.onLine 결과 사용: ${isOnline ? '온라인' : '오프라인'}`); + setNetworkStatus(isOnline ? 'online' : 'offline'); + return isOnline; } } catch (error) { console.error('[네트워크] 연결 확인 중 예상치 못한 오류:', error); - setNetworkStatus('offline'); - return false; + // 최후의 수단으로 navigator.onLine 사용 + const isOnline = navigator.onLine; + setNetworkStatus(isOnline ? 'online' : 'offline'); + return isOnline; } };