/* ============================================================ Feedback — 공용 헬퍼(STAGE_*, FEED_CHANNELS, rangeKey, PeriodCalendar 등)는 screens-episode.jsx에서 이동해왔다 (load order상 screens-episode.jsx 다음에 로드). 피드백 페이지 본체는 WbsFeedbackBoard(WBS 구조). ============================================================ */ const FEED_CHANNELS = [['INSTAGRAM','Instagram'],['LINKEDIN','LinkedIn'],['FACEBOOK','Facebook'],['NEWSROOM','Newsroom'],['OTHER','기타']]; const STAGE_LABEL = { PLAN: '기획', DESIGN: '디자인' }; const STAGE_COLOR = { PLAN: '#e8590c', DESIGN: '#1971c2' }; // 기획=주황(난색) · 디자인=파랑(한색) const STAGE_SOFT = { PLAN: '#fff1e8', DESIGN: '#e7f1fb' }; const STAGE_SHORT = { PLAN: '기', DESIGN: '디' }; // 작성자 역할 색: LGE=빨강, CNX·ADMIN=파랑 (요구 규칙). ROLE_BADGE(screens-episode.jsx) 색을 // 재사용하되 ADMIN도 CNX(파랑)로 통일 — 단일 출처로 팔레트 중복 제거. const memoRoleStyle = (role) => (role === 'LGE' ? ROLE_BADGE.LGE : ROLE_BADGE.CNX); const canDeleteNote = (note, user) => (note.author && note.author.id === user.id) || user.role === 'CNX' || user.role === 'ADMIN'; // 공용 메모 카드 — 에피소드별 메모·공통 메모 양쪽에서 재사용. 역할 색 배지 포함. function MemoNoteCard({ note, canDelete, onDelete }) { const role = note.author && note.author.role; const rc = memoRoleStyle(role); return (
{note.author && note.author.name} {role} {String(note.createdAt).slice(0, 10)} {canDelete && }
{note.body}
); } // 공용 메모 입력기 — 자체 body/busy 상태 보유. onSubmit(text)가 API 호출+목록 갱신을 담당. // 에피소드별 메모·공통 메모 입력에서 재사용(입력 스캐폴드 중복 제거). function NoteComposer({ placeholder, onSubmit }) { const [body, setBody] = useSE(''); const [busy, setBusy] = useSE(false); const submit = async () => { if (!body.trim() || busy) return; setBusy(true); try { await onSubmit(body.trim()); setBody(''); } catch (e) { alert('작성 실패: ' + (e.message || e)); } finally { setBusy(false); } }; return (