import { useState, useEffect } from 'react'; import { useAuth } from '@/contexts/auth'; import { toast } from '@/hooks/useToast.wrapper'; import { isSyncEnabled, setSyncEnabled, trySyncAllData, setLastSyncTime } from '@/utils/syncUtils'; import useNotifications from '@/hooks/useNotifications'; import { resetSyncFailureCount } from './syncResultHandler'; import { checkNetworkStatus } from '@/utils/network/checker'; /** * 동기화 토글 기능을 위한 커스텀 훅 */ export const useSyncToggle = () => { const [enabled, setEnabled] = useState(isSyncEnabled()); const { user } = useAuth(); const { addNotification } = useNotifications(); const [isRetrying, setIsRetrying] = useState(false); // 사용자 로그인 상태 변경 감지 useEffect(() => { // 사용자 로그인 상태에 따라 동기화 설정 업데이트 const updateSyncState = () => { if (!user && isSyncEnabled()) { // 사용자가 로그아웃했고 동기화가 활성화되어 있으면 비활성화 setSyncEnabled(false); setEnabled(false); console.log('로그아웃으로 인해 동기화 설정이 비활성화되었습니다.'); } // 동기화 상태 업데이트 setEnabled(isSyncEnabled()); // 로그인/로그아웃 시 실패 카운터 초기화 resetSyncFailureCount(); }; // 초기 호출 updateSyncState(); // 인증 상태 변경 이벤트 리스너 window.addEventListener('auth-state-changed', updateSyncState); // 스토리지 변경 이벤트에도 동기화 상태 확인 추가 const handleStorageChange = (event: StorageEvent) => { if (event.key === 'syncEnabled' || event.key === null) { setEnabled(isSyncEnabled()); console.log('스토리지 변경으로 동기화 상태 업데이트:', isSyncEnabled() ? '활성화' : '비활성화'); } }; window.addEventListener('storage', handleStorageChange); return () => { window.removeEventListener('auth-state-changed', updateSyncState); window.removeEventListener('storage', handleStorageChange); }; }, [user]); // 동기화 토글 핸들러 const handleSyncToggle = async (checked: boolean) => { if (!user && checked) { toast({ title: "로그인 필요", description: "데이터 동기화를 위해 로그인이 필요합니다.", variant: "destructive" }); addNotification( "로그인 필요", "데이터 동기화를 위해 로그인이 필요합니다." ); return; } try { // 네트워크 상태 확인 - navigator.onLine 우선 사용 const navigatorOnline = navigator.onLine; console.log(`[동기화] 기본 네트워크 상태 확인: ${navigatorOnline ? '온라인' : '오프라인'}`); if (checked && !navigatorOnline) { toast({ 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" }); } }; return { enabled, setEnabled, handleSyncToggle }; }; // 실제 동기화 수행 함수 (최대 2회까지 자동 재시도) const performSync = async (userId: string) => { if (!userId) return; let attempts = 0; const maxAttempts = 2; while (attempts < maxAttempts) { try { attempts++; console.log(`동기화 시도 ${attempts}/${maxAttempts}`); // 네트워크 상태 확인 - 기본 navigator.onLine 사용 if (!navigator.onLine) { console.log('네트워크 연결 없음, 동기화 건너뜀'); throw new Error('네트워크 연결 필요'); } const result = await trySyncAllData(userId); return result; } catch (error) { console.error(`동기화 시도 ${attempts} 실패:`, error); if (attempts < maxAttempts) { // 재시도 전 잠시 대기 await new Promise(resolve => setTimeout(resolve, 2000)); console.log(`${attempts+1}번째 동기화 재시도 중...`); } else { throw error; } } } };