/* ============================================================
Store screens — Part 1: Login, Home, Category, Product
============================================================ */
/* ---------------- LOGIN ---------------- */
function LoginScreen() {
const { login } = useContext(AppCtx);
const [email, setEmail] = useState('m.hebert@evansequip.com');
const [pw, setPw] = useState('••••••••');
return (
{/* Left brand panel */}
Employees only
Your company apparel store.
Sign in to browse Evans-branded gear and spend your annual $300 clothing allowance — no card required.
{[['coins','300 pts / year'],['shield','Private & secure'],['truck','Delivered to you']].map(([ic, t]) => (
))}
© 2026 Evans Equipment & Environmental
{/* Right form */}
Sign in
Use the account issued by your HR administrator.
Need access? Contact your HR administrator to have an account created.
);
}
/* ---------------- HOME ---------------- */
function HomeScreen() {
const { navigate, user } = useContext(AppCtx);
const remaining = user.pointsTotal - user.pointsUsed;
const cats = CATEGORIES.filter(c => user.categories.includes(c.id));
const featured = PRODUCTS.filter(p => user.categories.includes(p.cat)).slice(0, 4);
return (
{/* Welcome / allowance band */}
Welcome back
Hey {user.first} 👋
You have {remaining} points left to spend this year. Pick out your gear below.
{/* Allowance card */}
{/* Category tiles */}
Shop by category
Showing categories for your role · {user.role}
{cats.map((c, i) => )}
{/* Featured */}
Popular this season
navigate('category', { cat: cats[0].id })}>Browse all
);
}
function AllowanceStat({ label, value, sub, highlight, divider }) {
return (
);
}
function CategoryTile({ cat, i }) {
const { navigate } = useContext(AppCtx);
const sample = PRODUCTS.filter(p => p.cat === cat.id);
const tints = ['var(--teal-600)', 'var(--forest)', 'var(--teal-800)'];
return (
navigate('category', { cat: cat.id })}
style={{ borderRadius: 'var(--radius-lg)', overflow: 'hidden', cursor: 'pointer', border: '1px solid var(--line)', background: 'var(--surface)', transition: 'box-shadow .2s, transform .2s' }}
onMouseEnter={e => { e.currentTarget.style.boxShadow = 'var(--shadow-lg)'; e.currentTarget.style.transform = 'translateY(-4px)'; }}
onMouseLeave={e => { e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'none'; }}>
{sample.length} styles
{cat.label}
{cat.blurb}
);
}
/* ---------------- CATEGORY LISTING ---------------- */
function CategoryScreen({ cat }) {
const { navigate } = useContext(AppCtx);
const category = CATEGORIES.find(c => c.id === cat);
const all = PRODUCTS.filter(p => p.cat === cat);
const [sort, setSort] = useState('featured');
const [filter, setFilter] = useState('all');
let list = [...all];
if (filter === 'fr') list = list.filter(p => p.fr);
if (filter === 'jackets') list = list.filter(p => p.kind === 'jacket');
if (sort === 'low') list.sort((a, b) => a.price - b.price);
if (sort === 'high') list.sort((a, b) => b.price - a.price);
return (
navigate('home')}>Home
{category.label}
{category.label}
{all.length} styles · embroidered or printed with the Evans logo
{category.id === 'tech' && (
)}
);
}
/* ---------------- PRODUCT DETAIL ---------------- */
function ProductScreen({ id, color: initColor }) {
const { navigate, addToCart, user } = useContext(AppCtx);
const product = PRODUCTS.find(p => p.id === id);
const [color, setColor] = useState(initColor || product.colors[0]);
const [size, setSize] = useState('L');
const [qty, setQty] = useState(1);
const [added, setAdded] = useState(false);
const category = CATEGORIES.find(c => c.id === product.cat);
const remaining = user.pointsTotal - user.pointsUsed;
const doAdd = () => {
addToCart(product, color, size, qty);
setAdded(true);
setTimeout(() => setAdded(false), 1800);
};
return (
navigate('home')}>Home
navigate('category', { cat: product.cat })}>{category.label}
{product.name}
{/* Gallery */}
{product.colors.slice(0, 5).map(c => (
))}
{/* Info */}
{product.brand}
{product.fr && FR · NFPA 2112}
{product.name}
Style {product.sku}
{product.price} pts
(${product.price} value)
{product.desc}
{/* Color */}
{/* Size */}
Size
Size guide
{SIZES.map(s => (
))}
{/* Qty + add */}
{qty}
This order uses {product.price * qty} of your {remaining} remaining points. No payment needed when you're within your allowance.
);
}
Object.assign(window, { LoginScreen, HomeScreen, AllowanceStat, CategoryTile, CategoryScreen, ProductScreen });