import { useState } from 'react'; import { motion } from 'motion/react'; import { YoutubeFilled, InstagramFilled, FacebookFilled, GlobeFilled, TiktokFilled, VideoFilled, FileTextFilled, ShareFilled, } from '../components/icons/FilledIcons'; import type { ComponentType } from 'react'; // ─── Types ─── interface ChannelMetric { id: string; name: string; icon: ComponentType<{ size?: number; className?: string }>; brandColor: string; bgColor: string; followers: string; followersDelta: string; views: string; viewsDelta: string; engagement: string; engagementDelta: string; posts: number; score: number; } interface ContentPerformance { id: string; title: string; channel: string; type: 'video' | 'blog' | 'social'; views: string; likes: string; comments: string; ctr: string; publishedAt: string; } // ─── Mock Data ─── const CHANNELS: ChannelMetric[] = [ { id: 'youtube', name: 'YouTube', icon: YoutubeFilled, brandColor: '#FF0000', bgColor: '#FFF0F0', followers: '103K', followersDelta: '+2.1K', views: '270K', viewsDelta: '+18%', engagement: '4.2%', engagementDelta: '+0.8%', posts: 12, score: 65 }, { id: 'instagram_kr', name: 'Instagram KR', icon: InstagramFilled, brandColor: '#E1306C', bgColor: '#FFF0F5', followers: '14K', followersDelta: '+890', views: '45K', viewsDelta: '+32%', engagement: '3.1%', engagementDelta: '+1.2%', posts: 24, score: 35 }, { id: 'instagram_en', name: 'Instagram EN', icon: InstagramFilled, brandColor: '#E1306C', bgColor: '#FFF0F5', followers: '68.8K', followersDelta: '+1.2K', views: '120K', viewsDelta: '+8%', engagement: '5.6%', engagementDelta: '+0.3%', posts: 18, score: 55 }, { id: 'tiktok', name: 'TikTok', icon: TiktokFilled, brandColor: '#000000', bgColor: '#F5F5F5', followers: '0', followersDelta: 'NEW', views: '0', viewsDelta: '-', engagement: '0%', engagementDelta: '-', posts: 0, score: 0 }, { id: 'facebook', name: 'Facebook', icon: FacebookFilled, brandColor: '#1877F2', bgColor: '#F0F4FF', followers: '341', followersDelta: '+12', views: '2.1K', viewsDelta: '-5%', engagement: '0.8%', engagementDelta: '-0.2%', posts: 6, score: 40 }, { id: 'naver', name: 'Naver Blog', icon: GlobeFilled, brandColor: '#03C75A', bgColor: '#F0FFF5', followers: '-', followersDelta: '-', views: '8.2K', viewsDelta: '+45%', engagement: '2.4%', engagementDelta: '+1.1%', posts: 8, score: 72 }, ]; const TOP_CONTENT: ContentPerformance[] = [ { id: '1', title: '한번에 성공하는 코성형, VIEW의 비결', channel: 'YouTube', type: 'video', views: '12.4K', likes: '342', comments: '28', ctr: '8.2%', publishedAt: '3일 전' }, { id: '2', title: '안면윤곽 수술 종류와 회복기간', channel: 'Naver Blog', type: 'blog', views: '3.2K', likes: '-', comments: '12', ctr: '12.5%', publishedAt: '5일 전' }, { id: '3', title: 'Reel: 윤곽 전후 변화', channel: 'Instagram KR', type: 'social', views: '8.7K', likes: '567', comments: '45', ctr: '6.1%', publishedAt: '2일 전' }, { id: '4', title: 'Shorts: 사각턱 축소 과정', channel: 'YouTube', type: 'video', views: '5.1K', likes: '189', comments: '15', ctr: '4.8%', publishedAt: '4일 전' }, { id: '5', title: '코성형 가이드: 내 얼굴에 맞는 코', channel: 'Naver Blog', type: 'blog', views: '2.8K', likes: '-', comments: '8', ctr: '15.2%', publishedAt: '6일 전' }, ]; const OVERVIEW_STATS = [ { label: '총 노출', value: '445K', delta: '+24%', positive: true }, { label: '총 조회', value: '89.2K', delta: '+18%', positive: true }, { label: '평균 참여율', value: '3.8%', delta: '+0.6%', positive: true }, { label: '콘텐츠 발행', value: '68건', delta: '+12건', positive: true }, { label: '신규 팔로워', value: '+4.3K', delta: '+32%', positive: true }, { label: '전환 (상담)', value: '47건', delta: '+15건', positive: true }, ]; // ─── Funnel Data ─── const FUNNEL_STEPS = [ { label: '노출', labelEn: 'Impressions', value: 445000, display: '445K', color: '#6C5CE7' }, { label: '클릭', labelEn: 'Clicks', value: 89200, display: '89.2K', color: '#7C6DD8' }, { label: '웹사이트 유입', labelEn: 'Website Visits', value: 12400, display: '12.4K', color: '#9B8AD4' }, { label: '상담 문의', labelEn: 'Inquiries', value: 478, display: '478', color: '#B8A9E8' }, { label: '예약 전환', labelEn: 'Conversions', value: 47, display: '47', color: '#D5CDF5' }, ]; // ─── Channel Trend Data (4 weeks) ─── const CHANNEL_TREND = [ { week: 'W1', youtube: 85, instagram: 32, naver: 18, facebook: 8 }, { week: 'W2', youtube: 92, instagram: 41, naver: 24, facebook: 7 }, { week: 'W3', youtube: 78, instagram: 55, naver: 31, facebook: 9 }, { week: 'W4', youtube: 105, instagram: 68, naver: 38, facebook: 6 }, ]; const TREND_CHANNELS = [ { key: 'youtube' as const, label: 'YouTube', color: 'rgba(155,138,212,0.35)' }, { key: 'instagram' as const, label: 'Instagram', color: 'rgba(212,168,186,0.3)' }, { key: 'naver' as const, label: 'Naver', color: 'rgba(160,200,180,0.3)' }, { key: 'facebook' as const, label: 'Facebook', color: 'rgba(160,180,220,0.25)' }, ]; // ─── Heatmap Data (Day × Time Slot) ─── const DAYS = ['월', '화', '수', '목', '금', '토', '일']; const TIME_SLOTS = ['오전 (6-12)', '오후 (12-18)', '저녁 (18-24)', '심야 (0-6)']; // Engagement rate by day × time slot (0-10 scale) const HEATMAP_DATA = [ [3, 7, 8, 2], // 월 [4, 6, 9, 1], // 화 [5, 8, 7, 2], // 수 [6, 9, 8, 1], // 목 [4, 7, 10, 3], // 금 [2, 5, 6, 4], // 토 [1, 4, 5, 3], // 일 ]; // ─── Component ─── const typeIcons: Record> = { video: VideoFilled, blog: FileTextFilled, social: ShareFilled, }; const typeColors: Record = { video: { bg: 'bg-[#F3F0FF]', text: 'text-[#4A3A7C]' }, blog: { bg: 'bg-[#EFF0FF]', text: 'text-[#3A3F7C]' }, social: { bg: 'bg-[#FFF6ED]', text: 'text-[#7C5C3A]' }, }; function heatmapColor(value: number): string { if (value >= 9) return 'bg-[#2d2640] text-white'; if (value >= 7) return 'bg-[#4a4460] text-white'; if (value >= 5) return 'bg-[#8e89a8] text-white'; if (value >= 3) return 'bg-[#c8c4d8] text-[#4a4460]'; return 'bg-[#f0eef5] text-[#8e89a8]'; } export default function PerformancePage() { const [period, setPeriod] = useState<'7d' | '30d' | '90d'>('30d'); const funnelMax = FUNNEL_STEPS[0].value; const trendMax = Math.max(...CHANNEL_TREND.flatMap(w => [w.youtube, w.instagram, w.naver, w.facebook])); return (
{/* Header */}

Performance Intelligence

성과 대시보드

모든 채널의 마케팅 성과를 실시간으로 모니터링합니다.

{([ { key: '7d' as const, label: '7일' }, { key: '30d' as const, label: '30일' }, { key: '90d' as const, label: '90일' }, ]).map(p => ( ))}
{/* Overview Stats */}
{OVERVIEW_STATS.map((stat, i) => (

{stat.label}

{stat.value}

{stat.delta}

))}
{/* ═══ Section 1: Marketing Funnel ═══ */}

마케팅 퍼널

노출부터 전환까지 — 어디서 이탈하는지 파악

{FUNNEL_STEPS.map((step, i) => { const widthPct = Math.max((step.value / funnelMax) * 100, 8); const convRate = i > 0 ? ((step.value / FUNNEL_STEPS[i - 1].value) * 100).toFixed(1) : null; return ( {/* Label */}

{step.label}

{step.labelEn}

{/* Bar */}
{step.display}
{/* Conversion Rate */}
{convRate ? ( = 10 ? 'bg-[#F3F0FF] text-[#4A3A7C]' : 'bg-[#FFF6ED] text-[#7C5C3A]' }`}> {convRate}% ) : ( — )}
); })}
{/* Funnel insight */}

병목 구간: 클릭 → 웹사이트 유입 전환율 13.9% — 랜딩 페이지 최적화가 필요합니다. 업계 평균 20% 대비 낮음.

{/* ═══ Section 2: Channel Trend (Stacked Bar) ═══ */}

채널별 주간 트렌드

채널별 조회수 추이 비교 (단위: K)

{/* Legend */}
{TREND_CHANNELS.map(ch => (
{ch.label}
))}
{CHANNEL_TREND.map((week, wi) => { const total = week.youtube + week.instagram + week.naver + week.facebook; return (
{/* Total label above bar */}

{total}K

{/* Stacked bar */}
{TREND_CHANNELS.map(ch => { const val = week[ch.key]; const segH = (val / total) * 100; return (
{ch.label}: {val}K
); })}
{/* Week label */}

{week.week}

); })}
{/* Trend insight */}

성장 채널: Instagram 조회수 +112% (W1→W4). Naver Blog +111% 동반 성장. YouTube는 안정적 유지.

{/* ═══ Section 3: Day × Time Heatmap ═══ */}

최적 게시 시간

요일×시간대별 참여율 히트맵 — 진할수록 성과가 높음

{/* Scale legend */}
낮음 {[1, 3, 5, 7, 9].map(v => (
))} 높음
{/* Heatmap grid */}
{/* Time slot headers */}
{TIME_SLOTS.map(slot => (
{slot}
))}
{/* Rows */} {DAYS.map((day, di) => (
{day}
{HEATMAP_DATA[di].map((val, ti) => (
{val > 0 ? `${val * 10}%` : '-'}
))}
))}
{/* Heatmap insight */}

최적 시간: 금요일 저녁 (18-24시) 참여율 최고. 평일 오후 (12-18시)가 전반적으로 높음. 주말 오전은 피하세요.

{/* Channel Performance Grid */}

채널별 성과

{CHANNELS.map((ch, i) => { const Icon = ch.icon; return (

{ch.name}

{ch.posts}개 콘텐츠

= 70 ? 'bg-[#F3F0FF] text-[#4A3A7C]' : ch.score >= 40 ? 'bg-[#FFF6ED] text-[#7C5C3A]' : ch.score > 0 ? 'bg-[#FFF0F0] text-[#7C3A4B]' : 'bg-slate-50 text-slate-400' }`}> {ch.score || '-'}
); })}
{/* Top Content */}

인기 콘텐츠 TOP 5

콘텐츠 채널 조회수 좋아요 댓글 CTR 게시일
{TOP_CONTENT.map((content, i) => { const TypeIcon = typeIcons[content.type] ?? FileTextFilled; const colors = typeColors[content.type] ?? typeColors.blog; return (
{content.title}
{content.channel} {content.views} {content.likes} {content.comments} = 10 ? 'text-[#4A3A7C]' : 'text-slate-600' }`}>{content.ctr} {content.publishedAt}
); })}
{/* AI Recommendations */}

AI 개선 추천

{[ { title: 'YouTube Shorts 확대', desc: 'Shorts 조회수가 Long-form 대비 3.2배 높습니다. 주 3회 이상 Shorts 업로드를 권장합니다.' }, { title: 'Instagram Reels 시작', desc: 'KR 계정에 Reels 0개입니다. 경쟁 병원 평균 주 5개 — 즉시 시작이 필요합니다.' }, { title: '랜딩 페이지 최적화', desc: '클릭→유입 전환율 13.9%로 업계 평균 20% 대비 낮음. CTA 버튼 위치와 페이지 속도 개선 필요.' }, ].map((rec, i) => (

{rec.title}

{rec.desc}

))}
); } function MetricCell({ label, value, delta }: { label: string; value: string; delta: string }) { const isPositive = delta.startsWith('+'); const isNew = delta === 'NEW' || delta === '-'; return (

{label}

{value}

{delta}

); }