Refactor useSyncSettings hook
Refactors the useSyncSettings hook into smaller, more manageable modules to improve code organization and maintainability. The functionality of the hook remains unchanged.
This commit is contained in:
41
src/hooks/sync/syncResultHandler.ts
Normal file
41
src/hooks/sync/syncResultHandler.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
import { toast } from '@/hooks/useToast.wrapper';
|
||||||
|
import { SyncResult } from '@/utils/syncUtils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 동기화 결과 처리 함수
|
||||||
|
*/
|
||||||
|
export const handleSyncResult = (result: SyncResult) => {
|
||||||
|
if (result.success) {
|
||||||
|
if (result.downloadSuccess && result.uploadSuccess) {
|
||||||
|
toast({
|
||||||
|
title: "동기화 완료",
|
||||||
|
description: "모든 데이터가 클라우드에 동기화되었습니다.",
|
||||||
|
});
|
||||||
|
} else if (result.downloadSuccess) {
|
||||||
|
toast({
|
||||||
|
title: "다운로드만 성공",
|
||||||
|
description: "서버 데이터를 가져왔지만, 업로드에 실패했습니다.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
} else if (result.uploadSuccess) {
|
||||||
|
toast({
|
||||||
|
title: "업로드만 성공",
|
||||||
|
description: "로컬 데이터를 업로드했지만, 다운로드에 실패했습니다.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
} else if (result.partial) {
|
||||||
|
toast({
|
||||||
|
title: "동기화 일부 완료",
|
||||||
|
description: "일부 데이터만 동기화되었습니다. 다시 시도해보세요.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "일부 동기화 실패",
|
||||||
|
description: "일부 데이터 동기화 중 문제가 발생했습니다. 다시 시도해주세요.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
52
src/hooks/sync/useManualSync.ts
Normal file
52
src/hooks/sync/useManualSync.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { toast } from '@/hooks/useToast.wrapper';
|
||||||
|
import { trySyncAllData, SyncResult } from '@/utils/syncUtils';
|
||||||
|
import { getLastSyncTime, setLastSyncTime } from '@/utils/syncUtils';
|
||||||
|
import { handleSyncResult } from './syncResultHandler';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 수동 동기화 기능을 위한 커스텀 훅
|
||||||
|
*/
|
||||||
|
export const useManualSync = (user: any) => {
|
||||||
|
const [syncing, setSyncing] = useState(false);
|
||||||
|
|
||||||
|
// 수동 동기화 핸들러
|
||||||
|
const handleManualSync = async () => {
|
||||||
|
if (!user) {
|
||||||
|
toast({
|
||||||
|
title: "로그인 필요",
|
||||||
|
description: "데이터 동기화를 위해 로그인이 필요합니다.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await performSync(user.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 실제 동기화 수행 함수
|
||||||
|
const performSync = async (userId: string) => {
|
||||||
|
if (!userId) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setSyncing(true);
|
||||||
|
// 안전한 동기화 함수 사용
|
||||||
|
const result = await trySyncAllData(userId);
|
||||||
|
|
||||||
|
handleSyncResult(result);
|
||||||
|
setLastSyncTime(getLastSyncTime());
|
||||||
|
} catch (error) {
|
||||||
|
console.error('동기화 오류:', error);
|
||||||
|
toast({
|
||||||
|
title: "동기화 오류",
|
||||||
|
description: "동기화 중 문제가 발생했습니다. 다시 시도해주세요.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setSyncing(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { syncing, handleManualSync };
|
||||||
|
};
|
||||||
31
src/hooks/sync/useSyncStatus.ts
Normal file
31
src/hooks/sync/useSyncStatus.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { getLastSyncTime } from '@/utils/syncUtils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 동기화 상태와 마지막 동기화 시간을 관리하는 커스텀 훅
|
||||||
|
*/
|
||||||
|
export const useSyncStatus = () => {
|
||||||
|
const [lastSync, setLastSync] = useState<string | null>(getLastSyncTime());
|
||||||
|
|
||||||
|
// 마지막 동기화 시간 정기적으로 업데이트
|
||||||
|
useEffect(() => {
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
setLastSync(getLastSyncTime());
|
||||||
|
}, 10000); // 10초마다 업데이트
|
||||||
|
|
||||||
|
return () => clearInterval(intervalId);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 마지막 동기화 시간 포맷팅
|
||||||
|
const formatLastSyncTime = () => {
|
||||||
|
if (!lastSync) return "아직 동기화된 적 없음";
|
||||||
|
|
||||||
|
if (lastSync === '부분-다운로드') return "부분 동기화 (다운로드만)";
|
||||||
|
|
||||||
|
const date = new Date(lastSync);
|
||||||
|
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { lastSync, formatLastSyncTime };
|
||||||
|
};
|
||||||
116
src/hooks/sync/useSyncToggle.ts
Normal file
116
src/hooks/sync/useSyncToggle.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useAuth } from '@/contexts/auth';
|
||||||
|
import { toast } from '@/hooks/useToast.wrapper';
|
||||||
|
import {
|
||||||
|
isSyncEnabled,
|
||||||
|
setSyncEnabled
|
||||||
|
} from '@/utils/syncUtils';
|
||||||
|
import { trySyncAllData } from '@/utils/syncUtils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 동기화 토글 기능을 위한 커스텀 훅
|
||||||
|
*/
|
||||||
|
export const useSyncToggle = () => {
|
||||||
|
const [enabled, setEnabled] = useState(isSyncEnabled());
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
|
// 사용자 로그인 상태 변경 감지
|
||||||
|
useEffect(() => {
|
||||||
|
// 사용자 로그인 상태에 따라 동기화 설정 업데이트
|
||||||
|
const updateSyncState = () => {
|
||||||
|
if (!user && isSyncEnabled()) {
|
||||||
|
// 사용자가 로그아웃했고 동기화가 활성화되어 있으면 비활성화
|
||||||
|
setSyncEnabled(false);
|
||||||
|
setEnabled(false);
|
||||||
|
console.log('로그아웃으로 인해 동기화 설정이 비활성화되었습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 동기화 상태 업데이트
|
||||||
|
setEnabled(isSyncEnabled());
|
||||||
|
};
|
||||||
|
|
||||||
|
// 초기 호출
|
||||||
|
updateSyncState();
|
||||||
|
|
||||||
|
// 인증 상태 변경 이벤트 리스너
|
||||||
|
window.addEventListener('auth-state-changed', updateSyncState);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('auth-state-changed', updateSyncState);
|
||||||
|
};
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
|
// 동기화 토글 핸들러
|
||||||
|
const handleSyncToggle = async (checked: boolean) => {
|
||||||
|
if (!user && checked) {
|
||||||
|
toast({
|
||||||
|
title: "로그인 필요",
|
||||||
|
description: "데이터 동기화를 위해 로그인이 필요합니다.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (checked && user) {
|
||||||
|
try {
|
||||||
|
// 동기화 활성화 시 즉시 동기화 실행
|
||||||
|
await performSync(user.id);
|
||||||
|
} 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"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { enabled, setEnabled, handleSyncToggle };
|
||||||
|
};
|
||||||
|
|
||||||
|
// 실제 동기화 수행 함수
|
||||||
|
const performSync = async (userId: string) => {
|
||||||
|
if (!userId) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 안전한 동기화 함수 사용
|
||||||
|
const result = await trySyncAllData(userId);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('동기화 오류:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,206 +1,18 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useAuth } from '@/contexts/auth';
|
import { useAuth } from '@/contexts/auth';
|
||||||
import { toast } from '@/hooks/useToast.wrapper';
|
import { useSyncToggle } from './sync/useSyncToggle';
|
||||||
import {
|
import { useManualSync } from './sync/useManualSync';
|
||||||
isSyncEnabled,
|
import { useSyncStatus } from './sync/useSyncStatus';
|
||||||
setSyncEnabled,
|
|
||||||
getLastSyncTime,
|
|
||||||
trySyncAllData,
|
|
||||||
SyncResult
|
|
||||||
} from '@/utils/syncUtils';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 동기화 설정 관리를 위한 커스텀 훅
|
* 동기화 설정 관리를 위한 커스텀 훅
|
||||||
*/
|
*/
|
||||||
export const useSyncSettings = () => {
|
export const useSyncSettings = () => {
|
||||||
const [enabled, setEnabled] = useState(isSyncEnabled());
|
|
||||||
const [syncing, setSyncing] = useState(false);
|
|
||||||
const [lastSync, setLastSync] = useState<string | null>(getLastSyncTime());
|
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
const { enabled, setEnabled, handleSyncToggle } = useSyncToggle();
|
||||||
// 사용자 로그인 상태 변경 감지
|
const { syncing, handleManualSync } = useManualSync(user);
|
||||||
useEffect(() => {
|
const { lastSync, formatLastSyncTime } = useSyncStatus();
|
||||||
// 사용자 로그인 상태에 따라 동기화 설정 업데이트
|
|
||||||
const updateSyncState = () => {
|
|
||||||
if (!user && isSyncEnabled()) {
|
|
||||||
// 사용자가 로그아웃했고 동기화가 활성화되어 있으면 비활성화
|
|
||||||
setSyncEnabled(false);
|
|
||||||
setEnabled(false);
|
|
||||||
setLastSync(null);
|
|
||||||
console.log('로그아웃으로 인해 동기화 설정이 비활성화되었습니다.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 동기화 상태 업데이트
|
|
||||||
setEnabled(isSyncEnabled());
|
|
||||||
setLastSync(getLastSyncTime());
|
|
||||||
};
|
|
||||||
|
|
||||||
// 초기 호출
|
|
||||||
updateSyncState();
|
|
||||||
|
|
||||||
// 인증 상태 변경 이벤트 리스너
|
|
||||||
window.addEventListener('auth-state-changed', updateSyncState);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('auth-state-changed', updateSyncState);
|
|
||||||
};
|
|
||||||
}, [user]);
|
|
||||||
|
|
||||||
// 마지막 동기화 시간 정기적으로 업데이트
|
|
||||||
useEffect(() => {
|
|
||||||
const intervalId = setInterval(() => {
|
|
||||||
setLastSync(getLastSyncTime());
|
|
||||||
}, 10000); // 10초마다 업데이트
|
|
||||||
|
|
||||||
return () => clearInterval(intervalId);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 동기화 토글 핸들러
|
|
||||||
const handleSyncToggle = async (checked: boolean) => {
|
|
||||||
if (!user && checked) {
|
|
||||||
toast({
|
|
||||||
title: "로그인 필요",
|
|
||||||
description: "데이터 동기화를 위해 로그인이 필요합니다.",
|
|
||||||
variant: "destructive"
|
|
||||||
});
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (checked && user) {
|
|
||||||
try {
|
|
||||||
// 동기화 활성화 시 즉시 동기화 실행
|
|
||||||
await performSync();
|
|
||||||
} 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"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 수동 동기화 핸들러
|
|
||||||
const handleManualSync = async () => {
|
|
||||||
if (!user) {
|
|
||||||
toast({
|
|
||||||
title: "로그인 필요",
|
|
||||||
description: "데이터 동기화를 위해 로그인이 필요합니다.",
|
|
||||||
variant: "destructive"
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await performSync();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 실제 동기화 수행 함수
|
|
||||||
const performSync = async () => {
|
|
||||||
if (!user) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
setSyncing(true);
|
|
||||||
// 안전한 동기화 함수 사용
|
|
||||||
const result = await trySyncAllData(user.id);
|
|
||||||
|
|
||||||
handleSyncResult(result);
|
|
||||||
setLastSync(getLastSyncTime());
|
|
||||||
} catch (error) {
|
|
||||||
console.error('동기화 오류:', error);
|
|
||||||
toast({
|
|
||||||
title: "동기화 오류",
|
|
||||||
description: "동기화 중 문제가 발생했습니다. 다시 시도해주세요.",
|
|
||||||
variant: "destructive"
|
|
||||||
});
|
|
||||||
|
|
||||||
// 심각한 오류 발생 시 동기화 비활성화
|
|
||||||
if (!enabled) {
|
|
||||||
setEnabled(false);
|
|
||||||
setSyncEnabled(false);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setSyncing(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 동기화 결과 처리 함수
|
|
||||||
const handleSyncResult = (result: SyncResult) => {
|
|
||||||
if (result.success) {
|
|
||||||
if (result.downloadSuccess && result.uploadSuccess) {
|
|
||||||
toast({
|
|
||||||
title: "동기화 완료",
|
|
||||||
description: "모든 데이터가 클라우드에 동기화되었습니다.",
|
|
||||||
});
|
|
||||||
} else if (result.downloadSuccess) {
|
|
||||||
toast({
|
|
||||||
title: "다운로드만 성공",
|
|
||||||
description: "서버 데이터를 가져왔지만, 업로드에 실패했습니다.",
|
|
||||||
variant: "destructive"
|
|
||||||
});
|
|
||||||
} else if (result.uploadSuccess) {
|
|
||||||
toast({
|
|
||||||
title: "업로드만 성공",
|
|
||||||
description: "로컬 데이터를 업로드했지만, 다운로드에 실패했습니다.",
|
|
||||||
variant: "destructive"
|
|
||||||
});
|
|
||||||
} else if (result.partial) {
|
|
||||||
toast({
|
|
||||||
title: "동기화 일부 완료",
|
|
||||||
description: "일부 데이터만 동기화되었습니다. 다시 시도해보세요.",
|
|
||||||
variant: "destructive"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
toast({
|
|
||||||
title: "일부 동기화 실패",
|
|
||||||
description: "일부 데이터 동기화 중 문제가 발생했습니다. 다시 시도해주세요.",
|
|
||||||
variant: "destructive"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 마지막 동기화 시간 포맷팅
|
|
||||||
const formatLastSyncTime = () => {
|
|
||||||
if (!lastSync) return "아직 동기화된 적 없음";
|
|
||||||
|
|
||||||
if (lastSync === '부분-다운로드') return "부분 동기화 (다운로드만)";
|
|
||||||
|
|
||||||
const date = new Date(lastSync);
|
|
||||||
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled,
|
enabled,
|
||||||
|
|||||||
Reference in New Issue
Block a user