import React, { useEffect, useMemo, useState } from "react"; import { LayoutDashboard, ShoppingCart, BarChart3, Wallet, Table2, Settings, LogOut, RefreshCw, Search, ChevronDown, Check, X, Pencil, Trash2, Percent, BadgeCheck, } from "lucide-react"; /** * iStore POS (Apple-only) — single-file UI mock inspired by the provided POS layout. * - Product grid with category tabs + search * - Cart/order summary with totals, discount, and simple order meta * - Clean, responsive layout */ // ---------- Helpers const money = (n) => new Intl.NumberFormat(undefined, { style: "currency", currency: "USD", }).format(n); const nowLabel = () => { const d = new Date(); const weekday = d.toLocaleDateString(undefined, { weekday: "long" }); const date = d.toLocaleDateString(undefined, { day: "2-digit", month: "short", year: "numeric" }); const time = d.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" }); return `${weekday}, ${date} • ${time}`; }; const pill = (active) => `inline-flex items-center gap-2 rounded-full px-3 py-1 text-sm transition ${ active ? "bg-slate-900 text-white shadow-sm" : "bg-white text-slate-700 hover:bg-slate-50 border border-slate-200" }`; function dataUriCard({ title, subtitle, glyph = "" }) { // Simple “photo-like” SVG card so images work offline. const svg = ` ${glyph} ${escapeXml(title)} ${escapeXml(subtitle)} `; return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg.trim())}`; } function escapeXml(s) { return String(s) .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } // ---------- Data const PRODUCTS = [ { id: "iphone-15-pro", name: "iPhone 15 Pro", price: 999, category: "iPhone", variant: "128GB", available: true, glyph: "📱", }, { id: "iphone-15", name: "iPhone 15", price: 799, category: "iPhone", variant: "128GB", available: true, glyph: "📱", }, { id: "macbook-air-m3", name: "MacBook Air", price: 1099, category: "Mac", variant: "M3 • 13-inch", available: true, glyph: "💻", }, { id: "macbook-pro-m3", name: "MacBook Pro", price: 1599, category: "Mac", variant: "M3 • 14-inch", available: true, glyph: "💻", }, { id: "imac-m3", name: "iMac", price: 1299, category: "Mac", variant: "M3 • 24-inch", available: true, glyph: "🖥️", }, { id: "mac-mini", name: "Mac mini", price: 599, category: "Mac", variant: "M2", available: true, glyph: "🧊", }, { id: "ipad-pro", name: "iPad Pro", price: 999, category: "iPad", variant: "11-inch", available: true, glyph: "📟", }, { id: "ipad-air", name: "iPad Air", price: 599, category: "iPad", variant: "10.9-inch", available: true, glyph: "📟", }, { id: "apple-watch-ultra", name: "Apple Watch Ultra", price: 799, category: "Watch", variant: "49mm", available: true, glyph: "⌚", }, { id: "apple-watch-series", name: "Apple Watch Series", price: 399, category: "Watch", variant: "41mm", available: true, glyph: "⌚", }, { id: "airpods-pro", name: "AirPods Pro", price: 249, category: "Audio", variant: "2nd gen", available: true, glyph: "🎧", }, { id: "airpods-max", name: "AirPods Max", price: 549, category: "Audio", variant: "Over-ear", available: true, glyph: "🎧", }, { id: "homepod", name: "HomePod", price: 299, category: "Audio", variant: "2nd gen", available: true, glyph: "🔊", }, { id: "airtag-4pack", name: "AirTag (4‑pack)", price: 99, category: "Accessories", variant: "4 pack", available: true, glyph: "🏷️", }, { id: "magic-keyboard", name: "Magic Keyboard", price: 99, category: "Accessories", variant: "Wireless", available: false, glyph: "⌨️", }, ]; const CATEGORIES = ["All", "iPhone", "Mac", "iPad", "Watch", "Audio", "Accessories"]; const SEED_ORDER_ID = () => `#I${Math.floor(100000 + Math.random() * 900000)}`; // ---------- UI bits function Chip({ children, active, onClick }) { return ( ); } function IconDot({ ok }) { return ( {ok ? "Available" : "Out of stock"} ); } function Divider() { return
; } function SmallField({ label, children }) { return (
{label}
{children}
); } // ---------- Main export default function IStorePOS() { const [activeNav, setActiveNav] = useState("Menu Order"); const [category, setCategory] = useState("All"); const [query, setQuery] = useState(""); const [cart, setCart] = useState(() => { // Prefill like the screenshot (optional): const pre = [ { id: "airpods-pro", qty: 1, note: "—" }, { id: "macbook-air-m3", qty: 1, note: "Silver" }, { id: "iphone-15-pro", qty: 1, note: "Natural Titanium" }, ]; return pre; }); const [applyDiscount, setApplyDiscount] = useState(true); const [orderId, setOrderId] = useState(SEED_ORDER_ID); const [clock, setClock] = useState(nowLabel()); const [orderType, setOrderType] = useState("In-store"); const [counter, setCounter] = useState("Counter A"); useEffect(() => { const t = setInterval(() => setClock(nowLabel()), 15_000); return () => clearInterval(t); }, []); const productsWithImages = useMemo(() => { return PRODUCTS.map((p) => ({ ...p, image: p.image || dataUriCard({ title: p.name, subtitle: `${p.variant} • ${money(p.price)}`, glyph: p.glyph, }), })); }, []); const counts = useMemo(() => { const c = { All: productsWithImages.length }; for (const cat of CATEGORIES.slice(1)) { c[cat] = productsWithImages.filter((p) => p.category === cat).length; } return c; }, [productsWithImages]); const filtered = useMemo(() => { const q = query.trim().toLowerCase(); return productsWithImages .filter((p) => (category === "All" ? true : p.category === category)) .filter((p) => q ? `${p.name} ${p.variant} ${p.category}`.toLowerCase().includes(q) : true ); }, [productsWithImages, category, query]); const cartLines = useMemo(() => { return cart .map((line) => { const p = productsWithImages.find((x) => x.id === line.id); if (!p) return null; return { ...line, product: p, lineTotal: p.price * line.qty, }; }) .filter(Boolean); }, [cart, productsWithImages]); const subtotal = useMemo(() => cartLines.reduce((s, l) => s + l.lineTotal, 0), [cartLines]); const taxRate = 0.1; const taxes = useMemo(() => subtotal * taxRate, [subtotal]); const discountEligible = subtotal >= 500; const discount = useMemo(() => (applyDiscount && discountEligible ? subtotal * 0.1 : 0), [applyDiscount, discountEligible, subtotal]); const total = useMemo(() => Math.max(0, subtotal + taxes - discount), [subtotal, taxes, discount]); const addToCart = (id) => { setCart((prev) => { const idx = prev.findIndex((x) => x.id === id); if (idx >= 0) { const next = [...prev]; next[idx] = { ...next[idx], qty: next[idx].qty + 1 }; return next; } return [...prev, { id, qty: 1, note: "—" }]; }); }; const setQty = (id, qty) => { setCart((prev) => prev .map((x) => (x.id === id ? { ...x, qty } : x)) .filter((x) => x.qty > 0) ); }; const removeLine = (id) => setCart((prev) => prev.filter((x) => x.id !== id)); const randomizeOrder = () => { setOrderId(SEED_ORDER_ID()); setQuery(""); setCategory("All"); }; const navItems = [ { label: "Dashboard", icon: LayoutDashboard }, { label: "Menu Order", icon: ShoppingCart }, { label: "Analytics", icon: BarChart3 }, { label: "Withdrawal", icon: Wallet }, { label: "Manage Table", icon: Table2 }, ]; return (
{/* Sidebar */} {/* Main */}
{/* Top bar */}
Shop
iStore Downtown
{clock}
setQuery(e.target.value)} placeholder="Search products" className="w-full rounded-xl border border-slate-200 bg-white py-2 pl-9 pr-3 text-sm font-semibold text-slate-800 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-900/10" />
{/* Content */}
{/* Left: menu */}
{CATEGORIES.map((c) => ( setCategory(c)}> {c} {counts[c] ?? 0} ))}
Showing {filtered.length} items
{/* Grid */}
{filtered.map((p) => { const inStock = p.available; return (
{p.name}
{p.name}
{p.variant}
{money(p.price)}
); })}
{/* Right: order summary */}
iStore POS UI mock • Frontend only (no backend)
); }