mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
01f5dbd1ee
Northstar AI CRM — a full-featured agentic sales CRM for an enterprise hardware seller, built with CopilotKit, the AG-UI protocol, and a TypeScript Strands agent (@strands-agents/sdk + @ag-ui/aws-strands). The first TypeScript Strands example under examples/. Highlights: - Agentic canvas: tool calls render on the workspace — quote approval opens a quote page; analyze_team and generate_weekly_report open dedicated report pages; frontend tools navigate the workspace. - Generative UI cards, human-in-the-loop follow-up approval, and a live STATE_SNAPSHOT that syncs a SQLite CRM store with the board, dashboard, and report pages. - Dashboard, pipeline (Kanban), products, team, and reports surfaces. Self-contained under examples/showcases/strands-crm with an agent/ + frontend/ split and a concurrently dev script; listed in examples/README.md.
51 lines
1.2 KiB
TypeScript
51 lines
1.2 KiB
TypeScript
"use client";
|
|
import { useCallback, useSyncExternalStore } from "react";
|
|
|
|
const KEY = "northstar.sidebar.collapsed";
|
|
|
|
// Module-level subscriber set so every useSidebarCollapsed() instance re-reads
|
|
// the snapshot when any of them toggles. localStorage is the source of truth.
|
|
const listeners = new Set<() => void>();
|
|
|
|
function subscribe(cb: () => void): () => void {
|
|
listeners.add(cb);
|
|
return () => {
|
|
listeners.delete(cb);
|
|
};
|
|
}
|
|
|
|
function getSnapshot(): boolean {
|
|
try {
|
|
return localStorage.getItem(KEY) === "1";
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// SSR + first client render: default to expanded. useSyncExternalStore switches
|
|
// to getSnapshot after hydration, so a persisted collapsed state applies cleanly
|
|
// without a set-state-in-effect or a hydration mismatch.
|
|
function getServerSnapshot(): boolean {
|
|
return false;
|
|
}
|
|
|
|
export function useSidebarCollapsed(): {
|
|
collapsed: boolean;
|
|
toggle: () => void;
|
|
} {
|
|
const collapsed = useSyncExternalStore(
|
|
subscribe,
|
|
getSnapshot,
|
|
getServerSnapshot,
|
|
);
|
|
const toggle = useCallback(() => {
|
|
try {
|
|
localStorage.setItem(KEY, collapsed ? "0" : "1");
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
listeners.forEach((l) => l());
|
|
}, [collapsed]);
|
|
return { collapsed, toggle };
|
|
}
|