import { i18n } from "@lingui/core"; import { Plural, Trans, useLingui } from "@lingui/react/macro"; import type { Bot, Group, RunActivityRow } from "@rakazo/contracts"; import { botColors } from "@rakazo/ui-tokens"; import { BotAvatar, Button, EvooMascot, GroupAvatar } from "@rakazo/ui-web"; import { ExternalLink } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { runActivityLabel } from "../lib/agent-activity"; import { buildHeuteBrief, cleanBriefPreview, type DoingItem, type DoneItem, type JetztItem, } from "../lib/heute-brief"; import { rpc } from "../lib/rpc"; const MISSION_CONTROL_URL = "http://127.0.0.1:3088/"; type HeuteBriefProps = { bots: Bot[]; groups: Group[]; onOpenBot: (botId: string, spaceId: string) => void; onOpenGroup: (groupId: string, spaceId: string) => void; onOpenRun: (run: RunActivityRow) => void; onStartChat: () => void; }; export function HeuteBrief({ bots, groups, onOpenBot, onOpenGroup, onOpenRun, onStartChat, }: HeuteBriefProps) { const [activeRuns, setActiveRuns] = useState([]); const [recentRuns, setRecentRuns] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { let cancelled = false; let timer: number | undefined; const tick = async () => { try { const [active, recent] = await Promise.all([ rpc.runs.list({ filter: "active" }), rpc.runs.list({ filter: "recent" }), ]); if (cancelled) return; setActiveRuns(active.runs); setRecentRuns(recent.runs); } catch { if (cancelled) return; } finally { if (!cancelled) { setLoading(false); timer = window.setTimeout(() => void tick(), 15_000); } } }; void tick(); return () => { cancelled = true; if (timer !== undefined) window.clearTimeout(timer); }; }, []); const brief = useMemo( () => buildHeuteBrief({ bots, groups, activeRuns, recentRuns, }), [activeRuns, bots, groups, recentRuns], ); const botColorById = useMemo(() => new Map(bots.map((bot) => [bot.id, bot.color])), [bots]); const dateLabel = formatHeuteDate(new Date()); const hasContent = brief.needsYou.length > 0 || brief.doing.length > 0 || brief.done.length > 0; return (

{dateLabel}

{loading && !hasContent ? (

Loading…

) : !hasContent ? ( 0} /> ) : (
{brief.needsYou.length > 0 ? (

Needs you

{brief.needsYou.map((item) => ( ))}
{brief.actionCount > brief.needsYou.length ? (

) : null}
) : null} {brief.doing.length > 0 ? (

Doing

{brief.doing.map((item) => ( ))}
) : null} {brief.done.length > 0 ? (

Done

{brief.done.map((item) => ( ))}
) : null}
)}
); } function StatusLine({ actionCount, doingCount, loading, }: { actionCount: number; doingCount: number; loading: boolean; }) { if (loading && actionCount === 0 && doingCount === 0) { return Loading…; } if (actionCount > 0) { return ; } if (doingCount > 0) { return ; } return All quiet; } function EmptyDay({ onStartChat, hasBots }: { onStartChat: () => void; hasBots: boolean }) { return (

Quiet day so far

Start a conversation with an Oo when you are ready.

); } function ActionableChip({ label }: { label: string }) { return ( {label} ); } function NeedsYouRow({ item, botColorById, onOpenBot, onOpenGroup, onOpenRun, }: { item: JetztItem; botColorById: Map; onOpenBot: (botId: string, spaceId: string) => void; onOpenGroup: (groupId: string, spaceId: string) => void; onOpenRun: (run: RunActivityRow) => void; }) { const { t } = useLingui(); if (item.kind === "run") { const run = item.run; const title = run.groupName ? `${run.botName} · ${run.groupName}` : run.botName; const subtitle = run.promptSnippet || runActivityLabel(run.status); const label = t`${title}, ${runActivityLabel(run.status)}`; return ( ); } const { chatKind, chat } = item; const title = chat.name; const preview = cleanBriefPreview(chat.preview) || t`Unread reply`; const label = chatKind === "bot" ? t`1:1 conversation with ${title}` : t`Group conversation ${title}`; return ( ); } function DoingRow({ item, botColorById, onOpenRun, }: { item: DoingItem; botColorById: Map; onOpenRun: (run: RunActivityRow) => void; }) { const { t } = useLingui(); const run = item.run; const title = run.groupName ? `${run.botName} · ${run.groupName}` : run.botName; const subtitle = run.promptSnippet || runActivityLabel(run.status); const label = t`${title}, ${runActivityLabel(run.status)}`; return ( ); } function DoneRow({ item, botColorById, onOpenRun, }: { item: DoneItem; botColorById: Map; onOpenRun: (run: RunActivityRow) => void; }) { const { t } = useLingui(); const run = item.run; const title = run.groupName ? `${run.botName} · ${run.groupName}` : run.botName; const subtitle = run.promptSnippet || runActivityLabel(run.status); const label = t`${title}, ${runActivityLabel(run.status)}`; return ( ); } function jetztRowKey(item: JetztItem): string { if (item.kind === "run") return `run:${item.run.runId}`; return `unread:${item.chatKind}:${item.chat.id}`; } function formatHeuteDate(date: Date): string { const locale = i18n.locale || "de"; return date.toLocaleDateString(locale, { weekday: "long", day: "numeric", month: "long", }); }