diff --git a/src/pages/music/components/TrendsTab.jsx b/src/pages/music/components/TrendsTab.jsx index 8612b5f..e070694 100644 --- a/src/pages/music/components/TrendsTab.jsx +++ b/src/pages/music/components/TrendsTab.jsx @@ -1,3 +1,173 @@ +// src/pages/music/components/TrendsTab.jsx +import { useState, useEffect } from 'react'; +import { + getLatestTrendReport, getTrendReports, + getMarketSuggestions, triggerYoutubeResearch, +} from '../../../api'; + +const FLAG = { BR: '๐Ÿ‡ง๐Ÿ‡ท', US: '๐Ÿ‡บ๐Ÿ‡ธ', ID: '๐Ÿ‡ฎ๐Ÿ‡ฉ', MX: '๐Ÿ‡ฒ๐Ÿ‡ฝ', KR: '๐Ÿ‡ฐ๐Ÿ‡ท' }; + export default function TrendsTab() { - return null; + const [latestReport, setLatestReport] = useState(null); + const [reports, setReports] = useState([]); + const [suggestions, setSuggestions] = useState([]); + const [selectedReport, setSelectedReport] = useState(null); + const [researching, setResearching] = useState(false); + const [copiedIdx, setCopiedIdx] = useState(null); + + const loadAll = async () => { + const [latest, rpts, sugg] = await Promise.all([ + getLatestTrendReport().catch(() => null), + getTrendReports().catch(() => []), + getMarketSuggestions().catch(() => []), + ]); + setLatestReport(latest); + setReports(Array.isArray(rpts) ? rpts : rpts.reports ?? []); + setSuggestions(Array.isArray(sugg) ? sugg : sugg.suggestions ?? []); + }; + + useEffect(() => { loadAll(); }, []); + + const handleResearch = async () => { + setResearching(true); + try { + await triggerYoutubeResearch(); + } catch (e) { + console.error('triggerYoutubeResearch:', e); + } finally { + setResearching(false); + } + }; + + const handleCopy = (text, idx) => { + navigator.clipboard.writeText(text).then(() => { + setCopiedIdx(idx); + setTimeout(() => setCopiedIdx(null), 2000); + }); + }; + + // ์„ ํƒ๋œ ๋ฆฌํฌํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ, ์—†์œผ๋ฉด ์ตœ์‹  ๋ฆฌํฌํŠธ์˜ ์žฅ๋ฅด ํ‘œ์‹œ + const displayReport = selectedReport ?? latestReport; + const topGenres = displayReport?.top_genres?.slice(0, 5) ?? []; + const maxScore = topGenres.length > 0 ? Math.max(...topGenres.map(g => g.score)) : 1; + + return ( +
+ {/* ์ˆ˜์ง‘ ์ƒํƒœ ๋ฐ” */} +
+
+ + + ๋งˆ์ง€๋ง‰ ์ˆ˜์ง‘: {latestReport?.report_date ?? '์—†์Œ'} + {latestReport && ` ยท ${latestReport.top_genres?.length ?? 0}๊ฐœ ์žฅ๋ฅด`} + +
+ +
+ + {/* ์ธ๊ธฐ ์žฅ๋ฅด Top 5 */} +
+

๐Ÿ”ฅ ์˜ค๋Š˜์˜ ์ธ๊ธฐ ์žฅ๋ฅด Top 5

+ {topGenres.length === 0 ? ( +

+ ํŠธ๋ Œ๋“œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ˆ˜๋™ ์ˆ˜์ง‘์„ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ agent-office๊ฐ€ ๋‚ด์ผ 09:00์— ์ž๋™ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค. +

+ ) : ( +
+ {topGenres.map((g, i) => ( +
+
#{i + 1}
+
+
+ {g.genre} + + {(g.countries ?? []).map(c => FLAG[c] ?? c).join(' ')} + +
+
+
+
+
+
{g.score}
+
+ ))} +
+ )} +
+ + {/* Suno ํ”„๋กฌํ”„ํŠธ ์ถ”์ฒœ */} + {suggestions.length > 0 && ( +
+

โœจ AI ์ถ”์ฒœ Suno ํ”„๋กฌํ”„ํŠธ

+
+ {suggestions.map((s, i) => ( +
+
+ {s.genre} + + {(s.target_countries ?? []).map(c => FLAG[c] ?? c).join(' ')} + +
+ + {copiedIdx === i && ( + โœ“ ๋ณต์‚ฌ๋จ + )} + {s.reason && ( +
{s.reason}
+ )} +
+ ))} +
+
+ )} + + {/* ํŠธ๋ Œ๋“œ ๋ฆฌํฌํŠธ ์ด๋ ฅ */} +
+

๐Ÿ“‹ ํŠธ๋ Œ๋“œ ๋ฆฌํฌํŠธ ์ด๋ ฅ

+ {reports.length === 0 ? ( +

๋ฆฌํฌํŠธ ์ด๋ ฅ์ด ์—†์Šต๋‹ˆ๋‹ค

+ ) : ( +
+ {reports.map(r => ( +
setSelectedReport( + selectedReport?.report_date === r.report_date ? null : r + )} + > + + {r.report_date} + {r.report_date === latestReport?.report_date && ( + โ— ์˜ค๋Š˜ + )} + + + {r.top_genres?.length ?? 0}๊ฐœ ์žฅ๋ฅด ยท {r.recommended_styles?.length ?? 0}๊ฐœ ์ถ”์ฒœ + + ๋ณด๊ธฐ โ†’ +
+ ))} +
+ )} +
+
+ ); }