Files
zellyy-finance/src/pages/Analytics.tsx
gpt-engineer-app[bot] a138e81439 Adjust layout of category spending
Adjust the layout of the category spending chart to align vertically with the payment method chart, while keeping the payment method chart's position unchanged.
2025-03-22 12:53:08 +00:00

173 lines
7.1 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import NavBar from '@/components/NavBar';
import ExpenseChart from '@/components/ExpenseChart';
import AddTransactionButton from '@/components/AddTransactionButton';
import { useBudget } from '@/contexts/budget/BudgetContext';
import { MONTHS_KR } from '@/hooks/useTransactions';
import { useIsMobile } from '@/hooks/use-mobile';
import { getCategoryColor } from '@/utils/categoryColorUtils';
import { Separator } from '@/components/ui/separator';
// 새로 분리한 컴포넌트들 불러오기
import PeriodSelector from '@/components/analytics/PeriodSelector';
import SummaryCards from '@/components/analytics/SummaryCards';
import MonthlyComparisonChart from '@/components/analytics/MonthlyComparisonChart';
import CategorySpendingList from '@/components/analytics/CategorySpendingList';
import PaymentMethodChart from '@/components/analytics/PaymentMethodChart';
const Analytics = () => {
const [selectedPeriod, setSelectedPeriod] = useState('이번 달');
const {
budgetData,
getCategorySpending,
getPaymentMethodStats, // 새로 추가된 메서드
transactions
} = useBudget();
const isMobile = useIsMobile();
const [refreshTrigger, setRefreshTrigger] = useState(0);
const [monthlyData, setMonthlyData] = useState<any[]>([]);
// 페이지 가시성 변경시 데이터 새로고침
useEffect(() => {
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
console.log('분석 페이지 보임 - 데이터 새로고침');
setRefreshTrigger(prev => prev + 1);
// 이벤트 발생시켜 데이터 새로고침
try {
window.dispatchEvent(new Event('storage'));
window.dispatchEvent(new Event('transactionUpdated'));
window.dispatchEvent(new Event('budgetDataUpdated'));
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
} catch (e) {
console.error('이벤트 발생 오류:', e);
}
}
};
const handleFocus = () => {
console.log('분석 페이지 포커스 - 데이터 새로고침');
setRefreshTrigger(prev => prev + 1);
// 이벤트 발생시켜 데이터 새로고침
try {
window.dispatchEvent(new Event('storage'));
window.dispatchEvent(new Event('transactionUpdated'));
window.dispatchEvent(new Event('budgetDataUpdated'));
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
} catch (e) {
console.error('이벤트 발생 오류:', e);
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
window.addEventListener('focus', handleFocus);
window.addEventListener('transactionUpdated', () => setRefreshTrigger(prev => prev + 1));
window.addEventListener('budgetDataUpdated', () => setRefreshTrigger(prev => prev + 1));
window.addEventListener('categoryBudgetsUpdated', () => setRefreshTrigger(prev => prev + 1));
// 컴포넌트 마운트 시 초기 데이터 로드 이벤트 트리거
handleFocus();
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
window.removeEventListener('focus', handleFocus);
window.removeEventListener('transactionUpdated', () => {});
window.removeEventListener('budgetDataUpdated', () => {});
window.removeEventListener('categoryBudgetsUpdated', () => {});
};
}, []);
// 실제 예산 및 지출 데이터 사용
const totalBudget = budgetData?.monthly?.targetAmount || 0;
const totalExpense = budgetData?.monthly?.spentAmount || 0;
const savings = Math.max(0, totalBudget - totalExpense);
const savingsPercentage = totalBudget > 0 ? Math.round(savings / totalBudget * 100) : 0;
// 카테고리별 지출 차트 데이터 생성 - 색상 유틸리티 사용
const categorySpending = getCategorySpending();
const expenseData = categorySpending.map(category => ({
name: category.title,
value: category.current,
color: getCategoryColor(category.title) // 일관된 색상 적용
}));
// 결제 방법 데이터 가져오기
const paymentMethodData = getPaymentMethodStats();
const hasPaymentData = paymentMethodData.some(method => method.amount > 0);
// 월별 데이터 생성 - 샘플 데이터 제거하고 현재 달만 실제 데이터 사용
useEffect(() => {
console.log('Analytics 페이지: 월별 데이터 생성', {
totalBudget,
totalExpense
});
// 현재 월 가져오기
const today = new Date();
const currentMonth = today.getMonth();
// 현재 달만 실제 데이터 사용하는 배열 생성
const monthlyDataArray = [{
name: MONTHS_KR[currentMonth].split(' ')[0],
// '8월' 형식으로 변환
budget: totalBudget,
expense: totalExpense
}];
setMonthlyData(monthlyDataArray);
console.log('Analytics 페이지: 월별 데이터 생성 완료', monthlyDataArray);
}, [totalBudget, totalExpense, refreshTrigger]);
// 이전/다음 기간 이동 처리
const handlePrevPeriod = () => {
console.log('이전 기간으로 이동');
};
const handleNextPeriod = () => {
console.log('다음 기간으로 이동');
};
return <div className="min-h-screen bg-neuro-background pb-24">
<div className="max-w-md mx-auto px-6">
{/* Header */}
<header className="py-4 w-full">
<h1 className="font-bold neuro-text mb-3 text-xl"> </h1>
{/* Period Selector */}
<PeriodSelector selectedPeriod={selectedPeriod} onPrevPeriod={handlePrevPeriod} onNextPeriod={handleNextPeriod} />
{/* Summary Cards */}
<SummaryCards totalBudget={totalBudget} totalExpense={totalExpense} savingsPercentage={savingsPercentage} />
</header>
{/* Monthly Comparison Chart */}
<div className="mb-8 w-full">
<h2 className="text-lg font-semibold mb-3"> </h2>
<MonthlyComparisonChart monthlyData={monthlyData} isEmpty={totalBudget === 0 && totalExpense === 0} />
</div>
{/* Category Pie Chart - 왼쪽 여백 조정 */}
<h2 className="text-lg font-semibold mb-3"> </h2>
<div className="w-full mb-8">
{expenseData.some(item => item.value > 0) ?
<ExpenseChart data={expenseData} /> :
<div className="neuro-card h-52 w-full flex items-center justify-center text-gray-400">
<p> </p>
</div>
}
</div>
{/* 결제 방법 차트 추가 */}
<h2 className="text-lg font-semibold mb-3"> </h2>
<PaymentMethodChart
data={paymentMethodData}
isEmpty={!hasPaymentData}
/>
{/* Top Spending Categories */}
<h2 className="text-lg font-semibold mb-3 mt-6"> </h2>
<CategorySpendingList categories={categorySpending} totalExpense={totalExpense} className="mb-[50px]" />
</div>
<AddTransactionButton />
<NavBar />
</div>;
};
export default Analytics;