# Switch event merch checkout after a deadline

Imagine you're selling a concert shirt. With JavaScript or React, the button opens the preorder checkout before the deadline and the regular merch checkout afterward. With HTML attributes, one offer can change its tier price at the deadline. Visitors see a countdown beside the button.

## Set it up

1. For JavaScript or React, publish two offers: `concert-shirt-preorder` and `concert-shirt-standard`. Give each its intended price. For HTML, publish one `concert-shirt` offer with prices for the promo tiers.
2. Create a promo called `concert-merch` with a timed tier labeled **Preorder**, followed by a **Standard** tier. These labels match the code below.
3. Put the countdown and button on the merch page. Replace the host in the script URL or `apiBase` with your organization's real host.

For JavaScript or React, the promo tells the page which tier is active. The code maps that tier to a published offer. When the tier changes, the *next* click opens the new offer. It does not replace a checkout that someone already has open.

| JavaScript or React | They see | The button opens |
| --- | --- | --- |
| Before the deadline | The preorder countdown | `concert-shirt-preorder` |
| After the deadline | The regular merch state | `concert-shirt-standard` |

<scalar-tabs default="HTML">
<scalar-tab title="HTML">

For an HTML-only page, publish **one** offer named `concert-shirt` and configure its price for the active tier of `concert-merch`. The browser bundle renders the countdown and applies that tier's price when the buyer opens checkout.

```html title="merch.html"
<script defer
  src="https://your-org.plandalf.dev/js/plandalf-sdk.js"></script>
<div data-plandalf-promo="concert-merch"></div>
<button
  data-plandalf-present="concert-shirt"
  data-plandalf-apply-promo="concert-merch"
>Buy the shirt</button>
```

This changes the tier price **within one offer**. HTML attributes alone do not switch the button from `concert-shirt-preorder` to `concert-shirt-standard`. A declarative promo monitor follows any redirect URL configured on its active tier; the JavaScript and React examples explicitly disable that redirect. Use those programmatic examples for the two-offer behavior in the table above, and enforce any preorder cutoff in checkout configuration.

</scalar-tab>
<scalar-tab title="JavaScript">

```javascript title="merch.js"
import { Plandalf } from '@plandalf/sdk'

const sdk = new Plandalf({
  apiBase: 'https://your-org.plandalf.dev',
})
const button = document.querySelector('#buy-shirt')
let selectedOffer = null

const monitor = sdk.promo('concert-merch', {
  target: '#countdown', redirect: false,
})

function selectTier(label) {
  if (label === 'Preorder') {
    selectedOffer = 'concert-shirt-preorder'
    button.textContent = 'Preorder the shirt'
  } else if (label === 'Standard') {
    selectedOffer = 'concert-shirt-standard'
    button.textContent = 'Buy the shirt'
  } else {
    selectedOffer = null
    button.textContent = 'Merch unavailable'
  }
  button.disabled = !selectedOffer
}

void monitor.then(
  (promo) => selectTier(promo?.activeTier?.label),
  () => selectTier(null),
)
void (async () => {
  for await (const event of monitor.events) {
    if (event.type === 'tier-change') selectTier(event.to)
  }
})()

button.addEventListener('click', async () => {
  if (!selectedOffer) return
  const result = await sdk.present(selectedOffer)
  if (result.status === 'complete') {
    // Ask your server to confirm the order before promising shipment.
  }
})

// Call monitor.close() if this page is removed without navigation.
```

```html title="merch.html"
<div id="countdown"></div>
<button id="buy-shirt" disabled>Checking offer…</button>
```

</scalar-tab>
<scalar-tab title="React">

```tsx title="MerchPage.tsx"
import { useEffect, useRef, useState } from 'react'
import {
  PlandalfProvider, usePlandalf, usePresent,
} from '@plandalf/react'

function MerchButton() {
  const sdk = usePlandalf()
  const { present, presenting } = usePresent()
  const countdown = useRef<HTMLDivElement>(null)
  const [tier, setTier] = useState<string | null>()
  const offer = tier === 'Preorder' ? 'concert-shirt-preorder'
    : tier === 'Standard' ? 'concert-shirt-standard' : null

  useEffect(() => {
    if (!countdown.current) return
    let active = true
    const monitor = sdk.promo('concert-merch', {
      target: countdown.current, redirect: false,
    })
    void monitor.then(
      (promo) => {
        if (active) setTier(promo?.activeTier?.label ?? null)
      },
      () => { if (active) setTier(null) },
    )
    void (async () => {
      for await (const event of monitor.events) {
        if (active && event.type === 'tier-change') setTier(event.to)
      }
    })()
    return () => { active = false; monitor.close() }
  }, [sdk])

  async function buy() {
    if (!offer) return
    const result = await present(offer)
    if (result.status === 'complete') {
      // Confirm the order on your server before promising shipment.
    }
  }

  const label = tier === undefined ? 'Checking offer…'
    : tier === 'Preorder' ? 'Preorder the shirt'
    : offer ? 'Buy the shirt' : 'Merch unavailable'

  return <>
    <div ref={countdown} />
    <button disabled={!offer || presenting} onClick={buy}>
      {label}
    </button>
  </>
}

export function MerchPage() {
  return (
    <PlandalfProvider apiBase="https://your-org.plandalf.dev">
      <MerchButton />
    </PlandalfProvider>
  )
}
```

</scalar-tab>
</scalar-tabs>

If you only need the **price** to change, use one offer with promo tier pricing and pass `promo: 'concert-merch'` to `present()`. That keeps checkout pricing tied to the active promo tier. The two-offer example above switches the button between genuinely different checkouts; it does not make the old preorder link inaccessible. If the old checkout must stop taking orders at the deadline, enforce that where the checkout is created. A browser countdown by itself cannot enforce a price or cutoff.

Inspect [`promo()`](https://plandalf.com/docs/packages/sdk/classes/Plandalf#promo), [`PromoHandle`](https://plandalf.com/docs/packages/sdk/referenced-types/PromoHandle), and [`present()`](https://plandalf.com/docs/sdk/present) for the exact inputs and event types. See [promo tier setup](https://plandalf.com/docs/product-guides/promos/tiers) for the campaign configuration.

Source: https://plandalf.com/docs/guides/event-merch-deadline
