'use client'; import { useState, useEffect } from 'react'; import { Box, Container, Typography, Card, CardContent, Grid, } from '@mui/material'; import { PieChart as PieChartIcon, ShowChart as ShowChartIcon, Payments, People, } from '@mui/icons-material'; import { Chart as ChartJS, ArcElement, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, } from 'chart.js'; import { Pie, Line } from 'react-chartjs-2'; import Header from '@/shared/ui/Header'; import { cardStyles, colors, responsiveText, } from '@/shared/lib/button-styles'; // Chart.js 등록 ChartJS.register( ArcElement, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend ); // Mock 데이터 const mockAnalyticsData = { summary: { participants: 128, participantsDelta: 12, totalCost: 300000, expectedRevenue: 1350000, roi: 450, targetRoi: 300, }, channelPerformance: [ { channel: '우리동네TV', participants: 58, percentage: 45, color: '#F472B6' }, { channel: '링고비즈', participants: 38, percentage: 30, color: '#60A5FA' }, { channel: 'SNS', participants: 32, percentage: 25, color: '#FB923C' }, ], timePerformance: { peakTime: '오후 2-4시', peakParticipants: 35, avgPerHour: 8, }, roiDetail: { totalCost: 300000, prizeCost: 250000, channelCost: 50000, expectedRevenue: 1350000, salesIncrease: 1000000, newCustomerLTV: 350000, }, participantProfile: { age: [ { label: '20대', percentage: 35 }, { label: '30대', percentage: 40 }, { label: '40대', percentage: 25 }, ], gender: [ { label: '여성', percentage: 60 }, { label: '남성', percentage: 40 }, ], }, }; export default function AnalyticsPage() { const [lastUpdate, setLastUpdate] = useState(new Date()); const [updateText, setUpdateText] = useState('방금 전'); useEffect(() => { // 업데이트 시간 표시 갱신 const updateInterval = setInterval(() => { const now = new Date(); const diff = Math.floor((now.getTime() - lastUpdate.getTime()) / 1000); let text; if (diff < 60) { text = '방금 전'; } else if (diff < 3600) { text = `${Math.floor(diff / 60)}분 전`; } else { text = `${Math.floor(diff / 3600)}시간 전`; } setUpdateText(text); }, 30000); // 30초마다 갱신 // 5분마다 데이터 업데이트 시뮬레이션 const dataUpdateInterval = setInterval(() => { setLastUpdate(new Date()); setUpdateText('방금 전'); }, 300000); // 5분 return () => { clearInterval(updateInterval); clearInterval(dataUpdateInterval); }; }, [lastUpdate]); const { summary, channelPerformance, timePerformance, roiDetail, participantProfile } = mockAnalyticsData; return ( <>
{/* Title with Real-time Indicator */} 📊 요약 (실시간) {updateText} {/* Summary KPI Cards */} 참여자 수 {summary.participants} ↑ {summary.participantsDelta}명 (오늘) 총 비용 {Math.floor(summary.totalCost / 10000)}만 경품 {Math.floor(roiDetail.prizeCost / 10000)}만 + 채널{' '} {Math.floor(roiDetail.channelCost / 10000)}만 예상 수익 {Math.floor(summary.expectedRevenue / 10000)}만 매출 {Math.floor(roiDetail.salesIncrease / 10000)}만 + LTV{' '} {Math.floor(roiDetail.newCustomerLTV / 10000)}만 투자대비수익률 {summary.roi}% 목표 {summary.targetRoi}% 달성 {/* Charts Grid */} {/* Channel Performance */} 채널별 성과 {/* Pie Chart */} item.channel), datasets: [ { data: channelPerformance.map((item) => item.participants), backgroundColor: channelPerformance.map((item) => item.color), borderColor: '#fff', borderWidth: 2, }, ], }} options={{ responsive: true, maintainAspectRatio: true, plugins: { legend: { display: false, }, tooltip: { callbacks: { label: function (context) { const label = context.label || ''; const value = context.parsed || 0; const total = context.dataset.data.reduce((a: number, b: number) => a + b, 0); const percentage = ((value / total) * 100).toFixed(1); return `${label}: ${value}명 (${percentage}%)`; }, }, }, }, }} /> {/* Legend */} {channelPerformance.map((item) => ( {item.channel} {item.percentage}% ({item.participants}명) ))} {/* Time Trend */} 시간대별 참여 추이 {/* Line Chart */} {/* Stats */} 피크 시간: {timePerformance.peakTime} ({timePerformance.peakParticipants}명) 평균 시간당: {timePerformance.avgPerHour}명 {/* ROI Detail & Participant Profile */} {/* ROI Detail */} 투자대비수익률 상세 총 비용: {Math.floor(roiDetail.totalCost / 10000)}만원 • 경품 비용 {Math.floor(roiDetail.prizeCost / 10000)}만원 • 채널 비용 {Math.floor(roiDetail.channelCost / 10000)}만원 예상 수익: {Math.floor(roiDetail.expectedRevenue / 10000)}만원 • 매출 증가 {Math.floor(roiDetail.salesIncrease / 10000)}만원 • 신규 고객 LTV {Math.floor(roiDetail.newCustomerLTV / 10000)}만원 투자대비수익률 (수익 - 비용) ÷ 비용 × 100 ({Math.floor(roiDetail.expectedRevenue / 10000)}만 -{' '} {Math.floor(roiDetail.totalCost / 10000)}만) ÷{' '} {Math.floor(roiDetail.totalCost / 10000)}만 × 100 = {summary.roi}% {/* Participant Profile */} 참여자 프로필 {/* Age Distribution */} 연령별 {participantProfile.age.map((item) => ( {item.label} {item.percentage}% ))} {/* Gender Distribution */} 성별 {participantProfile.gender.map((item) => ( {item.label} {item.percentage}% ))} ); }