fix(music): TrendsTab 로딩상태·에러피드백·메타데이터 수정
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ const FLAG = { BR: '🇧🇷', US: '🇺🇸', ID: '🇮🇩', MX: '🇲🇽', K
|
|||||||
function fmtDateTime(iso) {
|
function fmtDateTime(iso) {
|
||||||
if (!iso) return null;
|
if (!iso) return null;
|
||||||
const d = new Date(iso);
|
const d = new Date(iso);
|
||||||
|
if (isNaN(d.getTime())) return iso.slice(0, 10);
|
||||||
const today = new Date().toDateString();
|
const today = new Date().toDateString();
|
||||||
if (d.toDateString() === today) {
|
if (d.toDateString() === today) {
|
||||||
return `오늘 ${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
|
return `오늘 ${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
|
||||||
@@ -24,8 +25,12 @@ export default function TrendsTab() {
|
|||||||
const [selectedReport, setSelectedReport] = useState(null);
|
const [selectedReport, setSelectedReport] = useState(null);
|
||||||
const [researching, setResearching] = useState(false);
|
const [researching, setResearching] = useState(false);
|
||||||
const [copiedIdx, setCopiedIdx] = useState(null);
|
const [copiedIdx, setCopiedIdx] = useState(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [researchMsg, setResearchMsg] = useState('');
|
||||||
|
|
||||||
const loadAll = async () => {
|
const loadAll = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
const [latest, rpts, sugg] = await Promise.all([
|
const [latest, rpts, sugg] = await Promise.all([
|
||||||
getLatestTrendReport().catch(() => null),
|
getLatestTrendReport().catch(() => null),
|
||||||
getTrendReports().catch(() => []),
|
getTrendReports().catch(() => []),
|
||||||
@@ -34,6 +39,11 @@ export default function TrendsTab() {
|
|||||||
setLatestReport(latest);
|
setLatestReport(latest);
|
||||||
setReports(Array.isArray(rpts) ? rpts : rpts.reports ?? []);
|
setReports(Array.isArray(rpts) ? rpts : rpts.reports ?? []);
|
||||||
setSuggestions(Array.isArray(sugg) ? sugg : sugg.suggestions ?? []);
|
setSuggestions(Array.isArray(sugg) ? sugg : sugg.suggestions ?? []);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('loadAll:', e);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => { loadAll(); }, []);
|
useEffect(() => { loadAll(); }, []);
|
||||||
@@ -42,6 +52,8 @@ export default function TrendsTab() {
|
|||||||
setResearching(true);
|
setResearching(true);
|
||||||
try {
|
try {
|
||||||
await triggerYoutubeResearch();
|
await triggerYoutubeResearch();
|
||||||
|
setResearchMsg('수집이 시작되었습니다. 잠시 후 새로고침하세요.');
|
||||||
|
setTimeout(() => setResearchMsg(''), 4000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('triggerYoutubeResearch:', e);
|
console.error('triggerYoutubeResearch:', e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -66,6 +78,8 @@ export default function TrendsTab() {
|
|||||||
? (selectedReport.recommended_styles ?? [])
|
? (selectedReport.recommended_styles ?? [])
|
||||||
: suggestions;
|
: suggestions;
|
||||||
|
|
||||||
|
if (loading) return <div className="yt-content"><p className="yt-empty">데이터 로딩 중...</p></div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="yt-content">
|
<div className="yt-content">
|
||||||
{/* 수집 상태 바 */}
|
{/* 수집 상태 바 */}
|
||||||
@@ -85,6 +99,7 @@ export default function TrendsTab() {
|
|||||||
>
|
>
|
||||||
{researching ? '수집 중...' : '↻ 수동 수집'}
|
{researching ? '수집 중...' : '↻ 수동 수집'}
|
||||||
</button>
|
</button>
|
||||||
|
{researchMsg && <p className="yt-empty" style={{ color: '#22c55e', marginTop: 4 }}>{researchMsg}</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 인기 장르 Top 5 */}
|
{/* 인기 장르 Top 5 */}
|
||||||
@@ -168,9 +183,10 @@ export default function TrendsTab() {
|
|||||||
<div
|
<div
|
||||||
key={r.id ?? r.report_date}
|
key={r.id ?? r.report_date}
|
||||||
className={`yt-report-row ${selectedReport?.report_date === r.report_date ? 'is-selected' : ''}`}
|
className={`yt-report-row ${selectedReport?.report_date === r.report_date ? 'is-selected' : ''}`}
|
||||||
onClick={() => setSelectedReport(
|
onClick={() => {
|
||||||
selectedReport?.report_date === r.report_date ? null : r
|
setSelectedReport(selectedReport?.report_date === r.report_date ? null : r);
|
||||||
)}
|
setCopiedIdx(null);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span className="yt-report-row__date">
|
<span className="yt-report-row__date">
|
||||||
{r.report_date}
|
{r.report_date}
|
||||||
@@ -179,7 +195,7 @@ export default function TrendsTab() {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span className="yt-report-row__meta">
|
<span className="yt-report-row__meta">
|
||||||
{r.top_genres?.length ?? 0}개 장르 · {r.recommended_styles?.length ?? 0}개 추천
|
{r.insights ? r.insights.slice(0, 60) + (r.insights.length >= 60 ? '…' : '') : ''}
|
||||||
</span>
|
</span>
|
||||||
<span className="yt-report-row__action">보기 →</span>
|
<span className="yt-report-row__action">보기 →</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user