"use client" import { useMemo, useState } from "react" import { useCustomer } from "autumn-js/react" import { toast } from "sonner" import { Building2, Check, ChevronsUpDown, LoaderIcon, Plus, } from "lucide-react" import { cn } from "@lib/utils" import { dmSansClassName, dmSans125ClassName } from "@/lib/fonts" import { useAuth } from "@lib/auth-context" import { authClient } from "@lib/auth" import { Popover, PopoverContent, PopoverTrigger } from "@ui/components/popover" import { Dialog, DialogContent, DialogTitle } from "@ui/components/dialog" import { OrgPlanBadge, resolveOrgPlan } from "@/components/org-plan-badge" import { useOrgSummaries } from "@/hooks/use-org-summaries" import { useTokenUsage, type PlanType } from "@/hooks/use-token-usage" const SURFACE_SHADOW = "0 2.842px 14.211px 0 rgba(0,0,0,0.25), 0.711px 0.711px 0.711px 0 rgba(255,255,255,0.10) inset" function generateOrgSlug(name: string): string { const base = name .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/(^-|-$)/g, "") || "org" return `${base}-${Math.floor(100000 + Math.random() * 900000)}` } export function SettingsOrgSwitcher() { const { org, organizations, setActiveOrg } = useAuth() const autumn = useCustomer() const { currentPlan } = useTokenUsage(autumn) const { data: orgSummaries } = useOrgSummaries() const [open, setOpen] = useState(false) const [switchingId, setSwitchingId] = useState(null) const [createOpen, setCreateOpen] = useState(false) const [createName, setCreateName] = useState("") const [creating, setCreating] = useState(false) const planByOrgId = useMemo(() => { const map = new Map() for (const summary of orgSummaries ?? []) { map.set(summary.orgId, summary.plan) } return map }, [orgSummaries]) const activeOrgPlan = org?.id ? resolveOrgPlan(org.id, true, currentPlan, planByOrgId) : currentPlan const sortedOrgs = useMemo( () => [...(organizations ?? [])].sort((a, b) => a.name.localeCompare(b.name)), [organizations], ) const handleSwitch = async (slug: string, id: string) => { if (id === org?.id) { setOpen(false) return } setSwitchingId(id) try { await setActiveOrg(slug) window.location.reload() } catch (error) { console.error("Failed to switch organization:", error) setSwitchingId(null) toast.error("Failed to switch organization") } } const handleCreate = async () => { const name = createName.trim() if (!name || creating) return setCreating(true) try { const result = await authClient.organization.create({ name, slug: generateOrgSlug(name), metadata: { signupSource: "consumer" }, }) if (result.error) { throw new Error(result.error.message ?? "Failed to create organization") } await setActiveOrg(result.data?.slug ?? "") window.location.reload() } catch (error) { setCreating(false) toast.error( error instanceof Error ? error.message : "Failed to create organization", ) } } return ( <> {sortedOrgs.map((organization) => { const isCurrent = organization.id === org?.id const isSwitching = switchingId === organization.id const plan = resolveOrgPlan( organization.id, isCurrent, currentPlan, planByOrgId, ) return ( ) })}
{ setCreateOpen(next) if (!next) setCreateName("") }} >
Create organization

A separate workspace with its own memories, connections, and members.

setCreateName(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") handleCreate() }} placeholder="Organization name" maxLength={80} className="w-full rounded-xl border border-[#2A2D35] bg-[#0D0F14] px-4 py-2.5 text-sm text-white placeholder:text-[#525D6E] focus:outline-none focus:border-[#4BA0FA]/50 transition-colors" />
) }