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.