From aeeab6704f28841767346eacb4a120e847a34fd8 Mon Sep 17 00:00:00 2001 From: gahusb Date: Sun, 17 May 2026 12:51:26 +0900 Subject: [PATCH] =?UTF-8?q?fix(insta):=20SlateDetail=20JSON=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EB=A0=8C=EB=8D=94=20=EC=98=A4=EB=A5=98=20+=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EC=8A=A4=ED=81=AC=EB=A1=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (1) React error #31 fix: cover_copy/cta_copy는 객체({headline,body,accent_color}), body_copies는 배열 — 직접 {slate.cover_copy}로 렌더하면 에러. 필드별로 분해 렌더하고, 10페이지 전체 카피(커버 1 + 본문 8 + CTA 1)를 detail에 노출하도록 SlateDetail 확장. (2) UX: handleCreateSlate 시작 시 window.scrollTo(0, 0)로 상단 progress 배너 노출 보장. KeywordsPanel의 🎴 버튼도 부모 handleCreateSlate 위임으로 통합 — Trends/Cards 양쪽 어디서 눌러도 동일 흐름(배너 + 자동 미리보기). (3) KeywordsPanel의 자체 slatePoll 제거 — 상단 ic-slate-progress 배너로 일원화하여 중복 진행 표시 회피. --- src/pages/insta/InstaCards.jsx | 82 ++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/src/pages/insta/InstaCards.jsx b/src/pages/insta/InstaCards.jsx index 15b0e68..eb1425b 100644 --- a/src/pages/insta/InstaCards.jsx +++ b/src/pages/insta/InstaCards.jsx @@ -337,6 +337,10 @@ export default function InstaCards() { return; } setSlateProgress({ keyword, status: 'starting', message: '카드 생성 시작...' }); + // 상단 progress 배너가 보이도록 스크롤 (Trends/Cards 어느 탭의 어느 위치에서 눌렀든) + if (typeof window !== 'undefined') { + window.scrollTo({ top: 0, behavior: 'smooth' }); + } try { const { task_id } = await createInstaSlate({ keyword, category, keyword_id }); let st = null; @@ -432,7 +436,7 @@ export default function InstaCards() {
- setSelectedSlateId(null)} /> +
{/* 오른쪽: 슬레이트 목록 + 상세 */} @@ -522,10 +526,6 @@ function KeywordsPanel({ onCreateSlate }) { const [category, setCategory] = useState('전체'); const [keywords, setKeywords] = useState([]); const [creating, setCreating] = useState(null); // keyword_id being created - const slatePoll = usePollTask((t) => { - if (t.status === 'succeeded') onCreateSlate?.(); - setCreating(null); - }); const load = useCallback(() => { const cat = category === '전체' ? undefined : category; @@ -534,18 +534,17 @@ function KeywordsPanel({ onCreateSlate }) { useEffect(() => { load(); }, [load]); + // 부모(InstaCards)의 handleCreateSlate에 위임 — progress 배너 + 스크롤 + 자동 미리보기 공통화 async function handleCreate(kw) { if (creating) return; setCreating(kw.id); try { - const res = await createInstaSlate({ + await onCreateSlate?.({ keyword: kw.keyword, category: kw.category, keyword_id: kw.id, }); - slatePoll.start(res.task_id); - } catch (e) { - alert('카드 생성 실패: ' + e.message); + } finally { setCreating(null); } } @@ -567,7 +566,7 @@ function KeywordsPanel({ onCreateSlate }) { ))}
- {slatePoll.task && } + {/* progress 표시는 상단 ic-slate-progress 배너에서 일괄 처리 */} {keywords.length === 0 ? (
키워드가 없습니다. 키워드 추출을 실행하세요.
@@ -754,11 +753,66 @@ function SlateDetail({ slate, onDelete, onRender }) { )} - {/* 커버 카피 / 바디 카피 */} - {slate.cover_copy && ( + {/* 커버 카피 (1/10) */} + {slate.cover_copy && typeof slate.cover_copy === 'object' && (
-
커버 카피
-
{slate.cover_copy}
+
🎯 커버 (1/10)
+
+ {slate.cover_copy.headline} + {slate.cover_copy.body && ( +
+ {slate.cover_copy.body} +
+ )} + {slate.cover_copy.accent_color && ( +
+ accent: {slate.cover_copy.accent_color} +
+ )} +
+
+ )} + + {/* 본문 카피 8장 (2~9/10) */} + {Array.isArray(slate.body_copies) && slate.body_copies.length > 0 && ( +
+
📝 본문 8장 (2~9/10)
+ {slate.body_copies.map((b, i) => ( +
0 ? '1px solid rgba(255,255,255,0.06)' : 'none', + padding: '10px 0', + }} + > + {i + 2}. {b?.headline || ''} + {b?.body && ( +
+ {b.body} +
+ )} +
+ ))} +
+ )} + + {/* CTA 카피 (10/10) */} + {slate.cta_copy && typeof slate.cta_copy === 'object' && ( +
+
📣 마무리 (10/10)
+
+ {slate.cta_copy.headline} + {slate.cta_copy.body && ( +
+ {slate.cta_copy.body} +
+ )} + {slate.cta_copy.cta && ( +
+ CTA: {slate.cta_copy.cta} +
+ )} +
)}