Refactor sync data module
Splits the large `src/utils/sync/data.ts` file into smaller, more manageable modules to improve code organization, readability, and maintainability.
This commit is contained in:
38
src/utils/sync/core/backup.ts
Normal file
38
src/utils/sync/core/backup.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 데이터 백업 및 복원 관련 기능
|
||||||
|
*/
|
||||||
|
import { BackupData } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 현재 로컬 데이터를 백업
|
||||||
|
*/
|
||||||
|
export const backupLocalData = (): BackupData => {
|
||||||
|
return {
|
||||||
|
budgetData: localStorage.getItem('budgetData'),
|
||||||
|
categoryBudgets: localStorage.getItem('categoryBudgets'),
|
||||||
|
transactions: localStorage.getItem('transactions')
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 백업 데이터를 로컬 스토리지에 복원
|
||||||
|
*/
|
||||||
|
export const restoreLocalData = (backup: BackupData): void => {
|
||||||
|
if (backup.budgetData) {
|
||||||
|
localStorage.setItem('budgetData', backup.budgetData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backup.categoryBudgets) {
|
||||||
|
localStorage.setItem('categoryBudgets', backup.categoryBudgets);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backup.transactions) {
|
||||||
|
localStorage.setItem('transactions', backup.transactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI 업데이트 이벤트 발생
|
||||||
|
window.dispatchEvent(new Event('budgetDataUpdated'));
|
||||||
|
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
|
||||||
|
window.dispatchEvent(new Event('transactionUpdated'));
|
||||||
|
};
|
||||||
17
src/utils/sync/core/index.ts
Normal file
17
src/utils/sync/core/index.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 동기화 코어 모듈
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 타입 정의 내보내기
|
||||||
|
export * from './types';
|
||||||
|
|
||||||
|
// 백업 및 복구 기능 내보내기
|
||||||
|
export * from './backup';
|
||||||
|
export * from './recovery';
|
||||||
|
|
||||||
|
// 상태 확인 기능 내보내기
|
||||||
|
export * from './status';
|
||||||
|
|
||||||
|
// 동기화 작업 내보내기
|
||||||
|
export * from './syncOperations';
|
||||||
18
src/utils/sync/core/recovery.ts
Normal file
18
src/utils/sync/core/recovery.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 동기화 과정에서 오류 발생 시 복구 기능
|
||||||
|
*/
|
||||||
|
import { BackupData } from './types';
|
||||||
|
import { restoreLocalData } from './backup';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 동기화 오류 시 데이터 복구
|
||||||
|
*/
|
||||||
|
export const recoverFromSyncError = (backup: BackupData, error: unknown): void => {
|
||||||
|
console.error('데이터 동기화 중 치명적 오류:', error);
|
||||||
|
|
||||||
|
// 백업 데이터 복원
|
||||||
|
restoreLocalData(backup);
|
||||||
|
|
||||||
|
console.log('백업 데이터 복원 완료');
|
||||||
|
};
|
||||||
91
src/utils/sync/core/status.ts
Normal file
91
src/utils/sync/core/status.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 서버 및 로컬 데이터 상태 확인 기능
|
||||||
|
*/
|
||||||
|
import { supabase } from '@/lib/supabase';
|
||||||
|
import { DataStatus, ServerDataStatus, LocalDataStatus } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 서버에 데이터가 있는지 확인
|
||||||
|
*/
|
||||||
|
export const checkServerDataStatus = async (userId: string): Promise<ServerDataStatus> => {
|
||||||
|
try {
|
||||||
|
// 서버에 예산 데이터 확인
|
||||||
|
const { data: budgetData } = await supabase
|
||||||
|
.from('budgets')
|
||||||
|
.select('count')
|
||||||
|
.eq('user_id', userId)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
// 서버에 트랜잭션 데이터 확인
|
||||||
|
const { data: transactionsData } = await supabase
|
||||||
|
.from('transactions')
|
||||||
|
.select('count')
|
||||||
|
.eq('user_id', userId)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
const hasBudgetData = (budgetData?.count || 0) > 0;
|
||||||
|
const hasTransactionData = (transactionsData?.count || 0) > 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
hasBudgetData,
|
||||||
|
hasTransactionData,
|
||||||
|
hasData: hasBudgetData || hasTransactionData
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('서버 데이터 상태 확인 오류:', error);
|
||||||
|
return {
|
||||||
|
hasBudgetData: false,
|
||||||
|
hasTransactionData: false,
|
||||||
|
hasData: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 로컬 데이터가 있는지 확인
|
||||||
|
*/
|
||||||
|
export const checkLocalDataStatus = (): LocalDataStatus => {
|
||||||
|
try {
|
||||||
|
const budgetDataStr = localStorage.getItem('budgetData');
|
||||||
|
const transactionsStr = localStorage.getItem('transactions');
|
||||||
|
|
||||||
|
let hasBudgetData = false;
|
||||||
|
if (budgetDataStr) {
|
||||||
|
const budgetData = JSON.parse(budgetDataStr);
|
||||||
|
hasBudgetData = budgetData?.monthly?.targetAmount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasTransactionData = false;
|
||||||
|
if (transactionsStr) {
|
||||||
|
const transactions = JSON.parse(transactionsStr);
|
||||||
|
hasTransactionData = Array.isArray(transactions) && transactions.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
hasBudgetData,
|
||||||
|
hasTransactionData,
|
||||||
|
hasData: hasBudgetData || hasTransactionData
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('로컬 데이터 상태 확인 오류:', error);
|
||||||
|
return {
|
||||||
|
hasBudgetData: false,
|
||||||
|
hasTransactionData: false,
|
||||||
|
hasData: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 서버와 로컬 데이터 상태 모두 확인
|
||||||
|
*/
|
||||||
|
export const checkDataStatus = async (userId: string): Promise<DataStatus> => {
|
||||||
|
const serverStatus = await checkServerDataStatus(userId);
|
||||||
|
const localStatus = checkLocalDataStatus();
|
||||||
|
|
||||||
|
return {
|
||||||
|
server: serverStatus,
|
||||||
|
local: localStatus
|
||||||
|
};
|
||||||
|
};
|
||||||
106
src/utils/sync/core/syncOperations.ts
Normal file
106
src/utils/sync/core/syncOperations.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 주요 동기화 작업 처리 모듈
|
||||||
|
*/
|
||||||
|
import { uploadBudgets, downloadBudgets } from '../budget';
|
||||||
|
import { uploadTransactions, downloadTransactions } from '../transaction';
|
||||||
|
import { setLastSyncTime } from '../time';
|
||||||
|
import { SyncResult } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 데이터 업로드 수행
|
||||||
|
*/
|
||||||
|
export const performUpload = async (userId: string): Promise<{
|
||||||
|
budgetUpload: boolean;
|
||||||
|
transactionUpload: boolean;
|
||||||
|
}> => {
|
||||||
|
try {
|
||||||
|
console.log('데이터 업로드 시작');
|
||||||
|
|
||||||
|
// 예산 데이터 업로드
|
||||||
|
let budgetUpload = false;
|
||||||
|
try {
|
||||||
|
await uploadBudgets(userId);
|
||||||
|
budgetUpload = true;
|
||||||
|
console.log('예산 업로드 성공');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('예산 업로드 실패:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 트랜잭션 데이터 업로드
|
||||||
|
let transactionUpload = false;
|
||||||
|
try {
|
||||||
|
await uploadTransactions(userId);
|
||||||
|
transactionUpload = true;
|
||||||
|
console.log('트랜잭션 업로드 성공');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('트랜잭션 업로드 실패:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { budgetUpload, transactionUpload };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('업로드 작업 실패:', error);
|
||||||
|
return { budgetUpload: false, transactionUpload: false };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 데이터 다운로드 수행
|
||||||
|
*/
|
||||||
|
export const performDownload = async (userId: string): Promise<{
|
||||||
|
budgetDownload: boolean;
|
||||||
|
transactionDownload: boolean;
|
||||||
|
}> => {
|
||||||
|
try {
|
||||||
|
console.log('데이터 다운로드 시작');
|
||||||
|
|
||||||
|
// 예산 데이터 다운로드
|
||||||
|
let budgetDownload = false;
|
||||||
|
try {
|
||||||
|
await downloadBudgets(userId);
|
||||||
|
budgetDownload = true;
|
||||||
|
console.log('예산 다운로드 성공');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('예산 다운로드 실패:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 트랜잭션 데이터 다운로드
|
||||||
|
let transactionDownload = false;
|
||||||
|
try {
|
||||||
|
await downloadTransactions(userId);
|
||||||
|
transactionDownload = true;
|
||||||
|
console.log('트랜잭션 다운로드 성공');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('트랜잭션 다운로드 실패:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { budgetDownload, transactionDownload };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('다운로드 작업 실패:', error);
|
||||||
|
return { budgetDownload: false, transactionDownload: false };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 동기화 결과 객체 생성
|
||||||
|
*/
|
||||||
|
export const createSyncResult = (
|
||||||
|
uploadResult: { budgetUpload: boolean; transactionUpload: boolean },
|
||||||
|
downloadResult: { budgetDownload: boolean; transactionDownload: boolean }
|
||||||
|
): SyncResult => {
|
||||||
|
const uploadSuccess = uploadResult.budgetUpload || uploadResult.transactionUpload;
|
||||||
|
const downloadSuccess = downloadResult.budgetDownload || downloadResult.transactionDownload;
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: uploadSuccess || downloadSuccess,
|
||||||
|
partial: (uploadSuccess || downloadSuccess) && !(uploadSuccess && downloadSuccess),
|
||||||
|
uploadSuccess,
|
||||||
|
downloadSuccess,
|
||||||
|
details: {
|
||||||
|
budgetUpload: uploadResult.budgetUpload,
|
||||||
|
budgetDownload: downloadResult.budgetDownload,
|
||||||
|
transactionUpload: uploadResult.transactionUpload,
|
||||||
|
transactionDownload: downloadResult.transactionDownload
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
45
src/utils/sync/core/types.ts
Normal file
45
src/utils/sync/core/types.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 동기화 관련 타입 정의
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 동기화 결과 타입 정의
|
||||||
|
export interface SyncResult {
|
||||||
|
success: boolean;
|
||||||
|
partial: boolean;
|
||||||
|
uploadSuccess: boolean;
|
||||||
|
downloadSuccess: boolean;
|
||||||
|
details?: {
|
||||||
|
budgetUpload?: boolean;
|
||||||
|
budgetDownload?: boolean;
|
||||||
|
transactionUpload?: boolean;
|
||||||
|
transactionDownload?: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 백업 데이터 타입 정의
|
||||||
|
export interface BackupData {
|
||||||
|
budgetData: string | null;
|
||||||
|
categoryBudgets: string | null;
|
||||||
|
transactions: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 서버 데이터 상태 타입
|
||||||
|
export interface ServerDataStatus {
|
||||||
|
hasBudgetData: boolean;
|
||||||
|
hasTransactionData: boolean;
|
||||||
|
hasData: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 로컬 데이터 상태 타입
|
||||||
|
export interface LocalDataStatus {
|
||||||
|
hasBudgetData: boolean;
|
||||||
|
hasTransactionData: boolean;
|
||||||
|
hasData: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 데이터 상태 타입
|
||||||
|
export interface DataStatus {
|
||||||
|
server: ServerDataStatus;
|
||||||
|
local: LocalDataStatus;
|
||||||
|
}
|
||||||
@@ -1,29 +1,28 @@
|
|||||||
|
|
||||||
import { supabase } from '@/lib/supabase';
|
/**
|
||||||
import { uploadBudgets, downloadBudgets } from './budget';
|
* 데이터 동기화 메인 모듈
|
||||||
import { uploadTransactions, downloadTransactions } from './transaction';
|
*/
|
||||||
|
import { isSyncEnabled } from './config';
|
||||||
import { setLastSyncTime } from './time';
|
import { setLastSyncTime } from './time';
|
||||||
|
import {
|
||||||
|
BackupData,
|
||||||
|
SyncResult,
|
||||||
|
backupLocalData,
|
||||||
|
recoverFromSyncError,
|
||||||
|
checkDataStatus,
|
||||||
|
performUpload,
|
||||||
|
performDownload,
|
||||||
|
createSyncResult
|
||||||
|
} from './core';
|
||||||
|
|
||||||
export interface SyncResult {
|
/**
|
||||||
success: boolean;
|
* 모든 데이터를 동기화합니다 (서버/로컬 상태에 따라 업로드/다운로드 순서 결정)
|
||||||
partial: boolean;
|
*/
|
||||||
uploadSuccess: boolean;
|
|
||||||
downloadSuccess: boolean;
|
|
||||||
details?: {
|
|
||||||
budgetUpload?: boolean;
|
|
||||||
budgetDownload?: boolean;
|
|
||||||
transactionUpload?: boolean;
|
|
||||||
transactionDownload?: boolean;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 모든 데이터를 동기화합니다 (업로드 우선 수행)
|
|
||||||
export const syncAllData = async (userId: string): Promise<SyncResult> => {
|
export const syncAllData = async (userId: string): Promise<SyncResult> => {
|
||||||
// 로컬 데이터 백업
|
// 로컬 데이터 백업
|
||||||
const backupBudgetData = localStorage.getItem('budgetData');
|
const backup: BackupData = backupLocalData();
|
||||||
const backupCategoryBudgets = localStorage.getItem('categoryBudgets');
|
|
||||||
const backupTransactions = localStorage.getItem('transactions');
|
|
||||||
|
|
||||||
|
// 기본 결과 객체 생성
|
||||||
const result: SyncResult = {
|
const result: SyncResult = {
|
||||||
success: false,
|
success: false,
|
||||||
partial: false,
|
partial: false,
|
||||||
@@ -40,132 +39,55 @@ export const syncAllData = async (userId: string): Promise<SyncResult> => {
|
|||||||
try {
|
try {
|
||||||
console.log('데이터 동기화 시작 - 사용자 ID:', userId);
|
console.log('데이터 동기화 시작 - 사용자 ID:', userId);
|
||||||
|
|
||||||
// 서버에 데이터가 있는지 먼저 확인
|
// 동기화 기능이 활성화되어 있는지 확인
|
||||||
const { data: budgetData } = await supabase
|
if (!isSyncEnabled()) {
|
||||||
.from('budgets')
|
console.log('동기화가 비활성화되어 있어 작업을 건너뜁니다.');
|
||||||
.select('count')
|
return result;
|
||||||
.eq('user_id', userId)
|
}
|
||||||
.single();
|
|
||||||
|
|
||||||
const { data: transactionsData } = await supabase
|
|
||||||
.from('transactions')
|
|
||||||
.select('count')
|
|
||||||
.eq('user_id', userId)
|
|
||||||
.single();
|
|
||||||
|
|
||||||
const serverHasBudgetData = (budgetData?.count || 0) > 0;
|
|
||||||
const serverHasTransactionData = (transactionsData?.count || 0) > 0;
|
|
||||||
const serverHasData = serverHasBudgetData || serverHasTransactionData;
|
|
||||||
|
|
||||||
// 로컬 데이터 존재 여부 확인
|
|
||||||
const localHasBudgetData = backupBudgetData && JSON.parse(backupBudgetData).monthly.targetAmount > 0;
|
|
||||||
const localHasTransactionData = backupTransactions && JSON.parse(backupTransactions).length > 0;
|
|
||||||
const localHasData = localHasBudgetData || localHasTransactionData;
|
|
||||||
|
|
||||||
|
// 서버와 로컬 데이터 상태 확인
|
||||||
|
const status = await checkDataStatus(userId);
|
||||||
console.log('데이터 존재 여부:', {
|
console.log('데이터 존재 여부:', {
|
||||||
서버: {
|
서버: {
|
||||||
예산: serverHasBudgetData,
|
예산: status.server.hasBudgetData,
|
||||||
거래: serverHasTransactionData
|
거래: status.server.hasTransactionData
|
||||||
},
|
},
|
||||||
로컬: {
|
로컬: {
|
||||||
예산: localHasBudgetData,
|
예산: status.local.hasBudgetData,
|
||||||
거래: localHasTransactionData
|
거래: status.local.hasTransactionData
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 서버에 데이터가 없고 로컬에 데이터가 있으면 업로드 먼저
|
// 동기화 전략 결정 - 서버에 데이터가 없고 로컬에 데이터가 있으면 업로드 먼저
|
||||||
if (!serverHasData && localHasData) {
|
if (!status.server.hasData && status.local.hasData) {
|
||||||
console.log('서버에 데이터가 없고 로컬에 데이터가 있어 업로드 우선 실행');
|
console.log('서버에 데이터가 없고 로컬에 데이터가 있어 업로드 우선 실행');
|
||||||
|
|
||||||
try {
|
// 업로드 수행
|
||||||
// 예산 데이터 업로드
|
const uploadResult = await performUpload(userId);
|
||||||
if (localHasBudgetData) {
|
result.uploadSuccess = uploadResult.budgetUpload || uploadResult.transactionUpload;
|
||||||
await uploadBudgets(userId);
|
result.details!.budgetUpload = uploadResult.budgetUpload;
|
||||||
result.details!.budgetUpload = true;
|
result.details!.transactionUpload = uploadResult.transactionUpload;
|
||||||
console.log('예산 업로드 성공');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 트랜잭션 데이터 업로드
|
|
||||||
if (localHasTransactionData) {
|
|
||||||
await uploadTransactions(userId);
|
|
||||||
result.details!.transactionUpload = true;
|
|
||||||
console.log('트랜잭션 업로드 성공');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 업로드 성공 설정
|
|
||||||
result.uploadSuccess = true;
|
|
||||||
} catch (uploadError) {
|
|
||||||
console.error('데이터 업로드 실패:', uploadError);
|
|
||||||
result.uploadSuccess = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 서버에 데이터가 있으면 다운로드 먼저 (기존 로직)
|
// 서버에 데이터가 있으면 다운로드 먼저
|
||||||
else if (serverHasData) {
|
else if (status.server.hasData) {
|
||||||
console.log('서버에 데이터가 있어 다운로드 우선 실행');
|
console.log('서버에 데이터가 있어 다운로드 우선 실행');
|
||||||
|
|
||||||
try {
|
// 다운로드 수행
|
||||||
// 예산 데이터 다운로드
|
const downloadResult = await performDownload(userId);
|
||||||
if (serverHasBudgetData) {
|
result.downloadSuccess = downloadResult.budgetDownload || downloadResult.transactionDownload;
|
||||||
await downloadBudgets(userId);
|
result.details!.budgetDownload = downloadResult.budgetDownload;
|
||||||
result.details!.budgetDownload = true;
|
result.details!.transactionDownload = downloadResult.transactionDownload;
|
||||||
console.log('예산 다운로드 성공');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 트랜잭션 데이터 다운로드
|
|
||||||
if (serverHasTransactionData) {
|
|
||||||
await downloadTransactions(userId);
|
|
||||||
result.details!.transactionDownload = true;
|
|
||||||
console.log('트랜잭션 다운로드 성공');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 다운로드 성공 설정
|
|
||||||
result.downloadSuccess = true;
|
|
||||||
} catch (downloadError) {
|
|
||||||
console.error('데이터 다운로드 실패:', downloadError);
|
|
||||||
result.downloadSuccess = false;
|
|
||||||
|
|
||||||
// 다운로드 실패 시 로컬 데이터 복원
|
|
||||||
if (backupBudgetData) {
|
|
||||||
localStorage.setItem('budgetData', backupBudgetData);
|
|
||||||
}
|
|
||||||
if (backupCategoryBudgets) {
|
|
||||||
localStorage.setItem('categoryBudgets', backupCategoryBudgets);
|
|
||||||
}
|
|
||||||
if (backupTransactions) {
|
|
||||||
localStorage.setItem('transactions', backupTransactions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI 업데이트
|
|
||||||
window.dispatchEvent(new Event('budgetDataUpdated'));
|
|
||||||
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
|
|
||||||
window.dispatchEvent(new Event('transactionUpdated'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 다운로드 후 로컬 데이터 있으면 추가 업로드 시도
|
// 다운로드 후 로컬 데이터 있으면 추가 업로드 시도
|
||||||
if (result.downloadSuccess && localHasData) {
|
if (result.downloadSuccess && status.local.hasData) {
|
||||||
console.log('다운로드 후 로컬 데이터 업로드 시도');
|
console.log('다운로드 후 로컬 데이터 업로드 시도');
|
||||||
|
|
||||||
try {
|
// 업로드 수행
|
||||||
// 예산 데이터 업로드
|
const uploadResult = await performUpload(userId);
|
||||||
if (localHasBudgetData) {
|
result.uploadSuccess = uploadResult.budgetUpload || uploadResult.transactionUpload;
|
||||||
await uploadBudgets(userId);
|
result.details!.budgetUpload = uploadResult.budgetUpload;
|
||||||
result.details!.budgetUpload = true;
|
result.details!.transactionUpload = uploadResult.transactionUpload;
|
||||||
console.log('예산 업로드 성공');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 트랜잭션 데이터 업로드
|
|
||||||
if (localHasTransactionData) {
|
|
||||||
await uploadTransactions(userId);
|
|
||||||
result.details!.transactionUpload = true;
|
|
||||||
console.log('트랜잭션 업로드 성공');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 업로드 성공 설정
|
|
||||||
result.uploadSuccess = true;
|
|
||||||
} catch (uploadError) {
|
|
||||||
console.error('데이터 업로드 실패:', uploadError);
|
|
||||||
result.uploadSuccess = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 양쪽 다 데이터가 없는 경우
|
// 양쪽 다 데이터가 없는 경우
|
||||||
@@ -193,34 +115,16 @@ export const syncAllData = async (userId: string): Promise<SyncResult> => {
|
|||||||
console.log('데이터 동기화 결과:', result);
|
console.log('데이터 동기화 결과:', result);
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('데이터 동기화 중 치명적 오류:', error);
|
// 오류 발생 시 백업 데이터 복원
|
||||||
|
recoverFromSyncError(backup, error);
|
||||||
// 백업 데이터 복원
|
|
||||||
if (backupBudgetData) {
|
|
||||||
localStorage.setItem('budgetData', backupBudgetData);
|
|
||||||
}
|
|
||||||
if (backupCategoryBudgets) {
|
|
||||||
localStorage.setItem('categoryBudgets', backupCategoryBudgets);
|
|
||||||
}
|
|
||||||
if (backupTransactions) {
|
|
||||||
localStorage.setItem('transactions', backupTransactions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI 업데이트
|
|
||||||
window.dispatchEvent(new Event('budgetDataUpdated'));
|
|
||||||
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
|
|
||||||
window.dispatchEvent(new Event('transactionUpdated'));
|
|
||||||
|
|
||||||
result.success = false;
|
|
||||||
result.partial = false;
|
|
||||||
result.uploadSuccess = false;
|
|
||||||
result.downloadSuccess = false;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 서버에 대한 안전한 동기화 래퍼
|
/**
|
||||||
|
* 서버에 대한 안전한 동기화 래퍼
|
||||||
|
*/
|
||||||
export const trySyncAllData = async (userId: string): Promise<SyncResult> => {
|
export const trySyncAllData = async (userId: string): Promise<SyncResult> => {
|
||||||
console.log('안전한 데이터 동기화 시도');
|
console.log('안전한 데이터 동기화 시도');
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
@@ -248,3 +152,6 @@ export const trySyncAllData = async (userId: string): Promise<SyncResult> => {
|
|||||||
|
|
||||||
return trySync();
|
return trySync();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SyncResult 타입 다시 내보내기 (기존 가져오는 코드와의 호환성)
|
||||||
|
export type { SyncResult } from './core';
|
||||||
|
|||||||
Reference in New Issue
Block a user