49b04e9710
New "Communication" area in the dashboard, built on the existing appshell-sdk wiring
(useQuery/sdk.command) like Team, with the IIOS MessageSocket for live streaming.
- messenger-api.ts / inbox-api.ts: mock (demo) + live (crm.messenger.* / crm.inbox.*)
behind one interface, switched by isShellConfigured().
- messenger-socket.tsx: MessengerSocketProvider — one IIOS MessageSocket per panel
(openThread history + live on("message") + send). REST 4s poll is the automatic
fallback when the socket isn't connected.
- messenger.tsx: conversation list ⇄ thread + composer + new-chat people picker
(DM 1 person / group 2+); inbox.tsx: filterable feed with Done/Snooze/Archive.
- sidebar: Communication group (Messenger + Inbox, always-visible); dashboard: panel switch.
- .npmrc: add the @insignia Gitea registry for @insignia/iios-kernel-client.
Works on mock immediately; goes live once NEXT_PUBLIC_SUPABASE_URL + the BFF + be-crm are set.
tsc clean; next build passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
80 lines
3.4 KiB
TypeScript
80 lines
3.4 KiB
TypeScript
"use client";
|
|
|
|
// ============================================================
|
|
// Dashboard shell — premium dark theme. Keeps the sidebar +
|
|
// header and swaps the inner content. Profile / Support / Rules
|
|
// render real views; other workspace modules show a placeholder.
|
|
// ============================================================
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { Sidebar, NAV_ITEMS } from "./sidebar";
|
|
import { Topbar } from "./topbar";
|
|
import { ToastProvider, PageHead, Btn, Icon } from "./ui";
|
|
import { Profile } from "./profile";
|
|
import { Support } from "./support";
|
|
import { Rules } from "./rules";
|
|
import { AiAssistant } from "./ai-assistant";
|
|
import { TeamManagement } from "./team-management";
|
|
import { Messenger } from "./messenger";
|
|
import { Inbox } from "./inbox";
|
|
import "../../app/dashboard/dashboard.css";
|
|
|
|
export function Dashboard() {
|
|
const [theme, setTheme] = useState<"dark" | "light">("dark");
|
|
const [active, setActive] = useState("dashboard");
|
|
|
|
useEffect(() => {
|
|
// Sync the persisted theme from localStorage (an external system) on mount.
|
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
try { const t = localStorage.getItem("lup_dash_theme"); if (t === "light" || t === "dark") setTheme(t); } catch {}
|
|
}, []);
|
|
function toggle() {
|
|
setTheme((t) => { const n = t === "dark" ? "light" : "dark"; try { localStorage.setItem("lup_dash_theme", n); } catch {} return n; });
|
|
}
|
|
|
|
const item = NAV_ITEMS.find((i) => i.key === active);
|
|
const title = item?.label ?? "Dashboard";
|
|
const subtitle = item?.subtitle ?? "Workspace module";
|
|
|
|
return (
|
|
<div className="dash-root" data-theme={theme}>
|
|
<Sidebar active={active} onSelect={setActive} />
|
|
<div className="dash-main">
|
|
<Topbar theme={theme} onToggle={toggle} title={title} subtitle={subtitle} />
|
|
<div className="dash-content">
|
|
<ToastProvider>
|
|
{active === "profile" ? <Profile />
|
|
: active === "support" ? <Support />
|
|
: active === "rules" ? <Rules />
|
|
: active === "ai" ? <AiAssistant />
|
|
: active === "messenger" ? <Messenger />
|
|
: active === "inbox" ? <Inbox />
|
|
: active === "team" ? <TeamManagement />
|
|
: <ComingSoon title={title} icon={item?.icon ?? "dashboard"} onGo={setActive} />}
|
|
</ToastProvider>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Placeholder for workspace modules that don't have a view yet — keeps the
|
|
// full navigation coherent and points users to the live sections.
|
|
function ComingSoon({ title, icon, onGo }: { title: string; icon: string; onGo: (k: string) => void }) {
|
|
return (
|
|
<div className="view">
|
|
<PageHead eyebrow="Workspace" title={title} subtitle="This module is part of the LynkedUp Pro workspace." icon={icon} />
|
|
<div className="card coming-soon">
|
|
<span className="coming-soon-ic"><Icon name={icon} size={34} /></span>
|
|
<h3>{title} is coming soon</h3>
|
|
<p>This area is reserved for the {title} module. In the meantime, the account experience is fully built out.</p>
|
|
<div className="coming-soon-actions">
|
|
<Btn icon="user" onClick={() => onGo("profile")}>Open Profile</Btn>
|
|
<Btn variant="outline" icon="chat" onClick={() => onGo("support")}>Support Center</Btn>
|
|
<Btn variant="ghost" icon="check-circle" onClick={() => onGo("rules")}>Rules</Btn>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|