Handle data reset with cloud sync
The prompt requests clarification on whether data reset should also delete cloud data when the user is logged in.
This commit is contained in:
@@ -1,10 +1,12 @@
|
|||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Trash2, Loader2 } from 'lucide-react';
|
import { Trash2, Loader2, CloudOff } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useToast } from '@/hooks/useToast.wrapper';
|
import { useToast } from '@/hooks/useToast.wrapper';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { resetAllStorageData } from '@/utils/storageUtils';
|
import { resetAllStorageData } from '@/utils/storageUtils';
|
||||||
|
import { clearCloudData } from '@/utils/syncUtils';
|
||||||
|
import { useAuth } from '@/contexts/auth/AuthProvider';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -18,15 +20,34 @@ import {
|
|||||||
const DataResetSection = () => {
|
const DataResetSection = () => {
|
||||||
const [isResetDialogOpen, setIsResetDialogOpen] = useState(false);
|
const [isResetDialogOpen, setIsResetDialogOpen] = useState(false);
|
||||||
const [isResetting, setIsResetting] = useState(false);
|
const [isResetting, setIsResetting] = useState(false);
|
||||||
|
const [isCloudResetSuccess, setIsCloudResetSuccess] = useState<boolean | null>(null);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
const handleResetAllData = () => {
|
const handleResetAllData = async () => {
|
||||||
// 데이터 초기화 수행
|
// 데이터 초기화 수행
|
||||||
try {
|
try {
|
||||||
setIsResetting(true);
|
setIsResetting(true);
|
||||||
console.log('모든 데이터 초기화 시작');
|
console.log('모든 데이터 초기화 시작');
|
||||||
|
|
||||||
|
// 클라우드 데이터 초기화 먼저 시도 (로그인 상태인 경우)
|
||||||
|
let cloudResetSuccess = false;
|
||||||
|
if (user) {
|
||||||
|
console.log('로그인 상태: 클라우드 데이터 초기화 시도');
|
||||||
|
cloudResetSuccess = await clearCloudData(user.id);
|
||||||
|
setIsCloudResetSuccess(cloudResetSuccess);
|
||||||
|
|
||||||
|
if (cloudResetSuccess) {
|
||||||
|
console.log('클라우드 데이터 초기화 성공');
|
||||||
|
} else {
|
||||||
|
console.warn('클라우드 데이터 초기화 실패 또는 부분 성공');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('로그인하지 않음: 클라우드 초기화 건너뜀');
|
||||||
|
setIsCloudResetSuccess(null);
|
||||||
|
}
|
||||||
|
|
||||||
// 초기화 실행 전에 사용자 설정 백업
|
// 초기화 실행 전에 사용자 설정 백업
|
||||||
const dontShowWelcomeValue = localStorage.getItem('dontShowWelcome');
|
const dontShowWelcomeValue = localStorage.getItem('dontShowWelcome');
|
||||||
const hasVisitedBefore = localStorage.getItem('hasVisitedBefore');
|
const hasVisitedBefore = localStorage.getItem('hasVisitedBefore');
|
||||||
@@ -77,10 +98,27 @@ const DataResetSection = () => {
|
|||||||
window.dispatchEvent(new StorageEvent('storage'));
|
window.dispatchEvent(new StorageEvent('storage'));
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
toast({
|
// 클라우드 초기화 상태에 따라 다른 메시지 표시
|
||||||
title: "모든 데이터가 초기화되었습니다.",
|
if (user) {
|
||||||
description: "모든 예산, 지출 내역, 설정이 초기화되었습니다.",
|
if (cloudResetSuccess) {
|
||||||
});
|
toast({
|
||||||
|
title: "모든 데이터가 초기화되었습니다.",
|
||||||
|
description: "로컬 및 클라우드의 모든 데이터가 초기화되었습니다.",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "로컬 데이터만 초기화됨",
|
||||||
|
description: "로컬 데이터는 초기화되었지만, 클라우드 데이터 초기화 중 문제가 발생했습니다.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "모든 데이터가 초기화되었습니다.",
|
||||||
|
description: "모든 예산, 지출 내역, 설정이 초기화되었습니다.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setIsResetDialogOpen(false);
|
setIsResetDialogOpen(false);
|
||||||
console.log('모든 데이터 초기화 완료');
|
console.log('모든 데이터 초기화 완료');
|
||||||
|
|
||||||
@@ -108,7 +146,9 @@ const DataResetSection = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<h3 className="font-medium">데이터 초기화</h3>
|
<h3 className="font-medium">데이터 초기화</h3>
|
||||||
<p className="text-xs text-gray-500 mt-1">모든 예산, 지출 내역, 설정이 초기화됩니다.</p>
|
<p className="text-xs text-gray-500 mt-1">
|
||||||
|
{user ? "로컬 및 클라우드의 모든 예산, 지출 내역이 초기화됩니다." : "모든 예산, 지출 내역, 설정이 초기화됩니다."}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
@@ -127,8 +167,20 @@ const DataResetSection = () => {
|
|||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>정말 모든 데이터를 초기화하시겠습니까?</DialogTitle>
|
<DialogTitle>정말 모든 데이터를 초기화하시겠습니까?</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
이 작업은 되돌릴 수 없으며, 모든 예산, 지출 내역, 설정이 영구적으로 삭제됩니다.
|
{user ? (
|
||||||
단, '환영합니다' 화면 표시 설정과 로그인 상태는 유지됩니다.
|
<>
|
||||||
|
이 작업은 되돌릴 수 없으며, 로컬 및 클라우드에 저장된 모든 예산, 지출 내역이 영구적으로 삭제됩니다.
|
||||||
|
<div className="flex items-center mt-2 text-amber-600">
|
||||||
|
<CloudOff size={16} className="mr-2" />
|
||||||
|
클라우드 데이터도 함께 삭제됩니다.
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
"이 작업은 되돌릴 수 없으며, 모든 예산, 지출 내역, 설정이 영구적으로 삭제됩니다."
|
||||||
|
)}
|
||||||
|
<div className="mt-2">
|
||||||
|
단, '환영합니다' 화면 표시 설정과 로그인 상태는 유지됩니다.
|
||||||
|
</div>
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogFooter className="flex flex-col sm:flex-row gap-2 sm:gap-0">
|
<DialogFooter className="flex flex-col sm:flex-row gap-2 sm:gap-0">
|
||||||
@@ -145,7 +197,7 @@ const DataResetSection = () => {
|
|||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
초기화 중...
|
초기화 중...
|
||||||
</>
|
</>
|
||||||
) : '확인, 모든 데이터 초기화'}
|
) : user ? '확인, 로컬 및 클라우드 데이터 초기화' : '확인, 모든 데이터 초기화'}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { resetAllData } from '@/contexts/budget/storage';
|
import { resetAllData } from '@/contexts/budget/storage';
|
||||||
import { resetAllStorageData } from '@/utils/storageUtils';
|
import { resetAllStorageData } from '@/utils/storageUtils';
|
||||||
|
import { clearCloudData } from '@/utils/syncUtils';
|
||||||
|
import { useAuth } from '@/contexts/auth/AuthProvider';
|
||||||
|
|
||||||
export const useDataInitialization = (resetBudgetData?: () => void) => {
|
export const useDataInitialization = (resetBudgetData?: () => void) => {
|
||||||
const [isInitialized, setIsInitialized] = useState(false);
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
// 모든 데이터 초기화 함수
|
// 모든 데이터 초기화 함수
|
||||||
const initializeAllData = useCallback(() => {
|
const initializeAllData = useCallback(async () => {
|
||||||
// 중요: 이미 방문한 적이 있으면 절대 초기화하지 않음
|
// 중요: 이미 방문한 적이 있으면 절대 초기화하지 않음
|
||||||
const hasVisitedBefore = localStorage.getItem('hasVisitedBefore') === 'true';
|
const hasVisitedBefore = localStorage.getItem('hasVisitedBefore') === 'true';
|
||||||
if (hasVisitedBefore) {
|
if (hasVisitedBefore) {
|
||||||
@@ -23,6 +25,12 @@ export const useDataInitialization = (resetBudgetData?: () => void) => {
|
|||||||
console.log('useDataInitialization - 초기화 전 dontShowWelcome 값:', dontShowWelcomeValue);
|
console.log('useDataInitialization - 초기화 전 dontShowWelcome 값:', dontShowWelcomeValue);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// 로그인 상태라면 클라우드 데이터도 초기화 (첫 방문 시)
|
||||||
|
if (user) {
|
||||||
|
console.log('로그인 상태: 클라우드 데이터도 초기화 시도');
|
||||||
|
await clearCloudData(user.id);
|
||||||
|
}
|
||||||
|
|
||||||
// 모든 데이터 완전히 삭제 및 초기화 (한 번만 실행)
|
// 모든 데이터 완전히 삭제 및 초기화 (한 번만 실행)
|
||||||
resetAllData();
|
resetAllData();
|
||||||
resetAllStorageData();
|
resetAllStorageData();
|
||||||
@@ -48,7 +56,7 @@ export const useDataInitialization = (resetBudgetData?: () => void) => {
|
|||||||
console.error('데이터 초기화 중 오류 발생:', error);
|
console.error('데이터 초기화 중 오류 발생:', error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}, [resetBudgetData]);
|
}, [resetBudgetData, user]);
|
||||||
|
|
||||||
// 분석 페이지 데이터 초기화 함수
|
// 분석 페이지 데이터 초기화 함수
|
||||||
const clearAllAnalyticsData = useCallback(() => {
|
const clearAllAnalyticsData = useCallback(() => {
|
||||||
@@ -100,8 +108,9 @@ export const useDataInitialization = (resetBudgetData?: () => void) => {
|
|||||||
console.log('이미 방문 기록이 있어 초기화를 건너뜁니다.');
|
console.log('이미 방문 기록이 있어 초기화를 건너뜁니다.');
|
||||||
setIsInitialized(true);
|
setIsInitialized(true);
|
||||||
} else {
|
} else {
|
||||||
const result = initializeAllData();
|
initializeAllData().then(result => {
|
||||||
setIsInitialized(result);
|
setIsInitialized(result);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
67
src/utils/sync/clearCloudData.ts
Normal file
67
src/utils/sync/clearCloudData.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
import { supabase } from '@/lib/supabase';
|
||||||
|
import { isSyncEnabled } from './syncSettings';
|
||||||
|
import { toast } from '@/hooks/useToast.wrapper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supabase에 저장된 사용자의 모든 데이터 삭제
|
||||||
|
*/
|
||||||
|
export const clearCloudData = async (userId: string): Promise<boolean> => {
|
||||||
|
if (!userId || !isSyncEnabled()) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('클라우드 데이터 초기화 시작...');
|
||||||
|
|
||||||
|
// 트랜잭션 데이터 삭제
|
||||||
|
const { error: txError } = await supabase
|
||||||
|
.from('transactions')
|
||||||
|
.delete()
|
||||||
|
.eq('user_id', userId);
|
||||||
|
|
||||||
|
if (txError) {
|
||||||
|
console.error('클라우드 트랜잭션 삭제 오류:', txError);
|
||||||
|
throw txError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 예산 데이터 삭제 (budgets 테이블이 있는 경우)
|
||||||
|
try {
|
||||||
|
const { error: budgetError } = await supabase
|
||||||
|
.from('budgets')
|
||||||
|
.delete()
|
||||||
|
.eq('user_id', userId);
|
||||||
|
|
||||||
|
if (budgetError) {
|
||||||
|
console.error('클라우드 예산 삭제 오류:', budgetError);
|
||||||
|
// 이 오류는 심각하지 않으므로 진행 계속
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log('budgets 테이블이 없거나 삭제 중 오류 발생:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 카테고리 예산 데이터 삭제 (category_budgets 테이블이 있는 경우)
|
||||||
|
try {
|
||||||
|
const { error: catBudgetError } = await supabase
|
||||||
|
.from('category_budgets')
|
||||||
|
.delete()
|
||||||
|
.eq('user_id', userId);
|
||||||
|
|
||||||
|
if (catBudgetError) {
|
||||||
|
console.error('클라우드 카테고리 예산 삭제 오류:', catBudgetError);
|
||||||
|
// 이 오류는 심각하지 않으므로 진행 계속
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log('category_budgets 테이블이 없거나 삭제 중 오류 발생:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('클라우드 데이터 초기화 완료');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('클라우드 데이터 초기화 중 오류 발생:', error);
|
||||||
|
toast({
|
||||||
|
title: "클라우드 데이터 초기화 실패",
|
||||||
|
description: "서버에서 데이터를 삭제하는 중 문제가 발생했습니다.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import { isSyncEnabled, setSyncEnabled, getLastSyncTime, setLastSyncTime, initSyncSettings } from './sync/syncSettings';
|
import { isSyncEnabled, setSyncEnabled, getLastSyncTime, setLastSyncTime, initSyncSettings } from './sync/syncSettings';
|
||||||
import { uploadTransactions, downloadTransactions, deleteTransactionFromServer } from './sync/transactionSync';
|
import { uploadTransactions, downloadTransactions, deleteTransactionFromServer } from './sync/transactionSync';
|
||||||
import { uploadBudgets, downloadBudgets } from './sync/budget';
|
import { uploadBudgets, downloadBudgets } from './sync/budget';
|
||||||
|
import { clearCloudData } from './sync/clearCloudData';
|
||||||
|
|
||||||
// Export all utility functions to maintain the same public API
|
// Export all utility functions to maintain the same public API
|
||||||
export {
|
export {
|
||||||
@@ -14,7 +14,8 @@ export {
|
|||||||
downloadBudgets,
|
downloadBudgets,
|
||||||
getLastSyncTime,
|
getLastSyncTime,
|
||||||
setLastSyncTime,
|
setLastSyncTime,
|
||||||
initSyncSettings
|
initSyncSettings,
|
||||||
|
clearCloudData
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user