make a user menu links component
All checks were successful
Deploy / deploy (ubuntu-latest, 2.44.0) (push) Successful in 2m16s
All checks were successful
Deploy / deploy (ubuntu-latest, 2.44.0) (push) Successful in 2m16s
This commit is contained in:
parent
59c737ce7b
commit
41b7420ec6
@ -1,18 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { ReactElement } from "react";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import { User } from "@/app/types/user/user";
|
||||
import { useUserContext } from "@/app/provider/user-provider";
|
||||
import { UserState } from "@/app/store/user-store";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import UserSettingsHeader from "@/components/dashboard/user/user-settings-header";
|
||||
|
||||
/**
|
||||
* The user billing page.
|
||||
@ -21,7 +11,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
*/
|
||||
const UserBillingPage = (): ReactElement => (
|
||||
<main className="w-[47rem] p-10 flex flex-col gap-5">
|
||||
<Header />
|
||||
<UserSettingsHeader title="Billing" />
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex flex-col gap-5">
|
||||
@ -30,32 +20,4 @@ const UserBillingPage = (): ReactElement => (
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
const Header = (): ReactElement => {
|
||||
const user: User | undefined = useUserContext(
|
||||
(state: UserState) => state.user
|
||||
);
|
||||
return (
|
||||
<div className="flex flex-col gap-1.5 select-none">
|
||||
<h1 className="text-2xl font-bold">Billing</h1>
|
||||
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/dashboard">
|
||||
Dashboard
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>{user?.username}</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Billing</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserBillingPage;
|
||||
|
@ -1,22 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { ReactElement } from "react";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import { User } from "@/app/types/user/user";
|
||||
import { useUserContext } from "@/app/provider/user-provider";
|
||||
import { UserState } from "@/app/store/user-store";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import AvatarSetting from "@/components/dashboard/user/profile/avatar-setting";
|
||||
import UsernameSetting from "@/components/dashboard/user/profile/username-setting";
|
||||
import EmailSetting from "@/components/dashboard/user/profile/email-setting";
|
||||
import TierSetting from "@/components/dashboard/user/profile/tier-setting";
|
||||
import UserSettingsHeader from "@/components/dashboard/user/user-settings-header";
|
||||
|
||||
/**
|
||||
* The user profile page.
|
||||
@ -25,7 +15,7 @@ import TierSetting from "@/components/dashboard/user/profile/tier-setting";
|
||||
*/
|
||||
const UserProfilePage = (): ReactElement => (
|
||||
<main className="w-[47rem] p-10 flex flex-col gap-5">
|
||||
<Header />
|
||||
<UserSettingsHeader title="My Profile" />
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex flex-col gap-5">
|
||||
@ -40,32 +30,4 @@ const UserProfilePage = (): ReactElement => (
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
const Header = (): ReactElement => {
|
||||
const user: User | undefined = useUserContext(
|
||||
(state: UserState) => state.user
|
||||
);
|
||||
return (
|
||||
<div className="flex flex-col gap-1.5 select-none">
|
||||
<h1 className="text-2xl font-bold">My Profile</h1>
|
||||
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/dashboard">
|
||||
Dashboard
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>{user?.username}</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>My Profile</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserProfilePage;
|
||||
|
@ -1,19 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { ReactElement } from "react";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import { User } from "@/app/types/user/user";
|
||||
import { useUserContext } from "@/app/provider/user-provider";
|
||||
import { UserState } from "@/app/store/user-store";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import TFASetting from "@/components/dashboard/user/settings/tfa/tfa-setting";
|
||||
import UserSettingsHeader from "@/components/dashboard/user/user-settings-header";
|
||||
|
||||
/**
|
||||
* The user settings page.
|
||||
@ -22,7 +12,7 @@ import TFASetting from "@/components/dashboard/user/settings/tfa/tfa-setting";
|
||||
*/
|
||||
const UserSettingsPage = (): ReactElement => (
|
||||
<main className="w-[47rem] p-10 flex flex-col gap-5">
|
||||
<Header />
|
||||
<UserSettingsHeader title="Settings" />
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex flex-col gap-5">
|
||||
@ -31,32 +21,4 @@ const UserSettingsPage = (): ReactElement => (
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
const Header = (): ReactElement => {
|
||||
const user: User | undefined = useUserContext(
|
||||
(state: UserState) => state.user
|
||||
);
|
||||
return (
|
||||
<div className="flex flex-col gap-1.5 select-none">
|
||||
<h1 className="text-2xl font-bold">Settings</h1>
|
||||
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/dashboard">
|
||||
Dashboard
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>{user?.username}</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Settings</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserSettingsPage;
|
||||
|
@ -23,7 +23,6 @@ import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.share
|
||||
import DashboardLoader from "@/components/dashboard/loader";
|
||||
import { hasFlag } from "@/lib/user";
|
||||
import { UserFlag } from "@/app/types/user/user-flag";
|
||||
import EmailVerificationScreen from "@/components/dashboard/user/email-verification-screen";
|
||||
|
||||
/**
|
||||
* The provider that will provide user context to children.
|
||||
|
21
src/app/types/dashboard/user-menu-link.ts
Normal file
21
src/app/types/dashboard/user-menu-link.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { ReactElement } from "react";
|
||||
|
||||
/**
|
||||
* A link in the user menu on the dashboard.
|
||||
*/
|
||||
export type UserMenuLink = {
|
||||
/**
|
||||
* The name of this link.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The icon for this link.
|
||||
*/
|
||||
icon: ReactElement;
|
||||
|
||||
/**
|
||||
* The href for this link.
|
||||
*/
|
||||
href: string;
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ReactElement } from "react";
|
||||
import { SidebarLink } from "@/app/types/sidebar-link";
|
||||
import { SidebarLink } from "@/app/types/dashboard/sidebar-link";
|
||||
import SimpleTooltip from "@/components/simple-tooltip";
|
||||
import Link from "next/link";
|
||||
import { cn } from "@/lib/utils";
|
@ -5,13 +5,13 @@ import Branding from "@/components/branding";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import Link from "next/link";
|
||||
import OrganizationSelector from "@/components/dashboard/sidebar/organization-selector";
|
||||
import Links from "@/components/dashboard/sidebar/links";
|
||||
import Links from "@/components/dashboard/sidebar/sidebar-links";
|
||||
import { User } from "@/app/types/user/user";
|
||||
import { useUserContext } from "@/app/provider/user-provider";
|
||||
import { UserState } from "@/app/store/user-store";
|
||||
import { hasFlag } from "@/lib/user";
|
||||
import { UserFlag } from "@/app/types/user/user-flag";
|
||||
import UserMenu from "@/components/dashboard/sidebar/user-menu";
|
||||
import UserMenu from "@/components/dashboard/sidebar/user-menu/user-menu";
|
||||
|
||||
/**
|
||||
* The sidebar to display on the dashboard.
|
||||
|
@ -0,0 +1,32 @@
|
||||
import { userMenuLinks } from "@/components/dashboard/sidebar/user-menu/user-menu";
|
||||
import Link from "next/link";
|
||||
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
||||
import { ReactElement } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { UserMenuLink } from "@/app/types/dashboard/user-menu-link";
|
||||
|
||||
const UserMenuLinks = (): ReactElement => {
|
||||
const path: string = usePathname();
|
||||
return (
|
||||
<>
|
||||
{userMenuLinks.map((link: UserMenuLink, index: number) => {
|
||||
const active = path.startsWith(link.href);
|
||||
return (
|
||||
<Link key={index} href={link.href} draggable={false}>
|
||||
<DropdownMenuItem
|
||||
className={cn(
|
||||
"gap-2.5 cursor-pointer",
|
||||
active && "opacity-70"
|
||||
)}
|
||||
>
|
||||
<div className="relative w-5 h-5">{link.icon}</div>
|
||||
<span>{link.name}</span>
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default UserMenuLinks;
|
@ -20,12 +20,31 @@ import {
|
||||
CreditCardIcon,
|
||||
UserIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import Link from "next/link";
|
||||
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Cookies, useCookies } from "next-client-cookies";
|
||||
import { Session } from "@/app/types/user/session";
|
||||
import { apiRequest } from "@/lib/api";
|
||||
import UserMenuLinks from "@/components/dashboard/sidebar/user-menu/user-menu-links";
|
||||
import { UserMenuLink } from "@/app/types/dashboard/user-menu-link";
|
||||
|
||||
export const userMenuLinks: UserMenuLink[] = [
|
||||
{
|
||||
name: "Profile",
|
||||
icon: <UserIcon />,
|
||||
href: "/dashboard/user/profile",
|
||||
},
|
||||
{
|
||||
name: "Billing",
|
||||
icon: <CreditCardIcon />,
|
||||
href: "/dashboard/user/billing",
|
||||
},
|
||||
{
|
||||
name: "Settings",
|
||||
icon: <Cog6ToothIcon />,
|
||||
href: "/dashboard/user/settings",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* The menu to manage the user.
|
||||
@ -93,24 +112,7 @@ const MyAccount = (): ReactElement => (
|
||||
My Account
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<Link href="/dashboard/user/profile" draggable={false}>
|
||||
<DropdownMenuItem className="gap-2.5 cursor-pointer">
|
||||
<UserIcon className="w-5 h-5" />
|
||||
<span>Profile</span>
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href="/dashboard/user/billing" draggable={false}>
|
||||
<DropdownMenuItem className="gap-2.5 cursor-pointer">
|
||||
<CreditCardIcon className="w-5 h-5" />
|
||||
<span>Billing</span>
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href="/dashboard/user/settings" draggable={false}>
|
||||
<DropdownMenuItem className="gap-2.5 cursor-pointer">
|
||||
<Cog6ToothIcon className="w-5 h-5" />
|
||||
<span>Settings</span>
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<UserMenuLinks />
|
||||
</DropdownMenuGroup>
|
||||
);
|
||||
|
64
src/components/dashboard/user/user-settings-header.tsx
Normal file
64
src/components/dashboard/user/user-settings-header.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
import { ReactElement } from "react";
|
||||
import { User } from "@/app/types/user/user";
|
||||
import { useUserContext } from "@/app/provider/user-provider";
|
||||
import { UserState } from "@/app/store/user-store";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { ChevronDownIcon } from "@heroicons/react/24/outline";
|
||||
import UserMenuLinks from "@/components/dashboard/sidebar/user-menu/user-menu-links";
|
||||
|
||||
/**
|
||||
* The header to display
|
||||
* on user settings pages.
|
||||
*
|
||||
* @param title the title of this header
|
||||
* @return the header jsx
|
||||
*/
|
||||
const UserSettingsHeader = ({ title }: { title: string }): ReactElement => {
|
||||
const user: User | undefined = useUserContext(
|
||||
(state: UserState) => state.user
|
||||
);
|
||||
return (
|
||||
<div className="flex flex-col gap-1.5 select-none">
|
||||
<h1 className="text-2xl font-bold">{title}</h1>
|
||||
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/dashboard">
|
||||
Dashboard
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger className="flex gap-1.5 items-center">
|
||||
@{user?.username}
|
||||
<ChevronDownIcon className="w-3 h-3" />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<UserMenuLinks />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>{title}</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default UserSettingsHeader;
|
Loading…
x
Reference in New Issue
Block a user