import React from "react";
import {
Activity,
AlertTriangle,
CheckCircle2,
Cpu,
Database,
GitBranch,
LineChart,
MessageSquare,
Settings,
ShieldCheck,
User,
Vote,
Wallet,
Zap,
Bot,
Boxes,
BookOpen,
FileText,
Network,
Video,
Palette,
Bell,
Store,
Plug,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Badge } from "@/components/ui/badge";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { Progress } from "@/components/ui/progress";
// ---------- Utility types ----------
type ModuleKey =
| "home"
| "messenger"
| "projects"
| "memory"
| "parser"
| "graph"
| "meetings"
| "agents"
| "training"
| "dao"
| "treasury"
| "integrations"
| "market"
| "analytics"
| "notifications"
| "admin"
| "creative"
| "security"
| "profile";
const MODULES: Array<{
key: ModuleKey;
label: string;
icon: React.ElementType;
}> = [
{ key: "home", label: "Головна / Оркестратор", icon: Cpu },
{ key: "messenger", label: "Чати та канали", icon: MessageSquare },
{ key: "projects", label: "Проєкти", icon: Boxes },
{ key: "memory", label: "База знань", icon: BookOpen },
{ key: "parser", label: "Парсер документів", icon: FileText },
{ key: "graph", label: "Граф знань", icon: Network },
{ key: "meetings", label: "Зустрічі", icon: Video },
{ key: "agents", label: "Агенти", icon: Bot },
{ key: "training", label: "Навчальний кабінет", icon: GitBranch },
{ key: "dao", label: "Голосування / DAO", icon: Vote },
{ key: "treasury", label: "Фінанси / Казна", icon: Wallet },
{ key: "integrations", label: "Інтеграції", icon: Plug },
{ key: "market", label: "Маркетплейс", icon: Store },
{ key: "analytics", label: "Аналітика", icon: LineChart },
{ key: "notifications", label: "Сповіщення", icon: Bell },
{ key: "admin", label: "Адмін-панель", icon: Settings },
{ key: "creative", label: "Креативна студія", icon: Palette },
{ key: "security", label: "Безпека / Аудит", icon: ShieldCheck },
{ key: "profile", label: "Профіль", icon: User },
];
// ---------- Reusable UI blocks ----------
function Sidebar({ active, onSelect }: { active: ModuleKey; onSelect: (k: ModuleKey) => void }) {
return (
);
}
function Topbar({ netOnline, orchOk }: { netOnline: boolean; orchOk: boolean }) {
return (
);
}
function HealthGrid() {
const items = [
{ title: "Messenger", ok: true },
{ title: "Parser", ok: false },
{ title: "KB Core", ok: true },
{ title: "RAG", ok: true },
{ title: "Wallet", ok: true },
{ title: "DAO", ok: true },
];
return (
{items.map((x) => (
{x.ok ? (
) : (
)}
{x.title}
{x.ok ? "Працює стабільно" : "Черга задач > p95"}
))}
);
}
function OrchestratorChat() {
return (
Чат з Оркестратором
Вітаю. Чим допомогти? Наприклад: "Розбери PDF та створй короткий бріф у Проєктах".
);
}
function ActivityFeed() {
const rows = [
{ t: "ingest.completed", d: "USDO готово", ts: "09:15" },
{ t: "message.created", d: "#general", ts: "09:12" },
{ t: "vote.finalized", d: "Постанова #12", ts: "08:55" },
{ t: "payment.sent", d: "Reward 2.5 μUTIL", ts: "08:40" },
];
return (
Стрічка подій
{rows.map((r, i) => (
-
{r.t}
— {r.d}
{r.ts}
))}
);
}
function TasksTable() {
const rows = [
{ agent: "parser-agent", task: "PDF→USDO", status: "running", eta: "2m" },
{ agent: "project-agent", task: "Бріф + Kanban", status: "queued", eta: "—" },
{ agent: "wallet-agent", task: "Нарахувати винагороду", status: "completed", eta: "0" },
];
const color = (s: string) => (s === "completed" ? "text-emerald-600" : s === "running" ? "text-amber-600" : "text-slate-500");
return (
Поточні задачі агентів
| Агент |
Задача |
Статус |
ETA |
{rows.map((r, i) => (
| {r.agent} |
{r.task} |
{r.status} |
{r.eta} |
))}
);
}
function AgentGraph() {
// Minimal static SVG graph placeholder
return (
Граф агентів
);
}
function HomeOrchestrator() {
return (
);
}
function Placeholder({ title }: { title: string }) {
return (
Розділ: {title}
Тут буде детальний екран модуля. Структура готова до підключення реальних даних та маршрутів.
);
}
function StartScreen({ onCreateDAO, onJoinDAO, onSolo, agentReady, onInstallAgent, installing, progress, modelProfile, setModelProfile, indexSize, setIndexSize }: { onCreateDAO: () => void; onJoinDAO: () => void; onSolo: () => void; agentReady: boolean; onInstallAgent: () => void; installing: boolean; progress: number; modelProfile: string; setModelProfile: (v: string) => void; indexSize: string; setIndexSize: (v: string) => void; }) {
return (
Ласкаво просимо до MicroDAO
Почніть зі створення спільноти DAO, приєднайтесь за інвайтом або спробуйте Solo-режим з локальним агентом.
Профіль моделі
{['Lite','Base','Plus','Pro'].map(p => (
))}
Автовибір за можливостями пристрою. Можна змінити пізніше.
Локальний індекс
{['200MB','500MB','1GB','5GB','20GB'].map(s => (
))}
int8 квантування заощаджує ×3–4 місця.
Можна змінити вибір пізніше у Налаштуваннях.
Локальний агент
{agentReady ? (
Готовий до роботи
) : (
<>
{installing ? (
) : (
)}
{installing ? 'Встановлення моделі…' : 'Ще не встановлено'}
{installing && (
Завантаження моделі: {Math.round(progress)}%
)}
Обсяг моделі підбирається автоматично за можливостями пристрою.
>
)}
);
}
export default function OrchestratorLayout() {
const [active, setActive] = React.useState("home");
const [orgId, setOrgId] = React.useState(null); // null = ще немає DAO/спільноти
const [agentReady, setAgentReady] = React.useState(false);
const [installing, setInstalling] = React.useState(false);
const [progress, setProgress] = React.useState(0);
const [modelProfile, setModelProfile] = React.useState('Base');
const [indexSize, setIndexSize] = React.useState('500MB');
const [netOnline, setNetOnline] = React.useState(typeof navigator !== 'undefined' ? navigator.onLine : true);
const [orchOk, setOrchOk] = React.useState(true);
React.useEffect(() => {
const on = () => setNetOnline(true);
const off = () => setNetOnline(false);
window.addEventListener('online', on);
window.addEventListener('offline', off);
const ping = setInterval(() => {
// TODO: replace with real /healthz ping
setOrchOk((v) => (Math.random() > 0.05));
}, 5000);
return () => { window.removeEventListener('online', on); window.removeEventListener('offline', off); clearInterval(ping); };
}, []);
// Симуляція інсталяції агента/моделі
const handleInstallAgent = () => {
if (installing || agentReady) return;
setInstalling(true);
setProgress(0);
const timer = setInterval(() => {
setProgress((p) => {
const next = Math.min(100, p + Math.random() * 18 + 5);
if (next >= 100) {
clearInterval(timer);
setInstalling(false);
setAgentReady(true);
}
return next;
});
}, 400);
};
// Роутінг після вибору режиму — встановлюємо orgId і відкриваємо домашню
const goReady = (id: string) => { setOrgId(id); setActive('home'); };
const content = () => {(0);
// Симуляція інсталяції агента/моделі
const handleInstallAgent = () => {
if (installing || agentReady) return;
setInstalling(true);
setProgress(0);
const timer = setInterval(() => {
setProgress((p) => {
const next = Math.min(100, p + Math.random() * 18 + 5);
if (next >= 100) {
clearInterval(timer);
setInstalling(false);
setAgentReady(true);
}
return next;
});
}, 400);
};
const content = () => {
if (!orgId) {
return (
goReady('dao-created')}
onJoinDAO={() => goReady('dao-joined')}
onSolo={() => goReady('solo-mode')}
agentReady={agentReady}
onInstallAgent={handleInstallAgent}
installing={installing}
progress={progress}
modelProfile={modelProfile}
setModelProfile={setModelProfile}
indexSize={indexSize}
setIndexSize={setIndexSize}
progress={progress}
/>
);
}
switch (active) {
case "home":
return ;
case "messenger":
return ;
case "projects":
return ;
case "memory":
return ;
case "parser":
return ;
case "graph":
return ;
case "meetings":
return ;
case "agents":
return ;
case "training":
return ;
case "dao":
return ;
case "treasury":
return ;
case "integrations":
return ;
case "market":
return ;
case "analytics":
return ;
case "notifications":
return ;
case "admin":
return ;
case "creative":
return ;
case "security":
return ;
case "profile":
return ;
}
};
return (
);
}