puffin-app/components/admin/AdminSidebar.tsx
Matt 683a65c1fd
All checks were successful
Build and Push Docker Images / docker (push) Successful in 2m15s
Implement Modern Maritime admin panel design with Monaco background
🎨 Complete UI redesign of admin panel with professional color scheme:

## New Modern Maritime Color Palette
- Deep Sea Blue (#1D2939) - Sidebar background
- Sail White (#F8F9FA) - Main background
- Maritime Teal (#008B8B) - Primary accent
- Sea Green (#1E8449) - Success/environmental theme
- Muted Gold (#D68910) - Revenue highlights
- Royal Purple (#884EA0) - Brand accent
- Off-White (#EAECEF) - Text on dark backgrounds

## Admin Panel Features
-  JWT-based authentication system
-  Protected routes with middleware
-  Elegant sidebar navigation with Puffin logo
-  Dashboard with stat cards (Orders, CO₂, Revenue, Fulfillment)
-  Monaco harbor image background on login page
-  Responsive glassmorphism design
-  WCAG AA contrast compliance

## New Files
- app/admin/ - Admin pages (login, dashboard, orders)
- app/api/admin/ - Auth API routes (login, logout, verify)
- components/admin/ - AdminSidebar component
- lib/auth.ts - JWT authentication utilities
- public/monaco_high_res.jpg - Luxury background image

## Updated
- tailwind.config.js - Custom maritime color palette
- package.json - Added jsonwebtoken dependency
- app/layout.tsx - RootLayoutClient integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 09:35:43 +01:00

112 lines
3.4 KiB
TypeScript

'use client';
import { useRouter, usePathname } from 'next/navigation';
import { LayoutDashboard, Package, LogOut } from 'lucide-react';
import { motion } from 'framer-motion';
import Image from 'next/image';
interface NavItem {
label: string;
href: string;
icon: React.ReactNode;
}
export function AdminSidebar() {
const router = useRouter();
const pathname = usePathname();
const navItems: NavItem[] = [
{
label: 'Dashboard',
href: '/admin/dashboard',
icon: <LayoutDashboard size={20} />,
},
{
label: 'Orders',
href: '/admin/orders',
icon: <Package size={20} />,
},
];
const handleLogout = async () => {
try {
await fetch('/api/admin/auth/logout', {
method: 'POST',
});
router.push('/admin/login');
} catch (error) {
console.error('Logout failed:', error);
}
};
return (
<div className="w-64 min-h-screen bg-deep-sea-blue text-off-white flex flex-col fixed left-0 top-0 bottom-0 shadow-2xl">
{/* Logo */}
<div className="p-6 border-b border-off-white/10">
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
className="flex items-center space-x-3"
>
<div className="w-10 h-10 bg-white rounded-full flex items-center justify-center shadow-lg p-1">
<Image
src="/puffinOffset.png"
alt="Puffin Offset Logo"
width={32}
height={32}
className="object-contain"
/>
</div>
<div>
<h1 className="font-bold text-lg text-off-white">Puffin Admin</h1>
<p className="text-xs text-off-white/80 font-medium">Management Portal</p>
</div>
</motion.div>
</div>
{/* Navigation */}
<nav className="flex-1 px-4 py-6 space-y-2">
{navItems.map((item, index) => {
const isActive = pathname === item.href;
return (
<motion.button
key={item.href}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.1 }}
onClick={() => router.push(item.href)}
className={`w-full flex items-center space-x-3 px-4 py-3 rounded-lg transition-all ${
isActive
? 'bg-maritime-teal text-white shadow-lg font-semibold'
: 'text-off-white/80 hover:bg-maritime-teal/20 hover:text-off-white font-medium'
}`}
>
{item.icon}
<span>{item.label}</span>
</motion.button>
);
})}
</nav>
{/* User Info & Logout */}
<div className="p-4 border-t border-off-white/10 space-y-2">
<div className="px-4 py-2 bg-off-white/5 rounded-lg">
<p className="text-xs text-off-white/70 font-medium">Signed in as</p>
<p className="text-sm font-semibold text-off-white">Administrator</p>
</div>
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={handleLogout}
className="w-full flex items-center space-x-3 px-4 py-3 rounded-lg bg-red-500/20 hover:bg-red-500/30 text-red-200 hover:text-white transition-all font-medium"
>
<LogOut size={20} />
<span>Logout</span>
</motion.button>
</div>
</div>
);
}