Skip to main content

Shopping Cart + Coupons

Difficulty: Advanced

Problem Statement​

Add products to cart, apply percentage/fixed coupons, compute net price.

Live Demo​

Try the running app below β€” this is the target behavior for the challenge.

Shopping Cart + Coupons β€” Live Demo

    Total: $0 β†’ Net: $0

    What Interviewers Expect​

    • Derived totals (do not store net as source of truth).
    • Extensible coupon logic.
    • Clear add product + apply coupon UX.

    Step-by-Step Implementation​

    Step 1 β€” Cart items state​

    Store product name + price objects.

    setItems((prev) => [...prev, { name: 'Laptop', price: 1000 }]);

    Step 2 β€” Derived total​

    Compute total from items array.

    const total = items.reduce((s, i) => s + i.price, 0);

    Step 3 β€” Coupon application​

    Apply selected coupon function to total.

    const net = coupon === '10' ? pctCoupon(total, 10) : total;

    Complete Implementation​

    Copy-paste ready single-file solution. Use this as your reference after attempting the challenge yourself, or paste it into CodeSandbox / StackBlitz to run locally.

    App.jsx
    import React, {useState} from 'react';

    function pctCoupon(total, percent) {
    return total - (percent / 100) * total;
    }

    function fixedCoupon(total, amount) {
    return Math.max(0, total - amount);
    }

    export default function App() {
    const [items, setItems] = useState([]);
    const [coupon, setCoupon] = useState('none');

    const total = items.reduce((sum, item) => sum + item.price, 0);
    const net =
    coupon === '10' ? pctCoupon(total, 10) : coupon === '50' ? fixedCoupon(total, 50) : total;

    return (
    <div>
    <div style={{display: 'flex', gap: '0.75rem', flexWrap: 'wrap', marginBottom: '0.75rem'}}>
    <button
    type="button"
    onClick={() => setItems((prev) => [...prev, {name: 'Headphones', price: 100}])}
    >
    Add Headphones ($100)
    </button>
    <button
    type="button"
    onClick={() => setItems((prev) => [...prev, {name: 'Laptop', price: 1000}])}
    >
    Add Laptop ($1000)
    </button>
    </div>

    <div style={{display: 'flex', gap: '0.5rem', alignItems: 'center', marginBottom: '0.75rem'}}>
    <label htmlFor="coupon">Coupon</label>
    <select id="coupon" value={coupon} onChange={(e) => setCoupon(e.target.value)}>
    <option value="none">None</option>
    <option value="10">10% off</option>
    <option value="50">$50 off</option>
    </select>
    </div>

    <ul>
    {items.map((item, index) => (
    <li key={`${item.name}-${index}`}>
    {item.name} β€” ${item.price}
    </li>
    ))}
    </ul>

    <p>
    <strong>Total:</strong> ${total} β†’ <strong>Net:</strong> ${net}
    </p>
    </div>
    );
    }

    Final Checklist​

    • UI works for primary flow
    • Edge cases handled (empty/disabled/loading where relevant)
    • State updates are immutable
    • Components are readable and reasonably split
    • You can explain trade-offs out loud in an interview

    Next Challenge​

    Continue to the next item in the sidebar when you're comfortable implementing this from scratch in 30–45 minutes.