Integrate Prototype_latest.jsx as the main App component. Skip tsc in build since prototype is plain JSX. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
847 lines
105 KiB
JavaScript
847 lines
105 KiB
JavaScript
import { useState, useEffect } from "react";
|
||
|
||
// ── Brand Logos (base64) ───────────────────────────────────
|
||
const BT_LOGO = "data:image/png;base64,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";
|
||
const FS_LOGO = "data:image/png;base64,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";
|
||
|
||
// ── Design System ──────────────────────────────────────────
|
||
const T = {
|
||
bt: {
|
||
pri: "#E8891C", sec: "#D07A18", acc: "#F5A623", warm: "#FDE8CC",
|
||
bg: "#FFFAF4", card: "#FFFFFF", surf: "#FFF3E4",
|
||
ink: "#1A1A1A", ink2: "#6B6B6B", ink3: "#ABABAB",
|
||
grey: "#808080",
|
||
grad: "linear-gradient(145deg, #D07A18 0%, #E8891C 40%, #F5A623 100%)",
|
||
gradDark: "linear-gradient(145deg, #1A1A1A 0%, #333333 40%, #4A4A4A 100%)",
|
||
},
|
||
fs: {
|
||
pri: "#9B6A34", sec: "#B07B3D", acc: "#E8891C", warm: "#F5E6D4",
|
||
bg: "#FFFBF6", card: "#FFFFFF", surf: "#F5EDE3",
|
||
ink: "#1A1A1A", ink2: "#6B6B6B", ink3: "#ABABAB",
|
||
grey: "#5C5C5C",
|
||
grad: "linear-gradient(145deg, #7A5428 0%, #9B6A34 40%, #B8863E 100%)",
|
||
gradDark: "linear-gradient(145deg, #3D2E1A 0%, #5C4530 40%, #7A5A3E 100%)",
|
||
},
|
||
gold: "#C5960C", silver: "#94A3B8", green: "#16A34A", white: "#FFF",
|
||
r: { sm: 10, md: 16, lg: 22, xl: 28 },
|
||
font: "'Georgia', 'Palatino Linotype', serif",
|
||
sans: "'Trebuchet MS', 'Lucida Grande', sans-serif",
|
||
};
|
||
const ease = "cubic-bezier(0.4, 0, 0.2, 1)";
|
||
|
||
const FadeIn = ({ children, delay = 0, y = 12, style = {} }) => {
|
||
const [v, setV] = useState(false);
|
||
useEffect(() => { const t = setTimeout(() => setV(true), delay); return () => clearTimeout(t); }, [delay]);
|
||
return <div style={{ opacity: v ? 1 : 0, transform: v ? "translateY(0)" : `translateY(${y}px)`, transition: `opacity 0.5s ${ease}, transform 0.5s ${ease}`, ...style }}>{children}</div>;
|
||
};
|
||
|
||
const BrandLogo = ({ brand, height = 28, style = {} }) => (
|
||
<img src={brand === "bt" ? BT_LOGO : FS_LOGO} alt={brand === "bt" ? "BreadTalk" : "FoodStreat"} style={{ height, objectFit: "contain", ...style }} />
|
||
);
|
||
|
||
const Phone = ({ children }) => (
|
||
<div style={{ width: 390, minHeight: 740, maxHeight: 844, background: "#0A0A0A", borderRadius: 50, padding: 10, position: "relative", boxShadow: "0 30px 80px rgba(0,0,0,0.35), 0 0 0 1.5px #2A2A2A" }}>
|
||
<div style={{ position: "absolute", top: 10, left: "50%", transform: "translateX(-50%)", width: 126, height: 32, background: "#0A0A0A", borderRadius: "0 0 18px 18px", zIndex: 100 }}>
|
||
<div style={{ width: 10, height: 10, borderRadius: "50%", background: "#1A1A1A", position: "absolute", left: "50%", top: 8, transform: "translateX(-50%)" }} />
|
||
</div>
|
||
<div style={{ width: "100%", height: "100%", borderRadius: 42, overflow: "hidden", background: T.bt.bg, position: "relative" }}>
|
||
<div style={{ height: 48 }} />
|
||
<div style={{ height: "calc(100% - 48px)", overflowY: "auto", overflowX: "hidden" }}>{children}</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
|
||
const Nav = ({ active, go, c }) => {
|
||
const items = [{ id: "home", icon: "⌂", label: "Home" }, { id: "card", icon: "◈", label: "Card" }, { id: "wallet", icon: "◉", label: "Wallet" }, { id: "rewards", icon: "✦", label: "Rewards" }, { id: "profile", icon: "○", label: "More" }];
|
||
return (
|
||
<div style={{ position: "sticky", bottom: 0, display: "flex", background: "rgba(255,255,255,0.92)", backdropFilter: "blur(16px)", borderTop: "1px solid rgba(0,0,0,0.06)", padding: "8px 4px 22px", zIndex: 50 }}>
|
||
{items.map(it => (
|
||
<div key={it.id} onClick={() => go(it.id)} style={{ flex: 1, textAlign: "center", cursor: "pointer" }}>
|
||
<div style={{ fontSize: 18, fontWeight: 300, color: active === it.id ? c.pri : c.ink3, transform: active === it.id ? "scale(1.15)" : "scale(1)", transition: `all 0.25s ${ease}`, fontFamily: T.sans }}>{it.icon}</div>
|
||
<div style={{ fontSize: 9, fontWeight: active === it.id ? 700 : 500, marginTop: 3, color: active === it.id ? c.pri : c.ink3, letterSpacing: 0.5, fontFamily: T.sans, textTransform: "uppercase" }}>{it.label}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
const Pill = ({ children, color, bg }) => <span style={{ display: "inline-block", padding: "4px 10px", borderRadius: 20, fontSize: 10, fontWeight: 700, fontFamily: T.sans, letterSpacing: 0.5, color: color || T.bt.pri, background: bg || "rgba(232,137,28,0.1)" }}>{children}</span>;
|
||
|
||
const SectionHead = ({ title, action, onAction, c }) => (
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", padding: "0 24px", marginBottom: 14 }}>
|
||
<h3 style={{ fontSize: 17, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: 0, letterSpacing: -0.3 }}>{title}</h3>
|
||
{action && <span onClick={onAction} style={{ fontSize: 12, fontWeight: 600, color: c.pri, cursor: "pointer", fontFamily: T.sans }}>{action}</span>}
|
||
</div>
|
||
);
|
||
|
||
// ═══ SPLASH ═══
|
||
const Splash = ({ onNext }) => {
|
||
const [ph, setPh] = useState(0);
|
||
useEffect(() => { const a = setTimeout(() => setPh(1), 300); const b = setTimeout(() => setPh(2), 900); return () => { clearTimeout(a); clearTimeout(b); }; }, []);
|
||
return (
|
||
<div onClick={onNext} style={{ height: 796, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", background: "linear-gradient(170deg, #0D0D0D 0%, #1A1A1A 35%, #2A2A2A 70%, #3A3A3A 100%)", cursor: "pointer", color: "#FFF", position: "relative", overflow: "hidden" }}>
|
||
<div style={{ position: "absolute", width: 400, height: 400, borderRadius: "50%", background: "radial-gradient(circle, rgba(232,137,28,0.12) 0%, transparent 70%)", top: "15%", left: "50%", transform: "translateX(-50%)" }} />
|
||
<div style={{ opacity: ph >= 1 ? 1 : 0, transform: ph >= 1 ? "scale(1)" : "scale(0.8)", transition: `all 0.8s ${ease}`, textAlign: "center" }}>
|
||
<BrandLogo brand="bt" height={42} style={{ filter: "brightness(1.2)", marginBottom: 20 }} />
|
||
<div style={{ fontSize: 12, fontWeight: 400, letterSpacing: 8, marginTop: 6, textTransform: "uppercase", opacity: 0.7, fontFamily: T.sans, color: "#E8891C" }}>Rewards</div>
|
||
</div>
|
||
<div style={{ position: "absolute", bottom: 80, opacity: ph >= 2 ? 0.5 : 0, transition: `opacity 0.6s ${ease}`, fontSize: 11, letterSpacing: 2, fontFamily: T.sans, textTransform: "uppercase" }}>tap to continue</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// ═══ HOME ═══
|
||
const Home = ({ brand, go, setBrand }) => {
|
||
const c = T[brand]; const isBT = brand === "bt";
|
||
return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
{/* Brand Tabs with Logos */}
|
||
<div style={{ display: "flex", background: c.card, padding: "0 8px" }}>
|
||
{[["bt", "BreadTalk"], ["fs", "FoodStreat"]].map(([b, l]) => (
|
||
<div key={b} onClick={() => setBrand(b)} style={{ flex: 1, padding: "12px 0 10px", textAlign: "center", cursor: "pointer", borderBottom: brand === b ? `2.5px solid ${T[b].pri}` : "2.5px solid transparent", transition: `all 0.3s ${ease}`, display: "flex", alignItems: "center", justifyContent: "center", gap: 6 }}>
|
||
<BrandLogo brand={b} height={b === "bt" ? 18 : 24} style={{ opacity: brand === b ? 1 : 0.4, transition: `opacity 0.3s ${ease}` }} />
|
||
</div>
|
||
))}
|
||
</div>
|
||
<FadeIn>
|
||
<div style={{ background: isBT ? "linear-gradient(145deg, #1A1A1A 0%, #333 40%, #4A4A4A 100%)" : c.grad, padding: "22px 24px 28px", position: "relative", overflow: "hidden" }}>
|
||
<div style={{ position: "absolute", right: -40, top: -40, width: 180, height: 180, borderRadius: "50%", background: "rgba(232,137,28,0.08)" }} />
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
|
||
<div>
|
||
<div style={{ fontSize: 12, color: "rgba(255,255,255,0.7)", fontFamily: T.sans }}>Good afternoon,</div>
|
||
<div style={{ fontSize: 22, fontWeight: 700, color: "#FFF", fontFamily: T.font, marginTop: 2 }}>Zeya</div>
|
||
</div>
|
||
<Pill color="#FFF" bg="rgba(232,137,28,0.3)">🥇 Gold</Pill>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 12, marginTop: 18 }}>
|
||
{[{ l: "Balance", v: "45,500", u: "MMK" }, { l: "Points", v: "2,340", u: "pts" }].map(d => (
|
||
<div key={d.l} style={{ flex: 1, background: "rgba(255,255,255,0.08)", borderRadius: T.r.md, padding: "12px 14px", backdropFilter: "blur(8px)", border: "1px solid rgba(255,255,255,0.06)" }}>
|
||
<div style={{ fontSize: 10, color: "rgba(255,255,255,0.55)", fontFamily: T.sans, letterSpacing: 0.5, textTransform: "uppercase" }}>{d.l}</div>
|
||
<div style={{ color: "#FFF", marginTop: 4 }}><span style={{ fontSize: 22, fontWeight: 800, fontFamily: T.font }}>{d.v}</span><span style={{ fontSize: 10, opacity: 0.6, marginLeft: 4, fontFamily: T.sans }}>{d.u}</span></div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={80}>
|
||
<div style={{ display: "flex", gap: 0, padding: "18px 16px 10px", justifyContent: "space-between" }}>
|
||
{[{ icon: "📱", label: "Pay", s: "card" }, { icon: "💰", label: "Top Up", s: "wallet" }, { icon: "⭐", label: "Stamps", s: "stamps" }, { icon: "🎁", label: "Rewards", s: "rewards" }].map(a => (
|
||
<div key={a.label} onClick={() => go(a.s)} style={{ width: 76, textAlign: "center", cursor: "pointer" }}>
|
||
<div style={{ width: 50, height: 50, borderRadius: T.r.md, background: c.card, display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto", fontSize: 22, boxShadow: "0 2px 8px rgba(0,0,0,0.04), 0 0 0 1px rgba(0,0,0,0.03)" }}>{a.icon}</div>
|
||
<div style={{ fontSize: 10, color: c.ink2, marginTop: 7, fontWeight: 600, fontFamily: T.sans }}>{a.label}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={160}>
|
||
<div style={{ padding: "6px 24px 0" }}>
|
||
<div style={{ background: isBT ? T.bt.grad : T.fs.grad, borderRadius: T.r.lg, padding: "18px 20px", color: "#FFF", position: "relative", overflow: "hidden" }}>
|
||
<div style={{ position: "absolute", right: -10, bottom: -10, fontSize: 60, opacity: 0.15, transform: "rotate(-15deg)" }}>{isBT ? "☕" : "🍜"}</div>
|
||
<div style={{ fontSize: 13, fontWeight: 600, fontFamily: T.sans, lineHeight: 1.5, maxWidth: "80%" }}>{isBT ? "Double stamps on all coffees this week ☕" : "FoodStreat Friday — 20% off all stalls 🎉"}</div>
|
||
<div style={{ marginTop: 12, fontSize: 11, fontWeight: 700, fontFamily: T.sans, background: "rgba(255,255,255,0.2)", display: "inline-block", padding: "6px 14px", borderRadius: 8 }}>View Details →</div>
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={240}>
|
||
<div style={{ marginTop: 20 }}>
|
||
<SectionHead title="Active Stamp Card" action="See All →" onAction={() => go("stamps")} c={c} />
|
||
<div style={{ margin: "0 24px", background: c.card, borderRadius: T.r.lg, padding: "18px", boxShadow: "0 2px 12px rgba(0,0,0,0.04)" }}>
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||
<div>
|
||
<div style={{ fontSize: 14, fontWeight: 700, color: c.ink, fontFamily: T.font }}>{isBT ? "Coffee Lover Card" : "Lunch Champion"}</div>
|
||
<div style={{ fontSize: 11, color: c.ink3, marginTop: 3, fontFamily: T.sans }}>{isBT ? "Buy 9 coffees, get 1 FREE" : "5 lunches = Free dessert"}</div>
|
||
</div>
|
||
<div style={{ fontSize: 16, fontWeight: 800, color: c.pri, fontFamily: T.font }}>{isBT ? "6" : "3"}<span style={{ fontSize: 11, color: c.ink3, fontWeight: 500 }}>/{isBT ? "10" : "5"}</span></div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 6, marginTop: 14 }}>
|
||
{Array.from({ length: isBT ? 10 : 5 }).map((_, i) => (
|
||
<div key={i} style={{ flex: 1, aspectRatio: "1", borderRadius: 8, maxHeight: 30, background: i < (isBT ? 6 : 3) ? c.pri : i === (isBT ? 9 : 4) ? c.warm : c.surf, border: i < (isBT ? 6 : 3) ? "none" : `1.5px dashed ${c.ink3}40`, display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||
{i < (isBT ? 6 : 3) ? <span style={{ color: "#FFF", fontSize: 10, fontWeight: 700 }}>✓</span> : i === (isBT ? 9 : 4) ? <span style={{ fontSize: 10 }}>🎁</span> : null}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={320}>
|
||
<div style={{ marginTop: 22, paddingBottom: 90 }}>
|
||
<SectionHead title="Recent Activity" c={c} />
|
||
<div style={{ padding: "0 24px" }}>
|
||
{[{ icon: isBT ? "🍞" : "🍜", name: isBT ? "BreadTalk Junction City" : "Tokyo Ramen", amount: isBT ? "-4,500" : "-6,500", time: "Today, 2:15 PM", tag: "+1 stamp" }, { icon: "💰", name: "MMQR Top-Up", amount: "+20,000", time: "Yesterday", tag: "" }, { icon: isBT ? "🍞" : "🍜", name: isBT ? "BreadTalk Sule Square" : "Thai Express", amount: isBT ? "-3,200" : "-5,000", time: "Feb 7", tag: "+1 stamp" }].map((tx, i) => (
|
||
<div key={i} style={{ display: "flex", alignItems: "center", gap: 14, padding: "13px 0", borderBottom: i < 2 ? `1px solid ${c.surf}` : "none" }}>
|
||
<div style={{ width: 42, height: 42, borderRadius: T.r.sm, background: tx.amount.startsWith("+") ? "#ECFDF5" : c.surf, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 18, flexShrink: 0 }}>{tx.icon}</div>
|
||
<div style={{ flex: 1, minWidth: 0 }}>
|
||
<div style={{ fontSize: 13, fontWeight: 600, color: c.ink, fontFamily: T.sans, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{tx.name}</div>
|
||
<div style={{ fontSize: 11, color: c.ink3, marginTop: 2, fontFamily: T.sans }}>{tx.time}</div>
|
||
</div>
|
||
<div style={{ textAlign: "right", flexShrink: 0 }}>
|
||
<div style={{ fontSize: 14, fontWeight: 700, fontFamily: T.font, color: tx.amount.startsWith("+") ? T.green : c.ink }}>{tx.amount}</div>
|
||
{tx.tag && <div style={{ fontSize: 9, color: c.pri, fontWeight: 700, marginTop: 2, fontFamily: T.sans }}>{tx.tag}</div>}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
<Nav active="home" go={go} c={c} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// ═══ CARD ═══
|
||
const CardScreen = ({ brand, go }) => {
|
||
const c = T[brand]; const [big, setBig] = useState(false); const isBT = brand === "bt";
|
||
return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<FadeIn><div style={{ padding: "14px 24px 6px" }}><h2 style={{ fontSize: 22, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: 0 }}>My Card</h2></div></FadeIn>
|
||
<FadeIn delay={60}>
|
||
<div style={{ padding: "10px 24px" }}>
|
||
<div style={{ background: isBT ? T.bt.gradDark : c.gradDark, borderRadius: T.r.xl, padding: "26px 24px 22px", color: "#FFF", position: "relative", overflow: "hidden", boxShadow: "0 12px 40px rgba(0,0,0,0.25)" }}>
|
||
<div style={{ position: "absolute", right: -30, bottom: -30, width: 160, height: 160, borderRadius: "50%", background: "rgba(232,137,28,0.08)" }} />
|
||
<div style={{ position: "absolute", right: 40, top: -20, width: 80, height: 80, borderRadius: "50%", background: "rgba(232,137,28,0.05)" }} />
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
|
||
<BrandLogo brand={brand} height={brand === "bt" ? 22 : 36} style={{ filter: "brightness(1.3)" }} />
|
||
<Pill color="#FFF" bg="rgba(232,137,28,0.3)">🥇 GOLD</Pill>
|
||
</div>
|
||
<div style={{ marginTop: 22, fontSize: 17, fontWeight: 600, letterSpacing: 3, fontFamily: T.sans }}>BT-2602-A7K9X</div>
|
||
<div style={{ display: "flex", justifyContent: "space-between", marginTop: 18 }}>
|
||
{[["Member", "Zeya"], ["Since", "Feb 2026"], ["Balance", "45,500"]].map(([l, v]) => (<div key={l}><div style={{ fontSize: 8, opacity: 0.5, textTransform: "uppercase", letterSpacing: 1.5, fontFamily: T.sans }}>{l}</div><div style={{ fontSize: 14, fontWeight: 600, marginTop: 3, fontFamily: T.font }}>{v}</div></div>))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={140}>
|
||
<div onClick={() => setBig(!big)} style={{ margin: "14px 24px", background: c.card, borderRadius: T.r.lg, padding: "22px 24px", textAlign: "center", cursor: "pointer", boxShadow: "0 2px 12px rgba(0,0,0,0.04)", transition: `transform 0.35s ${ease}`, transform: big ? "scale(1.03)" : "scale(1)" }}>
|
||
<div style={{ fontSize: 13, fontWeight: 700, color: c.ink, fontFamily: T.sans, marginBottom: 16 }}>Scan to Pay or Earn Stamps</div>
|
||
<div style={{ width: big ? 200 : 150, height: big ? 200 : 150, margin: "0 auto", background: c.surf, borderRadius: T.r.md, padding: 12, display: "grid", gridTemplateColumns: "repeat(9,1fr)", gridTemplateRows: "repeat(9,1fr)", gap: 2, transition: `all 0.35s ${ease}` }}>
|
||
{Array.from({ length: 81 }).map((_, i) => (<div key={i} style={{ background: [0,1,2,6,7,8,9,17,18,26,27,35,36,44,45,53,54,62,63,71,72,73,74,78,79,80,3,4,12,21,30,39,48,57,66,75,76,77,40,41,49,50,58,59,31,32,22,23,14,15].includes(i) ? c.ink : "transparent", borderRadius: 1.5 }} />))}
|
||
</div>
|
||
<div style={{ fontSize: 10, color: c.ink3, marginTop: 14, fontFamily: T.sans }}>{big ? "Tap to minimize" : "Tap to enlarge"} · Auto-refreshes in 0:45</div>
|
||
</div>
|
||
</FadeIn>
|
||
<div style={{ height: 80 }} />
|
||
<Nav active="card" go={go} c={c} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// ═══ WALLET ═══
|
||
const Wallet = ({ brand, go }) => {
|
||
const c = T[brand]; const [topUp, setTopUp] = useState(false); const [sel, setSel] = useState(null); const isBT = brand === "bt";
|
||
if (topUp) return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<div style={{ padding: "14px 24px", display: "flex", alignItems: "center", gap: 14 }}><span onClick={() => setTopUp(false)} style={{ cursor: "pointer", fontSize: 18, color: c.ink }}>←</span><h2 style={{ fontSize: 20, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: 0 }}>Top Up</h2></div>
|
||
<FadeIn><div style={{ padding: "0 24px" }}>
|
||
<div style={{ fontSize: 12, color: c.ink2, fontFamily: T.sans, marginBottom: 14, fontWeight: 600, letterSpacing: 0.3, textTransform: "uppercase" }}>Select Amount</div>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
|
||
{[5000, 10000, 20000, 50000].map(a => (<div key={a} onClick={() => setSel(a)} style={{ background: sel === a ? c.pri : c.card, color: sel === a ? "#FFF" : c.ink, borderRadius: T.r.md, padding: "20px 16px", textAlign: "center", border: `2px solid ${sel === a ? c.pri : c.surf}`, cursor: "pointer", transition: `all 0.2s ${ease}`, boxShadow: sel === a ? `0 4px 16px ${c.pri}30` : "none" }}><div style={{ fontSize: 22, fontWeight: 800, fontFamily: T.font }}>{a.toLocaleString()}</div><div style={{ fontSize: 10, opacity: 0.7, marginTop: 2, fontFamily: T.sans }}>MMK</div></div>))}
|
||
</div>
|
||
<div style={{ marginTop: 20, fontSize: 12, fontWeight: 600, color: c.ink, fontFamily: T.sans, textTransform: "uppercase" }}>Pay with</div>
|
||
<div style={{ marginTop: 10, background: c.card, borderRadius: T.r.md, padding: 16, border: `2px solid ${c.pri}`, display: "flex", alignItems: "center", gap: 14 }}>
|
||
<div style={{ width: 42, height: 42, borderRadius: T.r.sm, background: c.surf, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 20 }}>📱</div>
|
||
<div style={{ flex: 1 }}><div style={{ fontSize: 14, fontWeight: 700, color: c.ink, fontFamily: T.sans }}>MMQR Payment</div><div style={{ fontSize: 11, color: c.ink3, fontFamily: T.sans, marginTop: 2 }}>All Myanmar banks supported</div></div>
|
||
<div style={{ color: c.pri, fontSize: 16, fontWeight: 700 }}>✓</div>
|
||
</div>
|
||
<button style={{ marginTop: 24, width: "100%", padding: "16px 0", background: sel ? c.grad : c.surf, color: sel ? "#FFF" : c.ink3, border: "none", borderRadius: T.r.md, fontSize: 15, fontWeight: 700, fontFamily: T.sans, cursor: sel ? "pointer" : "default", boxShadow: sel ? `0 4px 20px ${c.pri}30` : "none" }}>Top Up {sel ? `${sel.toLocaleString()} MMK` : ""}</button>
|
||
</div></FadeIn>
|
||
<div style={{ height: 80 }} /><Nav active="wallet" go={go} c={c} />
|
||
</div>
|
||
);
|
||
return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<FadeIn><div style={{ padding: "14px 24px 6px" }}><h2 style={{ fontSize: 22, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: 0 }}>Wallet</h2></div></FadeIn>
|
||
<FadeIn delay={60}><div style={{ padding: "10px 24px" }}>
|
||
<div style={{ background: isBT ? T.bt.gradDark : c.gradDark, borderRadius: T.r.xl, padding: "26px 24px 22px", color: "#FFF", position: "relative", overflow: "hidden", boxShadow: "0 12px 40px rgba(0,0,0,0.25)" }}>
|
||
<div style={{ position: "absolute", right: -20, bottom: -20, width: 120, height: 120, borderRadius: "50%", background: "rgba(232,137,28,0.08)" }} />
|
||
<BrandLogo brand={brand} height={brand === "bt" ? 16 : 26} style={{ filter: "brightness(1.3)", marginBottom: 10 }} />
|
||
<div style={{ fontSize: 11, opacity: 0.6, fontFamily: T.sans, letterSpacing: 0.5, textTransform: "uppercase" }}>Available Balance</div>
|
||
<div style={{ fontSize: 38, fontWeight: 800, fontFamily: T.font, marginTop: 6 }}>45,500 <span style={{ fontSize: 13, fontWeight: 400, fontFamily: T.sans }}>MMK</span></div>
|
||
<div style={{ display: "flex", gap: 12, marginTop: 20 }}>
|
||
<button onClick={() => setTopUp(true)} style={{ flex: 1, padding: "13px 0", background: "rgba(255,255,255,0.1)", border: "1px solid rgba(255,255,255,0.15)", borderRadius: T.r.sm, color: "#FFF", fontSize: 13, fontWeight: 700, cursor: "pointer", fontFamily: T.sans, backdropFilter: "blur(8px)" }}>💰 Top Up</button>
|
||
<button onClick={() => go("card")} style={{ flex: 1, padding: "13px 0", background: "#E8891C", border: "none", borderRadius: T.r.sm, color: "#FFF", fontSize: 13, fontWeight: 700, cursor: "pointer", fontFamily: T.sans }}>📱 Pay</button>
|
||
</div>
|
||
</div>
|
||
</div></FadeIn>
|
||
<FadeIn delay={140}><div style={{ display: "flex", gap: 10, padding: "14px 24px" }}>
|
||
{[{ l: "Spent", v: "78,200", col: c.ink }, { l: "Top-ups", v: "100K", col: T.green }, { l: "Visits", v: "12", col: c.pri }].map(s => (<div key={s.l} style={{ flex: 1, background: c.card, borderRadius: T.r.md, padding: "14px 12px", boxShadow: "0 1px 4px rgba(0,0,0,0.03)" }}><div style={{ fontSize: 9, color: c.ink3, fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.5 }}>{s.l}</div><div style={{ fontSize: 18, fontWeight: 800, color: s.col, fontFamily: T.font, marginTop: 4 }}>{s.v}</div></div>))}
|
||
</div></FadeIn>
|
||
<div style={{ height: 80 }} /><Nav active="wallet" go={go} c={c} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// ═══ STAMPS ═══
|
||
const Stamps = ({ brand, go }) => {
|
||
const c = T[brand]; const isBT = brand === "bt";
|
||
const cards = isBT ? [{ name: "Coffee Lover Card", desc: "Buy 9 coffees, get 1 FREE ☕", stamps: 6, total: 10, reward: "Free Coffee", exp: "Mar 31" }, { name: "Pastry Explorer", desc: "Try 5 pastries, earn 3,000 pts 🥐", stamps: 2, total: 5, reward: "3,000 Points", exp: "Apr 30" }] : [{ name: "Lunch Champion", desc: "5 lunches = Free dessert 🍜", stamps: 3, total: 5, reward: "Free Dessert", exp: "Mar 15" }, { name: "Stall Hopper", desc: "Visit 8 different stalls 🎪", stamps: 5, total: 8, reward: "10K Voucher", exp: "May 31" }];
|
||
return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<FadeIn><div style={{ padding: "14px 24px 6px" }}><h2 style={{ fontSize: 22, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: 0 }}>Stamp Cards</h2><p style={{ fontSize: 12, color: c.ink3, fontFamily: T.sans, margin: "4px 0 0" }}>{cards.length} active cards</p></div></FadeIn>
|
||
{cards.map((cd, ci) => (
|
||
<FadeIn key={ci} delay={80 + ci * 100}>
|
||
<div style={{ margin: "12px 24px", background: c.card, borderRadius: T.r.lg, padding: "18px", boxShadow: "0 2px 12px rgba(0,0,0,0.04)" }}>
|
||
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||
<div><div style={{ fontSize: 15, fontWeight: 700, color: c.ink, fontFamily: T.font }}>{cd.name}</div><div style={{ fontSize: 11, color: c.ink3, marginTop: 4, fontFamily: T.sans }}>{cd.desc}</div></div>
|
||
<div style={{ fontSize: 16, fontWeight: 800, color: c.pri, fontFamily: T.font }}>{cd.stamps}<span style={{ fontSize: 11, color: c.ink3, fontWeight: 500 }}>/{cd.total}</span></div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 7, marginTop: 16, flexWrap: "wrap" }}>
|
||
{Array.from({ length: cd.total }).map((_, i) => (<div key={i} style={{ width: 40, height: 40, borderRadius: T.r.sm, background: i < cd.stamps ? c.pri : i === cd.total - 1 ? c.warm : c.surf, border: i < cd.stamps ? "none" : `1.5px dashed ${c.ink3}40`, display: "flex", alignItems: "center", justifyContent: "center" }}>{i < cd.stamps ? <span style={{ color: "#FFF", fontSize: 14, fontWeight: 700 }}>✓</span> : i === cd.total - 1 ? <span style={{ fontSize: 14 }}>🎁</span> : <span style={{ color: c.ink3, fontSize: 11, fontFamily: T.sans }}>{i + 1}</span>}</div>))}
|
||
</div>
|
||
<div style={{ marginTop: 12, height: 5, background: c.surf, borderRadius: 3, overflow: "hidden" }}><div style={{ width: `${(cd.stamps / cd.total) * 100}%`, height: "100%", background: c.grad, borderRadius: 3 }} /></div>
|
||
<div style={{ display: "flex", justifyContent: "space-between", marginTop: 10 }}><span style={{ fontSize: 10, color: c.ink3, fontFamily: T.sans }}>🎁 <strong style={{ color: c.ink }}>{cd.reward}</strong></span><span style={{ fontSize: 10, color: c.ink3, fontFamily: T.sans }}>Expires {cd.exp}</span></div>
|
||
</div>
|
||
</FadeIn>
|
||
))}
|
||
<div style={{ height: 90 }} /><Nav active="home" go={go} c={c} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// ═══ REWARDS CATALOG + REDEMPTION ═══
|
||
const REWARDS = {
|
||
bt: [
|
||
{ id: 1, cat: "Free Items", name: "Free Artisan Coffee", desc: "Any handcrafted coffee, any size", pts: 800, img: "☕", tier: null, exp: "30 days", pop: true },
|
||
{ id: 2, cat: "Free Items", name: "Signature Floss Bun", desc: "Our iconic pork floss bun", pts: 500, img: "🍞", tier: null, exp: "14 days", pop: false },
|
||
{ id: 3, cat: "Free Items", name: "Seasonal Pastry Box", desc: "Chef\u2019s selection of 3 seasonal pastries", pts: 1500, img: "🥐", tier: "Silver", exp: "14 days", pop: true },
|
||
{ id: 4, cat: "Discounts", name: "20% Off Any Order", desc: "Single transaction up to 15,000 MMK", pts: 600, img: "🏷️", tier: null, exp: "7 days", pop: false },
|
||
{ id: 5, cat: "Discounts", name: "Buy 1 Get 1 Coffee", desc: "Any two coffees, lower price free", pts: 1000, img: "🎉", tier: null, exp: "14 days", pop: true },
|
||
{ id: 6, cat: "Upgrades", name: "Free Size Upgrade", desc: "Upgrade any drink to next size", pts: 300, img: "⬆️", tier: null, exp: "30 days", pop: false },
|
||
{ id: 7, cat: "Experiences", name: "VIP Tasting Event", desc: "Exclusive access to new product tasting", pts: 3000, img: "🌟", tier: "Gold", exp: "Event date", pop: false },
|
||
{ id: 8, cat: "Experiences", name: "Baking Workshop", desc: "Learn from our master bakers \u2014 2hr", pts: 5000, img: "👨\u200d🍳", tier: "Platinum", exp: "Event date", pop: false },
|
||
],
|
||
fs: [
|
||
{ id: 1, cat: "Free Items", name: "Free Dessert", desc: "Any dessert from any stall", pts: 600, img: "🍰", tier: null, exp: "14 days", pop: true },
|
||
{ id: 2, cat: "Free Items", name: "Free Drink", desc: "Any beverage up to 2,000 MMK", pts: 400, img: "🥤", tier: null, exp: "14 days", pop: false },
|
||
{ id: 3, cat: "Discounts", name: "15% Off Lunch", desc: "Valid 11AM-2PM, single transaction", pts: 500, img: "🏷️", tier: null, exp: "7 days", pop: true },
|
||
{ id: 4, cat: "Discounts", name: "10,000 MMK Voucher", desc: "Use as credit at any stall", pts: 2000, img: "💵", tier: "Silver", exp: "30 days", pop: true },
|
||
{ id: 5, cat: "Upgrades", name: "Free Extra Portion", desc: "Double rice, noodle, or side", pts: 350, img: "⬆️", tier: null, exp: "14 days", pop: false },
|
||
{ id: 6, cat: "Experiences", name: "Stall Tour & Tasting", desc: "Behind-the-scenes at 3 stalls", pts: 4000, img: "🌟", tier: "Gold", exp: "Event date", pop: false },
|
||
],
|
||
};
|
||
|
||
const RewardsScreen = ({ brand, go }) => {
|
||
const c = T[brand]; const [cat, setCat] = useState("All"); const [det, setDet] = useState(null); const [confirming, setConfirming] = useState(null); const [done, setDone] = useState(null);
|
||
const rws = REWARDS[brand] || REWARDS.bt; const list = cat === "All" ? rws : rws.filter(r => r.cat === cat); const pts = 2340;
|
||
|
||
if (done) return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<div style={{ height: 700, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "0 32px", textAlign: "center" }}>
|
||
<FadeIn><div style={{ width: 100, height: 100, borderRadius: "50%", background: "#ECFDF5", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 44, margin: "0 auto 20px", boxShadow: "0 8px 30px rgba(22,163,74,0.15)" }}>🎉</div></FadeIn>
|
||
<FadeIn delay={200}><h2 style={{ fontSize: 24, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: "0 0 8px" }}>Reward Redeemed!</h2><p style={{ fontSize: 13, color: c.ink2, fontFamily: T.sans, margin: "0 0 24px", lineHeight: 1.6 }}>Your <strong>{done.name}</strong> voucher is ready.</p></FadeIn>
|
||
<FadeIn delay={400}>
|
||
<div style={{ background: c.card, borderRadius: T.r.lg, padding: 24, width: "100%", boxShadow: "0 4px 20px rgba(0,0,0,0.06)", position: "relative", overflow: "hidden" }}>
|
||
<div style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: 5, background: c.grad }} />
|
||
<div style={{ fontSize: 36, marginBottom: 10 }}>{done.img}</div>
|
||
<div style={{ fontSize: 16, fontWeight: 700, color: c.ink, fontFamily: T.font }}>{done.name}</div>
|
||
<div style={{ fontSize: 12, color: c.ink3, fontFamily: T.sans, margin: "6px 0 16px" }}>Valid for {done.exp}</div>
|
||
<div style={{ width: 120, height: 120, margin: "0 auto", background: c.surf, borderRadius: T.r.md, display: "grid", gridTemplateColumns: "repeat(7,1fr)", gridTemplateRows: "repeat(7,1fr)", gap: 2, padding: 8 }}>
|
||
{Array.from({ length: 49 }).map((_, i) => (<div key={i} style={{ background: [0,1,2,4,5,6,7,13,14,20,21,27,28,34,35,41,42,43,44,46,47,48,3,10,17,24,31,38,45].includes(i) ? c.ink : "transparent", borderRadius: 1.5 }} />))}
|
||
</div>
|
||
<div style={{ fontSize: 10, color: c.ink3, marginTop: 10, fontFamily: T.sans }}>Show this QR at checkout</div>
|
||
<div style={{ fontSize: 11, color: c.pri, fontWeight: 700, fontFamily: T.sans, marginTop: 4, letterSpacing: 1 }}>VCH-BT-2602-7K9X</div>
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={600}><div style={{ display: "flex", gap: 12, marginTop: 24, width: "100%" }}>
|
||
<button onClick={() => { setDone(null); setDet(null); setConfirming(null); }} style={{ flex: 1, padding: "14px 0", background: c.card, border: `2px solid ${c.surf}`, borderRadius: T.r.md, fontSize: 13, fontWeight: 700, color: c.ink, fontFamily: T.sans, cursor: "pointer" }}>Browse More</button>
|
||
<button onClick={() => { setDone(null); setDet(null); setConfirming(null); go("profile"); }} style={{ flex: 1, padding: "14px 0", background: c.grad, border: "none", borderRadius: T.r.md, fontSize: 13, fontWeight: 700, color: "#FFF", fontFamily: T.sans, cursor: "pointer", boxShadow: `0 4px 16px ${c.pri}30` }}>My Vouchers</button>
|
||
</div></FadeIn>
|
||
</div>
|
||
</div>
|
||
);
|
||
|
||
if (confirming) return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<div style={{ padding: "14px 24px", display: "flex", alignItems: "center", gap: 14 }}><span onClick={() => setConfirming(null)} style={{ cursor: "pointer", fontSize: 18, color: c.ink }}>←</span><h2 style={{ fontSize: 20, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: 0 }}>Confirm Redemption</h2></div>
|
||
<FadeIn><div style={{ padding: "12px 24px", textAlign: "center" }}>
|
||
<div style={{ background: c.card, borderRadius: T.r.xl, padding: "32px 24px", boxShadow: "0 4px 24px rgba(0,0,0,0.06)" }}>
|
||
<div style={{ fontSize: 56, marginBottom: 16 }}>{confirming.img}</div>
|
||
<h3 style={{ fontSize: 20, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: "0 0 6px" }}>{confirming.name}</h3>
|
||
<p style={{ fontSize: 13, color: c.ink2, fontFamily: T.sans, margin: "0 0 20px" }}>{confirming.desc}</p>
|
||
<div style={{ background: c.surf, borderRadius: T.r.md, padding: "16px 20px", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||
<div style={{ textAlign: "left" }}><div style={{ fontSize: 10, color: c.ink3, fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.5 }}>Cost</div><div style={{ fontSize: 22, fontWeight: 800, color: c.pri, fontFamily: T.font, marginTop: 2 }}>{confirming.pts.toLocaleString()}</div></div>
|
||
<div style={{ width: 1, height: 36, background: c.ink3 + "30" }} />
|
||
<div style={{ textAlign: "right" }}><div style={{ fontSize: 10, color: c.ink3, fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.5 }}>Your Points</div><div style={{ fontSize: 22, fontWeight: 800, color: c.ink, fontFamily: T.font, marginTop: 2 }}>{pts.toLocaleString()}</div></div>
|
||
</div>
|
||
<div style={{ marginTop: 14, background: "#ECFDF5", borderRadius: T.r.sm, padding: "10px 14px", fontSize: 12, color: T.green, fontWeight: 600, fontFamily: T.sans }}>✓ After: {(pts - confirming.pts).toLocaleString()} pts remaining</div>
|
||
<div style={{ marginTop: 16, textAlign: "left" }}>
|
||
<div style={{ fontSize: 11, color: c.ink3, fontFamily: T.sans, marginBottom: 8, fontWeight: 600 }}>Terms:</div>
|
||
{[`Valid for ${confirming.exp} after redemption`, "Single use — one transaction only", "Cannot combine with other promos", brand === "bt" ? "All BreadTalk outlets" : "All FoodStreat stalls"].map((t, i) => (
|
||
<div key={i} style={{ fontSize: 11, color: c.ink2, fontFamily: T.sans, padding: "3px 0", display: "flex", gap: 6 }}><span style={{ color: c.ink3, fontSize: 8, marginTop: 3 }}>●</span><span>{t}</span></div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<button onClick={() => setDone(confirming)} style={{ marginTop: 20, width: "100%", padding: "16px 0", background: c.grad, color: "#FFF", border: "none", borderRadius: T.r.md, fontSize: 15, fontWeight: 700, fontFamily: T.sans, cursor: "pointer", boxShadow: `0 6px 24px ${c.pri}35` }}>Redeem for {confirming.pts.toLocaleString()} Points</button>
|
||
<button onClick={() => setConfirming(null)} style={{ marginTop: 10, width: "100%", padding: "14px 0", background: "transparent", color: c.ink2, border: "none", fontSize: 13, fontWeight: 600, fontFamily: T.sans, cursor: "pointer" }}>Cancel</button>
|
||
</div></FadeIn>
|
||
</div>
|
||
);
|
||
|
||
if (det) {
|
||
const ok = pts >= det.pts;
|
||
return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<div style={{ padding: "14px 24px", display: "flex", alignItems: "center", gap: 14 }}><span onClick={() => setDet(null)} style={{ cursor: "pointer", fontSize: 18, color: c.ink }}>←</span><h2 style={{ fontSize: 20, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: 0 }}>Reward Details</h2></div>
|
||
<FadeIn>
|
||
<div style={{ margin: "0 24px", background: c.grad, borderRadius: T.r.xl, padding: "36px 24px 32px", textAlign: "center", color: "#FFF", position: "relative", overflow: "hidden" }}>
|
||
<div style={{ position: "absolute", right: -20, top: -20, width: 100, height: 100, borderRadius: "50%", background: "rgba(255,255,255,0.1)" }} />
|
||
<div style={{ fontSize: 60, marginBottom: 12, filter: "drop-shadow(0 4px 8px rgba(0,0,0,0.2))" }}>{det.img}</div>
|
||
<h3 style={{ fontSize: 22, fontWeight: 700, fontFamily: T.font, margin: "0 0 6px" }}>{det.name}</h3>
|
||
<p style={{ fontSize: 13, opacity: 0.85, fontFamily: T.sans, margin: 0 }}>{det.desc}</p>
|
||
{det.tier && <div style={{ marginTop: 12, display: "inline-block", padding: "4px 12px", background: "rgba(255,255,255,0.15)", borderRadius: 20, fontSize: 10, fontWeight: 700, fontFamily: T.sans }}>{det.tier}+ Only</div>}
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={100}>
|
||
<div style={{ margin: "16px 24px", background: c.card, borderRadius: T.r.lg, padding: 20, boxShadow: "0 2px 12px rgba(0,0,0,0.04)" }}>
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||
<div><div style={{ fontSize: 10, color: c.ink3, fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.5 }}>Required</div><div style={{ fontSize: 28, fontWeight: 800, color: c.pri, fontFamily: T.font, marginTop: 4 }}>{det.pts.toLocaleString()}</div></div>
|
||
<div style={{ textAlign: "right" }}><div style={{ fontSize: 10, color: c.ink3, fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.5 }}>Your Points</div><div style={{ fontSize: 28, fontWeight: 800, color: ok ? T.green : "#EF4444", fontFamily: T.font, marginTop: 4 }}>{pts.toLocaleString()}</div></div>
|
||
</div>
|
||
{!ok && <div style={{ marginTop: 14, background: "#FEF2F2", borderRadius: T.r.sm, padding: "10px 14px", fontSize: 12, color: "#EF4444", fontWeight: 600, fontFamily: T.sans }}>Need {(det.pts - pts).toLocaleString()} more points</div>}
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={180}>
|
||
<div style={{ margin: "0 24px", background: c.card, borderRadius: T.r.lg, padding: "18px 20px", boxShadow: "0 2px 12px rgba(0,0,0,0.04)" }}>
|
||
<div style={{ fontSize: 13, fontWeight: 700, color: c.ink, fontFamily: T.sans, marginBottom: 12 }}>Details</div>
|
||
{[["Validity", `${det.exp} after redemption`], ["Usage", "Single use"], ["Location", brand === "bt" ? "All BreadTalk outlets" : "All FoodStreat stalls"], ["Stackable", "No"]].map(([k, v], i) => (
|
||
<div key={i} style={{ display: "flex", justifyContent: "space-between", padding: "9px 0", borderBottom: i < 3 ? `1px solid ${c.surf}` : "none" }}>
|
||
<span style={{ fontSize: 12, color: c.ink3, fontFamily: T.sans }}>{k}</span><span style={{ fontSize: 12, color: c.ink, fontWeight: 600, fontFamily: T.sans }}>{v}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={260}><div style={{ padding: "20px 24px" }}>
|
||
<button onClick={() => ok && setConfirming(det)} style={{ width: "100%", padding: "16px 0", background: ok ? c.grad : c.surf, color: ok ? "#FFF" : c.ink3, border: "none", borderRadius: T.r.md, fontSize: 15, fontWeight: 700, fontFamily: T.sans, cursor: ok ? "pointer" : "default", boxShadow: ok ? `0 6px 24px ${c.pri}35` : "none" }}>{ok ? `Redeem for ${det.pts.toLocaleString()} Points` : "Not Enough Points"}</button>
|
||
</div></FadeIn>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<FadeIn>
|
||
<div style={{ padding: "14px 24px 6px" }}>
|
||
<h2 style={{ fontSize: 22, fontWeight: 700, color: c.ink, fontFamily: T.font, margin: 0 }}>Rewards</h2>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 6 }}><span style={{ fontSize: 13, color: c.ink2, fontFamily: T.sans }}>Your points:</span><span style={{ fontSize: 17, fontWeight: 800, color: c.pri, fontFamily: T.font }}>{pts.toLocaleString()}</span></div>
|
||
</div>
|
||
</FadeIn>
|
||
<FadeIn delay={60}>
|
||
<div style={{ display: "flex", gap: 8, padding: "12px 24px", overflowX: "auto" }}>
|
||
{["All", "Free Items", "Discounts", "Upgrades", "Experiences"].map(ct => (
|
||
<div key={ct} onClick={() => setCat(ct)} style={{ padding: "8px 16px", borderRadius: 20, whiteSpace: "nowrap", background: cat === ct ? c.pri : c.card, color: cat === ct ? "#FFF" : c.ink2, fontSize: 12, fontWeight: 600, fontFamily: T.sans, cursor: "pointer", border: `1.5px solid ${cat === ct ? c.pri : c.surf}`, transition: `all 0.25s ${ease}`, boxShadow: cat === ct ? `0 3px 12px ${c.pri}30` : "none" }}>{ct}</div>
|
||
))}
|
||
</div>
|
||
</FadeIn>
|
||
{cat === "All" && <FadeIn delay={120}><div style={{ padding: "4px 24px 8px" }}>
|
||
<div style={{ background: c.grad, borderRadius: T.r.lg, padding: "16px 18px", color: "#FFF", display: "flex", alignItems: "center", gap: 14, position: "relative", overflow: "hidden" }}>
|
||
<div style={{ position: "absolute", right: -10, top: -10, width: 70, height: 70, borderRadius: "50%", background: "rgba(255,255,255,0.08)" }} />
|
||
<div style={{ fontSize: 32 }}>✦</div>
|
||
<div><div style={{ fontSize: 14, fontWeight: 700, fontFamily: T.sans }}>Points Unlock Great Rewards</div><div style={{ fontSize: 11, opacity: 0.8, fontFamily: T.sans, marginTop: 2 }}>Earn more by visiting more</div></div>
|
||
</div>
|
||
</div></FadeIn>}
|
||
<div style={{ padding: "8px 24px 100px" }}>
|
||
{list.map((rw, i) => {
|
||
const ok = pts >= rw.pts;
|
||
return (
|
||
<FadeIn key={rw.id} delay={140 + i * 60}>
|
||
<div onClick={() => setDet(rw)} style={{ background: c.card, borderRadius: T.r.lg, padding: "16px", marginBottom: 10, cursor: "pointer", boxShadow: "0 1px 6px rgba(0,0,0,0.03), 0 0 0 1px rgba(0,0,0,0.02)", display: "flex", gap: 14, alignItems: "center", position: "relative", overflow: "hidden" }}>
|
||
<div style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: 4, background: ok ? c.grad : c.surf }} />
|
||
<div style={{ width: 52, height: 52, borderRadius: T.r.md, background: c.surf, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 26, flexShrink: 0 }}>{rw.img}</div>
|
||
<div style={{ flex: 1, minWidth: 0 }}>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
|
||
<span style={{ fontSize: 14, fontWeight: 700, color: c.ink, fontFamily: T.font }}>{rw.name}</span>
|
||
{rw.pop && <Pill color={T.gold} bg={T.gold + "15"}>⭐ Popular</Pill>}
|
||
{rw.tier && <Pill color={c.pri} bg={c.pri + "10"}>{rw.tier}+</Pill>}
|
||
</div>
|
||
<div style={{ fontSize: 11, color: c.ink3, fontFamily: T.sans, marginTop: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{rw.desc}</div>
|
||
</div>
|
||
<div style={{ textAlign: "center", flexShrink: 0, paddingLeft: 4 }}>
|
||
<div style={{ fontSize: 16, fontWeight: 800, fontFamily: T.font, color: ok ? c.pri : c.ink3 }}>{rw.pts.toLocaleString()}</div>
|
||
<div style={{ fontSize: 9, color: c.ink3, fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.5 }}>pts</div>
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
);
|
||
})}
|
||
</div>
|
||
<Nav active="rewards" go={go} c={c} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// ═══ PROFILE ═══
|
||
const Profile = ({ brand, go }) => {
|
||
const c = T[brand];
|
||
return (
|
||
<div style={{ background: c.bg, minHeight: 700 }}>
|
||
<FadeIn><div style={{ background: brand === "bt" ? T.bt.gradDark : c.gradDark, padding: "20px 24px 28px", color: "#FFF", borderRadius: `0 0 ${T.r.xl}px ${T.r.xl}px` }}>
|
||
<BrandLogo brand={brand} height={brand === "bt" ? 18 : 28} style={{ filter: "brightness(1.3)", marginBottom: 14 }} />
|
||
<div style={{ display: "flex", alignItems: "center", gap: 16 }}>
|
||
<div style={{ width: 56, height: 56, borderRadius: 18, background: "rgba(255,255,255,0.1)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 26 }}>👤</div>
|
||
<div><div style={{ fontSize: 18, fontWeight: 700, fontFamily: T.font }}>Zeya</div><div style={{ fontSize: 12, opacity: 0.6, fontFamily: T.sans, marginTop: 2 }}>+95 09 XXX XXX XXX</div><Pill color="#FFF" bg="rgba(232,137,28,0.3)">🥇 Gold</Pill></div>
|
||
</div>
|
||
</div></FadeIn>
|
||
<FadeIn delay={80}><div style={{ margin: "16px 24px", background: c.card, borderRadius: T.r.lg, padding: 18, boxShadow: "0 2px 12px rgba(0,0,0,0.04)" }}>
|
||
<div style={{ fontSize: 13, fontWeight: 700, color: c.ink, fontFamily: T.sans, marginBottom: 10 }}>Tier Progress</div>
|
||
<div style={{ display: "flex", justifyContent: "space-between", fontSize: 10, fontFamily: T.sans }}><span style={{ color: T.silver, fontWeight: 700 }}>Silver</span><span style={{ color: T.gold, fontWeight: 700 }}>● Gold</span><span style={{ color: c.ink3 }}>Platinum</span></div>
|
||
<div style={{ height: 6, background: c.surf, borderRadius: 3, marginTop: 6, overflow: "hidden" }}><div style={{ width: "65%", height: "100%", background: c.grad, borderRadius: 3 }} /></div>
|
||
<div style={{ fontSize: 11, color: c.ink3, marginTop: 8, fontFamily: T.sans }}>Spend <strong style={{ color: c.pri }}>350,000 MMK</strong> more for Platinum</div>
|
||
</div></FadeIn>
|
||
<FadeIn delay={140}><div style={{ padding: "0 24px 100px" }}>
|
||
{[{ icon: "🎫", label: "My Vouchers", sub: "2 active" }, { icon: "👤", label: "Edit Profile", sub: "" }, { icon: "🔔", label: "Notifications", sub: "" }, { icon: "📍", label: "Store Locator", sub: "" }, { icon: "🔗", label: "Linked NFC Cards", sub: "1 linked" }, { icon: "🌐", label: "Language", sub: "English" }, { icon: "❓", label: "Help & Support", sub: "" }].map((it, i) => (
|
||
<div key={i} style={{ display: "flex", alignItems: "center", gap: 14, padding: "14px 0", borderBottom: `1px solid ${c.surf}`, cursor: "pointer" }}>
|
||
<div style={{ width: 40, height: 40, borderRadius: T.r.sm, background: c.card, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 17, boxShadow: "0 1px 4px rgba(0,0,0,0.04)" }}>{it.icon}</div>
|
||
<div style={{ flex: 1 }}><div style={{ fontSize: 14, fontWeight: 600, color: c.ink, fontFamily: T.sans }}>{it.label}</div>{it.sub && <div style={{ fontSize: 11, color: c.ink3, fontFamily: T.sans, marginTop: 1 }}>{it.sub}</div>}</div>
|
||
<span style={{ color: c.ink3, fontSize: 13 }}>›</span>
|
||
</div>
|
||
))}
|
||
</div></FadeIn>
|
||
<Nav active="profile" go={go} c={c} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// ═══ POS WORKFLOW ═══
|
||
const POSWorkflow = ({ brand }) => {
|
||
const c = T[brand]; const isBT = brand === "bt";
|
||
const [step, setStep] = useState(0);
|
||
const [autoPlay, setAutoPlay] = useState(false);
|
||
|
||
useEffect(() => {
|
||
if (!autoPlay) return;
|
||
if (step >= 6) { setAutoPlay(false); return; }
|
||
const t = setTimeout(() => setStep(s => s + 1), 2200);
|
||
return () => clearTimeout(t);
|
||
}, [step, autoPlay]);
|
||
|
||
const memberData = { name: "Zeya", id: "BT-2602-A7K9X", tier: "Gold", tierIcon: "🥇", balance: "45,500", points: "2,340", stamps: "6/10", phone: "+95 09 XXX XXX" };
|
||
const orderItems = isBT
|
||
? [{ name: "Artisan Latte", qty: 1, price: 3500 }, { name: "Signature Floss Bun", qty: 2, price: 2800 }, { name: "Butter Croissant", qty: 1, price: 2200 }]
|
||
: [{ name: "Chicken Biryani", qty: 1, price: 5500 }, { name: "Thai Milk Tea", qty: 1, price: 2500 }, { name: "Mango Sticky Rice", qty: 1, price: 3000 }];
|
||
const total = orderItems.reduce((s, i) => s + i.qty * i.price, 0);
|
||
const pointsEarned = Math.floor(total / 100) * 2;
|
||
|
||
const steps = [
|
||
{ label: "Waiting", desc: "Ready to serve next customer", icon: "🔍" },
|
||
{ label: "Member Identified", desc: "QR scanned — member found", icon: "✅" },
|
||
{ label: "Order Entry", desc: "Items added to the bill", icon: "🛒" },
|
||
{ label: "Payment", desc: "Processing wallet payment", icon: "💳" },
|
||
{ label: "Loyalty Credited", desc: "Stamps & points awarded", icon: "⭐" },
|
||
{ label: "Voucher Applied", desc: "Discount voucher redeemed", icon: "🎫" },
|
||
{ label: "Complete", desc: "Transaction finished", icon: "🎉" },
|
||
];
|
||
|
||
const posGreen = "#22C55E"; const posBlue = "#3B82F6"; const posAmber = "#F59E0B";
|
||
|
||
return (
|
||
<div style={{ width: 620, background: "#111", borderRadius: 18, padding: 8, boxShadow: "0 20px 60px rgba(0,0,0,0.4), 0 0 0 1px #333" }}>
|
||
{/* Tablet bezel */}
|
||
<div style={{ background: "#F5F5F5", borderRadius: 12, overflow: "hidden", minHeight: 580 }}>
|
||
{/* POS Header Bar */}
|
||
<div style={{ background: "#1E293B", padding: "10px 20px", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
|
||
<div style={{ fontSize: 15, fontWeight: 800, color: "#FFF", fontFamily: T.sans }}>SmartSales</div>
|
||
<div style={{ fontSize: 10, color: "#94A3B8", fontFamily: T.sans }}>POS Terminal</div>
|
||
</div>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
|
||
<BrandLogo brand={brand} height={brand === "bt" ? 14 : 20} style={{ filter: "brightness(1.5)" }} />
|
||
<div style={{ fontSize: 10, color: "#94A3B8", fontFamily: T.sans }}>|</div>
|
||
<div style={{ fontSize: 10, color: "#94A3B8", fontFamily: T.sans }}>Cashier: Ma Aye</div>
|
||
<div style={{ width: 8, height: 8, borderRadius: "50%", background: posGreen }} />
|
||
</div>
|
||
</div>
|
||
|
||
{/* Step Progress Bar */}
|
||
<div style={{ background: "#FFF", padding: "12px 20px", borderBottom: "1px solid #E5E7EB", display: "flex", gap: 0, alignItems: "center" }}>
|
||
{steps.map((s, i) => (
|
||
<div key={i} style={{ display: "flex", alignItems: "center", flex: i < steps.length - 1 ? 1 : 0 }}>
|
||
<div onClick={() => setStep(i)} style={{
|
||
width: 28, height: 28, borderRadius: "50%", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 12, fontWeight: 700, fontFamily: T.sans, cursor: "pointer", flexShrink: 0, transition: `all 0.3s ${ease}`,
|
||
background: i < step ? posGreen : i === step ? c.pri : "#E5E7EB",
|
||
color: i <= step ? "#FFF" : "#9CA3AF",
|
||
boxShadow: i === step ? `0 0 0 3px ${c.pri}30` : "none",
|
||
}}>{i < step ? "✓" : i + 1}</div>
|
||
{i < steps.length - 1 && <div style={{ flex: 1, height: 2, background: i < step ? posGreen : "#E5E7EB", margin: "0 4px", transition: `background 0.3s ${ease}` }} />}
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Step Label */}
|
||
<div style={{ background: step === 6 ? "#ECFDF5" : "#FFF", padding: "10px 20px", borderBottom: "1px solid #E5E7EB", display: "flex", justifyContent: "space-between", alignItems: "center", transition: `background 0.3s ${ease}` }}>
|
||
<div>
|
||
<div style={{ fontSize: 16, fontWeight: 700, color: "#1E293B", fontFamily: T.font }}>{steps[step].icon} {steps[step].label}</div>
|
||
<div style={{ fontSize: 11, color: "#64748B", fontFamily: T.sans, marginTop: 2 }}>{steps[step].desc}</div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 8 }}>
|
||
<button onClick={() => setStep(Math.max(0, step - 1))} disabled={step === 0} style={{ padding: "6px 14px", borderRadius: 8, border: "1px solid #E5E7EB", background: "#FFF", color: step === 0 ? "#D1D5DB" : "#374151", fontSize: 11, fontWeight: 600, cursor: step === 0 ? "default" : "pointer", fontFamily: T.sans }}>← Back</button>
|
||
<button onClick={() => setStep(Math.min(6, step + 1))} disabled={step === 6} style={{ padding: "6px 14px", borderRadius: 8, border: "none", background: step === 6 ? "#D1D5DB" : c.pri, color: "#FFF", fontSize: 11, fontWeight: 600, cursor: step === 6 ? "default" : "pointer", fontFamily: T.sans }}>Next →</button>
|
||
<button onClick={() => { setStep(0); setAutoPlay(true); }} style={{ padding: "6px 14px", borderRadius: 8, border: `1px solid ${posGreen}`, background: autoPlay ? posGreen : "#FFF", color: autoPlay ? "#FFF" : posGreen, fontSize: 11, fontWeight: 600, cursor: "pointer", fontFamily: T.sans }}>▶ Auto</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Main POS Content */}
|
||
<div style={{ display: "flex", minHeight: 420 }}>
|
||
{/* LEFT: Order Panel */}
|
||
<div style={{ flex: 1, padding: 16, borderRight: "1px solid #E5E7EB" }}>
|
||
{/* Member Card (appears after step 1) */}
|
||
{step >= 1 && (
|
||
<FadeIn>
|
||
<div style={{ background: step >= 1 ? "#F0FDF4" : "#F8FAFC", border: `1.5px solid ${step >= 1 ? posGreen : "#E5E7EB"}`, borderRadius: 12, padding: "12px 14px", marginBottom: 12, transition: `all 0.3s ${ease}` }}>
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
|
||
<div style={{ display: "flex", gap: 10, alignItems: "center" }}>
|
||
<div style={{ width: 40, height: 40, borderRadius: 10, background: c.pri + "15", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 18 }}>👤</div>
|
||
<div>
|
||
<div style={{ fontSize: 14, fontWeight: 700, color: "#1E293B", fontFamily: T.sans }}>{memberData.name}</div>
|
||
<div style={{ fontSize: 10, color: "#64748B", fontFamily: T.sans }}>{memberData.id} · {memberData.phone}</div>
|
||
</div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 6, alignItems: "center" }}>
|
||
<span style={{ fontSize: 13 }}>{memberData.tierIcon}</span>
|
||
<span style={{ fontSize: 11, fontWeight: 700, color: T.gold, fontFamily: T.sans }}>{memberData.tier}</span>
|
||
</div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 8, marginTop: 10 }}>
|
||
{[["Wallet", `${memberData.balance} MMK`, posGreen], ["Points", memberData.points, c.pri], ["Stamps", memberData.stamps, posAmber]].map(([l, v, col]) => (
|
||
<div key={l} style={{ flex: 1, background: "#FFF", borderRadius: 8, padding: "6px 8px", border: "1px solid #E5E7EB" }}>
|
||
<div style={{ fontSize: 8, color: "#94A3B8", fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.5 }}>{l}</div>
|
||
<div style={{ fontSize: 13, fontWeight: 700, color: col, fontFamily: T.font, marginTop: 1 }}>{v}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
)}
|
||
|
||
{/* Scan Prompt (step 0) */}
|
||
{step === 0 && (
|
||
<FadeIn>
|
||
<div style={{ textAlign: "center", padding: "50px 20px" }}>
|
||
<div style={{ width: 80, height: 80, borderRadius: 20, background: "#F1F5F9", display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 16px", fontSize: 36, border: "2px dashed #CBD5E1" }}>📱</div>
|
||
<div style={{ fontSize: 16, fontWeight: 700, color: "#1E293B", fontFamily: T.font }}>Scan Member QR Code</div>
|
||
<div style={{ fontSize: 12, color: "#64748B", fontFamily: T.sans, marginTop: 6 }}>Point POS scanner at customer's app QR code</div>
|
||
<div style={{ marginTop: 16, display: "inline-flex", alignItems: "center", gap: 6, padding: "8px 16px", background: posBlue + "10", borderRadius: 8, border: `1px solid ${posBlue}20` }}>
|
||
<div style={{ width: 8, height: 8, borderRadius: "50%", background: posBlue, animation: "pulse 1.5s infinite" }} />
|
||
<span style={{ fontSize: 11, color: posBlue, fontWeight: 600, fontFamily: T.sans }}>Scanner Ready</span>
|
||
</div>
|
||
<div style={{ marginTop: 20, padding: "10px 16px", background: "#FFF7ED", borderRadius: 8, border: "1px solid #FED7AA", textAlign: "left" }}>
|
||
<div style={{ fontSize: 10, fontWeight: 700, color: posAmber, fontFamily: T.sans, marginBottom: 4 }}>💡 ALSO ACCEPTS</div>
|
||
<div style={{ fontSize: 11, color: "#92400E", fontFamily: T.sans, lineHeight: 1.5 }}>NFC Card Tap · Manual Member ID · Phone Number Lookup</div>
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
)}
|
||
|
||
{/* Order Items (step 2+) */}
|
||
{step >= 2 && (
|
||
<FadeIn>
|
||
<div style={{ background: "#FFF", borderRadius: 12, border: "1px solid #E5E7EB", overflow: "hidden" }}>
|
||
<div style={{ padding: "10px 14px", background: "#F8FAFC", borderBottom: "1px solid #E5E7EB", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||
<span style={{ fontSize: 12, fontWeight: 700, color: "#1E293B", fontFamily: T.sans }}>🛒 Order Items</span>
|
||
<span style={{ fontSize: 10, color: "#64748B", fontFamily: T.sans }}>Order #SS-2602-0847</span>
|
||
</div>
|
||
{orderItems.map((item, i) => (
|
||
<div key={i} style={{ padding: "10px 14px", display: "flex", justifyContent: "space-between", alignItems: "center", borderBottom: i < orderItems.length - 1 ? "1px solid #F1F5F9" : "none" }}>
|
||
<div>
|
||
<div style={{ fontSize: 13, fontWeight: 600, color: "#1E293B", fontFamily: T.sans }}>{item.name}</div>
|
||
<div style={{ fontSize: 10, color: "#94A3B8", fontFamily: T.sans }}>x{item.qty}</div>
|
||
</div>
|
||
<div style={{ fontSize: 13, fontWeight: 700, color: "#1E293B", fontFamily: T.font }}>{(item.qty * item.price).toLocaleString()}</div>
|
||
</div>
|
||
))}
|
||
<div style={{ padding: "12px 14px", background: "#F8FAFC", borderTop: "1px solid #E5E7EB" }}>
|
||
{step >= 5 && (
|
||
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
|
||
<span style={{ fontSize: 11, color: posGreen, fontWeight: 600, fontFamily: T.sans }}>🎫 Voucher: 20% Off</span>
|
||
<span style={{ fontSize: 11, color: posGreen, fontWeight: 700, fontFamily: T.font }}>-{Math.round(total * 0.2).toLocaleString()}</span>
|
||
</div>
|
||
)}
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||
<span style={{ fontSize: 14, fontWeight: 700, color: "#1E293B", fontFamily: T.sans }}>TOTAL</span>
|
||
<div>
|
||
{step >= 5 && <span style={{ fontSize: 11, color: "#94A3B8", textDecoration: "line-through", marginRight: 8, fontFamily: T.font }}>{total.toLocaleString()}</span>}
|
||
<span style={{ fontSize: 18, fontWeight: 800, color: c.pri, fontFamily: T.font }}>{step >= 5 ? Math.round(total * 0.8).toLocaleString() : total.toLocaleString()} <span style={{ fontSize: 10, fontWeight: 400 }}>MMK</span></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
)}
|
||
|
||
{/* Payment Processing (step 3) */}
|
||
{step === 3 && (
|
||
<FadeIn delay={100}>
|
||
<div style={{ marginTop: 12, background: posBlue + "08", border: `1.5px solid ${posBlue}30`, borderRadius: 12, padding: 16, textAlign: "center" }}>
|
||
<div style={{ fontSize: 28, marginBottom: 8 }}>💳</div>
|
||
<div style={{ fontSize: 14, fontWeight: 700, color: posBlue, fontFamily: T.sans }}>Processing Wallet Payment</div>
|
||
<div style={{ fontSize: 11, color: "#64748B", fontFamily: T.sans, marginTop: 4 }}>Debiting {total.toLocaleString()} MMK from member wallet...</div>
|
||
<div style={{ marginTop: 12, height: 4, background: "#E5E7EB", borderRadius: 2, overflow: "hidden" }}>
|
||
<div style={{ width: "70%", height: "100%", background: `linear-gradient(90deg, ${posBlue}, ${c.pri})`, borderRadius: 2 }} />
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
)}
|
||
|
||
{/* Loyalty Credited (step 4) */}
|
||
{step === 4 && (
|
||
<FadeIn delay={100}>
|
||
<div style={{ marginTop: 12, background: "#FFF7ED", border: "1.5px solid #FED7AA", borderRadius: 12, padding: 14 }}>
|
||
<div style={{ fontSize: 12, fontWeight: 700, color: posAmber, fontFamily: T.sans, marginBottom: 10 }}>⭐ LOYALTY AUTO-CREDITED</div>
|
||
<div style={{ display: "flex", gap: 10 }}>
|
||
<div style={{ flex: 1, background: "#FFF", borderRadius: 8, padding: "10px 12px", border: "1px solid #FED7AA", textAlign: "center" }}>
|
||
<div style={{ fontSize: 20, fontWeight: 800, color: c.pri, fontFamily: T.font }}>+{pointsEarned}</div>
|
||
<div style={{ fontSize: 9, color: "#92400E", fontFamily: T.sans, marginTop: 2 }}>POINTS (2x Gold)</div>
|
||
</div>
|
||
<div style={{ flex: 1, background: "#FFF", borderRadius: 8, padding: "10px 12px", border: "1px solid #FED7AA", textAlign: "center" }}>
|
||
<div style={{ fontSize: 20, fontWeight: 800, color: posAmber, fontFamily: T.font }}>+1</div>
|
||
<div style={{ fontSize: 9, color: "#92400E", fontFamily: T.sans, marginTop: 2 }}>STAMP ({isBT ? "Coffee Card" : "Lunch Card"})</div>
|
||
</div>
|
||
</div>
|
||
<div style={{ marginTop: 8, fontSize: 10, color: "#92400E", fontFamily: T.sans, textAlign: "center" }}>{isBT ? "Coffee Lover Card: 7/10 stamps" : "Lunch Champion: 4/5 stamps"} — {isBT ? "3 more to free coffee!" : "1 more to free dessert!"}</div>
|
||
</div>
|
||
</FadeIn>
|
||
)}
|
||
|
||
{/* Voucher Applied (step 5) */}
|
||
{step === 5 && (
|
||
<FadeIn delay={100}>
|
||
<div style={{ marginTop: 12, background: "#F0FDF4", border: `1.5px solid ${posGreen}40`, borderRadius: 12, padding: 14 }}>
|
||
<div style={{ fontSize: 12, fontWeight: 700, color: posGreen, fontFamily: T.sans, marginBottom: 8 }}>🎫 VOUCHER REDEEMED</div>
|
||
<div style={{ display: "flex", gap: 10, alignItems: "center", background: "#FFF", borderRadius: 8, padding: "10px 12px", border: "1px solid #BBF7D0" }}>
|
||
<div style={{ fontSize: 24 }}>🏷️</div>
|
||
<div style={{ flex: 1 }}>
|
||
<div style={{ fontSize: 13, fontWeight: 700, color: "#1E293B", fontFamily: T.sans }}>20% Off Any Order</div>
|
||
<div style={{ fontSize: 10, color: "#64748B", fontFamily: T.sans }}>VCH-BT-2602-7K9X · Scanned from app</div>
|
||
</div>
|
||
<div style={{ fontSize: 14, fontWeight: 800, color: posGreen, fontFamily: T.font }}>-{Math.round(total * 0.2).toLocaleString()}</div>
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
)}
|
||
|
||
{/* Complete (step 6) */}
|
||
{step === 6 && (
|
||
<FadeIn delay={100}>
|
||
<div style={{ marginTop: 12, background: "#F0FDF4", border: `1.5px solid ${posGreen}`, borderRadius: 12, padding: 20, textAlign: "center" }}>
|
||
<div style={{ fontSize: 36, marginBottom: 8 }}>🎉</div>
|
||
<div style={{ fontSize: 16, fontWeight: 700, color: posGreen, fontFamily: T.font }}>Transaction Complete!</div>
|
||
<div style={{ fontSize: 11, color: "#64748B", fontFamily: T.sans, marginTop: 4, lineHeight: 1.6 }}>
|
||
Receipt sent to app · Balance updated in real-time
|
||
</div>
|
||
<div style={{ display: "flex", gap: 8, marginTop: 14, justifyContent: "center" }}>
|
||
<button onClick={() => setStep(0)} style={{ padding: "10px 20px", borderRadius: 8, border: "none", background: posGreen, color: "#FFF", fontSize: 12, fontWeight: 700, fontFamily: T.sans, cursor: "pointer" }}>✓ Next Customer</button>
|
||
<button style={{ padding: "10px 20px", borderRadius: 8, border: "1px solid #E5E7EB", background: "#FFF", color: "#374151", fontSize: 12, fontWeight: 600, fontFamily: T.sans, cursor: "pointer" }}>🖨 Print Receipt</button>
|
||
</div>
|
||
</div>
|
||
</FadeIn>
|
||
)}
|
||
</div>
|
||
|
||
{/* RIGHT: Status & API Panel */}
|
||
<div style={{ width: 210, background: "#F8FAFC", padding: 14, overflow: "auto" }}>
|
||
<div style={{ fontSize: 10, fontWeight: 700, color: "#64748B", fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.8, marginBottom: 10 }}>System Log</div>
|
||
{/* API calls log */}
|
||
{[
|
||
step >= 0 && { api: "POS Ready", method: "SYS", status: "online", color: posGreen },
|
||
step >= 1 && { api: "/member/lookup", method: "POST", status: "200 OK", color: posGreen, detail: "QR → member_id: BT-2602-A7K9X" },
|
||
step >= 1 && { api: "/member/profile", method: "GET", status: "200 OK", color: posGreen, detail: "Tier: Gold, Balance: 45,500" },
|
||
step >= 2 && { api: "/order/create", method: "POST", status: "201", color: posBlue, detail: `${orderItems.length} items, ${total.toLocaleString()} MMK` },
|
||
step >= 3 && { api: "/wallet/pay", method: "POST", status: step >= 4 ? "200 OK" : "pending", color: step >= 4 ? posGreen : posAmber, detail: `Debit: ${total.toLocaleString()} MMK` },
|
||
step >= 4 && { api: "/loyalty/credit", method: "POST", status: "200 OK", color: posGreen, detail: `+${pointsEarned} pts, +1 stamp` },
|
||
step >= 4 && { api: "WebSocket → App", method: "PUSH", status: "sent", color: posBlue, detail: "Real-time balance update" },
|
||
step >= 5 && { api: "/voucher/redeem", method: "POST", status: "200 OK", color: posGreen, detail: "VCH-BT-2602-7K9X applied" },
|
||
step >= 5 && { api: "/order/update", method: "PATCH", status: "200 OK", color: posBlue, detail: `New total: ${Math.round(total * 0.8).toLocaleString()}` },
|
||
step >= 6 && { api: "/receipt/generate", method: "POST", status: "201", color: posGreen, detail: "Digital receipt → app" },
|
||
step >= 6 && { api: "/notification/push", method: "POST", status: "sent", color: posBlue, detail: "FCM → customer app" },
|
||
].filter(Boolean).map((log, i) => (
|
||
<FadeIn key={i} delay={i * 40}>
|
||
<div style={{ padding: "7px 8px", background: "#FFF", borderRadius: 8, marginBottom: 5, border: "1px solid #E5E7EB", fontSize: 9, fontFamily: "monospace" }}>
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||
<span style={{ fontWeight: 700, color: "#374151" }}>{log.method}</span>
|
||
<span style={{ color: log.color, fontWeight: 700, fontSize: 8 }}>● {log.status}</span>
|
||
</div>
|
||
<div style={{ color: "#64748B", marginTop: 2, fontWeight: 600 }}>{log.api}</div>
|
||
{log.detail && <div style={{ color: "#94A3B8", marginTop: 1, fontSize: 8 }}>{log.detail}</div>}
|
||
</div>
|
||
</FadeIn>
|
||
))}
|
||
|
||
{/* Data flow legend */}
|
||
<div style={{ marginTop: 12, padding: "10px 10px", background: "#FFF", borderRadius: 8, border: "1px solid #E5E7EB" }}>
|
||
<div style={{ fontSize: 9, fontWeight: 700, color: "#64748B", fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 6 }}>Data Flow</div>
|
||
{[
|
||
["POS Scanner", "→", "Membership API"],
|
||
["API", "→", "Wallet Service"],
|
||
["API", "→", "Loyalty Engine"],
|
||
["WebSocket", "→", "Customer App"],
|
||
].map(([from, arrow, to], i) => (
|
||
<div key={i} style={{ fontSize: 8, fontFamily: T.sans, color: "#64748B", padding: "3px 0", display: "flex", gap: 4, alignItems: "center" }}>
|
||
<span style={{ fontWeight: 700, color: "#374151" }}>{from}</span>
|
||
<span style={{ color: c.pri }}>{arrow}</span>
|
||
<span>{to}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// ═══ APP SHELL ═══
|
||
const SCREENS = { splash: "Splash", home: "Home", card: "Digital Card", wallet: "Wallet & Top-Up", stamps: "Stamp Cards", rewards: "Rewards Catalog", profile: "Profile & More", pos: "POS Workflow" };
|
||
|
||
export default function App() {
|
||
const [scr, setScr] = useState("splash"); const [brand, setBrand] = useState("bt");
|
||
const go = (s) => setScr(s);
|
||
const render = () => {
|
||
switch (scr) {
|
||
case "splash": return <Splash onNext={() => go("home")} />;
|
||
case "home": return <Home brand={brand} go={go} setBrand={setBrand} />;
|
||
case "card": return <CardScreen brand={brand} go={go} />;
|
||
case "wallet": return <Wallet brand={brand} go={go} />;
|
||
case "stamps": return <Stamps brand={brand} go={go} />;
|
||
case "rewards": return <RewardsScreen brand={brand} go={go} />;
|
||
case "profile": return <Profile brand={brand} go={go} />;
|
||
case "pos": return null;
|
||
default: return <Home brand={brand} go={go} setBrand={setBrand} />;
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div style={{ minHeight: "100vh", background: "linear-gradient(160deg, #0A0A0A 0%, #1A1A1A 30%, #2A2A2A 60%, #1A1A1A 100%)", display: "flex", alignItems: "flex-start", justifyContent: "center", gap: 28, padding: "28px 20px", flexWrap: "wrap", fontFamily: T.sans }}>
|
||
{scr === "pos" ? <POSWorkflow brand={brand} /> : <Phone>{render()}</Phone>}
|
||
<div style={{ width: 240, background: "rgba(255,255,255,0.04)", borderRadius: 24, padding: 22, border: "1px solid rgba(255,255,255,0.06)", backdropFilter: "blur(20px)" }}>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
|
||
<BrandLogo brand="bt" height={16} />
|
||
<span style={{ fontSize: 10, color: "rgba(255,255,255,0.35)", fontFamily: T.sans }}>Rewards</span>
|
||
</div>
|
||
<div style={{ fontSize: 10, color: "rgba(255,255,255,0.25)", fontFamily: T.sans, marginBottom: 18 }}>Interactive Prototype v2.2</div>
|
||
<div style={{ padding: "10px 14px", background: "rgba(232,137,28,0.1)", borderRadius: 12, marginBottom: 16, border: "1px solid rgba(232,137,28,0.2)" }}>
|
||
<div style={{ fontSize: 9, color: "rgba(255,255,255,0.4)", fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 1 }}>Current Screen</div>
|
||
<div style={{ fontSize: 14, color: "#E8891C", fontWeight: 700, fontFamily: T.font, marginTop: 3 }}>{SCREENS[scr]}</div>
|
||
</div>
|
||
<div style={{ fontSize: 9, color: "rgba(255,255,255,0.3)", fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 1, marginBottom: 8 }}>Navigate</div>
|
||
{Object.entries(SCREENS).map(([k, v]) => (
|
||
<div key={k} onClick={() => go(k)} style={{ padding: "9px 12px", borderRadius: 10, marginBottom: 4, cursor: "pointer", background: scr === k ? "rgba(232,137,28,0.12)" : "transparent", border: scr === k ? "1px solid rgba(232,137,28,0.2)" : "1px solid transparent", color: scr === k ? "#E8891C" : "rgba(255,255,255,0.5)", fontSize: 12, fontWeight: scr === k ? 700 : 400, fontFamily: T.sans, transition: `all 0.2s ${ease}` }}>{scr === k ? "● " : ""}{v}</div>
|
||
))}
|
||
<div style={{ marginTop: 16 }}>
|
||
<div style={{ fontSize: 9, color: "rgba(255,255,255,0.3)", fontFamily: T.sans, textTransform: "uppercase", letterSpacing: 1, marginBottom: 8 }}>Brand Theme</div>
|
||
<div style={{ display: "flex", gap: 8 }}>
|
||
{[["bt", "BreadTalk", T.bt.pri], ["fs", "FoodStreat", T.fs.pri]].map(([b, l, col]) => (
|
||
<div key={b} onClick={() => { setBrand(b); if (scr === "splash") go("home"); }} style={{ flex: 1, padding: "10px 6px", borderRadius: 10, textAlign: "center", background: brand === b ? col : "transparent", border: `1.5px solid ${brand === b ? col : "rgba(255,255,255,0.12)"}`, color: brand === b ? "#FFF" : "rgba(255,255,255,0.4)", fontSize: 10, fontWeight: 700, cursor: "pointer", fontFamily: T.sans, transition: `all 0.25s ${ease}` }}>{l}</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div style={{ marginTop: 16, padding: "12px 14px", borderRadius: 12, background: "rgba(22,163,74,0.08)", border: "1px solid rgba(22,163,74,0.15)" }}>
|
||
<div style={{ fontSize: 9, color: "#16A34A", fontWeight: 700, fontFamily: T.sans }}>REWARDS FLOW</div>
|
||
<div style={{ fontSize: 10, color: "rgba(255,255,255,0.4)", fontFamily: T.sans, marginTop: 6, lineHeight: 1.7 }}>Catalog → Detail → Confirm → Voucher QR</div>
|
||
</div>
|
||
<div style={{ marginTop: 8, padding: "12px 14px", borderRadius: 12, background: "rgba(59,130,246,0.08)", border: "1px solid rgba(59,130,246,0.15)" }}>
|
||
<div style={{ fontSize: 9, color: "#3B82F6", fontWeight: 700, fontFamily: T.sans }}>POS WORKFLOW</div>
|
||
<div style={{ fontSize: 10, color: "rgba(255,255,255,0.4)", fontFamily: T.sans, marginTop: 6, lineHeight: 1.7 }}>Scan QR → Identify → Order → Pay → Loyalty → Voucher → Done</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|