# CartRewardProgress

> Cumulative Cart V2 reward milestones with automatic gift and discount reconciliation.

Canonical URL: https://c22dfdd27662:3005/islands/cart/cart-reward-progress

Use `CartRewardProgress` above cart lines to show progress toward configured
rewards such as free shipping, discounts, fixed-price products, and free
gifts. By default it keeps eligible reward products and discount codes in sync
with the cart.

The effective Cart V2 profile creates this module. Do not embed it in page
source.

## Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `rewards` | `CartReward[]` | No | Cart profile rewards | Overrides rewards from the active cart profile |
| `currency` | string | No | Cart profile currency | Currency used for milestone amounts |
| `reconcile` | boolean | No | `true` | Automatically reconcile eligible gifts and discount codes |
| `variant` | `"rail" \| "cards" \| "compact_bar"` | No | `"rail"` | Milestone presentation |
| `messageAlignment` | `"left" \| "center"` | No | `"center"` | Progress-message alignment |
| `showThresholdLabels` | boolean | No | `true` | Show threshold amounts |
| `showRewardLabels` | boolean | No | `true` | Show reward names |
| `connectorStyle` | `"line" \| "segmented"` | No | `"line"` | Visual connection between milestones |

Reward thresholds and fixed values are expressed in minor currency units.

Progress uses confirmed Shopify merchandise spend after line discounts and before
order discounts, shipping, and tax. `whole_cart` uses `cart.cost.subtotalAmount`,
excluding reward and gift-card lines. Scoped rewards sum only the discounted costs
of qualifying products, variants, or collections. Compare-at prices never qualify.
The message targets the nearest locked milestone on the same spend basis.

`reconcile=true` adds or removes eligible gift lines and updates reward codes
through the cart coordinator, then reads Shopify's confirmed cart. Reconciliation
does not grant a discount. Reaching a threshold unlocks a milestone; `applied`
requires Shopify's allocation (including a shipping allocation for free shipping,
and the confirmed target line price for a gift).

Readiness comes from the same validation used by preflight and publishing.
Unready rewards show **Not configured** in preview, are hidden in published carts,
and cannot be claimed or automatically added. Gift availability is refreshed from
Shopify when the cart is read. An `all` variant policy includes newly added sizes;
`selected` retains the merchant's selection. Unavailable variants are excluded.

## Profile module example

```json
{
  "rewards": [
    {
      "id": "free-shipping",
      "threshold": 5000,
      "type": "free_shipping",
      "title": "Free shipping"
    }
  ],
  "reconcile": true,
  "variant": "cards",
  "messageAlignment": "left",
  "showThresholdLabels": true,
  "showRewardLabels": true,
  "connectorStyle": "segmented"
}
```

## Stylable Parts

| Part | Description |
|------|-------------|
| `root` | Outermost reward progress container |
| `message` | Current progress or unlocked message |
| `bar` | Progress track and fill |
| `milestones` | Milestone collection |
| `milestone` | Individual reward milestone |

## Events

| Event | Direction | Payload |
|-------|-----------|---------|
| `lx:cart_reward_failed` | Outbound | `{ message: string }` when automatic reconciliation fails |

## Related Islands

- [DrawerShell](/islands/cart/drawer-shell)
- [CartLines](/islands/cart/cart-lines)
- [CartCoupons](/islands/cart/cart-coupons)
- [CartSummary](/islands/cart/cart-summary)
