bookwiz.io / app / dashboard / components / Sidebar.tsx
Sidebar.tsx
Raw
'use client'

import { useState } from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { useAuth } from '@/components/AuthProvider'
import { useUsageStats } from '@/lib/hooks/useUsageStats'
import { 
  ChartBarIcon,
  BookOpenIcon,
  CreditCardIcon,
  DocumentTextIcon,
  ChatBubbleLeftIcon,
  Bars3Icon,
  XMarkIcon,
  ChevronLeftIcon,
  ChevronRightIcon,
  ChartPieIcon,
  PhotoIcon,
} from '@heroicons/react/24/outline'
import UserAccountCard from './UserAccountCard'
import ContactDialog from './ContactDialog'
import ShareDialog from '@/components/ShareDialog'
import Image from 'next/image'

// Primary navigation items (main features)
const primaryNavigationItems = [
  { name: 'Dashboard', href: '/dashboard', icon: ChartBarIcon, color: 'from-blue-500 to-purple-600' },
  { name: 'Books', href: '/dashboard/books', icon: BookOpenIcon, color: 'from-emerald-500 to-teal-600' },
  { name: 'Chat', href: '/dashboard/chat', icon: ChatBubbleLeftIcon, color: 'from-pink-500 to-rose-600' },
  { name: 'Images', href: '/dashboard/images', icon: PhotoIcon, color: 'from-purple-500 to-pink-600' },
]

// Secondary navigation items (settings & utilities)
const secondaryNavigationItems = [
  { name: 'Billing', href: '/dashboard/billing', icon: CreditCardIcon, color: 'from-orange-500 to-red-600' },
  { name: 'Usage', href: '/dashboard/usage', icon: ChartPieIcon, color: 'from-cyan-500 to-blue-600' },
  { name: 'Docs', href: '/dashboard/docs', icon: DocumentTextIcon, color: 'from-violet-500 to-purple-600' },
  { name: 'Support', href: '#', icon: ChatBubbleLeftIcon, color: 'from-gray-600 to-gray-700', isAction: true },
]

interface SidebarProps {
  collapsed?: boolean
  onToggleCollapse?: () => void
}

export default function Sidebar({ collapsed = false, onToggleCollapse }: SidebarProps) {
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
  const [isContactDialogOpen, setIsContactDialogOpen] = useState(false)
  const [isShareDialogOpen, setIsShareDialogOpen] = useState(false)
  const pathname = usePathname()
  const { user } = useAuth()
  const { usageStats } = useUsageStats()

  const isActivePath = (href: string) => {
    if (href === '/dashboard') {
      return pathname === '/dashboard'
    }
    return pathname?.startsWith(href)
  }

  const formatWords = (words: number) => {
    if (words >= 1000000) return `${(words / 1000000).toFixed(1)}M`
    if (words >= 1000) return `${(words / 1000).toFixed(1)}K`
    return words.toString()
  }

  const NavigationSection = ({ 
    items, 
    isCollapsed = false,
    isSecondary = false
  }: { 
    items: typeof primaryNavigationItems, 
    isCollapsed?: boolean,
    isSecondary?: boolean
  }) => (
    <div className="space-y-1">
      {items.map((item) => {
        const isActive = isActivePath(item.href)
        const isAction = (item as any).isAction
        
        const handleClick = () => {
          setIsMobileMenuOpen(false)
          if (isAction && item.name === 'Support') {
            setIsContactDialogOpen(true)
          }
        }
        
        return (
          <Link
            key={item.name}
            href={item.href}
            className={`group relative flex items-center ${isCollapsed ? 'justify-center px-3' : isSecondary ? 'px-4' : 'px-4'} ${isSecondary ? 'py-2' : 'py-3'} text-sm font-bold rounded-2xl transition-all duration-200 ${
              isActive
                ? 'text-white bg-white/10 shadow-lg backdrop-blur-sm'
                : isSecondary 
                  ? 'text-gray-600 hover:text-gray-400 hover:bg-white/2'
                  : 'text-gray-400 hover:text-white hover:bg-white/5'
            }`}
            onClick={handleClick}
            title={isCollapsed ? item.name : undefined}
          >
            {/* Gradient background for active state */}
            {isActive && (
              <div className={`absolute inset-0 rounded-2xl bg-gradient-to-r ${item.color} opacity-20 blur-xl`} />
            )}
            
            <div className={`relative z-10 ${isSecondary ? 'w-5 h-5' : 'w-6 h-6'} rounded-lg bg-gradient-to-br ${isSecondary ? 'from-gray-600 to-gray-700' : item.color} flex items-center justify-center ${isCollapsed ? '' : 'mr-4'} shadow-lg ${!isActive && 'opacity-60 group-hover:opacity-100'} ${isSecondary && !isActive ? 'opacity-30' : ''}`}>
              <item.icon className={`${isSecondary ? 'w-3 h-3' : 'w-4 h-4'} text-white`} />
            </div>
            
            {!isCollapsed && (
              <>
                <span className="relative z-10 font-semibold tracking-tight text-sm">{item.name}</span>
                {isActive && (
                  <div className="ml-auto w-2 h-2 bg-white rounded-full animate-pulse relative z-10" />
                )}
              </>
            )}
          </Link>
        )
      })}
    </div>
  )

  const SidebarContent = ({ isCollapsed = false }: { isCollapsed?: boolean }) => (
    <>
      {/* User Account Card */}
      {!isCollapsed && (
        <div className="p-6 pb-4">
          <UserAccountCard />
        </div>
      )}

      {/* Minimal Quick Stats */}
      {!isCollapsed && (
        <div className="px-6 pb-6">
          <div className="flex justify-between items-center text-sm">
            <div className="text-gray-400">
              <span className="text-white font-semibold">{usageStats.booksCreated}</span> books
            </div>
            <div className="text-gray-400">
              <span className="text-white font-semibold">{formatWords(usageStats.totalWords)}</span> words
            </div>
          </div>
        </div>
      )}

      {/* Primary Navigation */}
      <nav className={`flex-1 ${isCollapsed ? 'px-2' : 'px-4'} pb-4`}>
        <NavigationSection 
          items={primaryNavigationItems} 
          isCollapsed={isCollapsed} 
        />
      </nav>

      {/* Secondary Navigation - Positioned lower */}
      <div className={`${isCollapsed ? 'px-2' : 'px-4'} pb-4`}>
        <NavigationSection 
          items={secondaryNavigationItems} 
          isCollapsed={isCollapsed}
          isSecondary={true}
        />
      </div>

      {/* Minimal Brand Footer */}
      <div className={`${isCollapsed ? 'px-4' : 'px-8'} pt-4 pb-4 transition-all duration-300`}>
        <button
          onClick={() => setIsShareDialogOpen(true)}
          className={`flex items-center ${isCollapsed ? 'justify-center' : 'space-x-2'} group hover:scale-105 transition-all duration-200`}
        >
          <div className="w-6 h-6 rounded-lg bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500 flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow">
            <Image 
              src="/images/logo-glyph-white.png" 
              alt="Bookwiz" 
              width={16}
              height={12}
              className="w-4"
              style={{ filter: 'drop-shadow(0 0 2px rgba(124, 58, 237, 0.3))' }}
            />
          </div>
          {!isCollapsed && (
            <div className="text-gray-400 text-xs font-medium group-hover:text-white transition-colors">Bookwiz</div>
          )}
        </button>
      </div>
    </>
  )

  return (
    <>
      {/* Mobile menu button */}
      <div className="lg:hidden fixed top-4 right-4 z-50">
        <button
          onClick={() => setIsMobileMenuOpen(true)}
          className="p-3 rounded-2xl bg-black/20 backdrop-blur-xl border border-white/10 text-white hover:bg-black/40 transition-all duration-200 shadow-2xl"
        >
          <Bars3Icon className="h-5 w-5" />
        </button>
      </div>

      {/* Desktop Sidebar */}
      <div className={`hidden lg:flex lg:fixed lg:inset-y-0 lg:flex-col transition-all duration-300 ${
        collapsed ? 'lg:w-20' : 'lg:w-72'
      }`}>
        <div className="flex-1 flex flex-col bg-black/40 backdrop-blur-2xl border-r border-white/10">
          {/* Desktop Collapse Toggle */}
          <div className="absolute top-6 -right-3 z-10">
            <button
              onClick={onToggleCollapse}
              className="p-1.5 rounded-full bg-black/60 backdrop-blur-xl border border-white/20 text-white hover:bg-black/80 transition-all duration-200 shadow-lg"
            >
              {collapsed ? (
                <ChevronRightIcon className="h-4 w-4" />
              ) : (
                <ChevronLeftIcon className="h-4 w-4" />
              )}
            </button>
          </div>
          
          <SidebarContent isCollapsed={collapsed} />
        </div>
      </div>

      {/* Mobile Sidebar Overlay */}
      {isMobileMenuOpen && (
        <div className="lg:hidden fixed inset-0 z-40">
          {/* Backdrop */}
          <div 
            className="fixed inset-0 bg-black/80 backdrop-blur-sm"
            onClick={() => setIsMobileMenuOpen(false)}
          />
          
          {/* Sidebar */}
          <div className="fixed inset-y-0 left-0 w-72 max-w-[85vw] bg-black/60 backdrop-blur-2xl border-r border-white/10 transform transition-transform duration-300 ease-in-out">
            <div className="flex flex-col h-full">
              <div className="flex-1 flex flex-col">
                <SidebarContent />
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Contact Dialog */}
      <ContactDialog 
        isOpen={isContactDialogOpen}
        onClose={() => setIsContactDialogOpen(false)}
      />

      {/* Share Dialog */}
      <ShareDialog 
        isOpen={isShareDialogOpen}
        onClose={() => setIsShareDialogOpen(false)}
      />
    </>
  )
}