๐Ÿ‡ฎ๐Ÿ‡ณ
๐Ÿ‡ฎ๐Ÿ‡ณ
Republic Day Special Offer!Get 20% OFF on all courses
Enroll Now
P
Prakalpana
๐Ÿ“šLearn
โ€ขCode Your Future
Interview Prepโฑ๏ธ 24 min read๐Ÿ“… Dec 20

UI Interview: Design Amazon Shopping Cart (Complete Mock)

MI
Meera Iyerโ€ขPrincipal Engineer at Amazon
๐Ÿ“‘ Contents (10 sections)

๐Ÿ“ŒThe Interview Setting

Company: Amazon Round: Frontend System Design Duration: 45 minutes

๐Ÿ“Œ๐ŸŽค Interviewer: "Design a shopping cart for an e-commerce site."

Candidate's Clarifications:

  • 1Real-time inventory checks?
  • 2Guest checkout or login required?
  • 3Save for later, wishlist features?
  • 4Multi-seller cart (like Amazon)?
  • Interviewer: "Real-time inventory, both guest and logged-in, yes to save for later."

    ๐Ÿ“Œ๐Ÿ“ State Management

    // Cart state structure
    interface CartState {
    items: CartItem[];
    savedItems: CartItem[];
    appliedCoupons: Coupon[];
    shippingAddress: Address | null;
    selectedPayment: PaymentMethod | null;
    giftOptions: GiftOption[];
    }
    interface CartItem {
    id: string;
    productId: string;
    sellerId: string;
    name: string;
    image: string;
    price: number;
    originalPrice: number;
    quantity: number;
    maxQuantity: number; // Inventory limit
    isAvailable: boolean;
    deliveryEstimate: string;
    giftWrap: boolean;
    }
    // Cart context
    const CartContext = createContext<CartContextType>(null);
    const CartProvider = ({ children }) => {
    const [cart, dispatch] = useReducer(cartReducer, initialState);
    // Sync with server
    useEffect(() => {
    const syncCart = async () => {
    if (isLoggedIn) {
    await api.syncCart(cart);
    } else {
    localStorage.setItem('cart', JSON.stringify(cart));
    }
    };
    const debounced = debounce(syncCart, 1000);
    debounced();
    }, [cart]);
    return (
    <CartContext.Provider value={{ cart, dispatch }}>
    {children}
    </CartContext.Provider>
    );
    };

    ๐Ÿ“Œ๐ŸŽค Interviewer: "How do you handle quantity updates with inventory checks?"

    Candidate:

    const useQuantityUpdate = (itemId) => {
    const { dispatch } = useCart();
    const [isUpdating, setIsUpdating] = useState(false);
    const [error, setError] = useState(null);
    const updateQuantity = async (newQuantity) => {
    setIsUpdating(true);
    setError(null);
    // Optimistic update
    const previousQuantity = getItemQuantity(itemId);
    dispatch({ type: 'UPDATE_QUANTITY', itemId, quantity: newQuantity });
    try {
    // Verify inventory
    const { available, maxAllowed, currentPrice } = await api.checkInventory(
    itemId,
    newQuantity
    );
    if (!available) {
    // Rollback and show error
    dispatch({ type: 'UPDATE_QUANTITY', itemId, quantity: previousQuantity });
    setError('Item is no longer available');
    return;
    }
    if (newQuantity > maxAllowed) {
    // Adjust to max
    dispatch({ type: 'UPDATE_QUANTITY', itemId, quantity: maxAllowed });
    setError(`Only ${maxAllowed} available`);
    return;
    }
    // Update price if changed
    if (currentPrice !== getItemPrice(itemId)) {
    dispatch({ type: 'UPDATE_PRICE', itemId, price: currentPrice });
    toast.info('Price updated');
    }
    } catch (err) {
    // Rollback on network error
    dispatch({ type: 'UPDATE_QUANTITY', itemId, quantity: previousQuantity });
    setError('Failed to update. Please try again.');
    } finally {
    setIsUpdating(false);
    }
    };
    return { updateQuantity, isUpdating, error };
    };

    ๐Ÿ“Œ๐ŸŽค Interviewer: "What edge cases do you handle?"

    Candidate:

    1. Price Changes During Session

    // Poll for price updates
    useEffect(() => {
    const interval = setInterval(async () => {
    const productIds = cart.items.map(i => i.productId);
    const updates = await api.getPriceUpdates(productIds);
    for (const update of updates) {
    if (update.newPrice !== getItemPrice(update.productId)) {
    dispatch({
    type: 'PRICE_CHANGED',
    productId: update.productId,
    oldPrice: getItemPrice(update.productId),
    newPrice: update.newPrice
    });
    }
    }
    }, 60000); // Every minute
    return () => clearInterval(interval);
    }, [cart.items]);

    2. Item Goes Out of Stock

    // Real-time inventory via WebSocket
    useEffect(() => {
    const ws = new WebSocket('wss://inventory.amazon.com');
    ws.onmessage = (event) => {
    const { productId, inStock, availableQty } = JSON.parse(event.data);
    const item = cart.items.find(i => i.productId === productId);
    if (!item) return;
    if (!inStock) {
    dispatch({ type: 'MARK_UNAVAILABLE', productId });
    toast.error(`${item.name} is now out of stock`);
    } else if (item.quantity > availableQty) {
    dispatch({ type: 'REDUCE_QUANTITY', productId, maxQty: availableQty });
    toast.warning(`Only ${availableQty} available for ${item.name}`);
    }
    };
    return () => ws.close();
    }, []);

    3. Coupon Validation

    const applyCoupon = async (code) => {
    try {
    const result = await api.validateCoupon(code, cart);
    if (!result.valid) {
    setError(result.reason);
    return;
    }
    if (result.minimumOrder && cart.subtotal < result.minimumOrder) {
    setError(`Minimum order: โ‚น${result.minimumOrder}`);
    return;
    }
    if (result.excludedProducts.length > 0) {
    toast.warning('Coupon not applicable to some items');
    }
    dispatch({ type: 'APPLY_COUPON', coupon: result.coupon });
    } catch (err) {
    setError('Failed to apply coupon');
    }
    };

    4. Cart Merge on Login

    const handleLogin = async () => {
    const guestCart = getGuestCart();
    const userCart = await api.getUserCart();
    // Merge strategy
    const mergedItems = [];
    for (const guestItem of guestCart.items) {
    const existingItem = userCart.items.find(
    i => i.productId === guestItem.productId
    );
    if (existingItem) {
    // Combine quantities (up to max)
    mergedItems.push({
    ...existingItem,
    quantity: Math.min(
    existingItem.quantity + guestItem.quantity,
    existingItem.maxQuantity
    )
    });
    } else {
    mergedItems.push(guestItem);
    }
    }
    // Add user items not in guest cart
    for (const userItem of userCart.items) {
    if (!guestCart.items.find(i => i.productId === userItem.productId)) {
    mergedItems.push(userItem);
    }
    }
    dispatch({ type: 'SET_CART', items: mergedItems });
    clearGuestCart();
    };

    5. Concurrent Tab Updates

    // Sync across tabs
    useEffect(() => {
    const handleStorageChange = (e) => {
    if (e.key === 'cart' && e.newValue) {
    const newCart = JSON.parse(e.newValue);
    dispatch({ type: 'SYNC_FROM_STORAGE', cart: newCart });
    }
    };
    window.addEventListener('storage', handleStorageChange);
    return () => window.removeEventListener('storage', handleStorageChange);
    }, []);

    ๐Ÿ“Œ๐Ÿ“ Cart Summary Component

    const CartSummary = () => {
    const { cart } = useCart();
    const subtotal = cart.items.reduce(
    (sum, item) => sum + item.price * item.quantity, 0
    );
    const discount = cart.appliedCoupons.reduce(
    (sum, coupon) => sum + calculateDiscount(coupon, cart), 0
    );
    const shipping = subtotal >= 499 ? 0 : 40;
    const total = subtotal - discount + shipping;
    return (
    <div className="cart-summary">
    <div className="line">
    <span>Subtotal ({cart.items.length} items)</span>
    <span>โ‚น{subtotal.toLocaleString()}</span>
    </div>
    {discount > 0 && (
    <div className="line discount">
    <span>Discount</span>
    <span>-โ‚น{discount.toLocaleString()}</span>
    </div>
    )}
    <div className="line">
    <span>Shipping</span>
    <span>{shipping === 0 ? 'FREE' : `โ‚น${shipping}`}</span>
    </div>
    <div className="line total">
    <span>Total</span>
    <span>โ‚น{total.toLocaleString()}</span>
    </div>
    <button
    onClick={proceedToCheckout}
    disabled={cart.items.some(i => !i.isAvailable)}
    >
    Proceed to Checkout
    </button>
    </div>
    );
    };

    ๐Ÿ“Œ๐Ÿ“Š Interview Scoring

    CriteriaScore

    State Designโœ… Inventory Syncโœ… Edge Casesโœ… Optimistic UIโœ… Multi-tab Syncโœ…

    Result: Strong Hire ๐ŸŽ‰

    MI

    Written by

    Meera Iyer

    Principal Engineer at Amazon

    ๐Ÿš€ Master Interview Prep

    Join 500+ developers

    Explore Courses โ†’
    Chat on WhatsApp