javascript
46 lines · 8 steps
How a cart total is calculated with discounts
A single function turns line items and an optional promo code into a rounded, itemized total.
Explained by
highlit
1const DISCOUNT_CODES = {
2 SAVE10: { type: 'percent', value: 0.1 },
3 WELCOME5: { type: 'fixed', value: 5 },
4 FREESHIP: { type: 'shipping', value: Infinity },
5};
6
7function calculateCart(items, { taxRate = 0.08, shipping = 0, code = null } = {}) {
8 const subtotal = items.reduce(
9 (sum, item) => sum + item.price * item.quantity,
10 0
11 );
12
13 let discount = 0;
14 let shippingCost = shipping;
15 const promo = code ? DISCOUNT_CODES[code.trim().toUpperCase()] : null;
16
17 if (code && !promo) {
18 throw new Error(`Invalid discount code: ${code}`);
19 }
20
21 if (promo) {
22 if (promo.type === 'percent') {
23 discount = subtotal * promo.value;
24 } else if (promo.type === 'fixed') {
25 discount = Math.min(promo.value, subtotal);
26 } else if (promo.type === 'shipping') {
27 shippingCost = Math.max(0, shipping - promo.value);
28 }
29 }
30
31 const discountedSubtotal = subtotal - discount;
32 const tax = discountedSubtotal * taxRate;
33 const total = discountedSubtotal + tax + shippingCost;
34
35 const round = (n) => Math.round(n * 100) / 100;
36
37 return {
38 subtotal: round(subtotal),
39 discount: round(discount),
40 tax: round(tax),
41 shipping: round(shippingCost),
42 total: round(total),
43 };
44}
45
46export { calculateCart, DISCOUNT_CODES };
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A lookup table keyed by code lets you add promo types without touching the calculation logic.
- 2Validating unknown codes early with a thrown error keeps invalid state out of the math.
- 3Rounding only at the output boundary avoids compounding floating-point drift across intermediate sums.
Related explainers
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
javascript
import { useState, useEffect, useCallback, useRef } from 'react'; const cache = new Map(); const inflight = new Map();
Building a stale-while-revalidate hook in React
caching
request-deduplication
custom-hooks
Advanced
10 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
javascript
import { useEffect, useRef, useState } from 'react'; export function useDelayedFlag(active, delay = 300) { const [visible, setVisible] = useState(false);
Delaying a loading spinner with a React hook
custom-hooks
debouncing
cleanup
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-a-cart-total-is-calculated-with-discounts-explained-javascript-22bc/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.