From 6222b5671600979b1cba134917aa70f6ba01a748 Mon Sep 17 00:00:00 2001 From: gahusb Date: Sun, 17 May 2026 12:41:04 +0900 Subject: [PATCH] =?UTF-8?q?feat(insta):=20trends=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=9C=20progress=20=EB=B0=B0=EB=84=88?= =?UTF-8?q?=20+=20=EC=9E=90=EB=8F=99=20=EB=AF=B8=EB=A6=AC=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trends ํƒญ์˜ ๐ŸŽด ๋ฒ„ํŠผ ํด๋ฆญ์ด silent๋กœ ๋๋‚˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฌด๋™์ž‘์ฒ˜๋Ÿผ ๋ณด์ด๋˜ ์ด์Šˆ fix. handleCreateSlate๋ฅผ 3์ดˆ ๊ฐ„๊ฒฉ ํด๋ง์œผ๋กœ ํ™•์žฅ (์ตœ๋Œ€ 8๋ถ„): - ์‹œ์ž‘/์ง„ํ–‰/์„ฑ๊ณต/์‹คํŒจ ์ƒ๋‹จ ๋ฐฐ๋„ˆ๋กœ ์‹œ๊ฐํ™” - ์นด๋“œ ์ƒ์„ฑ ์™„๋ฃŒ ์‹œ ์ž๋™์œผ๋กœ Cards ํƒญ ์ „ํ™˜ + ์ƒˆ ์Šฌ๋ ˆ์ดํŠธ ์ž๋™ ์„ ํƒ โ†’ SlateDetail์ด ์นดํ”ผยท์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ฆ‰์‹œ ํ‘œ์‹œ - ์‹คํŒจ ์‹œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ + ํด๋ฆญ์œผ๋กœ dismiss - "Claude ์นดํ”ผ ์ถ”๋ก  + Playwright ์นด๋“œ 10์žฅ ์ƒ์„ฑ ์ค‘ (3~7๋ถ„)" ์•ˆ๋‚ด ๋ฌธ๊ตฌ --- src/pages/insta/InstaCards.css | 36 ++++++++++++++++++ src/pages/insta/InstaCards.jsx | 68 ++++++++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/src/pages/insta/InstaCards.css b/src/pages/insta/InstaCards.css index 367c8d0..2100a84 100644 --- a/src/pages/insta/InstaCards.css +++ b/src/pages/insta/InstaCards.css @@ -167,3 +167,39 @@ } .ic-impact__cat { font-weight: 600; text-transform: capitalize; color: rgba(255,255,255,.6); font-size: 0.82rem; } .ic-impact__count { color: #ec4899; font-weight: 700; font-size: 0.82rem; } + +/* โ”€โ”€ slate creation progress banner (์–‘ ํƒญ ๊ณตํ†ต) โ”€โ”€ */ +.ic-slate-progress { + margin: 8px 0 16px; + padding: 12px 16px; + border-radius: 8px; + font-size: 0.88rem; + display: flex; + align-items: center; + gap: 6px; + flex-wrap: wrap; + line-height: 1.5; +} +.ic-slate-progress--starting, +.ic-slate-progress--processing { + background: rgba(245, 158, 11, 0.12); + color: #fbbf24; + border-left: 4px solid #f59e0b; +} +.ic-slate-progress--succeeded { + background: rgba(16, 185, 129, 0.12); + color: #34d399; + border-left: 4px solid #10b981; + cursor: pointer; +} +.ic-slate-progress--failed { + background: rgba(239, 68, 68, 0.12); + color: #f87171; + border-left: 4px solid #ef4444; + cursor: pointer; +} +.ic-slate-progress__hint { + opacity: 0.7; + font-size: 0.78rem; + margin-left: 6px; +} diff --git a/src/pages/insta/InstaCards.jsx b/src/pages/insta/InstaCards.jsx index 975cb24..15b0e68 100644 --- a/src/pages/insta/InstaCards.jsx +++ b/src/pages/insta/InstaCards.jsx @@ -300,6 +300,10 @@ function PreferenceImpactPanel() { export default function InstaCards() { const [status, setStatus] = useState(null); const [selectedSlateId, setSelectedSlateId] = useState(null); + /* โ”€โ”€ ์นด๋“œ ์ƒ์„ฑ progress (Trends ํƒญ ํด๋ฆญ + Cards ํƒญ ์–‘์ชฝ ๋ชจ๋‘ ์‚ฌ์šฉ) โ”€โ”€ + * null = idle + * { keyword, status: 'starting'|'processing'|'succeeded'|'failed', message?, slate_id?, error? } */ + const [slateProgress, setSlateProgress] = useState(null); /* โ”€โ”€ ํƒญ ์ƒํƒœ (URL ๋™๊ธฐํ™”) โ”€โ”€ */ const [activeTab, setActiveTab] = useState(() => { @@ -323,13 +327,47 @@ export default function InstaCards() { loadStatus(); }, [loadStatus]); - /* โ”€โ”€ handleCreateSlate: ํ‚ค์›Œ๋“œ โ†’ ์Šฌ๋ ˆ์ดํŠธ ์ƒ์„ฑ (Trends ํƒญ์—์„œ๋„ ๊ณต์œ ) โ”€โ”€ */ + /* โ”€โ”€ handleCreateSlate: ํ‚ค์›Œ๋“œ โ†’ ์นดํ”ผ + ์ด๋ฏธ์ง€ ์ถ”๋ก  โ†’ ์ž๋™ ๋ฏธ๋ฆฌ๋ณด๊ธฐ โ”€โ”€ + * 1. createInstaSlate ํ˜ธ์ถœ โ†’ task_id + * 2. getInstaTask๋กœ ํด๋ง (3์ดˆ ๊ฐ„๊ฒฉ, ์ตœ๋Œ€ 8๋ถ„ = Claude ์นดํ”ผ + Playwright 10์žฅ ๋ Œ๋”) + * 3. ์™„๋ฃŒ ์‹œ Cards ํƒญ์œผ๋กœ ์ž๋™ ์ „ํ™˜ + ์Šฌ๋ ˆ์ดํŠธ ์„ ํƒ โ†’ SlateDetail์ด ์นดํ”ผยท์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ */ const handleCreateSlate = useCallback(async ({ keyword, category, keyword_id } = {}) => { + if (!keyword || !category) { + alert('keyword + category ํ•„์ˆ˜'); + return; + } + setSlateProgress({ keyword, status: 'starting', message: '์นด๋“œ ์ƒ์„ฑ ์‹œ์ž‘...' }); try { - await createInstaSlate({ keyword, category, keyword_id }); - setSelectedSlateId(null); + const { task_id } = await createInstaSlate({ keyword, category, keyword_id }); + let st = null; + // ์ตœ๋Œ€ 8๋ถ„ (3์ดˆ ร— 160) ํด๋ง + for (let i = 0; i < 160; i++) { + st = await getInstaTask(task_id); + setSlateProgress({ + keyword, + status: st.status, + message: st.message || `์ง„ํ–‰๋ฅ  ${st.progress}%`, + }); + if (st.status === 'succeeded' || st.status === 'failed') break; + await new Promise(r => setTimeout(r, 3000)); + } + if (st && st.status === 'succeeded' && st.result_id) { + // ์™„๋ฃŒ โ€” Cards ํƒญ์œผ๋กœ ์ž๋™ ์ด๋™ํ•ด์„œ SlateDetail ๋ณด์—ฌ์ฃผ๊ธฐ + setSlateProgress({ + keyword, status: 'succeeded', message: '์™„๋ฃŒ', slate_id: st.result_id, + }); + setSelectedSlateId(st.result_id); + switchTab('cards'); + // 3์ดˆ ํ›„ progress ๋ฐฐ๋„ˆ ์ž๋™ dismiss + setTimeout(() => setSlateProgress(null), 3000); + } else { + setSlateProgress({ + keyword, status: 'failed', + error: (st && st.error) || '์‹œ๊ฐ„ ์ดˆ๊ณผ ๋˜๋Š” ์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜', + }); + } } catch (e) { - alert('์นด๋“œ ์ƒ์„ฑ ์‹คํŒจ: ' + e.message); + setSlateProgress({ keyword, status: 'failed', error: e.message }); } }, []); @@ -347,6 +385,28 @@ export default function InstaCards() { >๐Ÿ“ˆ Trends + {/* โ”€โ”€ ์นด๋“œ ์ƒ์„ฑ progress ๋ฐฐ๋„ˆ (์–‘ ํƒญ ๊ณตํ†ต) โ”€โ”€ */} + {slateProgress && ( +
slateProgress.status !== 'processing' && slateProgress.status !== 'starting' && setSlateProgress(null)} + > + {slateProgress.status === 'starting' && 'โณ'} + {slateProgress.status === 'processing' && '๐ŸŽจ'} + {slateProgress.status === 'succeeded' && 'โœ…'} + {slateProgress.status === 'failed' && 'โš ๏ธ'} + {' '} + {slateProgress.keyword} + {' โ€” '} + {slateProgress.status === 'failed' + ? `์‹คํŒจ: ${slateProgress.error}` + : slateProgress.message} + {(slateProgress.status === 'starting' || slateProgress.status === 'processing') && ( + ยท Claude๋กœ 10ํŽ˜์ด์ง€ ์นดํ”ผ ์ถ”๋ก  + Playwright๋กœ ์นด๋“œ 10์žฅ ์ƒ์„ฑ ์ค‘ (3~7๋ถ„) + )} +
+ )} + {/* โ”€โ”€ Cards ํƒญ (๊ธฐ์กด 5-ํŒจ๋„) โ”€โ”€ */} {activeTab === 'cards' && ( <>