Fix: Display correct expense amount in monthly budget
The monthly budget and spending were not displaying the correct expense amount after adding an expense. This commit fixes the issue.
This commit is contained in:
@@ -1,12 +1,20 @@
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { FilteringProps, FilteringReturn } from './types';
|
||||
import { useMonthSelection } from './useMonthSelection';
|
||||
import { useFilterApplication } from './useFilterApplication';
|
||||
import { useTotalCalculation } from './useTotalCalculation';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { Transaction } from '@/contexts/budget/types';
|
||||
import { getCurrentMonth, getPrevMonth, getNextMonth } from '../dateUtils';
|
||||
import { filterTransactionsByMonth, filterTransactionsByQuery, calculateTotalExpenses } from '../filterUtils';
|
||||
|
||||
interface UseTransactionsFilteringProps {
|
||||
transactions: Transaction[];
|
||||
selectedMonth: string;
|
||||
setSelectedMonth: (month: string) => void;
|
||||
searchQuery: string;
|
||||
setFilteredTransactions: React.Dispatch<React.SetStateAction<Transaction[]>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 트랜잭션 필터링 관련 기능을 통합한 훅
|
||||
* 트랜잭션 필터링 관련 커스텀 훅
|
||||
* 월간, 검색어 필터링 및 총 지출 계산 기능을 제공합니다.
|
||||
*/
|
||||
export const useTransactionsFiltering = ({
|
||||
transactions,
|
||||
@@ -14,34 +22,52 @@ export const useTransactionsFiltering = ({
|
||||
setSelectedMonth,
|
||||
searchQuery,
|
||||
setFilteredTransactions
|
||||
}: FilteringProps): FilteringReturn => {
|
||||
// 월 선택 관련 기능
|
||||
const { handlePrevMonth, handleNextMonth } = useMonthSelection({
|
||||
selectedMonth,
|
||||
setSelectedMonth
|
||||
});
|
||||
}: UseTransactionsFilteringProps) => {
|
||||
// 필터링 적용
|
||||
useEffect(() => {
|
||||
console.log('트랜잭션 필터링 적용:', { 선택된월: selectedMonth, 검색어: searchQuery });
|
||||
|
||||
try {
|
||||
// 먼저 월별 필터링
|
||||
const monthFiltered = filterTransactionsByMonth(transactions, selectedMonth);
|
||||
console.log('월별 필터링 결과:', monthFiltered.length);
|
||||
|
||||
// 그 다음 검색어 필터링
|
||||
const searchFiltered = searchQuery
|
||||
? filterTransactionsByQuery(monthFiltered, searchQuery)
|
||||
: monthFiltered;
|
||||
|
||||
console.log('최종 필터링 결과:', searchFiltered.length);
|
||||
setFilteredTransactions(searchFiltered);
|
||||
|
||||
} catch (error) {
|
||||
console.error('트랜잭션 필터링 중 오류 발생:', error);
|
||||
// 오류 발생 시 원본 데이터 유지
|
||||
setFilteredTransactions(transactions);
|
||||
}
|
||||
}, [transactions, selectedMonth, searchQuery, setFilteredTransactions]);
|
||||
|
||||
// 필터 적용 관련 기능
|
||||
const { filterTransactions } = useFilterApplication({
|
||||
transactions,
|
||||
selectedMonth,
|
||||
searchQuery,
|
||||
setFilteredTransactions
|
||||
});
|
||||
// 이전 달로 이동
|
||||
const handlePrevMonth = useCallback(() => {
|
||||
setSelectedMonth(getPrevMonth(selectedMonth));
|
||||
}, [selectedMonth, setSelectedMonth]);
|
||||
|
||||
// 총 지출 계산 관련 기능
|
||||
const { getTotalExpenses } = useTotalCalculation();
|
||||
// 다음 달로 이동
|
||||
const handleNextMonth = useCallback(() => {
|
||||
setSelectedMonth(getNextMonth(selectedMonth));
|
||||
}, [selectedMonth, setSelectedMonth]);
|
||||
|
||||
// 강제 필터링 실행 함수 (외부에서 호출 가능)
|
||||
const forceRefresh = useCallback(() => {
|
||||
console.log('필터 강제 새로고침');
|
||||
filterTransactions();
|
||||
}, [filterTransactions]);
|
||||
// 총 지출 계산 - date-fns 없이도 사용 가능한 단순 버전
|
||||
const getTotalExpenses = useCallback((filteredTransactions: Transaction[]): number => {
|
||||
console.log('총 지출 계산 중...', filteredTransactions.length);
|
||||
const total = calculateTotalExpenses(filteredTransactions);
|
||||
console.log('계산된 총 지출:', total);
|
||||
return total;
|
||||
}, []);
|
||||
|
||||
return {
|
||||
handlePrevMonth,
|
||||
handleNextMonth,
|
||||
getTotalExpenses,
|
||||
forceRefresh
|
||||
getTotalExpenses
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,63 +1,108 @@
|
||||
|
||||
import { Transaction } from '@/components/TransactionCard';
|
||||
import { MONTHS_KR } from './dateUtils';
|
||||
import { Transaction } from '@/contexts/budget/types';
|
||||
|
||||
// 월별 거래 필터링
|
||||
export const filterTransactionsByMonth = (transactions: Transaction[], selectedMonth: string): Transaction[] => {
|
||||
console.log('월별 필터링:', selectedMonth, '트랜잭션 수:', transactions.length);
|
||||
/**
|
||||
* 월별로 트랜잭션 필터링
|
||||
*/
|
||||
export const filterTransactionsByMonth = (
|
||||
transactions: Transaction[],
|
||||
selectedMonth: string
|
||||
): Transaction[] => {
|
||||
console.log(`월별 트랜잭션 필터링: ${selectedMonth}, 총 데이터 수: ${transactions.length}`);
|
||||
|
||||
// 현재 날짜 정보
|
||||
const now = new Date();
|
||||
const currentYear = now.getFullYear();
|
||||
const currentMonth = now.getMonth() + 1; // JavaScript 월은 0부터 시작
|
||||
|
||||
// 선택된 월의 인덱스 (0-11)
|
||||
const selectedMonthIndex = MONTHS_KR.findIndex(month => month === selectedMonth);
|
||||
|
||||
// 특수 케이스 처리: '이번 달', '오늘', '이번 주' 등
|
||||
if (transactions.some(t => t.date.includes('오늘') || t.date.includes('어제') || t.date.includes('이번주'))) {
|
||||
return transactions;
|
||||
// 필터링 전 샘플 데이터 로그
|
||||
if (transactions.length > 0) {
|
||||
console.log('샘플 트랜잭션 날짜:', transactions.slice(0, 3).map(t => t.date));
|
||||
}
|
||||
|
||||
// 실제 필터링
|
||||
return transactions.filter(transaction => {
|
||||
// 날짜 형식이 '2023-05-15' 또는 '2023/05/15' 등의 형식인 경우
|
||||
if (transaction.date.includes('-') || transaction.date.includes('/')) {
|
||||
const parts = transaction.date.split(/[-\/]/);
|
||||
if (parts.length >= 2) {
|
||||
const transactionMonth = parseInt(parts[1]);
|
||||
const monthIndex = transactionMonth - 1; // 0-11 인덱스로 변환
|
||||
return monthIndex === selectedMonthIndex;
|
||||
}
|
||||
const filtered = transactions.filter(transaction => {
|
||||
// 트랜잭션 타입 확인 - 지출 항목만 포함
|
||||
if (transaction.type !== 'expense') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 날짜에 월이 포함된 경우 (예: '5월 15일')
|
||||
for (let i = 0; i < MONTHS_KR.length; i++) {
|
||||
if (transaction.date.includes(MONTHS_KR[i])) {
|
||||
return MONTHS_KR[i] === selectedMonth;
|
||||
try {
|
||||
// 날짜가 없는 경우 필터링 제외
|
||||
if (!transaction.date) {
|
||||
console.warn('날짜 없는 트랜잭션:', transaction);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 현재 월 포함 확인 (다양한 형식 지원)
|
||||
const dateIncludes = transaction.date.includes(selectedMonth);
|
||||
|
||||
// 월 이름으로 확인 (한글)
|
||||
const monthNumberMatch = selectedMonth.match(/\d{4}-(\d{2})/);
|
||||
let monthNameIncluded = false;
|
||||
|
||||
if (monthNumberMatch) {
|
||||
const monthNumber = parseInt(monthNumberMatch[1]);
|
||||
const koreanMonths = [
|
||||
'1월', '2월', '3월', '4월', '5월', '6월',
|
||||
'7월', '8월', '9월', '10월', '11월', '12월'
|
||||
];
|
||||
|
||||
// 해당 월의 한글 이름이 트랜잭션 날짜에 포함되어 있는지 확인
|
||||
if (monthNumber >= 1 && monthNumber <= 12) {
|
||||
monthNameIncluded = transaction.date.includes(koreanMonths[monthNumber - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return dateIncludes || monthNameIncluded;
|
||||
} catch (e) {
|
||||
console.error('트랜잭션 필터링 중 오류:', e, transaction);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 기본적으로 모든 트랜잭션 표시 (필터링 실패 시)
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
// 검색어로 거래 필터링
|
||||
export const filterTransactionsByQuery = (transactions: Transaction[], query: string): Transaction[] => {
|
||||
if (!query.trim()) return transactions;
|
||||
|
||||
const lowercaseQuery = query.toLowerCase();
|
||||
return transactions.filter(transaction =>
|
||||
transaction.title.toLowerCase().includes(lowercaseQuery) ||
|
||||
transaction.category.toLowerCase().includes(lowercaseQuery) ||
|
||||
transaction.amount.toString().includes(lowercaseQuery)
|
||||
);
|
||||
console.log(`월별 필터링 결과: ${filtered.length}개 항목 (${selectedMonth})`);
|
||||
return filtered;
|
||||
};
|
||||
|
||||
// 총 지출 계산
|
||||
export const calculateTotalExpenses = (transactions: Transaction[]): number => {
|
||||
return transactions
|
||||
.filter(t => t.type === 'expense')
|
||||
.reduce((total, transaction) => total + transaction.amount, 0);
|
||||
/**
|
||||
* 검색어로 트랜잭션 필터링
|
||||
*/
|
||||
export const filterTransactionsByQuery = (
|
||||
transactions: Transaction[],
|
||||
searchQuery: string
|
||||
): Transaction[] => {
|
||||
if (!searchQuery.trim()) return transactions;
|
||||
|
||||
const query = searchQuery.toLowerCase().trim();
|
||||
console.log(`검색어 필터링: "${query}"`);
|
||||
|
||||
const filtered = transactions.filter(transaction => {
|
||||
try {
|
||||
return (
|
||||
(transaction.title?.toLowerCase().includes(query)) ||
|
||||
(transaction.category?.toLowerCase().includes(query)) ||
|
||||
(transaction.paymentMethod?.toLowerCase().includes(query))
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('검색어 필터링 중 오류:', e, transaction);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`검색어 필터링 결과: ${filtered.length}개 항목`);
|
||||
return filtered;
|
||||
};
|
||||
|
||||
/**
|
||||
* 총 지출 금액 계산
|
||||
*/
|
||||
export const calculateTotalExpenses = (transactions: Transaction[]): number => {
|
||||
try {
|
||||
const total = transactions.reduce((sum, t) => {
|
||||
// 유효한 숫자인지 확인
|
||||
const amount = typeof t.amount === 'number' ? t.amount : 0;
|
||||
return sum + amount;
|
||||
}, 0);
|
||||
|
||||
console.log(`총 지출 계산: ${total}원 (${transactions.length}개 항목)`);
|
||||
return total;
|
||||
} catch (e) {
|
||||
console.error('총 지출 계산 중 오류:', e);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user