/* ============================================================= KASDAP ONE — CATALOG SCREEN (unified search + order) ============================================================= */ const { useState: useStateCat, useMemo: useMemoCat } = React; /* ---------- product card ---------- */ function ProductCard({ p }) { const { mode, priceOf, addToCart, inCart, cart, setQty, go, toast } = useStore(); const pr = priceOf(p, mode, 1); const line = cart.find(x => x.handle === p.id && x.mode === mode); const open = () => go('product', { id: p.id }); const add = (e) => { e.stopPropagation(); addToCart(p.id, 1, mode); toast(`${p.name} added to ${mode.toUpperCase()} order`, 'ok'); }; return React.createElement('div', { className: 'pcard' + (line ? ' incart' : ''), onClick: open }, React.createElement('div', { style: { position: 'relative' } }, React.createElement(ProductImage, { p, className: 'pimg' }), React.createElement('div', { className: 'pimg-tags' }, React.createElement('span', { className: 'rxtag ' + (p.rx ? 'rx' : 'otc') }, p.rx ? 'Rx' : 'OTC'), p.isNew && React.createElement('span', { className: 'rxtag new' }, 'NEW') ) ), React.createElement('div', { className: 'pcat' }, p.therapeutic || p.category), React.createElement('div', { className: 'pname' }, p.name), React.createElement('div', { className: 'psalt' }, p.salt || p.category), React.createElement('div', { className: 'pmeta' }, React.createElement(Stars, { value: p.rating, size: 11 }), React.createElement('span', { className: 'dotsep' }), React.createElement('span', null, p.packing) ), React.createElement('div', { className: 'pfoot' }, React.createElement('div', { className: 'price-col' }, mode === 'd2c' ? React.createElement(React.Fragment, null, React.createElement('div', { className: 'p-mrp' }, fmt(pr.mrp)), React.createElement('div', null, React.createElement('span', { className: 'p-now' }, fmt(pr.unit)), React.createElement('span', { className: 'p-unit' }, ' /pack')), pr.savePct > 0 && React.createElement('div', { className: 'p-save' }, pr.savePct + '% off MRP') ) : React.createElement(React.Fragment, null, React.createElement('div', { className: 'p-mrp' }, fmt(pr.boxMrp) + ' MRP'), React.createElement('div', null, React.createElement('span', { className: 'p-now' }, fmt(pr.unit)), React.createElement('span', { className: 'p-unit' }, ' /box')), React.createElement('div', { className: 'p-sub' }, fmt(pr.packPrice) + '/pack · ' + p.ppb + ' packs') ) ), line ? React.createElement('div', { className: 'qty mini', onClick: e => e.stopPropagation() }, React.createElement('button', { onClick: () => setQty(p.id, mode, line.qty - 1) }, React.createElement(Icon, { name: 'minus', size: 14 })), React.createElement('input', { value: line.qty, onChange: e => setQty(p.id, mode, parseInt(e.target.value) || 0) }), React.createElement('button', { onClick: () => setQty(p.id, mode, line.qty + 1) }, React.createElement(Icon, { name: 'plus', size: 14 })) ) : React.createElement('button', { className: 'addbtn', onClick: add, title: 'Add to order' }, React.createElement(Icon, { name: 'plus', size: 18 })) ) ); } /* ---------- filter rail ---------- */ function FilterRail({ state, set, facets }) { const top = facets.categories; const ther = facets.therapeutic.slice(0, 12); return React.createElement(React.Fragment, null, React.createElement('div', { className: 'fgroup' }, React.createElement('div', { className: 'ft' }, 'Therapy Area'), React.createElement('div', { className: 'frow' + (state.cat === null ? ' on' : ''), onClick: () => set({ cat: null }) }, React.createElement('span', { className: 'fi' }, React.createElement(Icon, { name: 'grid', size: 14 })), React.createElement('span', { className: 'fn' }, 'All categories'), React.createElement('span', { className: 'fc' }, facets.categories.reduce((s, c) => s + c[1], 0)) ), top.map(([c, n]) => React.createElement('div', { key: c, className: 'frow' + (state.cat === c ? ' on' : ''), onClick: () => set({ cat: state.cat === c ? null : c }) }, React.createElement('span', { className: 'fi' }, React.createElement(Icon, { name: (window.CATEGORY_ICON[c] || 'spark'), size: 14 })), React.createElement('span', { className: 'fn' }, c), React.createElement('span', { className: 'fc' }, n) )) ), React.createElement('div', { className: 'fgroup' }, React.createElement('div', { className: 'ft' }, 'Therapeutic Class'), ther.map(([t, n]) => React.createElement('div', { key: t, className: 'frow' + (state.ther === t ? ' on' : ''), onClick: () => set({ ther: state.ther === t ? null : t }) }, React.createElement('span', { className: 'fn', style: { textTransform: 'capitalize', fontSize: '.76rem' } }, t.toLowerCase()), React.createElement('span', { className: 'fc' }, n) )) ), React.createElement('div', { className: 'fgroup' }, React.createElement('div', { className: 'ft' }, 'Filters'), React.createElement('div', { className: 'switch' }, React.createElement('span', { style: { fontSize: '.8rem', color: 'var(--text-2)' } }, 'In stock only'), React.createElement('div', { className: 'toggle' + (state.inStock ? ' on' : ''), onClick: () => set({ inStock: !state.inStock }) }) ), React.createElement('div', { className: 'switch' }, React.createElement('span', { style: { fontSize: '.8rem', color: 'var(--text-2)' } }, 'OTC (non-Rx)'), React.createElement('div', { className: 'toggle' + (state.otc ? ' on' : ''), onClick: () => set({ otc: !state.otc }) }) ) ) ); } /* ---------- basket panel ---------- */ function BasketBody() { const { cartDetail, setQty, removeFromCart, mode } = useStore(); const { d2c, b2b } = cartDetail; if (cartDetail.count === 0) return React.createElement('div', { className: 'basket-empty' }, React.createElement('div', { className: 'be-ic' }, React.createElement(Icon, { name: 'cart', size: 24 })), React.createElement('div', null, React.createElement('div', { style: { fontWeight: 700, color: 'var(--text-2)', marginBottom: 4 } }, 'Your order is empty'), React.createElement('div', { style: { fontSize: '.78rem', lineHeight: 1.5 } }, 'Add packs as ', React.createElement('b', { style: { color: 'var(--emerald)' } }, 'D2C'), ' or boxes as ', React.createElement('b', { style: { color: 'var(--indigo)' } }, 'B2B'), ' — they live in one basket.')) ); const Group = (lines, m) => lines.length > 0 && React.createElement('div', { className: 'basket-group', key: m }, React.createElement('div', { className: 'bg-h ' + (m === 'd2c' ? 'em' : 'in') }, React.createElement('span', { className: 'bg-tag' }, m === 'd2c' ? 'D2C · RETAIL' : 'B2B · TRADE'), React.createElement('span', null, lines.length + (lines.length > 1 ? ' items' : ' item')), React.createElement('span', { className: 'bg-sub' }, fmt(lines.reduce((s, l) => s + l.lineTotal, 0))) ), lines.map(l => React.createElement('div', { className: 'bline', key: l.handle + l.mode }, React.createElement(ProductImage, { p: l.p, className: 'pimg' }), React.createElement('div', { className: 'bl-mid' }, React.createElement('div', { className: 'bl-name' }, l.p.name), React.createElement('div', { className: 'bl-meta' }, fmt(l.pr.unit) + ' / ' + l.pr.unitLabel), React.createElement('div', { className: 'bl-foot' }, React.createElement('div', { className: 'qty mini' }, React.createElement('button', { onClick: () => setQty(l.handle, l.mode, l.qty - 1) }, React.createElement(Icon, { name: 'minus', size: 13 })), React.createElement('input', { value: l.qty, onChange: e => setQty(l.handle, l.mode, parseInt(e.target.value) || 0) }), React.createElement('button', { onClick: () => setQty(l.handle, l.mode, l.qty + 1) }, React.createElement(Icon, { name: 'plus', size: 13 })) ), React.createElement('span', { className: 'bl-price' }, fmt(l.lineTotal)) ) ), React.createElement('button', { className: 'bl-del', onClick: () => removeFromCart(l.handle, l.mode), title: 'Remove' }, React.createElement(Icon, { name: 'trash', size: 14 })) )) ); return React.createElement(React.Fragment, null, Group(d2c, 'd2c'), Group(b2b, 'b2b')); } function BasketFoot() { const { cartDetail, go, toast, pricing } = useStore(); const { subtotal, gst, total, b2b, d2c, count } = cartDetail; const saveTotal = cartDetail.lines.reduce((s, l) => s + (l.pr.save || 0) * l.qty, 0); return React.createElement('div', { className: 'basket-foot' }, saveTotal > 0 && React.createElement('div', { className: 'sumrow save' }, React.createElement('span', null, 'You save'), React.createElement('span', { className: 'v' }, fmt(saveTotal))), React.createElement('div', { className: 'sumrow' }, React.createElement('span', null, 'Subtotal'), React.createElement('span', { className: 'v' }, fmt(subtotal))), React.createElement('div', { className: 'sumrow' }, React.createElement('span', null, 'GST (' + Math.round(pricing.gst * 100) + '%)'), React.createElement('span', { className: 'v' }, fmt(gst))), React.createElement('div', { className: 'sumrow tot' }, React.createElement('span', null, 'Total'), React.createElement('span', { className: 'v' }, fmt(total))), React.createElement('button', { className: 'btn btn-accent btn-block btn-lg', style: { marginTop: 12 }, disabled: count === 0, onClick: () => go('checkout') }, b2b.length && !d2c.length ? 'Review & Request Quote' : 'Proceed to Checkout', React.createElement(Icon, { name: 'arrow', size: 16 })), React.createElement('div', { className: 'secure' }, React.createElement(Icon, { name: 'shieldCheck', size: 13 }), 'SSL secured · GST invoice') ); } /* ---------- main catalog screen ---------- */ function CatalogScreen() { const { products, facets, mode, cartDetail } = useStore(); const [q, setQ] = useStateCat(''); const [sort, setSort] = useStateCat('rel'); const [f, setF] = useStateCat({ cat: null, ther: null, inStock: false, otc: false }); const [sheet, setSheet] = useStateCat(null); // 'basket' | 'filters' const set = (patch) => setF(s => ({ ...s, ...patch })); const results = useMemoCat(() => { const term = q.trim().toLowerCase(); let r = products.filter(p => { if (f.cat && p.category !== f.cat) return false; if (f.ther && p.therapeutic !== f.ther) return false; if (f.inStock && p.stock <= 0) return false; if (f.otc && p.rx) return false; if (term) { const hay = (p.name + ' ' + p.salt + ' ' + p.sku + ' ' + p.category + ' ' + p.therapeutic + ' ' + p.type).toLowerCase(); if (!hay.includes(term)) return false; } return true; }); if (sort === 'priceA') r = [...r].sort((a, b) => a.mrp - b.mrp); else if (sort === 'priceD') r = [...r].sort((a, b) => b.mrp - a.mrp); else if (sort === 'name') r = [...r].sort((a, b) => a.name.localeCompare(b.name)); else if (sort === 'rating') r = [...r].sort((a, b) => b.rating - a.rating); return r; }, [products, q, f, sort]); const chips = [['All', null], ...facets.categories.slice(0, 8).map(([c]) => [c, c])]; return React.createElement('div', { className: 'cat' }, /* left */ React.createElement('aside', { className: 'filters' }, React.createElement('div', { className: 'fh' }, React.createElement('h3', null, 'Filters'), (f.cat || f.ther || f.inStock || f.otc) && React.createElement('button', { className: 'chip', onClick: () => setF({ cat: null, ther: null, inStock: false, otc: false }) }, 'Clear')), React.createElement(FilterRail, { state: f, set, facets }) ), /* center */ React.createElement('div', { className: 'cat-center' }, React.createElement('div', { className: 'cat-search' }, React.createElement('div', { className: 'searchbar' }, React.createElement(Icon, { name: 'search', size: 19 }), React.createElement('input', { value: q, onChange: e => setQ(e.target.value), placeholder: 'Search 700+ SKUs — name, salt, SKU, therapy…' }), React.createElement('span', { className: 'kbd hide-mobile' }, 'esc to clear') ), React.createElement('div', { className: 'chips no-scrollbar' }, chips.map(([label, val]) => React.createElement('button', { key: label, className: 'chip' + (f.cat === val ? ' on' : ''), onClick: () => set({ cat: val }) }, label)) ) ), React.createElement('div', { className: 'cat-body' }, React.createElement('div', { className: 'cat-tb' }, React.createElement('div', { className: 'rc' }, React.createElement('b', null, results.length.toLocaleString('en-IN')), ' products · pricing for ', React.createElement('b', { style: { color: 'var(--accent)' } }, mode === 'd2c' ? 'retail' : 'trade')), React.createElement('div', { className: 'right' }, React.createElement('button', { className: 'chip filter-fab', onClick: () => setSheet('filters') }, React.createElement(Icon, { name: 'filter', size: 14 }), 'Filters'), React.createElement('select', { className: 'select', style: { width: 'auto', padding: '8px 32px 8px 12px', fontSize: '.78rem' }, value: sort, onChange: e => setSort(e.target.value) }, React.createElement('option', { value: 'rel' }, 'Relevance'), React.createElement('option', { value: 'priceA' }, 'Price: Low → High'), React.createElement('option', { value: 'priceD' }, 'Price: High → Low'), React.createElement('option', { value: 'rating' }, 'Top rated'), React.createElement('option', { value: 'name' }, 'Name A–Z') ) ) ), results.length === 0 ? React.createElement('div', { style: { textAlign: 'center', padding: '60px 20px', color: 'var(--text-3)' } }, React.createElement(Icon, { name: 'search', size: 32, style: { margin: '0 auto 12px' } }), React.createElement('div', { style: { fontWeight: 700, color: 'var(--text-2)' } }, 'No products match'), React.createElement('div', { style: { fontSize: '.82rem', marginTop: 4 } }, 'Try a different search or clear filters')) : React.createElement('div', { className: 'grid' }, results.slice(0, 240).map(p => React.createElement(ProductCard, { key: p.id, p }))) ) ), /* right */ React.createElement('aside', { className: 'basket' }, React.createElement('div', { className: 'basket-h' }, React.createElement('h3', null, React.createElement(Icon, { name: 'cart', size: 17 }), 'Your Order'), React.createElement('span', { className: 'badge' }, cartDetail.count + ' lines')), React.createElement('div', { className: 'basket-body' }, React.createElement(BasketBody, null)), React.createElement(BasketFoot, null) ), /* mobile FAB */ React.createElement('button', { className: 'cat-fab', onClick: () => setSheet('basket') }, React.createElement(Icon, { name: 'cart', size: 22 }), cartDetail.count > 0 && React.createElement('span', { className: 'cart-badge' }, cartDetail.count) ), /* sheets */ sheet === 'basket' && React.createElement('div', { className: 'sheet-overlay', onClick: () => setSheet(null) }, React.createElement('div', { className: 'sheet', style: { height: '82vh' }, onClick: e => e.stopPropagation() }, React.createElement('div', { className: 'sheet-handle' }), React.createElement('div', { className: 'basket-h' }, React.createElement('h3', null, 'Your Order'), React.createElement('span', { className: 'badge' }, cartDetail.count + ' lines')), React.createElement('div', { className: 'basket-body', style: { flex: 1, overflowY: 'auto' } }, React.createElement(BasketBody, null)), React.createElement(BasketFoot, null) ) ), sheet === 'filters' && React.createElement('div', { className: 'sheet-overlay', onClick: () => setSheet(null) }, React.createElement('div', { className: 'sheet', style: { height: '80vh' }, onClick: e => e.stopPropagation() }, React.createElement('div', { className: 'sheet-handle' }), React.createElement('div', { style: { padding: '8px 16px 16px', overflowY: 'auto' } }, React.createElement(FilterRail, { state: f, set, facets }), React.createElement('button', { className: 'btn btn-accent btn-block btn-lg', style: { marginTop: 8 }, onClick: () => setSheet(null) }, 'Show ' + results.length + ' products')) ) ) ); } Object.assign(window, { CatalogScreen, ProductCard });