Files
zellyy-finance/src/hooks/query/useSyncQueries.ts
hansoo 0a8b028a4c refactor: 코드베이스 정리 - Appwrite/Lovable 완전 제거
주요 변경사항:
• Appwrite SDK 및 관련 의존성 완전 제거
• Lovable 관련 도구 및 설정 제거
• 기존 Appwrite 기반 컴포넌트 및 훅 삭제
• Login/Register 페이지를 Clerk 기반으로 완전 전환

제거된 구성요소:
• src/lib/appwrite/ - 전체 디렉토리
• src/contexts/auth/ - 기존 인증 컨텍스트
• 구형 auth 컴포넌트들 (RegisterForm, LoginForm 등)
• useAuthQueries, useTransactionQueries 훅
• Appwrite 기반 테스트 파일들

설정 변경:
• package.json - appwrite, lovable-tagger 의존성 제거
• .env 파일 - Appwrite 환경변수 제거
• vercel.json - Supabase/Clerk 환경변수로 교체
• vite.config.ts - 청크 분할 설정 업데이트

성능 개선:
• 번들 크기 최적화 (Appwrite → Clerk + Supabase)
• 불필요한 코드 및 타입 정의 제거
• 테스트 설정을 Clerk/Supabase 모킹으로 업데이트

Task 11.4 완료: 기존 Appwrite 코드 완전 제거

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-13 14:13:28 +09:00

315 lines
8.8 KiB
TypeScript

/**
* 동기화 관련 React Query 훅들
*
* 기존 동기화 로직을 React Query로 전환하여
* 백그라운드 동기화와 상태 관리를 최적화합니다.
*/
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import {
trySyncAllData,
getLastSyncTime,
setLastSyncTime,
} from "@/utils/syncUtils";
import {
queryKeys,
queryConfigs,
handleQueryError,
invalidateQueries,
} from "@/lib/query/queryClient";
import { syncLogger } from "@/utils/logger";
import { useAuthStore } from "@/stores";
import { toast } from "@/hooks/useToast.wrapper";
import useNotifications from "@/hooks/useNotifications";
/**
* 마지막 동기화 시간 조회 쿼리
*/
export const useLastSyncTimeQuery = () => {
return useQuery({
queryKey: queryKeys.sync.lastSync(),
queryFn: async () => {
const lastSyncTime = getLastSyncTime();
syncLogger.info("마지막 동기화 시간 조회", { lastSyncTime });
return lastSyncTime;
},
staleTime: 30 * 1000, // 30초
gcTime: 5 * 60 * 1000, // 5분
});
};
/**
* 동기화 상태 조회 쿼리
*/
export const useSyncStatusQuery = () => {
const { user } = useAuthStore();
return useQuery({
queryKey: queryKeys.sync.status(),
queryFn: async () => {
if (!user?.id) {
return {
canSync: false,
reason: "사용자 인증이 필요합니다.",
lastSyncTime: null,
};
}
const lastSyncTime = getLastSyncTime();
const now = new Date();
const lastSync = lastSyncTime ? new Date(lastSyncTime) : null;
// 마지막 동기화로부터 얼마나 시간이 지났는지 계산
const timeSinceLastSync = lastSync
? Math.floor((now.getTime() - lastSync.getTime()) / 1000 / 60) // 분 단위
: null;
return {
canSync: true,
reason: null,
lastSyncTime,
timeSinceLastSync,
needsSync: !lastSync || timeSinceLastSync > 30, // 30분 이상 지났으면 동기화 필요
};
},
...queryConfigs.userInfo,
enabled: !!user?.id,
});
};
/**
* 수동 동기화 뮤테이션
*
* - 사용자가 수동으로 동기화를 트리거할 때 사용
* - 성공 시 모든 관련 쿼리 무효화
* - 알림 및 토스트 메시지 제공
*/
export const useManualSyncMutation = () => {
const queryClient = useQueryClient();
const { user } = useAuthStore();
const { addNotification } = useNotifications();
return useMutation({
mutationFn: async (): Promise<any> => {
if (!user?.id) {
throw new Error("사용자 인증이 필요합니다.");
}
syncLogger.info("수동 동기화 뮤테이션 시작", { userId: user.id });
// 동기화 실행
const result = await trySyncAllData(user.id);
if (!result.success) {
throw new Error(result.error || "동기화에 실패했습니다.");
}
// 동기화 시간 업데이트
const currentTime = new Date().toISOString();
setLastSyncTime(currentTime);
syncLogger.info("수동 동기화 성공", {
syncTime: currentTime,
result,
});
return { ...result, syncTime: currentTime };
},
// 뮤테이션 시작 시
onMutate: () => {
syncLogger.info("동기화 시작 알림");
addNotification("동기화 시작", "데이터 동기화가 시작되었습니다.");
},
// 성공 시 처리
onSuccess: (result) => {
// 모든 쿼리 무효화하여 최신 데이터 로드
invalidateQueries.all();
// 동기화 관련 쿼리 즉시 업데이트
queryClient.setQueryData(queryKeys.sync.lastSync(), result.syncTime);
// 성공 알림
toast({
title: "동기화 완료",
description: "모든 데이터가 성공적으로 동기화되었습니다.",
});
addNotification(
"동기화 완료",
"모든 데이터가 성공적으로 동기화되었습니다."
);
syncLogger.info("수동 동기화 뮤테이션 성공 완료", result);
},
// 에러 시 처리
onError: (error: any) => {
const friendlyMessage = handleQueryError(error, "동기화");
syncLogger.error("수동 동기화 뮤테이션 실패:", friendlyMessage);
toast({
title: "동기화 실패",
description: friendlyMessage,
variant: "destructive",
});
addNotification("동기화 실패", friendlyMessage);
},
});
};
/**
* 백그라운드 자동 동기화 뮤테이션
*
* - 조용한 동기화 (알림 없음)
* - 에러 시에도 사용자를 방해하지 않음
* - 성공 시에만 데이터 업데이트
*/
export const useBackgroundSyncMutation = () => {
const queryClient = useQueryClient();
const { user } = useAuthStore();
return useMutation({
mutationFn: async (): Promise<any> => {
if (!user?.id) {
throw new Error("사용자 인증이 필요합니다.");
}
syncLogger.info("백그라운드 동기화 시작", { userId: user.id });
const result = await trySyncAllData(user.id);
if (!result.success) {
throw new Error(result.error || "백그라운드 동기화에 실패했습니다.");
}
const currentTime = new Date().toISOString();
setLastSyncTime(currentTime);
syncLogger.info("백그라운드 동기화 성공", {
syncTime: currentTime,
});
return { ...result, syncTime: currentTime };
},
// 성공 시 조용히 데이터 업데이트
onSuccess: (result) => {
// 트랜잭션과 예산 데이터만 조용히 업데이트
invalidateQueries.transactions();
invalidateQueries.budget();
// 동기화 시간 업데이트
queryClient.setQueryData(queryKeys.sync.lastSync(), result.syncTime);
syncLogger.info("백그라운드 동기화 완료 - 데이터 업데이트됨");
},
// 에러 시 조용히 로그만 남김
onError: (error: any) => {
syncLogger.warn(
"백그라운드 동기화 실패 (조용히 처리됨):",
error?.message
);
},
});
};
/**
* 자동 동기화 간격 설정을 위한 쿼리
*
* - 설정된 간격에 따라 백그라운드 동기화 실행
* - 네트워크 상태에 따른 동적 조정
*/
export const useAutoSyncQuery = (intervalMinutes = 5) => {
const { user } = useAuthStore();
const backgroundSyncMutation = useBackgroundSyncMutation();
return useQuery({
queryKey: ["auto-sync", intervalMinutes],
queryFn: async () => {
if (!user?.id) {
return null;
}
// 백그라운드 동기화 실행
if (!backgroundSyncMutation.isPending) {
backgroundSyncMutation.mutate();
}
return new Date().toISOString();
},
enabled: !!user?.id,
refetchInterval: intervalMinutes * 60 * 1000, // 분을 밀리초로 변환
refetchIntervalInBackground: false, // 백그라운드에서는 실행하지 않음
staleTime: Infinity, // 항상 최신으로 유지
gcTime: 0, // 캐시하지 않음
});
};
/**
* 통합 동기화 훅 (기존 useManualSync와 호환성 유지)
*
* React Query 뮤테이션과 기존 인터페이스를 결합
*/
export const useSync = () => {
const { user } = useAuthStore();
const lastSyncQuery = useLastSyncTimeQuery();
const syncStatusQuery = useSyncStatusQuery();
const manualSyncMutation = useManualSyncMutation();
const backgroundSyncMutation = useBackgroundSyncMutation();
return {
// 동기화 상태
lastSyncTime: lastSyncQuery.data,
syncStatus: syncStatusQuery.data,
// 수동 동기화 (기존 handleManualSync와 동일한 인터페이스)
syncing: manualSyncMutation.isPending,
handleManualSync: manualSyncMutation.mutate,
// 백그라운드 동기화
backgroundSyncing: backgroundSyncMutation.isPending,
triggerBackgroundSync: backgroundSyncMutation.mutate,
// 동기화 가능 여부
canSync: !!user?.id && syncStatusQuery.data?.canSync,
// 쿼리 제어
refetchSyncStatus: syncStatusQuery.refetch,
refetchLastSyncTime: lastSyncQuery.refetch,
};
};
/**
* 동기화 설정 관리 훅
*/
export const useSyncSettings = () => {
const queryClient = useQueryClient();
// 자동 동기화 간격 설정 (localStorage 기반)
const setAutoSyncInterval = (intervalMinutes: number) => {
localStorage.setItem("auto-sync-interval", intervalMinutes.toString());
// 관련 쿼리 무효화
queryClient.invalidateQueries({
queryKey: ["auto-sync"],
});
syncLogger.info("자동 동기화 간격 설정됨", { intervalMinutes });
};
const getAutoSyncInterval = (): number => {
const stored = localStorage.getItem("auto-sync-interval");
return stored ? parseInt(stored, 10) : 5; // 기본값 5분
};
return {
setAutoSyncInterval,
getAutoSyncInterval,
currentInterval: getAutoSyncInterval(),
};
};