Refactor DataResetSection component
Refactor DataResetSection component into smaller components and extract logic into a separate hook for better maintainability.
This commit is contained in:
74
src/components/security/DataResetDialog.tsx
Normal file
74
src/components/security/DataResetDialog.tsx
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { CloudOff, Loader2 } from 'lucide-react';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogClose
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
|
||||||
|
interface DataResetDialogProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
onConfirm: () => Promise<void>;
|
||||||
|
isResetting: boolean;
|
||||||
|
isLoggedIn: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DataResetDialog: React.FC<DataResetDialogProps> = ({
|
||||||
|
isOpen,
|
||||||
|
onOpenChange,
|
||||||
|
onConfirm,
|
||||||
|
isResetting,
|
||||||
|
isLoggedIn
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Dialog open={isOpen} onOpenChange={onOpenChange}>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>정말 모든 데이터를 초기화하시겠습니까?</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
{isLoggedIn ? (
|
||||||
|
<>
|
||||||
|
이 작업은 되돌릴 수 없으며, 로컬 및 클라우드에 저장된 모든 예산, 지출 내역이 영구적으로 삭제됩니다.
|
||||||
|
<div className="flex items-center mt-2 text-amber-600">
|
||||||
|
<CloudOff size={16} className="mr-2" />
|
||||||
|
클라우드 데이터도 함께 삭제됩니다.
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
"이 작업은 되돌릴 수 없으며, 모든 예산, 지출 내역, 설정이 영구적으로 삭제됩니다."
|
||||||
|
)}
|
||||||
|
<div className="mt-2">
|
||||||
|
단, '환영합니다' 화면 표시 설정과 로그인 상태는 유지됩니다.
|
||||||
|
</div>
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<DialogFooter className="flex flex-col sm:flex-row gap-2 sm:gap-0">
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button variant="outline" className="sm:mr-2" disabled={isResetting}>취소</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
onClick={onConfirm}
|
||||||
|
disabled={isResetting}
|
||||||
|
>
|
||||||
|
{isResetting ? (
|
||||||
|
<>
|
||||||
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
초기화 중...
|
||||||
|
</>
|
||||||
|
) : isLoggedIn ? '확인, 로컬 및 클라우드 데이터 초기화' : '확인, 모든 데이터 초기화'}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DataResetDialog;
|
||||||
@@ -1,140 +1,19 @@
|
|||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Trash2, Loader2, CloudOff } from 'lucide-react';
|
import { Trash2 } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useToast } from '@/hooks/useToast.wrapper';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { resetAllStorageData } from '@/utils/storageUtils';
|
|
||||||
import { clearCloudData } from '@/utils/syncUtils';
|
|
||||||
import { useAuth } from '@/contexts/auth/AuthProvider';
|
import { useAuth } from '@/contexts/auth/AuthProvider';
|
||||||
import {
|
import { useDataReset } from '@/hooks/useDataReset';
|
||||||
Dialog,
|
import DataResetDialog from './DataResetDialog';
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogClose
|
|
||||||
} from '@/components/ui/dialog';
|
|
||||||
|
|
||||||
const DataResetSection = () => {
|
const DataResetSection = () => {
|
||||||
const [isResetDialogOpen, setIsResetDialogOpen] = useState(false);
|
const [isResetDialogOpen, setIsResetDialogOpen] = useState(false);
|
||||||
const [isResetting, setIsResetting] = useState(false);
|
|
||||||
const [isCloudResetSuccess, setIsCloudResetSuccess] = useState<boolean | null>(null);
|
|
||||||
const { toast } = useToast();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
const { isResetting, resetAllData } = useDataReset();
|
||||||
|
|
||||||
const handleResetAllData = async () => {
|
const handleResetAllData = async () => {
|
||||||
// 데이터 초기화 수행
|
await resetAllData();
|
||||||
try {
|
|
||||||
setIsResetting(true);
|
|
||||||
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 hasVisitedBefore = localStorage.getItem('hasVisitedBefore');
|
|
||||||
|
|
||||||
// 로그인 관련 설정 백업 (supabase 관련 모든 설정)
|
|
||||||
const authBackupItems: Record<string, string | null> = {};
|
|
||||||
|
|
||||||
// 로그인 관련 항목 수집
|
|
||||||
for (let i = 0; i < localStorage.length; i++) {
|
|
||||||
const key = localStorage.key(i);
|
|
||||||
if (key && (
|
|
||||||
key.includes('supabase') ||
|
|
||||||
key.includes('auth') ||
|
|
||||||
key.includes('sb-') ||
|
|
||||||
key.includes('token') ||
|
|
||||||
key.includes('user') ||
|
|
||||||
key.includes('session')
|
|
||||||
)) {
|
|
||||||
authBackupItems[key] = localStorage.getItem(key);
|
|
||||||
console.log(`백업 항목: ${key}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 데이터 초기화
|
|
||||||
resetAllStorageData();
|
|
||||||
|
|
||||||
// 사용자 설정 복원
|
|
||||||
if (dontShowWelcomeValue) {
|
|
||||||
localStorage.setItem('dontShowWelcome', dontShowWelcomeValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasVisitedBefore) {
|
|
||||||
localStorage.setItem('hasVisitedBefore', hasVisitedBefore);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 로그인 관련 설정 복원 (로그인 화면이 나타나지 않도록)
|
|
||||||
Object.entries(authBackupItems).forEach(([key, value]) => {
|
|
||||||
if (value) {
|
|
||||||
localStorage.setItem(key, value);
|
|
||||||
console.log(`복원 항목: ${key}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 스토리지 이벤트 트리거하여 다른 컴포넌트에 변경 알림
|
|
||||||
window.dispatchEvent(new Event('transactionUpdated'));
|
|
||||||
window.dispatchEvent(new Event('budgetDataUpdated'));
|
|
||||||
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
|
|
||||||
window.dispatchEvent(new StorageEvent('storage'));
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
// 클라우드 초기화 상태에 따라 다른 메시지 표시
|
|
||||||
if (user) {
|
|
||||||
if (cloudResetSuccess) {
|
|
||||||
toast({
|
|
||||||
title: "모든 데이터가 초기화되었습니다.",
|
|
||||||
description: "로컬 및 클라우드의 모든 데이터가 초기화되었습니다.",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
toast({
|
|
||||||
title: "로컬 데이터만 초기화됨",
|
|
||||||
description: "로컬 데이터는 초기화되었지만, 클라우드 데이터 초기화 중 문제가 발생했습니다.",
|
|
||||||
variant: "destructive"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
toast({
|
|
||||||
title: "모든 데이터가 초기화되었습니다.",
|
|
||||||
description: "모든 예산, 지출 내역, 설정이 초기화되었습니다.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsResetDialogOpen(false);
|
setIsResetDialogOpen(false);
|
||||||
console.log('모든 데이터 초기화 완료');
|
|
||||||
|
|
||||||
// 초기화 후 설정 페이지로 이동
|
|
||||||
setTimeout(() => navigate('/settings'), 500);
|
|
||||||
}, 500);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('데이터 초기화 실패:', error);
|
|
||||||
toast({
|
|
||||||
title: "데이터 초기화 실패",
|
|
||||||
description: "데이터를 초기화하는 중 문제가 발생했습니다.",
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setIsResetting(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -161,47 +40,13 @@ const DataResetSection = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Reset Dialog */}
|
<DataResetDialog
|
||||||
<Dialog open={isResetDialogOpen} onOpenChange={setIsResetDialogOpen}>
|
isOpen={isResetDialogOpen}
|
||||||
<DialogContent>
|
onOpenChange={setIsResetDialogOpen}
|
||||||
<DialogHeader>
|
onConfirm={handleResetAllData}
|
||||||
<DialogTitle>정말 모든 데이터를 초기화하시겠습니까?</DialogTitle>
|
isResetting={isResetting}
|
||||||
<DialogDescription>
|
isLoggedIn={!!user}
|
||||||
{user ? (
|
/>
|
||||||
<>
|
|
||||||
이 작업은 되돌릴 수 없으며, 로컬 및 클라우드에 저장된 모든 예산, 지출 내역이 영구적으로 삭제됩니다.
|
|
||||||
<div className="flex items-center mt-2 text-amber-600">
|
|
||||||
<CloudOff size={16} className="mr-2" />
|
|
||||||
클라우드 데이터도 함께 삭제됩니다.
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
"이 작업은 되돌릴 수 없으며, 모든 예산, 지출 내역, 설정이 영구적으로 삭제됩니다."
|
|
||||||
)}
|
|
||||||
<div className="mt-2">
|
|
||||||
단, '환영합니다' 화면 표시 설정과 로그인 상태는 유지됩니다.
|
|
||||||
</div>
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
<DialogFooter className="flex flex-col sm:flex-row gap-2 sm:gap-0">
|
|
||||||
<DialogClose asChild>
|
|
||||||
<Button variant="outline" className="sm:mr-2" disabled={isResetting}>취소</Button>
|
|
||||||
</DialogClose>
|
|
||||||
<Button
|
|
||||||
variant="destructive"
|
|
||||||
onClick={handleResetAllData}
|
|
||||||
disabled={isResetting}
|
|
||||||
>
|
|
||||||
{isResetting ? (
|
|
||||||
<>
|
|
||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
||||||
초기화 중...
|
|
||||||
</>
|
|
||||||
) : user ? '확인, 로컬 및 클라우드 데이터 초기화' : '확인, 모든 데이터 초기화'}
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
136
src/hooks/useDataReset.ts
Normal file
136
src/hooks/useDataReset.ts
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useToast } from '@/hooks/useToast.wrapper';
|
||||||
|
import { resetAllStorageData } from '@/utils/storageUtils';
|
||||||
|
import { clearCloudData } from '@/utils/syncUtils';
|
||||||
|
import { useAuth } from '@/contexts/auth/AuthProvider';
|
||||||
|
|
||||||
|
export interface DataResetResult {
|
||||||
|
isCloudResetSuccess: boolean | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDataReset = () => {
|
||||||
|
const [isResetting, setIsResetting] = useState(false);
|
||||||
|
const [isCloudResetSuccess, setIsCloudResetSuccess] = useState<boolean | null>(null);
|
||||||
|
const { toast } = useToast();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
|
const resetAllData = async (): Promise<DataResetResult> => {
|
||||||
|
try {
|
||||||
|
setIsResetting(true);
|
||||||
|
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 hasVisitedBefore = localStorage.getItem('hasVisitedBefore');
|
||||||
|
|
||||||
|
// 로그인 관련 설정 백업 (supabase 관련 모든 설정)
|
||||||
|
const authBackupItems: Record<string, string | null> = {};
|
||||||
|
|
||||||
|
// 로그인 관련 항목 수집
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
const key = localStorage.key(i);
|
||||||
|
if (key && (
|
||||||
|
key.includes('supabase') ||
|
||||||
|
key.includes('auth') ||
|
||||||
|
key.includes('sb-') ||
|
||||||
|
key.includes('token') ||
|
||||||
|
key.includes('user') ||
|
||||||
|
key.includes('session')
|
||||||
|
)) {
|
||||||
|
authBackupItems[key] = localStorage.getItem(key);
|
||||||
|
console.log(`백업 항목: ${key}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 데이터 초기화
|
||||||
|
resetAllStorageData();
|
||||||
|
|
||||||
|
// 사용자 설정 복원
|
||||||
|
if (dontShowWelcomeValue) {
|
||||||
|
localStorage.setItem('dontShowWelcome', dontShowWelcomeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasVisitedBefore) {
|
||||||
|
localStorage.setItem('hasVisitedBefore', hasVisitedBefore);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 로그인 관련 설정 복원 (로그인 화면이 나타나지 않도록)
|
||||||
|
Object.entries(authBackupItems).forEach(([key, value]) => {
|
||||||
|
if (value) {
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
console.log(`복원 항목: ${key}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 스토리지 이벤트 트리거하여 다른 컴포넌트에 변경 알림
|
||||||
|
window.dispatchEvent(new Event('transactionUpdated'));
|
||||||
|
window.dispatchEvent(new Event('budgetDataUpdated'));
|
||||||
|
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
|
||||||
|
window.dispatchEvent(new StorageEvent('storage'));
|
||||||
|
|
||||||
|
// 클라우드 초기화 상태에 따라 다른 메시지 표시
|
||||||
|
if (user) {
|
||||||
|
if (cloudResetSuccess) {
|
||||||
|
toast({
|
||||||
|
title: "모든 데이터가 초기화되었습니다.",
|
||||||
|
description: "로컬 및 클라우드의 모든 데이터가 초기화되었습니다.",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "로컬 데이터만 초기화됨",
|
||||||
|
description: "로컬 데이터는 초기화되었지만, 클라우드 데이터 초기화 중 문제가 발생했습니다.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "모든 데이터가 초기화되었습니다.",
|
||||||
|
description: "모든 예산, 지출 내역, 설정이 초기화되었습니다.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('모든 데이터 초기화 완료');
|
||||||
|
|
||||||
|
// 초기화 후 설정 페이지로 이동 (타임아웃으로 약간 지연)
|
||||||
|
setTimeout(() => navigate('/settings'), 500);
|
||||||
|
|
||||||
|
return { isCloudResetSuccess: cloudResetSuccess };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('데이터 초기화 실패:', error);
|
||||||
|
toast({
|
||||||
|
title: "데이터 초기화 실패",
|
||||||
|
description: "데이터를 초기화하는 중 문제가 발생했습니다.",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
return { isCloudResetSuccess: false };
|
||||||
|
} finally {
|
||||||
|
setIsResetting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isResetting,
|
||||||
|
isCloudResetSuccess,
|
||||||
|
resetAllData
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user