// src/pages/music/components/RevenueTab.jsx import { useState, useEffect } from 'react'; import { getRevenueDashboard, getRevenueRecords, addRevenueRecord, updateRevenueRecord, deleteRevenueRecord, } from '../../../api'; const COUNTRIES = ['BR', 'US', 'ID', 'MX', 'KR']; const currentMonth = () => new Date().toISOString().slice(0, 7); export default function RevenueTab() { const [dashboard, setDashboard] = useState(null); const [records, setRecords] = useState([]); const [form, setForm] = useState({ yt_video_id: '', record_month: currentMonth(), revenue_usd: '', views: '', country: 'BR', }); const [saving, setSaving] = useState(false); const [editingId, setEditingId] = useState(null); const [editForm, setEditForm] = useState({}); const loadAll = async () => { const [dash, recs] = await Promise.all([ getRevenueDashboard().catch(() => null), getRevenueRecords().catch(() => []), ]); setDashboard(dash); setRecords(Array.isArray(recs) ? recs : recs.records ?? []); }; useEffect(() => { loadAll(); }, []); const handleAdd = async () => { if (!form.yt_video_id || !form.revenue_usd || !form.views) return; setSaving(true); try { await addRevenueRecord({ yt_video_id: form.yt_video_id, record_month: form.record_month, revenue_usd: parseFloat(form.revenue_usd), views: parseInt(form.views, 10), country: form.country, }); setForm({ yt_video_id: '', record_month: currentMonth(), revenue_usd: '', views: '', country: 'BR' }); await loadAll(); } catch (e) { console.error('addRevenueRecord:', e); } finally { setSaving(false); } }; const handleEditSave = async () => { try { await updateRevenueRecord(editingId, { revenue_usd: parseFloat(editForm.revenue_usd), views: parseInt(editForm.views, 10), }); setEditingId(null); await loadAll(); } catch (e) { console.error('updateRevenueRecord:', e); } }; const handleDelete = async (id) => { if (!window.confirm('이 기록을 삭제할까요?')) return; try { await deleteRevenueRecord(id); await loadAll(); } catch (e) { console.error('deleteRevenueRecord:', e); } }; // 영상별 RPM 상위 5개 (bar chart 용) const chartData = records .filter(r => r.views > 0) .map(r => ({ label: r.yt_video_id, rpm: (r.revenue_usd / r.views) * 1000, })) .sort((a, b) => b.rpm - a.rpm) .slice(0, 5); const maxRpm = chartData.length > 0 ? Math.max(...chartData.map(d => d.rpm)) : 1; return (
{/* 대시보드 카드 3개 */}
총 수익
${dashboard?.total_revenue_usd?.toFixed(2) ?? '—'}
누적
총 조회수
{dashboard?.total_views != null ? (dashboard.total_views >= 1000 ? `${(dashboard.total_views / 1000).toFixed(1)}K` : String(dashboard.total_views)) : '—'}
누적
평균 RPM
${dashboard?.avg_rpm?.toFixed(2) ?? '—'}
가중평균
{/* 영상별 RPM 바 차트 */} {chartData.length > 0 && (

영상별 RPM 비교

{chartData.map((d, i) => (
{d.label.slice(0, 11)}
${d.rpm.toFixed(2)}
))}
)} {/* 수익 기록 추가 폼 */}

+ 수익 기록 추가

setForm(f => ({ ...f, yt_video_id: e.target.value }))} placeholder="dQw4w9WgXcQ" />
setForm(f => ({ ...f, record_month: e.target.value }))} />
setForm(f => ({ ...f, revenue_usd: e.target.value }))} placeholder="3.45" />
setForm(f => ({ ...f, views: e.target.value }))} placeholder="1200" />
{/* 수익 기록 테이블 */}

수익 기록

{records.length === 0 ? (

수익 기록이 없습니다. 위 폼으로 추가해보세요.

) : (
영상 ID 수익 조회수 RPM
{records.map(rec => ( editingId === rec.id ? (
{rec.yt_video_id.slice(0, 11)} {rec.record_month} setEditForm(f => ({ ...f, revenue_usd: e.target.value }))} /> setEditForm(f => ({ ...f, views: e.target.value }))} />
) : (
{ setEditingId(rec.id); setEditForm({ revenue_usd: rec.revenue_usd, views: rec.views }); }} style={{ cursor: 'pointer' }} > {rec.yt_video_id.slice(0, 11)} {rec.record_month} ${rec.revenue_usd?.toFixed(2)} {rec.views?.toLocaleString()} {rec.views > 0 ? `$${((rec.revenue_usd / rec.views) * 1000).toFixed(2)}` : '—'}
) ))}
)}
); }