From 6dfba4fbe793c2c207ca141e0e6e08d240c0b00a Mon Sep 17 00:00:00 2001
From: navin10sharma <3096611+navin10sharma@users.noreply.github.com>
Date: Sat, 26 Sep 2026 17:26:11 +0530
Subject: [PATCH 1/4] Demo pages: the SeatLayer demos design for the five SDK
demos
Every demo page now has the same frame: a light SeatLayer demos header
(Hosted, SDK, Charts & 3D), breadcrumbs, a switcher showing all five SDK
demos, a Try-it strip, the demo at full width, the code to copy with its
source file and docs, and a link to the next demo.
- Routes: seat-picker, best-available, season-tickets (was /season),
multiple-events (was /events) and checkout-handoff, which now runs the own
cart flow with the server steps. / lists the five demos.
- Prices follow NEXT_PUBLIC_SEATLAYER_CURRENCY, which now defaults to EUR.
- The renewal-offer form and the duplicated side panel are gone from the
screen. Renewal intent is explained in components/SeasonFlow.tsx.
- Control room and Plain HTML are no longer in the menu; both routes remain.
- SEATLAYER_BASE_PATH (optional) serves the app under a sub-path. fetch()
calls go through withBase() so they follow it.
---
app/best-available/page.tsx | 38 +-
app/checkout-handoff/page.tsx | 98 ++---
app/control-room/page.tsx | 4 +-
app/events/page.tsx | 16 -
app/globals.css | 596 ++++++++++++++++++-------------
app/layout.tsx | 34 +-
app/multiple-events/page.tsx | 39 ++
app/page.tsx | 70 +++-
app/season-tickets/page.tsx | 38 ++
app/season/page.tsx | 16 -
app/seat-picker/page.tsx | 41 ++-
components/BestAvailableFlow.tsx | 137 ++++---
components/CodePanel.tsx | 68 ++++
components/DemoHeader.tsx | 40 +++
components/DemoShell.tsx | 166 +++++++++
components/EventSwitcher.tsx | 92 +++--
components/HandoffTable.tsx | 38 ++
components/HoldCountdown.tsx | 4 +-
components/Icon.tsx | 85 +++++
components/Nav.tsx | 27 --
components/SeasonFlow.tsx | 167 +++------
components/SeasonWidget.tsx | 11 +-
components/SeatPickerFlow.tsx | 99 +++--
components/SeatSelection.tsx | 246 ++++++-------
components/SelectionSummary.tsx | 4 +-
lib/config.ts | 11 +-
lib/demos.ts | 66 ++++
lib/highlight.ts | 29 ++
lib/money.ts | 2 +-
lib/site.ts | 22 ++
lib/snippets.ts | 149 ++++++++
next.config.mjs | 11 +
scripts/check-routes.mjs | 15 +-
33 files changed, 1627 insertions(+), 852 deletions(-)
delete mode 100644 app/events/page.tsx
create mode 100644 app/multiple-events/page.tsx
create mode 100644 app/season-tickets/page.tsx
delete mode 100644 app/season/page.tsx
create mode 100644 components/CodePanel.tsx
create mode 100644 components/DemoHeader.tsx
create mode 100644 components/DemoShell.tsx
create mode 100644 components/HandoffTable.tsx
create mode 100644 components/Icon.tsx
delete mode 100644 components/Nav.tsx
create mode 100644 lib/demos.ts
create mode 100644 lib/highlight.ts
create mode 100644 lib/site.ts
create mode 100644 lib/snippets.ts
diff --git a/app/best-available/page.tsx b/app/best-available/page.tsx
index 5c4525a..3de9a99 100644
--- a/app/best-available/page.tsx
+++ b/app/best-available/page.tsx
@@ -1,16 +1,36 @@
-import { RouteIntro } from "@/components/RouteIntro";
+import type { Metadata } from "next";
+import { DemoShell } from "@/components/DemoShell";
import { BestAvailableFlow } from "@/components/BestAvailableFlow";
+import { bestAvailable } from "@/lib/snippets";
+
+export const metadata: Metadata = { title: "Best available" };
export default function Page() {
return (
- <>
-
+ Pass a category key from your published chart as the second argument, for example{" "}
+
- The buyer SDK selects seats and creates a hold. A hold is a short,
- revocable claim on inventory: it is not a ticket and it is not a payment. The
- browser ends up with an opaque hold id and a display-only set of line items. It
- never has booking authority.
-
- Your server holds the secret key. It reads the hold back from SeatLayer to get the
- authoritative seats and prices, creates your own checkout session for that amount
- with your own payment gateway, and books the hold once the payment has succeeded.
- Your own order id is passed as the booking reference, which is what makes a repeat
- of the same request safe: an unknown outcome is reconciled by repeating it with the
- same reference, never by generating a new one.
-
- More:
- Idempotency and conflicts
- {" "}
- and the Node server SDK.
-
+ Set bestAvailable(2, "stalls").
+ What the browser does
- What your server does
- Where it is in this repository
-
-
-
- app/api/hold/route.ts inspects the hold and books it. The server SDK
- path runs only when SEATLAYER_SECRET_KEY is set.
- app/api/events/route.ts serves the events you configure, and reads
- their real names with the same key when it is present.
- components/SeatPickerFlow.tsx is the browser side that produces the
- hold id in the first place.
- Rules that do not bend
-
-
-
- SEATLAYER_SECRET_KEY in .env.local. It is read only inside the route
+ handler and never sent to the browser.
+
+ Set up to three event keys in .env.local. With a secret key on the server, the route
+ reads each event's real name.
+
+ The seat map inside your own React app. Buyers pick seats, SeatLayer holds them, and your own + checkout takes the payment. Pick a demo, try it, then copy the code. +
+
+ Use a published season key (sea_) and a pk_test_ key from your dashboard.
+
+ Use your event key and a pk_test_ key from your dashboard. Keep the sk_{" "}
+ secret key on your server.
+
Loading the seat map
, + loading: () =>Loading the seat map
, }); -const quantities = [1, 2, 3, 4, 5, 6, 7, 8]; - /** * Best available for a group. * * `bestAvailable(quantity, categoryKey?)` asks the server to find an adjacent * block and hold it in the same call. It resolves to null when no such block * exists, which is not the same answer as sold out, so the two are worded - * differently below. - * - * The category filter is a plain field: the buyer SDK exposes the category on - * each selected seat, not a list of the chart's categories, so the stable - * category key from the published chart is typed in. + * differently below. Pass a category key from your published chart as the + * second argument to search one price band only. */ export function BestAvailableFlow() { const chartRef = useRef