Skip to main content

Reward Progress Bar Based on Live Cart State

A progress bar that reads the shopper's cart total and shows how much more they need to add to unlock the next reward tier - updating live as the cart changes.

Example

import React from 'react';
import { Flexbox, Box, Text } from '@evlop/native-components';
import { Money, useCart, CustomBlock } from '@evlop/shopify';

const MILESTONES = [
{ label: '5% off', amount: 30 },
{ label: '10% off', amount: 100 },
{ label: '15% off', amount: 200 },
];

const CartProgressBar: CustomBlock.Section = () => {
const cart = useCart();
const total = +(cart?.totalPrice?.amount ?? 0);
const currency = cart?.totalPrice?.currencyCode ?? 'USD';

const max = MILESTONES[MILESTONES.length - 1].amount;
const progress = Math.min(total / max, 1);
const nextMilestone = MILESTONES.find((m) => total < m.amount);

return (
<Flexbox flexDirection="column" gap={8} p="md">
<Text fontWeight="Bold">
{nextMilestone ? (
<>
Add <Money amount={String(nextMilestone.amount - total)} currencyCode={currency} /> more to get {nextMilestone.label}
</>
) : (
'You unlocked the top reward!'
)}
</Text>

<Box height={8} borderRadius={4} backgroundColor="gray-100">
<Box height={8} borderRadius={4} backgroundColor="primary-500" width={`${progress * 100}%`} />
</Box>
</Flexbox>
);
};

export default CartProgressBar;

How it works

  • useCart() (from @evlop/shopify) returns the live ShopifyCart for the current session and re-renders the block automatically whenever the cart changes - adding, removing, or updating quantity all flow straight through, with no manual data fetching or subscriptions. It works in any block type, not just Section.
  • cart.totalPrice is a { amount: string, currencyCode: string } pair - total/currency are derived from it, and fed into <Money amount={...} currencyCode={...} /> (Money's alternate form, for when you have a raw amount/currency pair rather than a MoneyV2 object to pass as price).
  • The bar is just two nested Boxes - an outer one for the track, an inner one whose width is a progress * 100 percentage string. No animation or measuring is needed since a percentage width already resizes itself as progress changes.

This block needs no configurationSchema - MILESTONES is a plain constant in the file. To let a merchant configure the thresholds/labels/discount copy instead, pull them from data via an array settings panel field instead of hardcoding them.