150 lines
5.4 KiB
TypeScript
150 lines
5.4 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { useRouter } from "next/navigation"
|
|
import { useTheme } from "next-themes"
|
|
import { cn } from "@/lib/utils"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
|
import { useUser } from "@/providers/user-provider"
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import {
|
|
Search,
|
|
Bell,
|
|
Sun,
|
|
Moon,
|
|
Menu,
|
|
LogOut,
|
|
User,
|
|
Settings,
|
|
} from "lucide-react"
|
|
|
|
interface TopbarProps {
|
|
onMenuClick: () => void
|
|
}
|
|
|
|
export function Topbar({ onMenuClick }: TopbarProps) {
|
|
const router = useRouter()
|
|
const { theme, setTheme } = useTheme()
|
|
const { user, logout } = useUser()
|
|
const [searchOpen, setSearchOpen] = useState(false)
|
|
if (!user) return null
|
|
const initials = user.name.split(" ").map((n) => n[0]).join("")
|
|
|
|
return (
|
|
<header className="sticky top-0 z-20 flex h-16 items-center gap-4 border-b bg-background px-4 lg:px-6">
|
|
{/* Mobile menu button */}
|
|
<Button variant="ghost" size="icon" className="lg:hidden" onClick={onMenuClick}>
|
|
<Menu className="h-5 w-5" />
|
|
</Button>
|
|
|
|
{/* Search */}
|
|
<div className="relative hidden flex-1 sm:block md:w-80">
|
|
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
|
<Input
|
|
placeholder="Search leads, companies..."
|
|
className="h-9 w-full max-w-sm pl-9 bg-muted/50"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex flex-1 items-center justify-end gap-3">
|
|
{/* Mobile search toggle */}
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="sm:hidden"
|
|
onClick={() => setSearchOpen(!searchOpen)}
|
|
>
|
|
<Search className="h-5 w-5" />
|
|
</Button>
|
|
|
|
{/* Theme toggle */}
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
|
|
className="text-muted-foreground"
|
|
>
|
|
{theme === "dark" ? <Sun className="h-5 w-5" /> : <Moon className="h-5 w-5" />}
|
|
</Button>
|
|
|
|
{/* Notifications */}
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="ghost" size="icon" className="relative text-muted-foreground">
|
|
<Bell className="h-5 w-5" />
|
|
<span className="absolute -right-0.5 -top-0.5 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground">
|
|
3
|
|
</span>
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-80">
|
|
<DropdownMenuLabel>Notifications</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<div className="space-y-1 p-2">
|
|
{[
|
|
{ text: "New lead assigned to you", time: "5m ago" },
|
|
{ text: "Lead status updated to Closed", time: "1h ago" },
|
|
{ text: "Note added to Brightwave Studios", time: "3h ago" },
|
|
].map((n, i) => (
|
|
<div key={i} className="flex items-start gap-3 rounded-lg p-2 hover:bg-muted/50">
|
|
<div className="h-2 w-2 mt-2 rounded-full bg-primary shrink-0" />
|
|
<div className="flex-1 space-y-0.5">
|
|
<p className="text-sm">{n.text}</p>
|
|
<p className="text-xs text-muted-foreground">{n.time}</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
|
|
{/* User profile */}
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="ghost" className="relative h-9 gap-2 pl-2 pr-3">
|
|
<Avatar className="h-7 w-7">
|
|
<AvatarImage src={user.avatar} />
|
|
<AvatarFallback>{initials}</AvatarFallback>
|
|
</Avatar>
|
|
<span className="hidden text-sm font-medium md:inline-block">{user.name}</span>
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-56">
|
|
<DropdownMenuLabel className="font-normal">
|
|
<div className="flex flex-col space-y-1">
|
|
<p className="text-sm font-medium">{user.name}</p>
|
|
<p className="text-xs text-muted-foreground">{user.email}</p>
|
|
<Badge variant="secondary" className="mt-1 w-fit text-xs capitalize">{user.role}</Badge>
|
|
</div>
|
|
</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem onClick={() => router.push("/profile")}>
|
|
<User className="mr-2 h-4 w-4" />
|
|
Profile
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem onClick={() => router.push("/settings")}>
|
|
<Settings className="mr-2 h-4 w-4" />
|
|
Settings
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem className="text-destructive" onClick={logout}>
|
|
<LogOut className="mr-2 h-4 w-4" />
|
|
Log out
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</header>
|
|
)
|
|
}
|