Refactor Transactions page

Refactors the Transactions page into smaller, more manageable components to improve code organization and maintainability. The functionality remains the same.
This commit is contained in:
gpt-engineer-app[bot]
2025-03-17 23:24:12 +00:00
parent dea8b9f8ba
commit f1f9227abf
7 changed files with 296 additions and 126 deletions

View File

@@ -0,0 +1,37 @@
import React from 'react';
interface EmptyTransactionsProps {
searchQuery: string;
selectedMonth: string;
setSearchQuery: (query: string) => void;
isDisabled: boolean;
}
const EmptyTransactions: React.FC<EmptyTransactionsProps> = ({
searchQuery,
selectedMonth,
setSearchQuery,
isDisabled
}) => {
return (
<div className="text-center py-10">
<p className="text-gray-500 mb-3">
{searchQuery.trim()
? '검색 결과가 없습니다.'
: `${selectedMonth}에 등록된 지출이 없습니다.`}
</p>
{searchQuery.trim() && (
<button
className="text-neuro-income"
onClick={() => setSearchQuery('')}
disabled={isDisabled}
>
</button>
)}
</div>
);
};
export default EmptyTransactions;

View File

@@ -0,0 +1,37 @@
import React from 'react';
import TransactionCard, { Transaction } from '@/components/TransactionCard';
interface TransactionDateGroupProps {
date: string;
transactions: Transaction[];
onTransactionDelete: (id: string) => void;
}
const TransactionDateGroup: React.FC<TransactionDateGroupProps> = ({
date,
transactions,
onTransactionDelete
}) => {
return (
<div>
<div className="flex items-center gap-2 mb-3">
<div className="h-1 flex-1 neuro-pressed"></div>
<h2 className="text-sm font-medium text-gray-500">{date}</h2>
<div className="h-1 flex-1 neuro-pressed"></div>
</div>
<div className="grid gap-3">
{transactions.map(transaction => (
<TransactionCard
key={transaction.id}
transaction={transaction}
onDelete={onTransactionDelete}
/>
))}
</div>
</div>
);
};
export default TransactionDateGroup;

View File

@@ -0,0 +1,61 @@
import React from 'react';
import { Loader2 } from 'lucide-react';
import { Transaction } from '@/components/TransactionCard';
import TransactionsList from './TransactionsList';
import EmptyTransactions from './EmptyTransactions';
interface TransactionsContentProps {
isLoading: boolean;
isProcessing: boolean;
transactions: Transaction[];
groupedTransactions: Record<string, Transaction[]>;
searchQuery: string;
selectedMonth: string;
setSearchQuery: (query: string) => void;
onTransactionDelete: (id: string) => void;
isDisabled: boolean;
}
const TransactionsContent: React.FC<TransactionsContentProps> = ({
isLoading,
isProcessing,
transactions,
groupedTransactions,
searchQuery,
selectedMonth,
setSearchQuery,
onTransactionDelete,
isDisabled
}) => {
if (isLoading || isProcessing) {
return <LoadingState isProcessing={isProcessing} />;
}
if (!isLoading && !isProcessing && transactions.length === 0) {
return (
<EmptyTransactions
searchQuery={searchQuery}
selectedMonth={selectedMonth}
setSearchQuery={setSearchQuery}
isDisabled={isDisabled}
/>
);
}
return (
<TransactionsList
groupedTransactions={groupedTransactions}
onTransactionDelete={onTransactionDelete}
/>
);
};
const LoadingState: React.FC<{ isProcessing: boolean }> = ({ isProcessing }) => (
<div className="flex justify-center items-center py-10">
<Loader2 className="h-8 w-8 animate-spin text-neuro-income" />
<span className="ml-2 text-gray-500">{isProcessing ? '처리 중...' : '로딩 중...'}</span>
</div>
);
export default TransactionsContent;

View File

@@ -0,0 +1,87 @@
import React from 'react';
import { Calendar, Search, ChevronLeft, ChevronRight } from 'lucide-react';
import { formatCurrency } from '@/utils/formatters';
interface TransactionsHeaderProps {
selectedMonth: string;
searchQuery: string;
setSearchQuery: (query: string) => void;
handlePrevMonth: () => void;
handleNextMonth: () => void;
budgetData: any;
totalExpenses: number;
isDisabled: boolean;
}
const TransactionsHeader: React.FC<TransactionsHeaderProps> = ({
selectedMonth,
searchQuery,
setSearchQuery,
handlePrevMonth,
handleNextMonth,
budgetData,
totalExpenses,
isDisabled
}) => {
return (
<header className="py-8">
<h1 className="text-2xl font-bold neuro-text mb-5"> </h1>
{/* Search */}
<div className="neuro-pressed mb-5 flex items-center px-4 py-3 rounded-xl">
<Search size={18} className="text-gray-500 mr-2" />
<input
type="text"
placeholder="지출 검색..."
className="bg-transparent flex-1 outline-none text-sm"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
disabled={isDisabled}
/>
</div>
{/* Month Selector */}
<div className="flex items-center justify-between mb-5">
<button
className="neuro-flat p-2 rounded-full"
onClick={handlePrevMonth}
disabled={isDisabled}
>
<ChevronLeft size={20} />
</button>
<div className="flex items-center gap-2">
<Calendar size={18} className="text-neuro-income" />
<span className="font-medium text-lg">{selectedMonth}</span>
</div>
<button
className="neuro-flat p-2 rounded-full"
onClick={handleNextMonth}
disabled={isDisabled}
>
<ChevronRight size={20} />
</button>
</div>
{/* Summary */}
<div className="grid grid-cols-2 gap-4 mb-8">
<div className="neuro-card">
<p className="text-sm text-gray-500 mb-1"> </p>
<p className="text-lg font-bold text-neuro-income">
{formatCurrency(budgetData?.monthly?.targetAmount || 0)}
</p>
</div>
<div className="neuro-card">
<p className="text-sm text-gray-500 mb-1"> </p>
<p className="text-lg font-bold text-neuro-income">
{formatCurrency(totalExpenses)}
</p>
</div>
</div>
</header>
);
};
export default TransactionsHeader;

View File

@@ -0,0 +1,29 @@
import React from 'react';
import TransactionCard, { Transaction } from '@/components/TransactionCard';
import TransactionDateGroup from './TransactionDateGroup';
interface TransactionsListProps {
groupedTransactions: Record<string, Transaction[]>;
onTransactionDelete: (id: string) => void;
}
const TransactionsList: React.FC<TransactionsListProps> = ({
groupedTransactions,
onTransactionDelete
}) => {
return (
<div className="space-y-6 mb-[50px]">
{Object.entries(groupedTransactions).map(([date, dateTransactions]) => (
<TransactionDateGroup
key={date}
date={date}
transactions={dateTransactions}
onTransactionDelete={onTransactionDelete}
/>
))}
</div>
);
};
export default TransactionsList;