-
- Appointments & Schedule
-
-
- Today's clinic schedule and what's coming up. Sample data.
-
+
+
+
+ Appointments & Schedule
+
+
+ Today's clinic schedule and what's coming up. Sample data.
+
+
+
@@ -225,6 +244,14 @@ export function AppointmentsView() {
))}
+
+
setAddOpen(false)}
+ onOpenChange={setAddOpen}
+ open={addOpen}
+ />
);
}
diff --git a/frontend/components/command-palette.tsx b/frontend/components/command-palette.tsx
index 1e954c9..70cc90f 100644
--- a/frontend/components/command-palette.tsx
+++ b/frontend/components/command-palette.tsx
@@ -1,11 +1,6 @@
"use client";
-import {
- ArrowDownIcon,
- ArrowUpIcon,
- CornerDownLeftIcon,
- Search,
-} from "lucide-react";
+import { ArrowDownIcon, ArrowUpIcon, CornerDownLeftIcon } from "lucide-react";
import { useRouter } from "next/navigation";
import {
createContext,
@@ -32,7 +27,6 @@ import {
CommandPanel,
} from "@/components/ui/command";
import { Kbd, KbdGroup } from "@/components/ui/kbd";
-import { useSidebar } from "@/components/ui/sidebar";
import { navItems } from "@/lib/nav";
type CommandPaletteContextValue = { open: () => void };
@@ -171,28 +165,3 @@ export function CommandPaletteProvider({ children }: { children: ReactNode }) {
);
}
-
-// Sidebar-footer affordance: shows the ⌘K hint and opens the palette on click.
-// Hidden when the sidebar is collapsed to its icon rail.
-export function SidebarCommandButton() {
- const { open } = useCommandPalette();
- const { state } = useSidebar();
- const { t } = useTranslation();
-
- if (state === "collapsed") return null;
-
- return (
-
- );
-}
diff --git a/frontend/components/sidebar-02/app-sidebar.tsx b/frontend/components/sidebar-02/app-sidebar.tsx
index d7f567d..dc28042 100644
--- a/frontend/components/sidebar-02/app-sidebar.tsx
+++ b/frontend/components/sidebar-02/app-sidebar.tsx
@@ -5,7 +5,6 @@ import {
SidebarContent,
SidebarFooter,
SidebarHeader,
- SidebarSeparator,
SidebarTrigger,
useSidebar,
} from "@/components/ui/sidebar";
@@ -20,11 +19,9 @@ import { motion } from "framer-motion";
import Image from "next/image";
import { useTranslation } from "react-i18next";
import type { Route } from "./nav-main";
-import { SidebarCommandButton } from "@/components/command-palette";
import DashboardNavigation from "@/components/sidebar-02/nav-main";
import { NotificationsPopover } from "@/components/sidebar-02/nav-notifications";
import { NavUser } from "@/components/sidebar-02/nav-user";
-import { OrgSwitcher } from "@/components/sidebar-02/team-switcher";
const sampleNotifications = [
{
@@ -117,22 +114,7 @@ export function DashboardSidebar() {
-
-
-
-
-
-
-
+
);
diff --git a/frontend/components/sidebar-02/nav-main.tsx b/frontend/components/sidebar-02/nav-main.tsx
index 2cee71a..c683793 100644
--- a/frontend/components/sidebar-02/nav-main.tsx
+++ b/frontend/components/sidebar-02/nav-main.tsx
@@ -89,11 +89,10 @@ export default function DashboardNavigation({ routes }: { routes: Route[] }) {
{route.subs?.map((subRoute) => (
}
>
- {subRoute.icon}
{subRoute.title}
diff --git a/frontend/components/sidebar-02/nav-user.tsx b/frontend/components/sidebar-02/nav-user.tsx
index c888577..d39d985 100644
--- a/frontend/components/sidebar-02/nav-user.tsx
+++ b/frontend/components/sidebar-02/nav-user.tsx
@@ -1,17 +1,33 @@
"use client";
import {
+ Building2,
+ Check,
ChevronsUpDown,
LogOut,
Moon,
+ Plus,
+ Search,
Settings as SettingsIcon,
Sun,
} from "lucide-react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useTheme } from "next-themes";
+import { useState } from "react";
+import { useCommandPalette } from "@/components/command-palette";
+import { CreateClinicForm } from "@/components/clinic/create-clinic-form";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
+import {
+ Dialog,
+ DialogDescription,
+ DialogHeader,
+ DialogPanel,
+ DialogPopup,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Kbd, KbdGroup } from "@/components/ui/kbd";
import {
Menu,
MenuGroup,
@@ -20,6 +36,9 @@ import {
MenuPopup,
MenuSeparator,
MenuShortcut,
+ MenuSub,
+ MenuSubPopup,
+ MenuSubTrigger,
MenuTrigger,
} from "@/components/ui/menu";
import {
@@ -57,6 +76,9 @@ function GitHubIcon({ className }: { className?: string }) {
);
}
+// The sidebar's single footer row. Its menu also hosts the command-palette
+// shortcut hint (below Theme) and a clinic switcher submenu (below that) whose
+// popup reveals the active clinic's details on hover.
export function NavUser() {
const { isMobile, state } = useSidebar();
const isCollapsed = state === "collapsed";
@@ -64,10 +86,21 @@ export function NavUser() {
const { resolvedTheme, setTheme } = useTheme();
const isDark = resolvedTheme === "dark";
const { data } = authClient.useSession();
+ const { open: openCommand } = useCommandPalette();
+ const { data: orgs } = authClient.useListOrganizations();
+ const { data: activeOrg } = authClient.useActiveOrganization();
+
+ const [createOpen, setCreateOpen] = useState(false);
const name = data?.user?.name ?? "Clinician";
const email = data?.user?.email ?? "";
const initials = initialsFromName(name);
+ const activeName = activeOrg?.name ?? "Select clinic";
+
+ const setActive = async (organizationId: string) => {
+ if (organizationId === activeOrg?.id) return;
+ await authClient.organization.setActive({ organizationId });
+ };
const signOut = async () => {
const { error } = await authClient.signOut();
@@ -99,7 +132,7 @@ export function NavUser() {
<>
{name}
-
+
{email}
@@ -109,7 +142,7 @@ export function NavUser() {
@@ -120,7 +153,7 @@ export function NavUser() {
{name}
-
+
{email}
@@ -145,6 +178,61 @@ export function NavUser() {
Theme
{isDark ? "Dark" : "Light"}
+
+ {/* Command palette: hint + shortcut, sits below Theme. */}
+
+
+ {/* Clinic switcher: hover reveals the active clinic's details. */}
+
+
+
+ {activeName}
+
+
+
+
+ {activeOrg?.name ?? "No clinic selected"}
+
+
+ {activeOrg?.slug ? `/${activeOrg.slug}` : "—"} ·{" "}
+ {orgs?.length ?? 0}{" "}
+ {orgs?.length === 1 ? "clinic" : "clinics"}
+
+
+
+
+
+ Switch clinic
+
+ {(orgs ?? []).map((org) => (
+
+ ))}
+
+
+
+
+
+
+
+ {/* Create a new clinic */}
+
);
}
diff --git a/frontend/components/sidebar-02/team-switcher.tsx b/frontend/components/sidebar-02/team-switcher.tsx
deleted file mode 100644
index 201a4f4..0000000
--- a/frontend/components/sidebar-02/team-switcher.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-"use client";
-
-import { Building2, ChevronsUpDown, Info, Plus } from "lucide-react";
-import { useState } from "react";
-
-import { CreateClinicForm } from "@/components/clinic/create-clinic-form";
-import {
- Dialog,
- DialogDescription,
- DialogHeader,
- DialogPanel,
- DialogPopup,
- DialogTitle,
-} from "@/components/ui/dialog";
-import {
- Menu,
- MenuGroup,
- MenuGroupLabel,
- MenuItem,
- MenuPopup,
- MenuSeparator,
- MenuTrigger,
-} from "@/components/ui/menu";
-import {
- SidebarMenu,
- SidebarMenuButton,
- SidebarMenuItem,
- useSidebar,
-} from "@/components/ui/sidebar";
-import { authClient } from "@/lib/auth-client";
-
-function InfoRow({ label, value }: { label: string; value: string }) {
- return (
-
- {label}
- {value}
-
- );
-}
-
-// Switches the active clinic (organization). Scopes every subsequent patient
-// API call. Lives in the sidebar footer; its menu also opens dialogs to view
-// clinic info or create a new clinic.
-export function OrgSwitcher() {
- const { isMobile, state } = useSidebar();
- const isCollapsed = state === "collapsed";
- const { data: orgs } = authClient.useListOrganizations();
- const { data: activeOrg } = authClient.useActiveOrganization();
-
- const [infoOpen, setInfoOpen] = useState(false);
- const [createOpen, setCreateOpen] = useState(false);
-
- const setActive = async (organizationId: string) => {
- if (organizationId === activeOrg?.id) return;
- await authClient.organization.setActive({ organizationId });
- };
-
- const activeName = activeOrg?.name ?? "Select clinic";
-
- return (
-
-
-
-
-
- {/* Read-only clinic details */}
-
-
- {/* Create a new clinic (replaces the old /onboarding redirect) */}
-
-
- );
-}