Refactors the RecentTransactionsSection component into smaller, more manageable components and extracts related logic into separate hooks to improve code organization and maintainability.
118 lines
3.5 KiB
TypeScript
118 lines
3.5 KiB
TypeScript
|
|
import { useCallback, useRef, useState } from 'react';
|
|
import { toast } from '@/hooks/useToast.wrapper';
|
|
|
|
/**
|
|
* 최근 거래내역 관련 로직을 처리하는 커스텀 훅
|
|
* 삭제 로직과 상태 관리 등을 담당
|
|
*/
|
|
export const useRecentTransactions = (
|
|
deleteTransaction: (id: string) => void
|
|
) => {
|
|
const [isDeleting, setIsDeleting] = useState(false);
|
|
|
|
// 삭제 중인 ID 추적
|
|
const deletingIdRef = useRef<string | null>(null);
|
|
|
|
// 타임아웃 추적
|
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
|
|
// 삭제 요청 타임스탬프 추적 (급발진 방지)
|
|
const lastDeleteTimeRef = useRef<Record<string, number>>({});
|
|
|
|
// 완전히 새로운 삭제 처리 함수
|
|
const handleDeleteTransaction = useCallback(async (id: string): Promise<boolean> => {
|
|
return new Promise(resolve => {
|
|
try {
|
|
// 삭제 진행 중인지 확인
|
|
if (isDeleting || deletingIdRef.current === id) {
|
|
console.log('이미 삭제 작업이 진행 중입니다');
|
|
resolve(true);
|
|
return;
|
|
}
|
|
|
|
// 급발진 방지 (300ms)
|
|
const now = Date.now();
|
|
if (lastDeleteTimeRef.current[id] && now - lastDeleteTimeRef.current[id] < 300) {
|
|
console.warn('삭제 요청이 너무 빠릅니다. 무시합니다.');
|
|
resolve(true);
|
|
return;
|
|
}
|
|
|
|
// 타임스탬프 업데이트
|
|
lastDeleteTimeRef.current[id] = now;
|
|
|
|
// 삭제 상태 설정
|
|
setIsDeleting(true);
|
|
deletingIdRef.current = id;
|
|
|
|
// 안전장치: 타임아웃 설정 (최대 900ms)
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
}
|
|
timeoutRef.current = setTimeout(() => {
|
|
console.warn('삭제 타임아웃 - 상태 초기화');
|
|
setIsDeleting(false);
|
|
deletingIdRef.current = null;
|
|
resolve(true); // UI 응답성 위해 성공 간주
|
|
}, 900);
|
|
|
|
// 비동기 작업을 동기적으로 처리하여 UI 블로킹 방지
|
|
setTimeout(async () => {
|
|
try {
|
|
deleteTransaction(id);
|
|
|
|
// 안전장치 타임아웃 제거
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = null;
|
|
}
|
|
|
|
// 상태 초기화 (지연 적용)
|
|
setTimeout(() => {
|
|
setIsDeleting(false);
|
|
deletingIdRef.current = null;
|
|
}, 100);
|
|
} catch (err) {
|
|
console.error('삭제 처리 오류:', err);
|
|
}
|
|
}, 0);
|
|
|
|
// 즉시 성공 반환 (UI 응답성 향상)
|
|
resolve(true);
|
|
} catch (error) {
|
|
console.error('삭제 처리 전체 오류:', error);
|
|
|
|
// 항상 상태 정리
|
|
setIsDeleting(false);
|
|
deletingIdRef.current = null;
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = null;
|
|
}
|
|
toast({
|
|
title: "오류 발생",
|
|
description: "처리 중 문제가 발생했습니다.",
|
|
variant: "destructive",
|
|
duration: 1500
|
|
});
|
|
resolve(false);
|
|
}
|
|
});
|
|
}, [deleteTransaction, isDeleting]);
|
|
|
|
// 컴포넌트 언마운트 시 타임아웃 정리 (리액트 컴포넌트에서 처리해야함)
|
|
const cleanupTimeouts = useCallback(() => {
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = null;
|
|
}
|
|
}, []);
|
|
|
|
return {
|
|
handleDeleteTransaction,
|
|
isDeleting,
|
|
cleanupTimeouts
|
|
};
|
|
};
|