The network check was incorrectly reporting a lack of connection when sync was enabled. This commit addresses the issue.
240 lines
8.3 KiB
TypeScript
240 lines
8.3 KiB
TypeScript
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
};
|