"use client"
import { Logo } from "@ui/assets/Logo"
import { useAuth } from "@lib/auth-context"
import NovaOrb from "@/components/nova/nova-orb"
import { useEffect, useRef, useState } from "react"
import { cn } from "@lib/utils"
import { dmSansClassName, dmSans125ClassName } from "@/lib/fonts"
import Account from "@/components/settings/account"
import Billing from "@/components/settings/billing"
import Integrations from "@/components/settings/integrations"
import ConnectionsMCP from "@/components/settings/connections-mcp"
import Support from "@/components/settings/support"
import { ErrorBoundary } from "@/components/error-boundary"
import { useRouter } from "next/navigation"
import { useQuery } from "@tanstack/react-query"
import { useIsMobile } from "@hooks/use-mobile"
import { useLocalStorageUsername } from "@hooks/use-local-storage-username"
import { useHasCompanyBrain } from "@/hooks/use-company-brain"
import {
LogOut,
RotateCcw,
Trash2,
Sun,
LoaderIcon,
User as UserIcon,
Zap,
HelpCircle,
CreditCard,
ShieldAlert,
ChevronRight,
ArrowUpRight,
Building2,
X,
} from "lucide-react"
import { authClient } from "@lib/auth"
import {
Dialog,
DialogContent,
DialogClose,
DialogTitle,
} from "@ui/components/dialog"
import { Popover, PopoverContent, PopoverTrigger } from "@ui/components/popover"
import { useResetOrganization } from "@/hooks/use-reset-organization"
import { useDeleteUserAccount } from "@/hooks/use-account-settings"
import { useDeleteOrganization } from "@/hooks/use-delete-organization"
import { SettingsOrgSwitcher } from "@/components/settings/settings-org-switcher"
export const TABS = [
"account",
"billing",
"integrations",
"connections",
"support",
] as const
export type SettingsTab = (typeof TABS)[number]
type NavItem = {
id: SettingsTab
label: string
description: string
icon: React.ReactNode
}
const NAV_ITEMS: NavItem[] = [
{
id: "account",
label: "Account",
description: "Your profile and organization",
icon: ,
},
{
id: "billing",
label: "Billing",
description: "Plan, usage and payments",
icon: ,
},
{
id: "integrations",
label: "Integrations",
description: "Save, sync and search across tools",
icon: ,
},
{
id: "connections",
label: "Connections & MCP",
description: "Drive, Notion, OneDrive, MCP",
icon: ,
},
{
id: "support",
label: "Support & Help",
description: "Get help or share feedback",
icon: ,
},
]
const MODAL_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"
const INSET_SHADOW = "inset 1.313px 1.313px 3.938px rgba(0,0,0,0.7)"
export function parseHashToTab(hash: string): SettingsTab {
const cleaned = hash.replace("#", "").toLowerCase()
return TABS.includes(cleaned as SettingsTab)
? (cleaned as SettingsTab)
: "account"
}
function IdentityCard({ displayName }: { displayName: string }) {
const firstName = displayName?.split(" ")[0] || ""
return (
{firstName ? `${firstName}'s` : "Your"}
supermemory
)
}
export function SettingsContent({
activeTab,
onTabChange,
dialogPortalContainer,
className,
showIdentity = true,
}: {
activeTab: SettingsTab
onTabChange: (tab: SettingsTab) => void
dialogPortalContainer?: HTMLElement | null
className?: string
showIdentity?: boolean
}) {
const { user, org, organizations, setActiveOrg, clearActiveOrg } = useAuth()
const isCompanyBrain = useHasCompanyBrain()
// Company Brain orgs manage tools in the Configure view; hide the generic tabs.
const navItems = isCompanyBrain
? NAV_ITEMS.filter(
(item) => item.id !== "integrations" && item.id !== "connections",
)
: NAV_ITEMS
const router = useRouter()
const isMobile = useIsMobile()
const localStorageUsername = useLocalStorageUsername()
const [isResetDialogOpen, setIsResetDialogOpen] = useState(false)
const [resetConfirmation, setResetConfirmation] = useState("")
const resetOrganization = useResetOrganization()
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false)
const [deleteEmailConfirm, setDeleteEmailConfirm] = useState("")
const deleteUserAccount = useDeleteUserAccount()
const [isDeleteOrgDialogOpen, setIsDeleteOrgDialogOpen] = useState(false)
const [deleteOrgConfirm, setDeleteOrgConfirm] = useState("")
const deleteOrgInputRef = useRef(null)
const deleteOrgDialogTimerRef = useRef | null>(
null,
)
const deleteOrganization = useDeleteOrganization()
const activeOrgId = org?.id
const previousOrgIdRef = useRef(activeOrgId)
// Only owners can delete the organization.
const activeMemberRoleQuery = useQuery({
queryKey: ["organization", org?.id, "active-member-role"],
queryFn: async () => {
const result = await authClient.organization.getActiveMember()
if (result.error) {
throw new Error(result.error.message ?? "Failed to load team role")
}
return result.data?.role ?? null
},
enabled: !!org?.id,
staleTime: 60_000,
})
const isOwner = (activeMemberRoleQuery.data ?? "").toLowerCase() === "owner"
const [dangerMenuOpen, setDangerMenuOpen] = useState(false)
useEffect(() => {
if (previousOrgIdRef.current === activeOrgId) return
previousOrgIdRef.current = activeOrgId
setDangerMenuOpen(false)
setIsDeleteOrgDialogOpen(false)
setDeleteOrgConfirm("")
}, [activeOrgId])
useEffect(() => {
if (!isDeleteOrgDialogOpen) return
document.body.style.pointerEvents = ""
const focusTimer = setTimeout(() => {
deleteOrgInputRef.current?.focus()
}, 0)
return () => clearTimeout(focusTimer)
}, [isDeleteOrgDialogOpen])
useEffect(() => {
return () => {
if (deleteOrgDialogTimerRef.current) {
clearTimeout(deleteOrgDialogTimerRef.current)
}
}
}, [])
const openDeleteOrganizationDialog = () => {
setDangerMenuOpen(false)
setDeleteOrgConfirm("")
if (deleteOrgDialogTimerRef.current) {
clearTimeout(deleteOrgDialogTimerRef.current)
}
deleteOrgDialogTimerRef.current = setTimeout(() => {
document.body.style.pointerEvents = ""
setIsDeleteOrgDialogOpen(true)
deleteOrgDialogTimerRef.current = null
}, 120)
}
const displayName =
user?.displayUsername ||
localStorageUsername ||
user?.name ||
user?.email?.split("@")[0] ||
""
const handleLogout = async () => {
await authClient.signOut()
router.push("/login")
}
const handleIntegrations = () => {
void router.push("/integrations")
}
const handleDeleteAccount = async () => {
if (deleteEmailConfirm !== user?.email) return
deleteUserAccount.mutate(
{ confirmation: deleteEmailConfirm },
{
onSuccess: () => {
setIsDeleteDialogOpen(false)
setDeleteEmailConfirm("")
router.push("/login")
},
},
)
}
const handleDeleteOrganization = async () => {
if (!org || deleteOrgConfirm !== org.name) return
deleteOrganization.mutate(org.id, {
onSuccess: async () => {
setIsDeleteOrgDialogOpen(false)
setDeleteOrgConfirm("")
const remaining = (organizations ?? []).filter((o) => o.id !== org.id)
if (remaining[0]) {
await setActiveOrg(remaining[0].slug)
window.location.href = "/"
} else {
await clearActiveOrg()
window.location.href = "/onboarding"
}
},
})
}
return (
<>
{/* Left rail */}
{/* Content */}
Something went wrong loading this section.{" "}
}
>
{activeTab === "account" && }
{activeTab === "billing" && }
{activeTab === "integrations" && }
{activeTab === "connections" && }
{activeTab === "support" && }
{/* Reset data dialog */}
{(() => {
const confirmText = org?.name || user?.name || ""
return (
)
})()}
{/* Delete account dialog */}
{/* Delete organization dialog */}
>
)
}