/* 회의록 브레인 — 앱 셸 (사이드바 · 토픽바 · 전역 상태) */ function App() { const DS = window.CalComDesignSystem_436c9d; const { Switch } = DS; const D = window.MB_DATA; const [screen, setScreen] = React.useState("input"); // input | search | board | dashboard const [meetings, setMeetings] = React.useState(D.MEETINGS); const [actions, setActions] = React.useState( D.ACTIONS.map((a) => ({ ...a })) ); const [modalMeeting, setModalMeeting] = React.useState(null); const [toast, setToast] = React.useState({ show: false, msg: "" }); const [navOpen, setNavOpen] = React.useState(false); const [theme, setTheme] = React.useState("dark"); // 테마 적용 React.useEffect(() => { document.documentElement.setAttribute("data-mb-theme", theme); }, [theme]); const showToast = (msg) => { setToast({ show: true, msg }); clearTimeout(showToast._t); showToast._t = setTimeout(() => setToast((s) => ({ ...s, show: false })), 2600); }; // 회의록 저장 (화면 ①) const handleSave = ({ meeting, actions: newActions }) => { setMeetings((ms) => [meeting, ...ms]); if (newActions && newActions.length) { setActions((as) => [ ...newActions.map((a, i) => ({ id: `na-${meeting.id}-${i}`, title: a.title, owner: a.owner, start: a.start, end: a.end, status: "planned", meeting: meeting.id, })), ...as, ]); } showToast("회의록을 저장했습니다"); }; // 액션 상태 순환 (화면 ③) — 보드는 데모 비주얼(시드+세션 저장분)이라 로컬 상태만 변경 const cycle = (id) => { setActions((as) => as.map((a) => a.id === id ? { ...a, status: D.STATUS_CYCLE[a.status] } : a )); }; const navItems = [ { key: "input", label: "회의록 입력", icon: "file-plus", count: meetings.length }, { key: "search", label: "RAG 검색", icon: "search" }, { key: "board", label: "액션 보드", icon: "gantt", count: actions.length }, { key: "dashboard", label: "누적 대시보드", icon: "dashboard" }, ]; const go = (key) => { setScreen(key); setNavOpen(false); }; const screenMeta = { input: { title: "회의록 입력", sub: "AI 정리 · 저장" }, search: { title: "RAG 검색", sub: "출처 기반 답변" }, board: { title: "액션 보드", sub: "담당자별 타임라인" }, dashboard: { title: "누적 대시보드", sub: "회의 기록 누적" }, }[screen]; const doneCount = actions.filter((a) => a.status === "done").length; return (
{/* 사이드바 */} {navOpen &&
setNavOpen(false)} />} {/* 메인 */}
{screenMeta.title}
{screenMeta.sub}
{meetings.length} 회의록
{doneCount}/{actions.length} 액션 완료
{screen === "input" && ( )} {screen === "search" && ( )} {screen === "board" && ( )} {screen === "dashboard" && ( )}
setModalMeeting(null)} />
); } window.App = App;