Dental Care
This commit is contained in:
651
components/landing/navbar.tsx
Normal file
651
components/landing/navbar.tsx
Normal file
@@ -0,0 +1,651 @@
|
||||
"use client";
|
||||
import { MenuIcon, SearchIcon, LogOut, User, Shield } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogClose,
|
||||
} from "@/components/ui/dialog";
|
||||
import Image from "next/image";
|
||||
import { authClient } from "@/lib/auth-session/auth-client";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuContent,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuLink,
|
||||
NavigationMenuList,
|
||||
NavigationMenuTrigger,
|
||||
} from "@/components/ui/navigation-menu";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupButton,
|
||||
InputGroupInput,
|
||||
} from "@/components/ui/input-group";
|
||||
import { ModeToggle } from "../ui/mode-toggle";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type User = {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
image?: string | null;
|
||||
role?: string;
|
||||
} | null;
|
||||
|
||||
type NavbarProps = {
|
||||
user?: User;
|
||||
isAdmin?: boolean;
|
||||
};
|
||||
|
||||
const Navbar = ({ user, isAdmin: userIsAdmin }: NavbarProps) => {
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
let ticking = false;
|
||||
const handleScroll = () => {
|
||||
if (!ticking) {
|
||||
window.requestAnimationFrame(() => {
|
||||
setIsScrolled(window.scrollY > 50);
|
||||
ticking = false;
|
||||
});
|
||||
ticking = true;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||
return () => window.removeEventListener("scroll", handleScroll);
|
||||
}, []);
|
||||
|
||||
const [showLogoutDialog, setShowLogoutDialog] = useState(false);
|
||||
const [showRequiredDialog, setShowRequiredDialog] = useState(false);
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const [showSuggestions, setShowSuggestions] = useState(false);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const handleSignOut = async () => {
|
||||
setShowLogoutDialog(false);
|
||||
try {
|
||||
await authClient.signOut();
|
||||
toast.success("Signed out successfully");
|
||||
router.push("/sign-in");
|
||||
router.refresh();
|
||||
} catch {
|
||||
toast.error("Failed to sign out");
|
||||
}
|
||||
};
|
||||
|
||||
// Handle search submit
|
||||
const handleSearch = (e?: React.FormEvent) => {
|
||||
if (e) e.preventDefault();
|
||||
if (searchValue.trim()) {
|
||||
router.push(`/search?query=${encodeURIComponent(searchValue.trim())}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getInitials = (name: string) => {
|
||||
return name
|
||||
.split(" ")
|
||||
.map((n) => n[0])
|
||||
.join("")
|
||||
.toUpperCase()
|
||||
.slice(0, 2);
|
||||
};
|
||||
const Services = [
|
||||
{
|
||||
title: "Preventive Care",
|
||||
description:
|
||||
"Cleanings, exams, and routine check-ups to keep smiles healthy",
|
||||
href: "/services/preventive-care",
|
||||
},
|
||||
{
|
||||
title: "Cosmetic Dentistry",
|
||||
description: "Teeth whitening, veneers, and smile makeovers",
|
||||
href: "/services/cosmetic-dentistry",
|
||||
},
|
||||
{
|
||||
title: "Orthodontics",
|
||||
description: "Braces and clear aligners for children and adults",
|
||||
href: "/services/orthodontics",
|
||||
},
|
||||
{
|
||||
title: "Pediatric Dentistry",
|
||||
description: "Gentle, kid-friendly dental care for your little ones",
|
||||
href: "/services/pediatric-dentistry",
|
||||
},
|
||||
{
|
||||
title: "Emergency Care",
|
||||
description:
|
||||
"Same-day treatment for tooth pain, injuries, and urgent issues",
|
||||
href: "/services/emergency-care",
|
||||
},
|
||||
{
|
||||
title: "Patient Resources",
|
||||
description: "New patient forms, insurance info, and financing options",
|
||||
href: "/patient-resources",
|
||||
},
|
||||
];
|
||||
|
||||
// Filtered suggestions based on searchValue
|
||||
const suggestions =
|
||||
searchValue.trim().length > 0
|
||||
? Services.filter(
|
||||
(s) =>
|
||||
s.title.toLowerCase().includes(searchValue.toLowerCase()) ||
|
||||
s.description.toLowerCase().includes(searchValue.toLowerCase())
|
||||
)
|
||||
: [];
|
||||
|
||||
const aboutItems = [
|
||||
{
|
||||
title: "Our Story",
|
||||
description: "Learn about Dental U Care's mission and values",
|
||||
href: "/#about",
|
||||
},
|
||||
{
|
||||
title: "Our Team",
|
||||
description: "Meet our expert dental professionals",
|
||||
href: "/#team",
|
||||
},
|
||||
{
|
||||
title: "Features",
|
||||
description: "Discover our online booking system features",
|
||||
href: "/#features",
|
||||
},
|
||||
{
|
||||
title: "Pricing",
|
||||
description: "Transparent pricing for all dental services",
|
||||
href: "/#pricing",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="sticky top-0 z-50 py-2">
|
||||
<div
|
||||
className={cn(
|
||||
"container transition-all duration-300",
|
||||
isScrolled && "px-6 lg:px-12"
|
||||
)}
|
||||
>
|
||||
<nav
|
||||
className={cn(
|
||||
"flex items-center justify-between rounded-full px-6 py-6 transition-all duration-300 ",
|
||||
isScrolled
|
||||
? "border-2 border-accent dark:border-gray-900 bg-background/80 shadow-lg"
|
||||
: "border-2 border-accent dark:border-gray-800 bg-background/80 shadow-lg"
|
||||
)}
|
||||
>
|
||||
<Link href="/" className="flex items-center gap-2">
|
||||
<Image
|
||||
src="/tooth.svg"
|
||||
alt="Dental U Care"
|
||||
width={32}
|
||||
height={32}
|
||||
className="h-8 w-8"
|
||||
/>
|
||||
<span className="text-2xl font-semibold bg-gradient-to-r from-blue-600 to-blue-800 text-transparent bg-clip-text tracking-tighter">
|
||||
Dental U Care
|
||||
</span>
|
||||
</Link>
|
||||
<NavigationMenu className="hidden lg:block">
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger className="bg-transparent hover:bg-transparent focus:bg-transparent data-[active]:bg-transparent data-[state=open]:bg-transparent">
|
||||
About
|
||||
</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<div className="grid w-[500px] grid-cols-2 p-3">
|
||||
{aboutItems.map((item, index) => (
|
||||
<NavigationMenuLink
|
||||
href={item.href}
|
||||
key={index}
|
||||
className="rounded-md p-3 transition-colors"
|
||||
>
|
||||
<div key={item.title}>
|
||||
<p className="text-foreground mb-1 font-semibold">
|
||||
{item.title}
|
||||
</p>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
</NavigationMenuLink>
|
||||
))}
|
||||
</div>
|
||||
</NavigationMenuContent>
|
||||
</NavigationMenuItem>
|
||||
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger className="bg-transparent hover:bg-transparent focus:bg-transparent data-[active]:bg-transparent data-[state=open]:bg-transparent">
|
||||
Services
|
||||
</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<div className="grid w-[600px] grid-cols-2 p-3">
|
||||
{Services.map((service, index) => (
|
||||
<NavigationMenuLink
|
||||
href={service.href}
|
||||
key={index}
|
||||
className="rounded-md p-3 transition-colors"
|
||||
>
|
||||
<div key={service.title}>
|
||||
<p className="text-foreground mb-1 font-semibold">
|
||||
{service.title}
|
||||
</p>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{service.description}
|
||||
</p>
|
||||
</div>
|
||||
</NavigationMenuLink>
|
||||
))}
|
||||
</div>
|
||||
</NavigationMenuContent>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink
|
||||
href="/#pricing"
|
||||
className="group inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-all hover:text-accent-foreground hover:border-b-2 hover:border-primary focus:outline-none disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
Pricing
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink
|
||||
href="/#contact"
|
||||
className="group inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-all hover:text-accent-foreground hover:border-b-2 hover:border-primary focus:outline-none disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
Contact
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
<div className="hidden items-center gap-4 lg:flex">
|
||||
<div className="relative">
|
||||
<form onSubmit={handleSearch} className="contents">
|
||||
<InputGroup
|
||||
className={cn(
|
||||
"w-64 transition-all duration-300 border border-gray-300 hover:border-primary hover:shadow-sm dark:border-gray-700 dark:hover:border-primary rounded-md",
|
||||
isScrolled && "w-58"
|
||||
)}
|
||||
>
|
||||
<InputGroupInput
|
||||
ref={inputRef}
|
||||
placeholder="Search services..."
|
||||
className="border-0 focus-visible:ring-0"
|
||||
value={searchValue}
|
||||
onChange={(e) => {
|
||||
setSearchValue(e.target.value);
|
||||
setShowSuggestions(true);
|
||||
}}
|
||||
onFocus={() => setShowSuggestions(true)}
|
||||
onBlur={() =>
|
||||
setTimeout(() => setShowSuggestions(false), 100)
|
||||
}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") handleSearch();
|
||||
}}
|
||||
aria-label="Search services"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<SearchIcon className="h-4 w-4" />
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton size="sm" type="submit">
|
||||
Search
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
{showSuggestions && suggestions.length > 0 && (
|
||||
<ul className="absolute left-0 z-50 mt-1 w-full bg-background border border-gray-200 dark:border-gray-700 rounded-md shadow-lg max-h-56 overflow-auto">
|
||||
{suggestions.map((s) => (
|
||||
<li
|
||||
key={s.title}
|
||||
className="px-4 py-2 cursor-pointer hover:bg-accent"
|
||||
onMouseDown={() => {
|
||||
setShowSuggestions(false);
|
||||
setSearchValue("");
|
||||
router.push(s.href);
|
||||
}}
|
||||
>
|
||||
<span className="font-semibold">{s.title}</span>
|
||||
<span className="block text-xs text-muted-foreground">
|
||||
{s.description}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
<ModeToggle />
|
||||
|
||||
{user ? (
|
||||
<>
|
||||
<Button
|
||||
className={cn(isScrolled ? "hidden" : "lg:inline-flex")}
|
||||
asChild
|
||||
>
|
||||
<Link href="/patient/book-appointment">Book Now</Link>
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="rounded-full"
|
||||
>
|
||||
<Avatar className="h-8 w-8">
|
||||
<AvatarImage
|
||||
src={user.image || undefined}
|
||||
alt={user.name}
|
||||
/>
|
||||
<AvatarFallback>
|
||||
{getInitials(user.name)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-56">
|
||||
<DropdownMenuLabel>
|
||||
<div className="flex flex-col space-y-1">
|
||||
<p className="text-sm font-medium leading-none">
|
||||
{user.name}
|
||||
</p>
|
||||
<p className="text-xs leading-none text-muted-foreground">
|
||||
{user.email}
|
||||
</p>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{userIsAdmin && (
|
||||
<>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href="/admin" className="cursor-pointer">
|
||||
<Shield className="mr-2 h-4 w-4" />
|
||||
<span>Dashboard</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
{user?.role === "dentist" && (
|
||||
<>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href="/dentist" className="cursor-pointer">
|
||||
<User className="mr-2 h-4 w-4" />
|
||||
<span>Dashboard</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
{user?.role === "patient" && (
|
||||
<>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href="/patient" className="cursor-pointer">
|
||||
<User className="mr-2 h-4 w-4" />
|
||||
<span>Dashboard</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
onClick={() => setShowLogoutDialog(true)}
|
||||
className="cursor-pointer text-red-600"
|
||||
>
|
||||
<LogOut className="mr-2 h-4 w-4" />
|
||||
<span>Sign Out</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(isScrolled ? "hidden" : "lg:inline-flex")}
|
||||
>
|
||||
<Link href="/sign-in">Sign In</Link>
|
||||
</Button>
|
||||
<Button
|
||||
className={cn(isScrolled ? "hidden" : "lg:inline-flex")}
|
||||
onClick={() => setShowRequiredDialog(true)}
|
||||
>
|
||||
Book Now
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Sheet>
|
||||
<SheetTrigger asChild className="lg:hidden">
|
||||
<Button variant="outline" size="icon">
|
||||
<MenuIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="top" className="max-h-screen overflow-auto">
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
<a href="#" className="flex items-center gap-2">
|
||||
<Image
|
||||
src="/tooth.svg"
|
||||
alt="Dental U Care"
|
||||
width={32}
|
||||
height={32}
|
||||
className="h-8 w-8"
|
||||
/>
|
||||
<span className="text-lg font-semibold tracking-tighter">
|
||||
Dental U Care
|
||||
</span>
|
||||
</a>
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="flex flex-col p-4">
|
||||
<Accordion type="single" collapsible className="mb-2 mt-4">
|
||||
<AccordionItem value="about" className="border-none">
|
||||
<AccordionTrigger className="text-base hover:no-underline">
|
||||
About
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="grid gap-2">
|
||||
{aboutItems.map((item, index) => (
|
||||
<a
|
||||
href={item.href}
|
||||
key={index}
|
||||
className="rounded-md p-3 transition-colors"
|
||||
>
|
||||
<div key={item.title}>
|
||||
<p className="text-foreground mb-1 font-semibold">
|
||||
{item.title}
|
||||
</p>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="solutions" className="border-none">
|
||||
<AccordionTrigger className="text-base hover:no-underline">
|
||||
Services
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="grid md:grid-cols-2">
|
||||
{Services.map((service, index) => (
|
||||
<a
|
||||
href={service.href}
|
||||
key={index}
|
||||
className="rounded-md p-3 transition-colors"
|
||||
>
|
||||
<div key={service.title}>
|
||||
<p className="text-foreground mb-1 font-semibold">
|
||||
{service.title}
|
||||
</p>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{service.description}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
<div className="flex flex-col gap-6">
|
||||
<Link href="/#contact" className="font-medium">
|
||||
Contact
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mt-6 flex flex-col gap-4">
|
||||
{user ? (
|
||||
<>
|
||||
<div className="flex items-center gap-3 rounded-lg border p-4">
|
||||
<Avatar className="h-10 w-10">
|
||||
<AvatarImage
|
||||
src={user.image || undefined}
|
||||
alt={user.name}
|
||||
/>
|
||||
<AvatarFallback>
|
||||
{getInitials(user.name)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm font-medium leading-none">
|
||||
{user.name}
|
||||
</p>
|
||||
<p className="text-xs leading-none text-muted-foreground mt-1">
|
||||
{user.email}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button asChild>
|
||||
<Link href="/patient/book-appointment">Book Now</Link>
|
||||
</Button>
|
||||
{userIsAdmin && (
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/admin">
|
||||
<Shield className="mr-2 h-4 w-4" />
|
||||
Admin Dashboard
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
{user?.role === "dentist" && (
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/dentist">
|
||||
<User className="mr-2 h-4 w-4" />
|
||||
Dentist Dashboard
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
{user?.role === "patient" && (
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/patient">
|
||||
<User className="mr-2 h-4 w-4" />
|
||||
Dashboard
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => setShowLogoutDialog(true)}
|
||||
>
|
||||
<LogOut className="mr-2 h-4 w-4" />
|
||||
Sign Out
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button variant="outline">
|
||||
<Link href="/sign-in">Sign in</Link>
|
||||
</Button>
|
||||
<Button onClick={() => setShowRequiredDialog(true)}>
|
||||
Book Now
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</nav>
|
||||
</div>
|
||||
<Dialog open={showLogoutDialog} onOpenChange={setShowLogoutDialog}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Log out</DialogTitle>
|
||||
<DialogDescription>
|
||||
Are you sure you want to log out?
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">Cancel</Button>
|
||||
</DialogClose>
|
||||
<Button variant="destructive" onClick={handleSignOut}>
|
||||
Log out
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Dialog open={showRequiredDialog} onOpenChange={setShowRequiredDialog}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Sign in required</DialogTitle>
|
||||
<DialogDescription>
|
||||
You need to sign in to book an appointment. Would you like to sign
|
||||
in now?
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">Cancel</Button>
|
||||
</DialogClose>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setShowRequiredDialog(false);
|
||||
router.push("/sign-in");
|
||||
}}
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { Navbar };
|
||||
Reference in New Issue
Block a user