Companion to the design pack (vapehub-basket-IMPLEMENTATION-BRIEF.md + vapehub-product-basket-checkout-REVIEW.md, both in this folder). This records the functional decisions baked into the prototype and, for each, what the production build must supply. Where the prototype hardcodes something, it says so and points at the real source.
The basket is folded into the homepage build — vapehub-homepage-src/handover/vapehub-homepage.html, all classes/ids namespaced vhb-*, opened from the header basket icon (#vh-basket-link). /basket/ is kept as the link's real fallback href.
type — the attribute several behaviours key offMultiple features need to know what kind of product each cart line is. The prototype fakes this with a kit:true flag on the two device lines; production needs a real type (or category) on every product, from the catalogue. Suggested values:
type | Examples |
|---|---|
kit / device | Hayati Pro Max Plus, Aura Bar 10K, Vaporesso XROS 5 |
pod / refill | prefilled pods, refill packs, coils |
e-liquid | nic salts, shortfills, 10ml |
pouch | nicotine pouches |
accessory | batteries, chargers, cases |
This single attribute drives the adaptive heading (§2), recommendation relevance (§3), and can inform multibuy grouping (§4).
The question that prompted this doc: what if the basket has no kit in it?
Rule the prototype now implements — recomputed on every cart change:
``js hasKit = cart.some(line => line.type === 'kit' || line.type === 'device') heading = hasKit ? 'Complete your kit' : 'Add to your order' ``
In the prototype line.type is stood in by the kit boolean. Swap it for the real type from §1 and the rule is unchanged.
Prototype = 3 hardcoded items. Production must select by relevance (brief §4), which needs:
type/category for the fallback ladder (category complements → category bestsellers).Exclusions: already in cart, out of stock, discontinued. Price bias toward low-cost items (£2.89–£5.99) that help close the free-delivery gap. A hardcoded "you may also like" is explicitly not acceptable — relevance is the whole point.
Prototype applies multibuy per SKU: multibuy = {n, price}, line total = floor(qty/n)×price + (qty%n)×unitPrice. VapeHub's real deals are often mix-and-match across a group ("any 3 big-puff kits for £23", "Hayati pods 3 for £15"). Get the exact rules from the promo engine; if group-based, evaluate a deal group across cart lines, not per line. This is the single biggest logic risk (brief §3).
| Thing | Prototype value | Production source |
|---|---|---|
| Free-delivery threshold | £30 | config |
| Delivery from | £2.99 | config |
| Dispatch cutoff | 16:00, browser clock | server time + working-days / bank-holiday calendar (after Fri 4pm → Monday) |
| Loyalty earn rate | 10 pts/£1, 100 pts = £1 | real loyalty rate (confirm the scheme) |
| Multibuy | per-SKU | promo engine (see §4) |
| Recommendations | 3 hardcoded | compatible mapping / rec service (see §3) |
| Payments | cards only — VISA / MC / AMEX | Worldpay; express-pay slot reserved above the CTA for Apple/Google Pay when live |
role="dialog" + aria-modal, focus trap, Esc closes and returns focus to the trigger, aria-live="polite" on the subtotal and free-delivery message.prefers-reduced-motion: no drawer slide, celebration, flash or badge bump./basket/ page (brief §10) reusing the same component + cart state; the drawer stays the fast-path overlay. The header basket link already points at /basket/ as its fallback href, so wiring the route is all that's left.Prototype reference: open the homepage build, click the header basket icon. Demo images are watermarked white-bg stand-ins with the background cut out (vapehub-homepage-src/cutout-products.py); production should use clean transparent source art.