# Astro example

One small Astro app, three pages, all against `https://app.nisebookings.com`:

- `/` — the **widget** on a prerendered page (`src/pages/index.astro`): one script tag plus
  `<nise-booking>`, themed with two CSS variables.
- `/book` — your **own UI**, server-rendered (`src/pages/book.astro`): the frontmatter fetches the
  catalogue and the times from the public API, the form posts back to the same page, and every slot is
  a submit button — the whole flow works without client JavaScript, including `409 slot_unavailable`.
- `/api/webhook` — a **webhook** endpoint as an Astro server route (`src/pages/api/webhook.ts`): it
  verifies the Standard Webhooks signature against the raw body and answers 204.

## Run it

```bash
cp .env.example .env          # paste a key: your own, or POST /api/sandbox for a 24-hour one
npm install
npm run dev                   # http://localhost:4321
```

Node 20 or newer. The app is static by default (`astro build` prerenders `/`); the pages that need a
server set `export const prerender = false`, which is why `astro.config.mjs` carries the Node adapter.

Production build:

```bash
NISE_KEY=<public key> npm run build      # the static page bakes the key in at build time
node --env-file=.env dist/server/entry.mjs
```

Two things that bite in Astro, and how this example handles them:

- **Scoped styles.** A `<style>` block is scoped to the component that writes it, so styles in the
  layout do not reach the pages slotted into it. This example marks the layout's block `is:global`.
- **Env vars.** `astro dev` loads `.env` into `import.meta.env`; the built Node server only sees the
  process environment. `src/lib/nise.ts` reads both (`env('NISE_KEY')`).

The widget needs the origin in the account's **Toegestane websites** (Instellingen → Insluiten) — the
sandbox accepts any origin, a real account does not.

Verified with Astro 7 / `@astrojs/node` 11 against a fresh sandbox: `/` renders the widget with the
catalogue, `/book` listed the services and 40 real slots, a click booked a real appointment
(`status approved`), a second click on the same time showed the "just taken" message, and the webhook
route answered 204 for a correctly signed payload and 401 for a wrong one.

The step-by-step explanation is [`../../12-astro.md`](../../12-astro.md).
