Spaces:
Sleeping
Sleeping
| import React, { useState, useMemo } from 'react'; | |
| import { useShop } from '../contexts/ShopContext'; | |
| import { Shop } from '../types'; | |
| interface ShopSelectorProps { | |
| compact?: boolean; | |
| } | |
| const ShopSelector: React.FC<ShopSelectorProps> = ({ compact = false }) => { | |
| const { shops, currentShop, setCurrentShop, isLoading, isAllShopsMode } = useShop(); | |
| const [isOpen, setIsOpen] = useState(false); | |
| // Calculate total orders across all shops | |
| const totalOrders = useMemo(() => { | |
| return shops.reduce((sum, shop) => sum + (shop.order_count || 0), 0); | |
| }, [shops]); | |
| if (isLoading) { | |
| return ( | |
| <div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-100 animate-pulse"> | |
| <div className="w-8 h-8 rounded-full bg-slate-200"></div> | |
| <div className="h-4 w-24 bg-slate-200 rounded"></div> | |
| </div> | |
| ); | |
| } | |
| if (shops.length === 0) { | |
| return ( | |
| <div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-amber-50 border border-amber-200"> | |
| <span className="material-symbols-outlined text-amber-600">warning</span> | |
| <span className="text-sm text-amber-700">No shops configured</span> | |
| </div> | |
| ); | |
| } | |
| const handleSelect = (shop: Shop | null) => { | |
| setCurrentShop(shop); | |
| setIsOpen(false); | |
| }; | |
| // Determine display text and styling based on mode | |
| const displayName = isAllShopsMode ? 'All Shops' : (currentShop?.name || 'Select Shop'); | |
| const displayLabel = isAllShopsMode ? 'Viewing All' : 'Current Shop'; | |
| return ( | |
| <div className="relative"> | |
| <button | |
| onClick={() => setIsOpen(!isOpen)} | |
| className={` | |
| flex items-center gap-2 px-3 py-2 rounded-lg | |
| ${isAllShopsMode | |
| ? 'bg-gradient-to-r from-purple-100 to-indigo-100 border border-purple-200 hover:border-purple-300' | |
| : 'bg-gradient-to-r from-primary/10 to-primary/5 border border-primary/20 hover:border-primary/40' | |
| } | |
| transition-all duration-200 group | |
| ${compact ? 'pr-2' : 'min-w-[200px]'} | |
| `} | |
| > | |
| {/* Shop Icon */} | |
| <div className={`w-8 h-8 rounded-full flex items-center justify-center shadow-sm ${isAllShopsMode | |
| ? 'bg-gradient-to-br from-purple-500 to-indigo-500' | |
| : 'bg-gradient-to-br from-primary to-primary/70' | |
| }`}> | |
| <span className="material-symbols-outlined text-white text-sm"> | |
| {isAllShopsMode ? 'dashboard' : 'storefront'} | |
| </span> | |
| </div> | |
| {/* Shop Name */} | |
| {!compact && ( | |
| <div className="flex-1 text-left overflow-hidden"> | |
| <p className="text-xs text-text-secondary font-medium">{displayLabel}</p> | |
| <p className={`text-sm font-semibold truncate ${isAllShopsMode ? 'text-purple-700' : 'text-text-main'}`}> | |
| {displayName} | |
| </p> | |
| </div> | |
| )} | |
| {/* Dropdown Arrow */} | |
| <span className={`material-symbols-outlined text-text-secondary transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}> | |
| expand_more | |
| </span> | |
| </button> | |
| {/* Dropdown Menu */} | |
| {isOpen && ( | |
| <> | |
| {/* Backdrop */} | |
| <div | |
| className="fixed inset-0 z-40" | |
| onClick={() => setIsOpen(false)} | |
| /> | |
| {/* Menu */} | |
| <div className="absolute top-full left-0 right-0 mt-2 z-50 bg-white rounded-xl shadow-xl border border-border-light overflow-hidden min-w-[240px]"> | |
| <div className="p-2 border-b border-border-light bg-slate-50"> | |
| <p className="text-xs font-medium text-text-secondary px-2">Select View</p> | |
| </div> | |
| <div className="max-h-72 overflow-y-auto py-1"> | |
| {/* All Shops Option */} | |
| <button | |
| onClick={() => handleSelect(null)} | |
| className={` | |
| w-full flex items-center gap-3 px-3 py-3 text-left | |
| transition-colors duration-150 border-b border-border-light | |
| ${isAllShopsMode | |
| ? 'bg-purple-50 text-purple-700' | |
| : 'hover:bg-slate-50 text-text-main' | |
| } | |
| `} | |
| > | |
| <div className={` | |
| w-9 h-9 rounded-full flex items-center justify-center | |
| ${isAllShopsMode | |
| ? 'bg-gradient-to-br from-purple-500 to-indigo-500 text-white' | |
| : 'bg-gradient-to-br from-purple-100 to-indigo-100 text-purple-600' | |
| } | |
| `}> | |
| <span className="material-symbols-outlined text-lg">dashboard</span> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <p className={`text-sm font-semibold ${isAllShopsMode ? 'text-purple-700' : 'text-text-main'}`}> | |
| 📊 All Shops | |
| </p> | |
| <p className="text-xs text-text-secondary"> | |
| {shops.length} shops • {totalOrders} total orders | |
| </p> | |
| </div> | |
| {isAllShopsMode && ( | |
| <span className="material-symbols-outlined text-purple-600 text-lg">check_circle</span> | |
| )} | |
| </button> | |
| {/* Divider with label */} | |
| <div className="px-3 py-2 bg-slate-50"> | |
| <p className="text-[10px] font-semibold text-text-secondary uppercase tracking-wider">Individual Shops</p> | |
| </div> | |
| {/* Individual Shops */} | |
| {shops.map((shop) => ( | |
| <button | |
| key={shop.id} | |
| onClick={() => handleSelect(shop)} | |
| className={` | |
| w-full flex items-center gap-3 px-3 py-2.5 text-left | |
| transition-colors duration-150 | |
| ${currentShop?.id === shop.id && !isAllShopsMode | |
| ? 'bg-primary/10 text-primary' | |
| : 'hover:bg-slate-50 text-text-main' | |
| } | |
| `} | |
| > | |
| <div className={` | |
| w-8 h-8 rounded-full flex items-center justify-center text-sm | |
| ${currentShop?.id === shop.id && !isAllShopsMode | |
| ? 'bg-primary text-white' | |
| : 'bg-slate-200 text-text-secondary' | |
| } | |
| `}> | |
| <span className="material-symbols-outlined text-sm">storefront</span> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <p className={`text-sm font-medium truncate ${currentShop?.id === shop.id && !isAllShopsMode ? 'text-primary' : ''}`}> | |
| {shop.name} | |
| </p> | |
| <p className="text-xs text-text-secondary"> | |
| {shop.order_count || 0} orders | |
| </p> | |
| </div> | |
| {currentShop?.id === shop.id && !isAllShopsMode && ( | |
| <span className="material-symbols-outlined text-primary text-lg">check_circle</span> | |
| )} | |
| </button> | |
| ))} | |
| </div> | |
| {/* Manage Shops Link */} | |
| <div className="p-2 border-t border-border-light bg-slate-50"> | |
| <a | |
| href="#/shops" | |
| onClick={() => setIsOpen(false)} | |
| className="flex items-center gap-2 px-2 py-1.5 text-sm text-primary hover:text-primary/80 transition-colors" | |
| > | |
| <span className="material-symbols-outlined text-sm">settings</span> | |
| Manage Shops | |
| </a> | |
| </div> | |
| </div> | |
| </> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| export default ShopSelector; | |