Files
hellojewellers/src/components/retailer/RetailerShell.tsx
priyanshuvish d58c08ce28 first commit
2025-10-14 12:07:18 +05:30

217 lines
7.6 KiB
TypeScript

import {
LayoutDashboard,
Package,
Grid,
Users,
MessageCircle,
Calendar,
FileText,
Store,
BarChart3,
Settings,
Search,
Bell,
ChevronDown,
Globe,
Moon,
Sun,
} from "lucide-react";
import { useState, useEffect } from "react";
import { RetailerPage } from "../../RetailerApp";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
import { AIAssistant } from "../AIAssistant";
import { SmartSearch } from "../SmartSearch";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
import { NotificationsPanel } from "./NotificationsPanel";
interface RetailerShellProps {
children: React.ReactNode;
currentPage: RetailerPage;
onNavigate: (page: RetailerPage) => void;
brandName: string;
}
const navItems = [
{ id: "dashboard" as RetailerPage, icon: LayoutDashboard, label: "Dashboard" },
{ id: "inventory" as RetailerPage, icon: Package, label: "Inventory" },
{ id: "curation" as RetailerPage, icon: Grid, label: "Curation" },
{ id: "customers" as RetailerPage, icon: Users, label: "Customers" },
{ id: "chat" as RetailerPage, icon: MessageCircle, label: "Chat", badge: 3 },
{ id: "appointments" as RetailerPage, icon: Calendar, label: "Appointments" },
{ id: "quotes-orders" as RetailerPage, icon: FileText, label: "Quotes & Orders" },
{ id: "storefront" as RetailerPage, icon: Store, label: "Storefront" },
{ id: "analytics" as RetailerPage, icon: BarChart3, label: "Analytics" },
];
export function RetailerShell({ children, currentPage, onNavigate, brandName }: RetailerShellProps) {
const [theme, setTheme] = useState<"light" | "dark">("light");
const [language, setLanguage] = useState("en");
useEffect(() => {
const root = document.documentElement;
if (theme === "dark") {
root.classList.add("dark");
} else {
root.classList.remove("dark");
}
}, [theme]);
return (
<div className="min-h-screen bg-bg-page flex">
{/* Sidebar */}
<aside className="w-64 bg-background border-r border-border flex flex-col">
{/* Brand Header */}
<div className="h-16 px-4 flex items-center gap-3 border-b border-border">
<div className="w-10 h-10 rounded-[12px] bg-primary/10 flex items-center justify-center flex-shrink-0">
<Store className="w-6 h-6 text-primary" />
</div>
<div className="flex-1 min-w-0">
<p className="text-[14px] truncate">{brandName}</p>
<p className="text-[12px] text-text-secondary">Retailer Portal</p>
</div>
</div>
{/* Navigation */}
<nav className="flex-1 p-3 space-y-1 overflow-y-auto">
{navItems.map((item) => {
const Icon = item.icon;
const isActive = currentPage === item.id;
return (
<button
key={item.id}
onClick={() => onNavigate(item.id)}
className={`w-full flex items-center gap-3 px-3 py-2 rounded-[10px] transition-colors ${
isActive
? "bg-primary text-primary-foreground"
: "text-text-secondary hover:bg-accent/10 hover:text-text-primary"
}`}
>
<Icon className="w-5 h-5 flex-shrink-0" />
<span className="text-[14px] flex-1 text-left">{item.label}</span>
{item.badge && (
<span className="px-2 py-0.5 rounded-full bg-destructive text-destructive-foreground text-[11px]">
{item.badge}
</span>
)}
</button>
);
})}
</nav>
{/* Settings at bottom */}
<div className="p-3 border-t border-border">
<button
onClick={() => onNavigate("team")}
className={`w-full flex items-center gap-3 px-3 py-2 rounded-[10px] transition-colors ${
currentPage === "team"
? "bg-primary text-primary-foreground"
: "text-text-secondary hover:bg-accent/10 hover:text-text-primary"
}`}
>
<Settings className="w-5 h-5" />
<span className="text-[14px]">Team & Settings</span>
</button>
</div>
</aside>
{/* Main Content */}
<div className="flex-1 flex flex-col min-w-0">
{/* Top Bar */}
<header className="h-16 bg-background border-b border-border px-6 flex items-center justify-between">
<div className="flex items-center gap-4 flex-1">
{/* Smart AI Search */}
<div className="w-96">
<SmartSearch
portalType="retailer"
placeholder="Search SKUs, collections, customers... (⌘K)"
onNavigate={(page) => onNavigate(page as RetailerPage)}
/>
</div>
</div>
<div className="flex items-center gap-3">
{/* Language Selector */}
<div className="flex items-center gap-2">
<Globe className="w-4 h-4 text-muted-foreground" />
<Select value={language} onValueChange={setLanguage}>
<SelectTrigger className="w-[120px] h-9">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="en">English</SelectItem>
<SelectItem value="hi">ि</SelectItem>
<SelectItem value="mr"></SelectItem>
<SelectItem value="gu"></SelectItem>
</SelectContent>
</Select>
</div>
{/* Theme Toggle */}
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
{theme === "light" ? (
<Moon className="w-5 h-5" />
) : (
<Sun className="w-5 h-5" />
)}
</Button>
{/* Notifications */}
<NotificationsPanel unreadCount={3} />
{/* Profile */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="gap-2">
<div className="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center">
<span className="text-[14px]">A</span>
</div>
<span className="text-[14px]">Admin</span>
<ChevronDown className="w-4 h-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => onNavigate("setup")}>
Brand Settings
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onNavigate("team")}>
Team & Roles
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Sign out</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</header>
{/* Page Content */}
<main className="flex-1 overflow-auto">{children}</main>
</div>
{/* AI Assistant */}
<AIAssistant portalType="retailer" />
</div>
);
}