Refactor useTransactions hook
Refactor the useTransactions hook into smaller, more manageable files to improve code organization and maintainability. All existing functionality is preserved.
This commit is contained in:
@@ -1,218 +1,10 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { Transaction } from '@/components/TransactionCard';
|
||||
import { useAuth } from '@/contexts/auth/AuthProvider';
|
||||
import { toast } from '@/hooks/useToast.wrapper';
|
||||
import {
|
||||
getCurrentMonth,
|
||||
getPrevMonth,
|
||||
getNextMonth
|
||||
} from './dateUtils';
|
||||
import {
|
||||
filterTransactionsByMonth,
|
||||
filterTransactionsByQuery,
|
||||
calculateTotalExpenses
|
||||
} from './filterUtils';
|
||||
import {
|
||||
loadTransactionsFromStorage,
|
||||
saveTransactionsToStorage,
|
||||
loadBudgetFromStorage
|
||||
} from './storageUtils';
|
||||
import {
|
||||
syncTransactionsWithSupabase,
|
||||
updateTransactionInSupabase,
|
||||
deleteTransactionFromSupabase
|
||||
} from './supabaseUtils';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
|
||||
// useTransactions 훅
|
||||
import { useTransactionsCore } from './useTransactionsCore';
|
||||
|
||||
/**
|
||||
* 메인 트랜잭션 훅
|
||||
* useTransactionsCore를 통해 모든 트랜잭션 관련 기능에 접근합니다.
|
||||
*/
|
||||
export const useTransactions = () => {
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [filteredTransactions, setFilteredTransactions] = useState<Transaction[]>([]);
|
||||
const [selectedMonth, setSelectedMonth] = useState(getCurrentMonth());
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [totalBudget, setTotalBudget] = useState(0);
|
||||
const { user } = useAuth();
|
||||
const [refreshKey, setRefreshKey] = useState(0); // 강제 새로고침을 위한 키
|
||||
|
||||
// 월 변경 처리
|
||||
const handlePrevMonth = () => {
|
||||
setSelectedMonth(getPrevMonth(selectedMonth));
|
||||
};
|
||||
|
||||
const handleNextMonth = () => {
|
||||
setSelectedMonth(getNextMonth(selectedMonth));
|
||||
};
|
||||
|
||||
// 트랜잭션 로드
|
||||
const loadTransactions = useCallback(() => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const localTransactions = loadTransactionsFromStorage();
|
||||
setTransactions(localTransactions);
|
||||
|
||||
// 예산 가져오기
|
||||
const budgetAmount = loadBudgetFromStorage();
|
||||
setTotalBudget(budgetAmount);
|
||||
} catch (err) {
|
||||
console.error('트랜잭션 로드 중 오류:', err);
|
||||
setError('데이터를 불러오는 중 문제가 발생했습니다.');
|
||||
toast({
|
||||
title: "데이터 로드 실패",
|
||||
description: "지출 내역을 불러오는데 실패했습니다.",
|
||||
variant: "destructive",
|
||||
duration: 4000
|
||||
});
|
||||
} finally {
|
||||
// 로딩 상태를 약간 지연시켜 UI 업데이트가 원활하게 이루어지도록 함
|
||||
setTimeout(() => setIsLoading(false), 300);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 필터 적용
|
||||
useEffect(() => {
|
||||
// 1. 월별 필터링
|
||||
let filtered = filterTransactionsByMonth(transactions, selectedMonth);
|
||||
|
||||
// 2. 검색어 필터링
|
||||
if (searchQuery.trim()) {
|
||||
filtered = filterTransactionsByQuery(filtered, searchQuery);
|
||||
}
|
||||
|
||||
console.log('필터링 결과:', filtered.length, '트랜잭션');
|
||||
setFilteredTransactions(filtered);
|
||||
}, [transactions, selectedMonth, searchQuery]);
|
||||
|
||||
// 초기 데이터 로드 및 이벤트 리스너 설정
|
||||
useEffect(() => {
|
||||
console.log('useTransactions - 초기 데이터 로드');
|
||||
loadTransactions();
|
||||
|
||||
// 트랜잭션 업데이트 이벤트 리스너
|
||||
const handleTransactionUpdated = () => {
|
||||
console.log('트랜잭션 업데이트 이벤트 감지됨');
|
||||
loadTransactions();
|
||||
};
|
||||
|
||||
// 스토리지 변경 이벤트 리스너
|
||||
const handleStorageChange = (e: StorageEvent) => {
|
||||
if (e.key === 'transactions' || e.key === null) {
|
||||
console.log('로컬 스토리지 변경 감지됨:', e.key);
|
||||
loadTransactions();
|
||||
}
|
||||
};
|
||||
|
||||
// 페이지 포커스/가시성 이벤트 리스너
|
||||
const handleFocus = () => {
|
||||
console.log('창 포커스 - 트랜잭션 새로고침');
|
||||
loadTransactions();
|
||||
};
|
||||
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
console.log('페이지 가시성 변경 - 트랜잭션 새로고침');
|
||||
loadTransactions();
|
||||
}
|
||||
};
|
||||
|
||||
// 이벤트 리스너 등록
|
||||
window.addEventListener('transactionUpdated', handleTransactionUpdated);
|
||||
window.addEventListener('storage', handleStorageChange);
|
||||
window.addEventListener('focus', handleFocus);
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
// 컴포넌트 마운트시에만 수동으로 트랜잭션 업데이트 이벤트 발생
|
||||
window.dispatchEvent(new Event('transactionUpdated'));
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('transactionUpdated', handleTransactionUpdated);
|
||||
window.removeEventListener('storage', handleStorageChange);
|
||||
window.removeEventListener('focus', handleFocus);
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
};
|
||||
}, [loadTransactions, refreshKey]);
|
||||
|
||||
// 트랜잭션 업데이트
|
||||
const updateTransaction = (updatedTransaction: Transaction) => {
|
||||
const updatedTransactions = transactions.map(transaction =>
|
||||
transaction.id === updatedTransaction.id ? updatedTransaction : transaction
|
||||
);
|
||||
|
||||
// 로컬 스토리지 업데이트
|
||||
saveTransactionsToStorage(updatedTransactions);
|
||||
|
||||
// 상태 업데이트
|
||||
setTransactions(updatedTransactions);
|
||||
|
||||
// Supabase 업데이트 시도
|
||||
if (user) {
|
||||
updateTransactionInSupabase(user, updatedTransaction);
|
||||
}
|
||||
|
||||
// 이벤트 발생
|
||||
window.dispatchEvent(new Event('transactionUpdated'));
|
||||
|
||||
// 약간의 지연을 두고 토스트 표시
|
||||
setTimeout(() => {
|
||||
toast({
|
||||
title: "지출이 수정되었습니다",
|
||||
description: `${updatedTransaction.title} 항목이 업데이트되었습니다.`,
|
||||
duration: 3000
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
// 트랜잭션 삭제
|
||||
const deleteTransaction = (id: string) => {
|
||||
const updatedTransactions = transactions.filter(transaction => transaction.id !== id);
|
||||
|
||||
// 로컬 스토리지 업데이트
|
||||
saveTransactionsToStorage(updatedTransactions);
|
||||
|
||||
// 상태 업데이트
|
||||
setTransactions(updatedTransactions);
|
||||
|
||||
// Supabase 삭제 시도
|
||||
if (user) {
|
||||
deleteTransactionFromSupabase(user, id);
|
||||
}
|
||||
|
||||
// 이벤트 발생
|
||||
window.dispatchEvent(new Event('transactionUpdated'));
|
||||
|
||||
// 약간의 지연을 두고 토스트 표시
|
||||
setTimeout(() => {
|
||||
toast({
|
||||
title: "지출이 삭제되었습니다",
|
||||
description: "선택한 지출 항목이 삭제되었습니다.",
|
||||
duration: 3000
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
// 데이터 강제 새로고침
|
||||
const refreshTransactions = () => {
|
||||
setRefreshKey(prev => prev + 1);
|
||||
loadTransactions();
|
||||
};
|
||||
|
||||
return {
|
||||
transactions: filteredTransactions,
|
||||
allTransactions: transactions,
|
||||
isLoading,
|
||||
error,
|
||||
totalBudget,
|
||||
selectedMonth,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
handlePrevMonth,
|
||||
handleNextMonth,
|
||||
updateTransaction,
|
||||
deleteTransaction,
|
||||
totalExpenses: calculateTotalExpenses(filteredTransactions),
|
||||
refreshTransactions
|
||||
};
|
||||
return useTransactionsCore();
|
||||
};
|
||||
|
||||
100
src/hooks/transactions/useTransactionsCore.ts
Normal file
100
src/hooks/transactions/useTransactionsCore.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { useTransactionsState } from './useTransactionsState';
|
||||
import { useTransactionsFiltering } from './useTransactionsFiltering';
|
||||
import { useTransactionsLoader } from './useTransactionsLoader';
|
||||
import { useTransactionsOperations } from './useTransactionsOperations';
|
||||
import { useTransactionsEvents } from './useTransactionsEvents';
|
||||
|
||||
/**
|
||||
* 핵심 트랜잭션 훅
|
||||
* 모든 트랜잭션 관련 훅을 통합합니다.
|
||||
*/
|
||||
export const useTransactionsCore = () => {
|
||||
// 상태 관리
|
||||
const {
|
||||
transactions,
|
||||
setTransactions,
|
||||
filteredTransactions,
|
||||
setFilteredTransactions,
|
||||
selectedMonth,
|
||||
setSelectedMonth,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
error,
|
||||
setError,
|
||||
totalBudget,
|
||||
setTotalBudget,
|
||||
refreshKey,
|
||||
setRefreshKey
|
||||
} = useTransactionsState();
|
||||
|
||||
// 데이터 로딩
|
||||
const { loadTransactions } = useTransactionsLoader(
|
||||
setTransactions,
|
||||
setTotalBudget,
|
||||
setIsLoading,
|
||||
setError
|
||||
);
|
||||
|
||||
// 필터링
|
||||
const {
|
||||
handlePrevMonth,
|
||||
handleNextMonth,
|
||||
getTotalExpenses
|
||||
} = useTransactionsFiltering(
|
||||
transactions,
|
||||
selectedMonth,
|
||||
setSelectedMonth,
|
||||
searchQuery,
|
||||
setFilteredTransactions
|
||||
);
|
||||
|
||||
// 트랜잭션 작업
|
||||
const {
|
||||
updateTransaction,
|
||||
deleteTransaction
|
||||
} = useTransactionsOperations(
|
||||
transactions,
|
||||
setTransactions
|
||||
);
|
||||
|
||||
// 이벤트 리스너
|
||||
useTransactionsEvents(loadTransactions, refreshKey);
|
||||
|
||||
// 데이터 강제 새로고침
|
||||
const refreshTransactions = useCallback(() => {
|
||||
setRefreshKey(prev => prev + 1);
|
||||
loadTransactions();
|
||||
}, [loadTransactions, setRefreshKey]);
|
||||
|
||||
return {
|
||||
// 데이터
|
||||
transactions: filteredTransactions,
|
||||
allTransactions: transactions,
|
||||
|
||||
// 상태
|
||||
isLoading,
|
||||
error,
|
||||
totalBudget,
|
||||
|
||||
// 필터링
|
||||
selectedMonth,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
handlePrevMonth,
|
||||
handleNextMonth,
|
||||
|
||||
// 작업
|
||||
updateTransaction,
|
||||
deleteTransaction,
|
||||
|
||||
// 합계
|
||||
totalExpenses: getTotalExpenses(filteredTransactions),
|
||||
|
||||
// 새로고침
|
||||
refreshTransactions
|
||||
};
|
||||
};
|
||||
59
src/hooks/transactions/useTransactionsEvents.ts
Normal file
59
src/hooks/transactions/useTransactionsEvents.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* 트랜잭션 이벤트 관련 훅
|
||||
* 각종 이벤트 리스너를 설정합니다.
|
||||
*/
|
||||
export const useTransactionsEvents = (
|
||||
loadTransactions: () => void,
|
||||
refreshKey: number
|
||||
) => {
|
||||
// 이벤트 리스너 설정
|
||||
useEffect(() => {
|
||||
console.log('useTransactions - 이벤트 리스너 설정');
|
||||
|
||||
// 트랜잭션 업데이트 이벤트 리스너
|
||||
const handleTransactionUpdated = () => {
|
||||
console.log('트랜잭션 업데이트 이벤트 감지됨');
|
||||
loadTransactions();
|
||||
};
|
||||
|
||||
// 스토리지 변경 이벤트 리스너
|
||||
const handleStorageChange = (e: StorageEvent) => {
|
||||
if (e.key === 'transactions' || e.key === null) {
|
||||
console.log('로컬 스토리지 변경 감지됨:', e.key);
|
||||
loadTransactions();
|
||||
}
|
||||
};
|
||||
|
||||
// 페이지 포커스/가시성 이벤트 리스너
|
||||
const handleFocus = () => {
|
||||
console.log('창 포커스 - 트랜잭션 새로고침');
|
||||
loadTransactions();
|
||||
};
|
||||
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
console.log('페이지 가시성 변경 - 트랜잭션 새로고침');
|
||||
loadTransactions();
|
||||
}
|
||||
};
|
||||
|
||||
// 이벤트 리스너 등록
|
||||
window.addEventListener('transactionUpdated', handleTransactionUpdated);
|
||||
window.addEventListener('storage', handleStorageChange);
|
||||
window.addEventListener('focus', handleFocus);
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
// 컴포넌트 마운트시에만 수동으로 트랜잭션 업데이트 이벤트 발생
|
||||
window.dispatchEvent(new Event('transactionUpdated'));
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('transactionUpdated', handleTransactionUpdated);
|
||||
window.removeEventListener('storage', handleStorageChange);
|
||||
window.removeEventListener('focus', handleFocus);
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
};
|
||||
}, [loadTransactions, refreshKey]);
|
||||
};
|
||||
55
src/hooks/transactions/useTransactionsFiltering.ts
Normal file
55
src/hooks/transactions/useTransactionsFiltering.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { Transaction } from '@/components/TransactionCard';
|
||||
import {
|
||||
filterTransactionsByMonth,
|
||||
filterTransactionsByQuery,
|
||||
calculateTotalExpenses
|
||||
} from './filterUtils';
|
||||
import { getPrevMonth, getNextMonth } from './dateUtils';
|
||||
|
||||
/**
|
||||
* 트랜잭션 필터링 관련 훅
|
||||
* 월별 및 검색어 필터링 기능을 제공합니다.
|
||||
*/
|
||||
export const useTransactionsFiltering = (
|
||||
transactions: Transaction[],
|
||||
selectedMonth: string,
|
||||
setSelectedMonth: (month: string) => void,
|
||||
searchQuery: string,
|
||||
setFilteredTransactions: (transactions: Transaction[]) => void
|
||||
) => {
|
||||
// 월 변경 처리
|
||||
const handlePrevMonth = () => {
|
||||
setSelectedMonth(getPrevMonth(selectedMonth));
|
||||
};
|
||||
|
||||
const handleNextMonth = () => {
|
||||
setSelectedMonth(getNextMonth(selectedMonth));
|
||||
};
|
||||
|
||||
// 필터 적용
|
||||
useEffect(() => {
|
||||
// 1. 월별 필터링
|
||||
let filtered = filterTransactionsByMonth(transactions, selectedMonth);
|
||||
|
||||
// 2. 검색어 필터링
|
||||
if (searchQuery.trim()) {
|
||||
filtered = filterTransactionsByQuery(filtered, searchQuery);
|
||||
}
|
||||
|
||||
console.log('필터링 결과:', filtered.length, '트랜잭션');
|
||||
setFilteredTransactions(filtered);
|
||||
}, [transactions, selectedMonth, searchQuery, setFilteredTransactions]);
|
||||
|
||||
// 필터링된 트랜잭션의 총 지출 계산
|
||||
const getTotalExpenses = (filteredTransactions: Transaction[]) => {
|
||||
return calculateTotalExpenses(filteredTransactions);
|
||||
};
|
||||
|
||||
return {
|
||||
handlePrevMonth,
|
||||
handleNextMonth,
|
||||
getTotalExpenses
|
||||
};
|
||||
};
|
||||
49
src/hooks/transactions/useTransactionsLoader.ts
Normal file
49
src/hooks/transactions/useTransactionsLoader.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { toast } from '@/hooks/useToast.wrapper';
|
||||
import {
|
||||
loadTransactionsFromStorage,
|
||||
loadBudgetFromStorage
|
||||
} from './storageUtils';
|
||||
|
||||
/**
|
||||
* 트랜잭션 로딩 관련 훅
|
||||
* 로컬 스토리지에서 트랜잭션 데이터를 로드합니다.
|
||||
*/
|
||||
export const useTransactionsLoader = (
|
||||
setTransactions: (transactions: any[]) => void,
|
||||
setTotalBudget: (budget: number) => void,
|
||||
setIsLoading: (isLoading: boolean) => void,
|
||||
setError: (error: string | null) => void
|
||||
) => {
|
||||
// 트랜잭션 로드
|
||||
const loadTransactions = useCallback(() => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const localTransactions = loadTransactionsFromStorage();
|
||||
setTransactions(localTransactions);
|
||||
|
||||
// 예산 가져오기
|
||||
const budgetAmount = loadBudgetFromStorage();
|
||||
setTotalBudget(budgetAmount);
|
||||
} catch (err) {
|
||||
console.error('트랜잭션 로드 중 오류:', err);
|
||||
setError('데이터를 불러오는 중 문제가 발생했습니다.');
|
||||
toast({
|
||||
title: "데이터 로드 실패",
|
||||
description: "지출 내역을 불러오는데 실패했습니다.",
|
||||
variant: "destructive",
|
||||
duration: 4000
|
||||
});
|
||||
} finally {
|
||||
// 로딩 상태를 약간 지연시켜 UI 업데이트가 원활하게 이루어지도록 함
|
||||
setTimeout(() => setIsLoading(false), 300);
|
||||
}
|
||||
}, [setTransactions, setTotalBudget, setIsLoading, setError]);
|
||||
|
||||
return {
|
||||
loadTransactions
|
||||
};
|
||||
};
|
||||
84
src/hooks/transactions/useTransactionsOperations.ts
Normal file
84
src/hooks/transactions/useTransactionsOperations.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { Transaction } from '@/components/TransactionCard';
|
||||
import { useAuth } from '@/contexts/auth/AuthProvider';
|
||||
import { toast } from '@/hooks/useToast.wrapper';
|
||||
import { saveTransactionsToStorage } from './storageUtils';
|
||||
import {
|
||||
updateTransactionInSupabase,
|
||||
deleteTransactionFromSupabase
|
||||
} from './supabaseUtils';
|
||||
|
||||
/**
|
||||
* 트랜잭션 작업 관련 훅
|
||||
* 트랜잭션 업데이트, 삭제 기능을 제공합니다.
|
||||
*/
|
||||
export const useTransactionsOperations = (
|
||||
transactions: Transaction[],
|
||||
setTransactions: (transactions: Transaction[]) => void
|
||||
) => {
|
||||
const { user } = useAuth();
|
||||
|
||||
// 트랜잭션 업데이트
|
||||
const updateTransaction = useCallback((updatedTransaction: Transaction) => {
|
||||
const updatedTransactions = transactions.map(transaction =>
|
||||
transaction.id === updatedTransaction.id ? updatedTransaction : transaction
|
||||
);
|
||||
|
||||
// 로컬 스토리지 업데이트
|
||||
saveTransactionsToStorage(updatedTransactions);
|
||||
|
||||
// 상태 업데이트
|
||||
setTransactions(updatedTransactions);
|
||||
|
||||
// Supabase 업데이트 시도
|
||||
if (user) {
|
||||
updateTransactionInSupabase(user, updatedTransaction);
|
||||
}
|
||||
|
||||
// 이벤트 발생
|
||||
window.dispatchEvent(new Event('transactionUpdated'));
|
||||
|
||||
// 약간의 지연을 두고 토스트 표시
|
||||
setTimeout(() => {
|
||||
toast({
|
||||
title: "지출이 수정되었습니다",
|
||||
description: `${updatedTransaction.title} 항목이 업데이트되었습니다.`,
|
||||
duration: 3000
|
||||
});
|
||||
}, 100);
|
||||
}, [transactions, setTransactions, user]);
|
||||
|
||||
// 트랜잭션 삭제
|
||||
const deleteTransaction = useCallback((id: string) => {
|
||||
const updatedTransactions = transactions.filter(transaction => transaction.id !== id);
|
||||
|
||||
// 로컬 스토리지 업데이트
|
||||
saveTransactionsToStorage(updatedTransactions);
|
||||
|
||||
// 상태 업데이트
|
||||
setTransactions(updatedTransactions);
|
||||
|
||||
// Supabase 삭제 시도
|
||||
if (user) {
|
||||
deleteTransactionFromSupabase(user, id);
|
||||
}
|
||||
|
||||
// 이벤트 발생
|
||||
window.dispatchEvent(new Event('transactionUpdated'));
|
||||
|
||||
// 약간의 지연을 두고 토스트 표시
|
||||
setTimeout(() => {
|
||||
toast({
|
||||
title: "지출이 삭제되었습니다",
|
||||
description: "선택한 지출 항목이 삭제되었습니다.",
|
||||
duration: 3000
|
||||
});
|
||||
}, 100);
|
||||
}, [transactions, setTransactions, user]);
|
||||
|
||||
return {
|
||||
updateTransaction,
|
||||
deleteTransaction
|
||||
};
|
||||
};
|
||||
56
src/hooks/transactions/useTransactionsState.ts
Normal file
56
src/hooks/transactions/useTransactionsState.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Transaction } from '@/components/TransactionCard';
|
||||
import { getCurrentMonth } from './dateUtils';
|
||||
|
||||
/**
|
||||
* 트랜잭션 관련 상태 관리 훅
|
||||
* 트랜잭션, 필터링, 로딩 상태 등을 관리합니다.
|
||||
*/
|
||||
export const useTransactionsState = () => {
|
||||
// 트랜잭션 상태
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [filteredTransactions, setFilteredTransactions] = useState<Transaction[]>([]);
|
||||
|
||||
// 필터링 상태
|
||||
const [selectedMonth, setSelectedMonth] = useState(getCurrentMonth());
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
||||
// 로딩 및 에러 상태
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// 예산 상태
|
||||
const [totalBudget, setTotalBudget] = useState(0);
|
||||
|
||||
// 새로고침 키
|
||||
const [refreshKey, setRefreshKey] = useState(0);
|
||||
|
||||
return {
|
||||
// 상태
|
||||
transactions,
|
||||
setTransactions,
|
||||
filteredTransactions,
|
||||
setFilteredTransactions,
|
||||
|
||||
// 필터링 상태
|
||||
selectedMonth,
|
||||
setSelectedMonth,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
|
||||
// 로딩 및 에러 상태
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
error,
|
||||
setError,
|
||||
|
||||
// 예산 상태
|
||||
totalBudget,
|
||||
setTotalBudget,
|
||||
|
||||
// 새로고침 키
|
||||
refreshKey,
|
||||
setRefreshKey
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user