This commit is contained in:
Owen Schwartz 2024-10-13 22:49:29 -04:00
commit b53d093065
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
5 changed files with 143 additions and 113 deletions

View file

@ -0,0 +1,87 @@
"use client";
import { Avatar, AvatarFallback } from "@app/components/ui/avatar";
import { Badge } from "@app/components/ui/badge";
import { Button } from "@app/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "@app/components/ui/dropdown-menu";
import Link from "next/link";
type HeaderProps = {
name?: string;
email: string;
orgName: string;
};
export default function Header({ email, orgName, name }: HeaderProps) {
function getInitials() {
if (name) {
const [firstName, lastName] = name.split(" ");
return `${firstName[0]}${lastName[0]}`;
}
return email.substring(0, 2).toUpperCase();
}
return (
<>
<div className="flex items-center justify-between">
<Badge variant="outline" className="text-md font-bold">
{orgName}
</Badge>
<div className="flex items-center">
<div className="flex items-center gap-3">
<span className="text-lg font-medium">
{name || email}
</span>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="relative h-10 w-10 rounded-full"
>
<Avatar className="h-10 w-10">
<AvatarFallback>
{getInitials()}
</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-56"
align="end"
forceMount
>
<DropdownMenuLabel className="font-normal">
<div className="flex flex-col space-y-1">
{name && (
<p className="text-sm font-medium leading-none">
{name}
</p>
)}
<p className="text-xs leading-none text-muted-foreground">
{email}
</p>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Log out</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
</>
);
}

View file

@ -12,12 +12,14 @@ interface TopbarNavProps extends React.HTMLAttributes<HTMLElement> {
icon: React.ReactNode; icon: React.ReactNode;
}[]; }[];
disabled?: boolean; disabled?: boolean;
orgId: string;
} }
export function TopbarNav({ export function TopbarNav({
className, className,
items, items,
disabled = false, disabled = false,
orgId,
...props ...props
}: TopbarNavProps) { }: TopbarNavProps) {
const pathname = usePathname(); const pathname = usePathname();
@ -34,10 +36,10 @@ export function TopbarNav({
{items.map((item) => ( {items.map((item) => (
<Link <Link
key={item.href} key={item.href}
href={item.href} href={item.href.replace("{orgId}", orgId)}
className={cn( className={cn(
"px-2 py-3 text-md", "px-2 py-3 text-md",
pathname === item.href pathname === item.href.replace("{orgId}", orgId)
? "border-b-2 border-stone-600 text-stone-600" ? "border-b-2 border-stone-600 text-stone-600"
: "hover:text-gray-600 text-stone-400", : "hover:text-gray-600 text-stone-400",
"whitespace-nowrap", "whitespace-nowrap",

View file

@ -1,7 +1,9 @@
import { Metadata } from "next"; import { Metadata } from "next";
import { TopbarNav } from "./components/TopbarNav"; import { TopbarNav } from "./components/TopbarNav";
import { LayoutGrid, Tent } from "lucide-react"; import { Cog, LayoutGrid, Tent, Users } from "lucide-react";
import Header from "./components/Header"; import Header from "./components/Header";
import { verifySession } from "@app/lib/auth/verifySession";
import { redirect } from "next/navigation";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Configuration", title: "Configuration",
@ -11,39 +13,54 @@ export const metadata: Metadata = {
const topNavItems = [ const topNavItems = [
{ {
title: "Sites", title: "Sites",
href: "/configuration/sites", href: "/{orgId}/sites",
icon: <Tent />, icon: <Tent />,
}, },
{ {
title: "Resources", title: "Resources",
href: "/configuration/resources", href: "/{orgId}/resources",
icon: <LayoutGrid />, icon: <LayoutGrid />,
}, },
{
title: "Users",
href: "/{orgId}/users",
icon: <Users />,
},
{
title: "General",
href: "/{orgId}/general",
icon: <Cog />,
},
]; ];
interface ConfigurationLaytoutProps { interface ConfigurationLaytoutProps {
children: React.ReactNode; children: React.ReactNode;
params: { siteId: string }; params: { orgId: string };
} }
export default async function ConfigurationLaytout({ export default async function ConfigurationLaytout({
children, children,
params, params,
}: ConfigurationLaytoutProps) { }: ConfigurationLaytoutProps) {
const user = await verifySession();
if (!user) {
redirect("/auth/login");
}
return ( return (
<> <>
<div className="w-full bg-stone-200 border-b border-stone-300 mb-5 select-none px-3"> <div className="w-full bg-stone-200 border-b border-stone-300 mb-5 select-none sm:px-0 px-3">
<div className="container mx-auto flex flex-col content-between gap-3 pt-2"> <div className="container mx-auto flex flex-col content-between gap-3 pt-2">
<Header <Header
email="mschwartz10612@gmail.com" email={user.email}
orgName="Home Lab 1" orgName={params.orgId}
name="Milo Schwartz"
/> />
<TopbarNav items={topNavItems} /> <TopbarNav items={topNavItems} orgId={params.orgId}/>
</div> </div>
</div> </div>
<div className="container mx-auto px-3">{children}</div> <div className="container mx-auto sm:px-0 px-3">{children}</div>
</> </>
); );
} }

View file

@ -1,26 +1,30 @@
import React from 'react'; import React from "react";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { ProfileForm } from "@app/components/profile-form"; import { ProfileForm } from "@app/components/profile-form";
import { CreateSiteForm } from "./components/create-site"; import { CreateSiteForm } from "./components/create-site";
export default function SettingsProfilePage({ params }: { params: { siteId: string } }) { export default function SettingsProfilePage({
const isCreateForm = params.siteId === "create"; params,
}: {
params: { siteId: string };
}) {
const isCreateForm = params.siteId === "create";
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div> <div>
<h3 className="text-lg font-medium"> <h3 className="text-lg font-medium">
{isCreateForm ? "Create Site" : "Profile"} {isCreateForm ? "Create Site" : "Profile"}
</h3> </h3>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
{isCreateForm {isCreateForm
? "Create a new site for your profile." ? "Create a new site for your profile."
: "This is how others will see you on the site."} : "This is how others will see you on the site."}
</p> </p>
</div> </div>
<Separator /> <Separator />
{isCreateForm ? <CreateSiteForm /> : <ProfileForm />} {isCreateForm ? <CreateSiteForm /> : <ProfileForm />}
</div> </div>
); );
} }

View file

@ -1,80 +0,0 @@
"use client";
import { Avatar, AvatarFallback } from "@app/components/ui/avatar";
import { Badge } from "@app/components/ui/badge";
import { Button } from "@app/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "@app/components/ui/dropdown-menu";
type HeaderProps = {
name?: string;
email: string;
orgName: string;
};
export default function Header({ email, orgName, name }: HeaderProps) {
function getInitials() {
if (name) {
const [firstName, lastName] = name.split(" ");
return `${firstName[0]}${lastName[0]}`;
}
return email.substring(0, 2).toUpperCase();
}
return (
<>
<div className="flex items-center justify-between">
<Badge variant="outline" className="text-md font-bold">{orgName}</Badge>
<div className="flex items-center gap-3">
<span className="text-lg font-medium">{name || email}</span>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="relative h-10 w-10 rounded-full"
>
<Avatar className="h-10 w-10">
<AvatarFallback>
{getInitials()}
</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-56"
align="end"
forceMount
>
<DropdownMenuLabel className="font-normal">
<div className="flex flex-col space-y-1">
{name && (
<p className="text-sm font-medium leading-none">
{name}
</p>
)}
<p className="text-xs leading-none text-muted-foreground">
{email}
</p>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Log out</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</>
);
}