Files
NewStrcuture_Backup/src/components/layout/sidebar.tsx
T
Ace adbcc4b9af feat: add system monitor component and API for performance metrics
feat: implement conversations API with message retrieval and posting

feat: add avatar URL handling for users and update user role definitions

feat: create chat system tables in the database with initial seed data

fix: update user roles from "sales_user" to "sales" for consistency

chore: add middleware for system API route access

fixed fuckups on john's side, added a benchmark

Made Graphs actualy load from database and realtime data, graphs will update and percentages will be mathematically made,  and made realtime

added chatcart edits, made graphs glow.

added in some little small home feeling fuctions

added in a slide show, in login with qoutes from creators because i want to leave a print on it saying we made this shit, we built it brick for brick

login page added qoutes some random, and made them shuffle from left to right one dissapears other come in

adding shape to the textbox for the qoutes

Fixed my chat fuckups when it comes to chats
2026-06-18 22:48:03 +02:00

216 lines
7.5 KiB
TypeScript

"use client"
import { useState } from "react"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { motion, AnimatePresence } from "framer-motion"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
import {
LayoutDashboard,
Users,
Settings,
ChevronLeft,
ChevronRight,
Building2,
PanelLeftClose,
MessageSquare,
} from "lucide-react"
import { COMPANY_NAME } from "@/lib/constants"
import { useUser } from "@/providers/user-provider"
import { useNotifications } from "@/providers/notification-provider"
const navItems = [
{ href: "/dashboard", label: "Dashboard", icon: LayoutDashboard },
{ href: "/leads", label: "Leads", icon: Users },
{ href: "/chats", label: "Chats", icon: MessageSquare },
{ href: "/users", label: "Users", icon: Building2 },
{ href: "/settings", label: "Settings", icon: Settings },
]
interface SidebarProps {
collapsed: boolean
onToggle: () => void
mobileOpen: boolean
onMobileClose: () => void
}
export function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: SidebarProps) {
const pathname = usePathname()
const { user } = useUser()
const { unreadChatCount } = useNotifications()
if (!user) return null
const initials = user.name.split(" ").map((n) => n[0]).join("")
const sidebarContent = (
<div
className={cn(
"flex h-full flex-col bg-sidebar text-sidebar-foreground transition-all duration-300",
collapsed ? "w-16" : "w-64"
)}
>
{/* Logo */}
<div className={cn("flex h-16 items-center border-b border-sidebar-border px-4", collapsed ? "justify-center" : "justify-between")}>
<Link href="/" className="flex items-center gap-3 overflow-hidden">
<img
src="/logo/CompanyLogo.png"
alt={COMPANY_NAME}
className="h-8 w-8 shrink-0 rounded-lg object-contain"
/>
<AnimatePresence mode="wait">
{!collapsed && (
<motion.span
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -10 }}
transition={{ duration: 0.15 }}
className="text-sm font-semibold whitespace-nowrap"
>
{COMPANY_NAME}
</motion.span>
)}
</AnimatePresence>
</Link>
{!collapsed && (
<Button
variant="ghost"
size="icon"
onClick={onToggle}
className="h-6 w-6 text-sidebar-foreground/60 hover:text-sidebar-foreground"
>
<PanelLeftClose className="h-4 w-4" />
</Button>
)}
</div>
{/* Navigation */}
<nav className="flex-1 space-y-1 p-3">
{navItems.map((item) => {
const isActive = pathname === item.href || (item.href !== "/" && pathname.startsWith(item.href))
return collapsed ? (
<TooltipProvider key={item.href} delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Link
href={item.href}
className={cn(
"relative flex h-10 w-10 items-center justify-center rounded-lg transition-colors",
isActive
? "bg-sidebar-primary text-sidebar-primary-foreground"
: "text-sidebar-foreground/60 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
)}
>
<item.icon className="h-5 w-5" />
{item.label === "Chats" && unreadChatCount > 0 && (
<span className="absolute -right-0.5 -top-0.5 flex h-3 w-3 rounded-full bg-red-500 animate-pulse shadow-[0_0_10px_#ef4444]" />
)}
</Link>
</TooltipTrigger>
<TooltipContent side="right" className="ml-2">
{item.label}
</TooltipContent>
</Tooltip>
</TooltipProvider>
) : (
<Link
key={item.href}
href={item.href}
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
isActive
? "bg-sidebar-primary text-sidebar-primary-foreground"
: "text-sidebar-foreground/60 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
)}
>
<div className="relative shrink-0">
<item.icon className="h-5 w-5" />
{item.label === "Chats" && unreadChatCount > 0 && (
<span className="absolute -right-1 -top-1 flex h-2.5 w-2.5 rounded-full bg-red-500 animate-pulse shadow-[0_0_8px_#ef4444]" />
)}
</div>
<motion.span
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="truncate"
>
{item.label}
</motion.span>
</Link>
)
})}
</nav>
{/* Collapse toggle at bottom (only in collapsed mode) */}
{collapsed && (
<div className="border-t border-sidebar-border p-3">
<Button
variant="ghost"
size="icon"
onClick={onToggle}
className="h-10 w-10 text-sidebar-foreground/60 hover:text-sidebar-foreground"
>
<ChevronRight className="h-4 w-4" />
</Button>
</div>
)}
{/* User info */}
<div className={cn("border-t border-sidebar-border p-3", collapsed && "flex justify-center")}>
{collapsed ? (
<Avatar className="h-10 w-10">
<AvatarImage src={user.avatar} />
<AvatarFallback className="text-sm font-medium">{initials}</AvatarFallback>
</Avatar>
) : (
<div className="flex items-center gap-3">
<Avatar className="h-9 w-9">
<AvatarImage src={user.avatar} />
<AvatarFallback className="text-sm font-medium">{initials}</AvatarFallback>
</Avatar>
<div className="flex-1 overflow-hidden">
<p className="text-sm font-medium truncate">{user.name}</p>
<p className="text-xs text-sidebar-foreground/60 truncate capitalize">{user.role}</p>
</div>
</div>
)}
</div>
</div>
)
return (
<>
{/* Desktop sidebar */}
<aside className="hidden lg:fixed lg:inset-y-0 lg:z-30 lg:flex">
{sidebarContent}
</aside>
{/* Mobile sidebar overlay */}
<AnimatePresence>
{mobileOpen && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onMobileClose}
className="fixed inset-0 z-40 bg-black/60 lg:hidden"
/>
<motion.aside
initial={{ x: -300 }}
animate={{ x: 0 }}
exit={{ x: -300 }}
transition={{ type: "spring", damping: 30, stiffness: 300 }}
className="fixed inset-y-0 left-0 z-50 lg:hidden"
>
{sidebarContent}
</motion.aside>
</>
)}
</AnimatePresence>
</>
)
}