"use client";
import * as React from "react";
import { Check, CircleOff, FolderKanban, Plus } from "lucide-react";
import { useRouter } from "next/navigation";
import { useApp } from "@/components/app/store";
import { useApi } from "@/lib/client/api";
import { useIsMobile } from "@/lib/client/hooks";
import { ActionSheet, type ActionSheetItem } from "@/components/ui/sheet";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { toast } from "@/components/ui/toast";
import { ProjectIcon } from "./project-icon";
import type { PublicProject } from "@/lib/client/types";
/**
* Active-project quick switcher. Phone: iOS-style ActionSheet; desktop: dropdown.
* Wrap any trigger (`children`); selecting sets `activeProjectId` (new chats inherit the project).
*/
export function ProjectSwitcher({ children, onNavigate }: { children: React.ReactElement; onNavigate?: () => void }) {
const { activeProjectId, setActiveProjectId } = useApp();
const isMobile = useIsMobile();
const router = useRouter();
const [open, setOpen] = React.useState(false);
const { data } = useApi<{ projects: PublicProject[] }>(open || !isMobile ? "/api/projects" : null);
const projects = React.useMemo(() => (data?.projects ?? []).filter((p) => !p.archived), [data]);
const choose = (id: string | null) => {
setActiveProjectId(id);
const p = id ? projects.find((x) => x.id === id) : null;
toast.info(p ? `Active project: ${p.name}` : "No active project", p ? "New chats will use its instructions and models." : "New chats start without project context.");
};
if (isMobile) {
const items: (ActionSheetItem | "separator")[] = [
{ key: "none", label: "No project", icon: , selected: !activeProjectId, onSelect: () => choose(null) },
...projects.map((p) => ({ key: p.id, label: p.name, icon: , selected: p.id === activeProjectId, hint: p.conversationCount ? `${p.conversationCount}` : undefined, onSelect: () => choose(p.id) })),
"separator",
{
key: "new",
label: "New project",
icon: ,
onSelect: () => {
onNavigate?.();
router.push("/app/projects?new=1");
},
},
];
return (
<>
{React.cloneElement(children as React.ReactElement<{ onClick?: () => void }>, { onClick: () => setOpen(true) })}
>
);
}
return (
{children}
Active project
choose(null)}>
No project {!activeProjectId ? : null}
{projects.length ? : null}
{projects.map((p) => (
choose(p.id)}>
{p.name}
{p.id === activeProjectId ? : null}
))}
{
onNavigate?.();
router.push("/app/projects?new=1");
}}
>
New project
);
}