Fix issue deleting transactions
Fixes an issue where deleting a transaction on the transaction history screen would cause the application to freeze.
This commit is contained in:
@@ -23,16 +23,9 @@ interface TransactionCardProps {
|
||||
|
||||
const TransactionCard: React.FC<TransactionCardProps> = ({
|
||||
transaction,
|
||||
onUpdate
|
||||
}) => {
|
||||
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
||||
const { title, amount, date, category, type } = transaction;
|
||||
|
||||
const handleSaveTransaction = (updatedTransaction: Transaction) => {
|
||||
if (onUpdate) {
|
||||
onUpdate(updatedTransaction);
|
||||
}
|
||||
};
|
||||
const { title, amount, date, category } = transaction;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -54,7 +47,6 @@ const TransactionCard: React.FC<TransactionCardProps> = ({
|
||||
transaction={transaction}
|
||||
open={isEditDialogOpen}
|
||||
onOpenChange={setIsEditDialogOpen}
|
||||
onSave={handleSaveTransaction}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogFooter,
|
||||
DialogClose
|
||||
DialogClose,
|
||||
DialogDescription
|
||||
} from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Form } from '@/components/ui/form';
|
||||
@@ -78,20 +79,19 @@ const TransactionEditDialog: React.FC<TransactionEditDialogProps> = ({
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
// 컨텍스트를 통해 트랜잭션 삭제
|
||||
deleteTransaction(transaction.id);
|
||||
|
||||
// 부모 컴포넌트의 onDelete 콜백이 있다면 호출
|
||||
if (onDelete) {
|
||||
onDelete(transaction.id);
|
||||
}
|
||||
|
||||
// 다이얼로그 닫기를 먼저 수행 (UI 블로킹 방지)
|
||||
onOpenChange(false);
|
||||
|
||||
toast({
|
||||
title: "지출이 삭제되었습니다",
|
||||
description: `${transaction.title} 항목이 삭제되었습니다.`,
|
||||
});
|
||||
// 약간의 지연 후 삭제 작업 수행 (안정성 향상)
|
||||
setTimeout(() => {
|
||||
// 컨텍스트를 통해 트랜잭션 삭제
|
||||
deleteTransaction(transaction.id);
|
||||
|
||||
// 부모 컴포넌트의 onDelete 콜백이 있다면 호출
|
||||
if (onDelete) {
|
||||
onDelete(transaction.id);
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -99,6 +99,9 @@ const TransactionEditDialog: React.FC<TransactionEditDialogProps> = ({
|
||||
<DialogContent className={`sm:max-w-md mx-auto ${isMobile ? 'rounded-xl overflow-hidden' : ''}`}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>지출 수정</DialogTitle>
|
||||
<DialogDescription>
|
||||
지출 내역을 수정하거나 삭제할 수 있습니다.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<Form {...form}>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { Transaction } from '../types';
|
||||
import {
|
||||
@@ -11,6 +12,7 @@ import { toast } from '@/hooks/useToast.wrapper'; // 래퍼 사용
|
||||
export const useTransactionState = () => {
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [lastDeletedId, setLastDeletedId] = useState<string | null>(null);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
// 초기 트랜잭션 로드 및 이벤트 리스너 설정
|
||||
useEffect(() => {
|
||||
@@ -72,9 +74,15 @@ export const useTransactionState = () => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 트랜잭션 삭제 함수
|
||||
// 트랜잭션 삭제 함수 - 안정성 개선
|
||||
const deleteTransaction = useCallback((transactionId: string) => {
|
||||
console.log('트랜잭션 삭제:', transactionId);
|
||||
// 이미 삭제 중이면 중복 삭제 방지
|
||||
if (isDeleting) {
|
||||
console.log('이미 삭제 작업이 진행 중입니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('트랜잭션 삭제 시작:', transactionId);
|
||||
|
||||
// 중복 삭제 방지
|
||||
if (lastDeletedId === transactionId) {
|
||||
@@ -82,24 +90,50 @@ export const useTransactionState = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsDeleting(true);
|
||||
setLastDeletedId(transactionId);
|
||||
|
||||
setTransactions(prev => {
|
||||
const updated = prev.filter(transaction => transaction.id !== transactionId);
|
||||
saveTransactionsToStorage(updated);
|
||||
|
||||
// 토스트는 한 번만 호출
|
||||
toast({
|
||||
title: "지출이 삭제되었습니다",
|
||||
description: "지출 항목이 성공적으로 삭제되었습니다.",
|
||||
try {
|
||||
setTransactions(prev => {
|
||||
// 기존 트랜잭션 목록 백업 (문제 발생 시 복원용)
|
||||
const originalTransactions = [...prev];
|
||||
|
||||
// 삭제할 항목 필터링
|
||||
const updated = prev.filter(transaction => transaction.id !== transactionId);
|
||||
|
||||
// 항목이 실제로 삭제되었는지 확인
|
||||
if (updated.length === originalTransactions.length) {
|
||||
console.log('삭제할 트랜잭션을 찾을 수 없음:', transactionId);
|
||||
setIsDeleting(false);
|
||||
return originalTransactions;
|
||||
}
|
||||
|
||||
// 저장소에 업데이트된 목록 저장
|
||||
saveTransactionsToStorage(updated);
|
||||
|
||||
// 토스트 메시지 표시
|
||||
toast({
|
||||
title: "지출이 삭제되었습니다",
|
||||
description: "지출 항목이 성공적으로 삭제되었습니다.",
|
||||
});
|
||||
|
||||
return updated;
|
||||
});
|
||||
|
||||
return updated;
|
||||
});
|
||||
|
||||
// 5초 후 lastDeletedId 초기화
|
||||
setTimeout(() => setLastDeletedId(null), 5000);
|
||||
}, [lastDeletedId]);
|
||||
} catch (error) {
|
||||
console.error('트랜잭션 삭제 중 오류 발생:', error);
|
||||
toast({
|
||||
title: "삭제 실패",
|
||||
description: "지출 항목 삭제 중 오류가 발생했습니다.",
|
||||
variant: "destructive"
|
||||
});
|
||||
} finally {
|
||||
// 삭제 상태 초기화 (1초 후)
|
||||
setTimeout(() => {
|
||||
setIsDeleting(false);
|
||||
setLastDeletedId(null);
|
||||
}, 1000);
|
||||
}
|
||||
}, [lastDeletedId, isDeleting]);
|
||||
|
||||
// 트랜잭션 초기화 함수
|
||||
const resetTransactions = useCallback(() => {
|
||||
|
||||
@@ -66,6 +66,7 @@ export const useTransactionsCore = () => {
|
||||
|
||||
// 데이터 강제 새로고침
|
||||
const refreshTransactions = useCallback(() => {
|
||||
console.log('트랜잭션 강제 새로고침');
|
||||
setRefreshKey(prev => prev + 1);
|
||||
loadTransactions();
|
||||
}, [loadTransactions, setRefreshKey]);
|
||||
|
||||
@@ -17,8 +17,7 @@ const Transactions = () => {
|
||||
setSearchQuery,
|
||||
handlePrevMonth,
|
||||
handleNextMonth,
|
||||
updateTransaction,
|
||||
deleteTransaction,
|
||||
refreshTransactions,
|
||||
totalExpenses,
|
||||
} = useTransactions();
|
||||
|
||||
@@ -48,15 +47,13 @@ const Transactions = () => {
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
console.log('거래내역 페이지 보임 - 데이터 새로고침');
|
||||
// 상태 업데이트 트리거
|
||||
setIsDataLoaded(prev => !prev);
|
||||
refreshTransactions();
|
||||
}
|
||||
};
|
||||
|
||||
const handleFocus = () => {
|
||||
console.log('거래내역 페이지 포커스 - 데이터 새로고침');
|
||||
// 상태 업데이트 트리거
|
||||
setIsDataLoaded(prev => !prev);
|
||||
refreshTransactions();
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
@@ -66,7 +63,7 @@ const Transactions = () => {
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
window.removeEventListener('focus', handleFocus);
|
||||
};
|
||||
}, []);
|
||||
}, [refreshTransactions]);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-neuro-background pb-24">
|
||||
@@ -168,8 +165,7 @@ const Transactions = () => {
|
||||
{transactions.map(transaction => (
|
||||
<TransactionCard
|
||||
key={transaction.id}
|
||||
transaction={transaction}
|
||||
onUpdate={updateTransaction}
|
||||
transaction={transaction}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user