feat(impersonation): open user picker from account menu
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
7624327ab9
commit
39e13da41b
2 changed files with 43 additions and 14 deletions
|
|
@ -274,15 +274,9 @@ export function AppSidebar({
|
||||||
<hr />
|
<hr />
|
||||||
<NavSecondary
|
<NavSecondary
|
||||||
items={
|
items={
|
||||||
!adminUrl && !canImpersonate
|
adminUrl
|
||||||
? data.navSecondary
|
? [...data.navSecondary, { title: "Admin", url: adminUrl, icon: Shield }]
|
||||||
: [
|
: data.navSecondary
|
||||||
...data.navSecondary,
|
|
||||||
...(adminUrl ? [{ title: "Admin", url: adminUrl, icon: Shield }] : []),
|
|
||||||
...(canImpersonate
|
|
||||||
? [{ title: "Impersonate", url: "/impersonate", icon: UserCog }]
|
|
||||||
: []),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
className="mt-auto"
|
className="mt-auto"
|
||||||
/>
|
/>
|
||||||
|
|
@ -327,6 +321,7 @@ export function AppSidebar({
|
||||||
avatar: "",
|
avatar: "",
|
||||||
}}
|
}}
|
||||||
showCallsign={showCallsign}
|
showCallsign={showCallsign}
|
||||||
|
canImpersonate={canImpersonate}
|
||||||
/>
|
/>
|
||||||
</SidebarFooter>
|
</SidebarFooter>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { BadgeCheck, Bird, Bomb, ChevronsUpDown, FileTextIcon, LogOut } from "lucide-react";
|
import { BadgeCheck, Bird, Bomb, ChevronsUpDown, FileTextIcon, LogOut, Users2 } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
@ -21,10 +21,14 @@ import {
|
||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
useSidebar,
|
useSidebar,
|
||||||
} from "@/components/ui/sidebar";
|
} from "@/components/ui/sidebar";
|
||||||
|
import type { User } from "@/payload-types";
|
||||||
|
import { ImpersonationModal } from "@/components/frontend/impersonation/ImpersonationModal";
|
||||||
|
import { getImpersonationUsers } from "@/app/(frontend)/impersonate/actions";
|
||||||
|
|
||||||
export function NavUser({
|
export function NavUser({
|
||||||
user,
|
user,
|
||||||
showCallsign = false,
|
showCallsign = false,
|
||||||
|
canImpersonate = false,
|
||||||
}: {
|
}: {
|
||||||
user: {
|
user: {
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
|
@ -32,10 +36,14 @@ export function NavUser({
|
||||||
avatar: string;
|
avatar: string;
|
||||||
};
|
};
|
||||||
showCallsign?: boolean;
|
showCallsign?: boolean;
|
||||||
|
canImpersonate?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { isMobile } = useSidebar();
|
const { isMobile } = useSidebar();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [loggingOut, setLoggingOut] = useState(false);
|
const [loggingOut, setLoggingOut] = useState(false);
|
||||||
|
const [showImpersonationModal, setShowImpersonationModal] = useState(false);
|
||||||
|
const [impersonationUsers, setImpersonationUsers] = useState<any[]>([]);
|
||||||
|
const [loadingImpersonationUsers, setLoadingImpersonationUsers] = useState(false);
|
||||||
|
|
||||||
const primaryLine = showCallsign ? user.username : user.displayName;
|
const primaryLine = showCallsign ? user.username : user.displayName;
|
||||||
const secondaryLine = showCallsign ? user.displayName : user.username;
|
const secondaryLine = showCallsign ? user.displayName : user.username;
|
||||||
|
|
@ -53,6 +61,24 @@ export function NavUser({
|
||||||
router.refresh();
|
router.refresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOpenImpersonationModal = async () => {
|
||||||
|
setLoadingImpersonationUsers(true);
|
||||||
|
try {
|
||||||
|
const users = await getImpersonationUsers();
|
||||||
|
setImpersonationUsers(users);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to load impersonation users:", error);
|
||||||
|
} finally {
|
||||||
|
setLoadingImpersonationUsers(false);
|
||||||
|
}
|
||||||
|
setShowImpersonationModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleImpersonationStarted = async () => {
|
||||||
|
router.push("/");
|
||||||
|
router.refresh();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
|
|
@ -122,10 +148,12 @@ export function NavUser({
|
||||||
Account
|
Account
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
{/* <DropdownMenuItem> */}
|
{canImpersonate && (
|
||||||
{/* <Bell /> */}
|
<DropdownMenuItem onClick={handleOpenImpersonationModal}>
|
||||||
{/* Notifications */}
|
<Users2 />
|
||||||
{/* </DropdownMenuItem> */}
|
Impersonate
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem onSelect={() => handleLogout()}>
|
<DropdownMenuItem onSelect={() => handleLogout()}>
|
||||||
|
|
@ -135,6 +163,12 @@ export function NavUser({
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
|
<ImpersonationModal
|
||||||
|
open={showImpersonationModal}
|
||||||
|
onOpenChange={setShowImpersonationModal}
|
||||||
|
users={impersonationUsers}
|
||||||
|
onStart={handleImpersonationStarted}
|
||||||
|
/>
|
||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue