tf-checkout-react 2.0.0-beta.24 → 2.0.0-beta.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +543 -101
- package/docs/API.md +73 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,25 +7,40 @@ components, plus the shared API and React Query hooks. Which paths a buyer can
|
|
|
7
7
|
actually use depend on the event, the deployed API, the buyer's session and the
|
|
8
8
|
payment provider.
|
|
9
9
|
|
|
10
|
-
This reference describes **2.0.0-beta.
|
|
10
|
+
This reference describes **2.0.0-beta.26**. It is a prerelease with a different
|
|
11
11
|
API from 1.x. Pin the version while evaluating it. npm's `latest` and `beta`
|
|
12
12
|
tags can move independently and an unqualified install may select 1.x:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
15
|
npm view tf-checkout-react dist-tags
|
|
16
|
-
npm install tf-checkout-react@2.0.0-beta.
|
|
16
|
+
npm install tf-checkout-react@2.0.0-beta.26 @tanstack/react-query react react-dom
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
The [API reference](https://unpkg.com/tf-checkout-react@2.0.0-beta.
|
|
19
|
+
The [API reference](https://unpkg.com/tf-checkout-react@2.0.0-beta.26/docs/API.md)
|
|
20
20
|
is included as `docs/API.md` in this package.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
[
|
|
22
|
+
## Choose a checkout layout
|
|
23
|
+
|
|
24
|
+
| Your goal | Start here | What the SDK renders |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| Add a complete checkout to an event page | [`EmbeddedCheckout`](#embeddedcheckout) | A ready-made ticket or seat selection view followed by add-ons, buyer details, waiver and payment when applicable. |
|
|
27
|
+
| Continue a cart created by an earlier flow | [`ResumedCheckout`](#resume-a-server-cart) | Ready-made buyer details, waiver and payment for the current session's existing cart. |
|
|
28
|
+
| Keep the checkout on one page and arrange the sections yourself | [Single-page composition](#single-page-checkout) | Ticket selection, seats, add-ons, billing and payment sections in the host's layout. |
|
|
29
|
+
| Show progressive steps or connect routes | [Step-by-step composition](#step-by-step-checkout) | The same sections; your application controls what is visible and how the buyer moves between steps. |
|
|
30
|
+
| Organize the form as an accordion | [Accordion composition](#accordion-checkout) | Native HTML disclosure sections around the SDK's checkout components. |
|
|
31
|
+
| Build your own checkout UI | [Headless APIs](#headless-apis) | The shared engine, hooks and API; your application owns the UI and navigation. |
|
|
32
|
+
|
|
33
|
+
`EmbeddedCheckout` and `ResumedCheckout` are the ready-made flows in this
|
|
34
|
+
version. The 1.x `*Container` components and named single-page/accordion
|
|
35
|
+
examples are not drop-in 2.x exports. The [migration guide](#migrating-from-1x)
|
|
36
|
+
shows how to reproduce those layouts with the current components.
|
|
37
|
+
|
|
38
|
+
[Requirements](#requirements) · [Quick start](#quick-start) ·
|
|
39
|
+
[Configure sessions](#configuration-and-sessions) · [Ready-made checkout](#embeddedcheckout) ·
|
|
40
|
+
[Custom layouts](#compose-sections) · [Payments](#payments) ·
|
|
41
|
+
[Authentication](#authentication) · [Component reference](#component-reference) ·
|
|
27
42
|
[Styling](#styling-and-localization) · [Migration](#migrating-from-1x) ·
|
|
28
|
-
[
|
|
43
|
+
[Troubleshooting](#testing-and-troubleshooting)
|
|
29
44
|
|
|
30
45
|
## Requirements
|
|
31
46
|
|
|
@@ -50,17 +65,25 @@ Its `dist/styles` files and referenced assets are part of the npm package.
|
|
|
50
65
|
|
|
51
66
|
## Quick start
|
|
52
67
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
This example puts the ready-made checkout on one event page. You need a test
|
|
69
|
+
event ID and the matching **public** SDK client ID. Ask your Ticket Fairy
|
|
70
|
+
integration contact for these values and the appropriate environment.
|
|
71
|
+
|
|
72
|
+
1. Install the package and its peers using the command above.
|
|
73
|
+
2. Replace `EVENT_ID` and `PUBLIC_SDK_CLIENT_ID` below. Configure the SDK once
|
|
74
|
+
in your browser entry, before rendering the checkout.
|
|
75
|
+
3. Mount `App` in your React application. The package entry imports its CSS;
|
|
76
|
+
the bundler must process CSS imports and their assets.
|
|
56
77
|
|
|
57
78
|
```tsx
|
|
58
79
|
import { useState } from 'react'
|
|
59
80
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
60
|
-
import {
|
|
81
|
+
import {
|
|
82
|
+
configureCheckout, EmbeddedCheckout, type PlaceOrderResult,
|
|
83
|
+
} from 'tf-checkout-react'
|
|
61
84
|
|
|
62
85
|
configureCheckout({
|
|
63
|
-
env: '
|
|
86
|
+
env: 'STAG',
|
|
64
87
|
clientId: 'PUBLIC_SDK_CLIENT_ID',
|
|
65
88
|
clientSecret: '',
|
|
66
89
|
cookieAuth: true,
|
|
@@ -69,30 +92,41 @@ configureCheckout({
|
|
|
69
92
|
const queryClient = new QueryClient()
|
|
70
93
|
|
|
71
94
|
export function App() {
|
|
72
|
-
const [
|
|
95
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
96
|
+
|
|
73
97
|
return (
|
|
74
98
|
<QueryClientProvider client={queryClient}>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
{order ? (
|
|
100
|
+
<section role="status">
|
|
101
|
+
<h1>Checking your order</h1>
|
|
102
|
+
<p>Check your order status before making another purchase.</p>
|
|
103
|
+
{order.pending && <p>Your payment is pending.</p>}
|
|
104
|
+
{order.needIdVerification && <p>Identity verification may be required.</p>}
|
|
105
|
+
</section>
|
|
106
|
+
) : (
|
|
107
|
+
<EmbeddedCheckout
|
|
108
|
+
eventId="EVENT_ID"
|
|
109
|
+
confirmationMode="redirect"
|
|
110
|
+
onComplete={setOrder}
|
|
111
|
+
/>
|
|
112
|
+
)}
|
|
82
113
|
</QueryClientProvider>
|
|
83
114
|
)
|
|
84
115
|
}
|
|
85
116
|
```
|
|
86
117
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
118
|
+
The buyer first chooses tickets or seats. After reservation, the checkout shows
|
|
119
|
+
applicable add-ons, buyer details, waiver and payment. `onComplete` hands the
|
|
120
|
+
result to the host; the example displays a neutral status instead of claiming
|
|
121
|
+
that tickets are ready. Connect that screen to **your backend's authoritative
|
|
122
|
+
order status** using `order.orderHash`, handle any required ID verification and
|
|
123
|
+
pending voucher, and provide support if the status cannot be established. The
|
|
124
|
+
callback alone is not proof of settlement or ticket issuance.
|
|
91
125
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
[
|
|
126
|
+
Use `env: 'PROD'` with the matching production public client ID when your
|
|
127
|
+
integration is ready. This beta's stock payment UI can ask a buyer to retry an
|
|
128
|
+
unconfirmed payment; that wording does not establish that retrying is safe. See
|
|
129
|
+
[Payments](#payments) before using the stock flow in production.
|
|
96
130
|
|
|
97
131
|
## Configuration and sessions
|
|
98
132
|
|
|
@@ -147,7 +181,31 @@ third-party dependencies should be tested in that framework.
|
|
|
147
181
|
seat selection, add-ons, billing, waivers, payment and inline completion as the
|
|
148
182
|
flow requires. It must be under `QueryClientProvider`.
|
|
149
183
|
|
|
150
|
-
Only `eventId` is required. Callbacks and options are optional.
|
|
184
|
+
Only `eventId` is required. Callbacks and options are optional. The component
|
|
185
|
+
owns its checkout provider; do not wrap it in another `CheckoutProvider` to
|
|
186
|
+
control its internal steps. The host still supplies `QueryClientProvider`.
|
|
187
|
+
|
|
188
|
+
### What the buyer sees
|
|
189
|
+
|
|
190
|
+
1. **Tickets:** the event's catalog, quantities, applicable codes and any
|
|
191
|
+
organizer-configured waiting list. Seated events can open a seat map.
|
|
192
|
+
2. **Checkout:** a selection summary and the applicable add-ons, buyer/holder
|
|
193
|
+
details, waiver and payment. The reservation timer is displayed when available.
|
|
194
|
+
3. **Completion:** `inline` shows the SDK's confirmation view; `redirect` calls
|
|
195
|
+
`onComplete` and leaves the host to show the next screen. The quick start uses
|
|
196
|
+
`redirect` so the host can check order status before presenting a receipt.
|
|
197
|
+
|
|
198
|
+
`initialView="seats"` opens the seat-selection view first for an applicable
|
|
199
|
+
seated event. `onViewChange` reports `tickets`, `seats` or `checkout`; it does
|
|
200
|
+
not turn the component into a controlled router. For custom paths or step
|
|
201
|
+
arrangements, use [section composition](#compose-sections).
|
|
202
|
+
|
|
203
|
+
When choosing `confirmationMode="redirect"`, provide `onComplete` to receive
|
|
204
|
+
the result and navigate to your status page. Although the prop is optional in
|
|
205
|
+
the type, without that handoff the checkout remains mounted and no host status
|
|
206
|
+
page is reached.
|
|
207
|
+
|
|
208
|
+
### Options and callbacks
|
|
151
209
|
|
|
152
210
|
| Prop | Type / default | Description |
|
|
153
211
|
| --- | --- | --- |
|
|
@@ -179,98 +237,408 @@ session authorities; use the one appropriate to your configured journey.
|
|
|
179
237
|
for the public checkout registration or account-completion journey; those
|
|
180
238
|
paths force it on in this version.
|
|
181
239
|
|
|
240
|
+
### Example: brand the ready-made checkout
|
|
241
|
+
|
|
242
|
+
Use the same `QueryClientProvider` and one-time configuration as the quick
|
|
243
|
+
start. Here `onViewChange` can update surrounding page content; `onComplete`
|
|
244
|
+
passes the order result to the host's status screen.
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
import { useState } from 'react'
|
|
248
|
+
import { EmbeddedCheckout, type PlaceOrderResult } from 'tf-checkout-react'
|
|
249
|
+
|
|
250
|
+
export function BrandedCheckout() {
|
|
251
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
252
|
+
const [view, setView] = useState('tickets')
|
|
253
|
+
|
|
254
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
<main>
|
|
258
|
+
<p>Checkout step: {view}</p>
|
|
259
|
+
<EmbeddedCheckout
|
|
260
|
+
eventId="EVENT_ID"
|
|
261
|
+
confirmationMode="redirect"
|
|
262
|
+
onComplete={setOrder}
|
|
263
|
+
onViewChange={setView}
|
|
264
|
+
initialPromoCode="WELCOME"
|
|
265
|
+
referrer="REFERRER_ID"
|
|
266
|
+
readAttributionFromUrl={false}
|
|
267
|
+
locale="en-US"
|
|
268
|
+
messages={{ 'tickets.getTickets': 'Continue to checkout' }}
|
|
269
|
+
theme={{ colorScheme: 'light', accent: '#6b2bd9', radiusCard: '16px' }}
|
|
270
|
+
className="festival-checkout"
|
|
271
|
+
/>
|
|
272
|
+
</main>
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Use a promo or referral only when it belongs to this visit. Remove those props
|
|
278
|
+
when they do not apply. By default the component also reads `promo` /
|
|
279
|
+
`promo_code` and `ttf_r` / `referrer_id` from the URL. The example disables
|
|
280
|
+
that behavior so the host controls attribution. `initialPromoCode` is applied
|
|
281
|
+
once when the catalog mounts. It is not a guarantee that a code is valid.
|
|
282
|
+
`theme` changes SDK design tokens, `className` lets your stylesheet target this
|
|
283
|
+
instance, and `messages` overrides individual SDK copy keys. `locale` and
|
|
284
|
+
`messages` do not automatically translate the event's own content or an
|
|
285
|
+
external payment-provider page. See [Styling and localization](#styling-and-localization)
|
|
286
|
+
for the available theme tokens and locales.
|
|
287
|
+
|
|
288
|
+
### Example: connect host navigation and sign-in
|
|
289
|
+
|
|
290
|
+
Pass callbacks when the surrounding application owns these actions. For
|
|
291
|
+
example, `openSignIn` can open your sign-in UI, and `onOrder` can hand the
|
|
292
|
+
result to your order-status screen. `onViewChange` is a notification, not a
|
|
293
|
+
way to force the checkout to a particular step.
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
import { EmbeddedCheckout, type PlaceOrderResult } from 'tf-checkout-react'
|
|
297
|
+
|
|
298
|
+
type View = 'tickets' | 'seats' | 'checkout'
|
|
299
|
+
|
|
300
|
+
export function HostCheckout(props: {
|
|
301
|
+
eventId: string
|
|
302
|
+
openSignIn: (email?: string) => void
|
|
303
|
+
showOrderStatus: (order: PlaceOrderResult) => void
|
|
304
|
+
reportView: (view: View) => void
|
|
305
|
+
}) {
|
|
306
|
+
return (
|
|
307
|
+
<EmbeddedCheckout
|
|
308
|
+
eventId={props.eventId}
|
|
309
|
+
onLogin={props.openSignIn}
|
|
310
|
+
onViewChange={props.reportView}
|
|
311
|
+
confirmationMode="redirect"
|
|
312
|
+
onComplete={props.showOrderStatus}
|
|
313
|
+
/>
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
The email passed to `openSignIn` can be absent. Supplying `onLogin` replaces
|
|
319
|
+
the built-in login modal; your host must complete the appropriate sign-in
|
|
320
|
+
journey. An event-scoped checkout identity is not automatically a full
|
|
321
|
+
account session. `showOrderStatus` must check the order and provider rather
|
|
322
|
+
than treating the callback as a paid receipt.
|
|
323
|
+
|
|
182
324
|
### Resume a server cart
|
|
183
325
|
|
|
184
|
-
`ResumedCheckout`
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
326
|
+
`ResumedCheckout` is a ready-made layout for a cart that **already exists in
|
|
327
|
+
the current session**, such as one created by a preceding resale flow. It
|
|
328
|
+
starts with buyer details and payment; it does not show ticket selection, create
|
|
329
|
+
the cart, or accept a cart ID. Its `confirmationMode` defaults to `redirect`.
|
|
330
|
+
Provide `onComplete` for the redirect/status handoff: without it the successful
|
|
331
|
+
flow remains on its loading transition. Alternatively select `inline` and
|
|
332
|
+
account for the confirmation and verification-copy limitations below.
|
|
189
333
|
|
|
190
334
|
```tsx
|
|
191
335
|
import { useState } from 'react'
|
|
192
|
-
import { ResumedCheckout } from 'tf-checkout-react'
|
|
336
|
+
import { ResumedCheckout, type PlaceOrderResult } from 'tf-checkout-react'
|
|
193
337
|
|
|
338
|
+
// Mount only after your preceding flow created a cart in this session.
|
|
194
339
|
export function ResumePage() {
|
|
195
|
-
const [
|
|
340
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
341
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
342
|
+
|
|
196
343
|
return (
|
|
197
|
-
<>
|
|
198
344
|
<ResumedCheckout
|
|
199
345
|
eventId="EVENT_ID"
|
|
200
346
|
isFromResale
|
|
201
|
-
confirmationMode="
|
|
202
|
-
onComplete={
|
|
347
|
+
confirmationMode="redirect"
|
|
348
|
+
onComplete={setOrder}
|
|
203
349
|
/>
|
|
204
|
-
<p role="status">{notice}</p>
|
|
205
|
-
</>
|
|
206
350
|
)
|
|
207
351
|
}
|
|
208
352
|
```
|
|
209
353
|
|
|
354
|
+
Wrap this page in the same `QueryClientProvider` as the quick start. Set
|
|
355
|
+
`isFromResale` only for the resale path. Check the result with your backend,
|
|
356
|
+
including any verification or pending-payment requirements. If the preceding
|
|
357
|
+
flow did not create a cart, or the session changed, return the buyer to that
|
|
358
|
+
flow instead of assuming a cart can be resumed.
|
|
359
|
+
|
|
210
360
|
Props are `eventId` (required), `isFromResale` (default `false`),
|
|
211
|
-
`onComplete`, `confirmationMode`
|
|
212
|
-
`
|
|
213
|
-
|
|
214
|
-
`
|
|
215
|
-
|
|
216
|
-
`EmbeddedCheckout`, this component does not accept `locale`, `messages`,
|
|
217
|
-
`auth` or `onLogin` props in this version.
|
|
361
|
+
`onComplete`, `confirmationMode`, `requireEmailConfirmation`,
|
|
362
|
+
`collectTicketHolders`, `collectHolderContact` (each default `true`),
|
|
363
|
+
`privacyPolicy`, `brandOptInLabel`, `additionalConditions`, `theme` and
|
|
364
|
+
`className`. Unlike `EmbeddedCheckout`, this component does not accept
|
|
365
|
+
`locale`, `messages`, `auth` or `onLogin` props in this version.
|
|
218
366
|
|
|
219
367
|
## Compose sections
|
|
220
368
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
independent carts.
|
|
226
|
-
|
|
369
|
+
Use sections when the ready-made flow does not fit your page. Put all sections
|
|
370
|
+
for one checkout inside a single `CheckoutProvider`, under the host's
|
|
371
|
+
`QueryClientProvider`. The provider shares one checkout instance with its
|
|
372
|
+
children. The default store is app-wide: mounting two flows does not create two
|
|
373
|
+
independent carts. Configure the SDK once, before mounting the provider.
|
|
374
|
+
|
|
375
|
+
The examples below assume the quick start's `configureCheckout` and
|
|
376
|
+
`QueryClientProvider` setup. They demonstrate page layout and section wiring;
|
|
377
|
+
your host still needs to implement order-status reconciliation, expiry and
|
|
378
|
+
recovery for its event and enabled payment methods.
|
|
379
|
+
|
|
380
|
+
These are wiring recipes, not complete buyer navigation. Each includes a return
|
|
381
|
+
from the seat view and keeps `Tickets` mounted while switching views. The host
|
|
382
|
+
still needs to implement Edit and Back from checkout (including payment to
|
|
383
|
+
billing), preserve entered details, handle seat holds and cart expiry, and
|
|
384
|
+
guard event/session changes and in-flight or retained payments. Use
|
|
385
|
+
`EmbeddedCheckout` for its built-in Back and guarded Edit behavior.
|
|
386
|
+
The seat-view Back button only changes views: it does not itself release reserved
|
|
387
|
+
seats or cancel an already-started reservation or cart priming. Coordinate any
|
|
388
|
+
in-flight work and the hold's expiry or release under your deployed backend
|
|
389
|
+
contract before permitting a conflicting selection.
|
|
390
|
+
|
|
391
|
+
### Single-page checkout
|
|
392
|
+
|
|
393
|
+
This layout keeps the buyer on one browser page. Selecting tickets or seats
|
|
394
|
+
reveals a single combined form with add-ons, buyer details, waiver and payment.
|
|
395
|
+
The host supplies the status view after `onComplete`.
|
|
227
396
|
|
|
228
397
|
```tsx
|
|
229
398
|
import { useState } from 'react'
|
|
230
399
|
import {
|
|
231
|
-
AddOns, BillingInfo, CheckoutProvider,
|
|
232
|
-
Tickets, WaiverSigning,
|
|
400
|
+
AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
|
|
401
|
+
Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
|
|
233
402
|
} from 'tf-checkout-react'
|
|
234
403
|
|
|
235
|
-
|
|
236
|
-
const
|
|
237
|
-
const [
|
|
404
|
+
function SinglePageContents({ eventId }: { eventId: string }) {
|
|
405
|
+
const checkout = useCheckoutContext()
|
|
406
|
+
const [view, setView] = useState<'tickets' | 'seats' | 'checkout'>('tickets')
|
|
407
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
408
|
+
|
|
409
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
410
|
+
|
|
411
|
+
return (
|
|
412
|
+
<main>
|
|
413
|
+
<div hidden={view !== 'tickets'}>
|
|
414
|
+
<Tickets
|
|
415
|
+
eventId={eventId}
|
|
416
|
+
onContinue={() => setView('checkout')}
|
|
417
|
+
onSelectSeats={() => setView('seats')}
|
|
418
|
+
/>
|
|
419
|
+
</div>
|
|
420
|
+
{view === 'seats' && (
|
|
421
|
+
<>
|
|
422
|
+
<button type="button" onClick={() => setView('tickets')}>Back to tickets</button>
|
|
423
|
+
<SeatMap eventId={eventId} onContinue={() => setView('checkout')} />
|
|
424
|
+
</>
|
|
425
|
+
)}
|
|
426
|
+
{view === 'checkout' && (
|
|
427
|
+
<>
|
|
428
|
+
<TimerBanner seconds={checkout.secondsLeft} />
|
|
429
|
+
<AddOns eventId={eventId} />
|
|
430
|
+
<BillingInfo
|
|
431
|
+
eventId={eventId}
|
|
432
|
+
requireEmailConfirmation
|
|
433
|
+
collectTicketHolders
|
|
434
|
+
collectHolderContact
|
|
435
|
+
/>
|
|
436
|
+
<WaiverSigning eventId={eventId} />
|
|
437
|
+
<Payment
|
|
438
|
+
eventId={eventId}
|
|
439
|
+
requireEmailConfirmation
|
|
440
|
+
collectTicketHolders
|
|
441
|
+
requireHolderContact
|
|
442
|
+
onComplete={setOrder}
|
|
443
|
+
/>
|
|
444
|
+
</>
|
|
445
|
+
)}
|
|
446
|
+
</main>
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export function SinglePageCheckout({ eventId }: { eventId: string }) {
|
|
238
451
|
return (
|
|
239
452
|
<CheckoutProvider theme={{ colorScheme: 'light', accent: '#2458d3' }}>
|
|
240
|
-
<
|
|
241
|
-
<AddOns eventId={eventId} />
|
|
242
|
-
<BillingInfo eventId={eventId} requireEmailConfirmation />
|
|
243
|
-
<WaiverSigning eventId={eventId} />
|
|
244
|
-
<OrderSummary eventId={eventId} />
|
|
245
|
-
<Payment
|
|
246
|
-
eventId={eventId}
|
|
247
|
-
requireEmailConfirmation
|
|
248
|
-
onComplete={(order) => setNotice(order.pending ? 'Payment pending' : 'Order submitted')}
|
|
249
|
-
/>
|
|
250
|
-
<p role="status">{notice}</p>
|
|
453
|
+
<SinglePageContents eventId={eventId} />
|
|
251
454
|
</CheckoutProvider>
|
|
252
455
|
)
|
|
253
456
|
}
|
|
254
457
|
```
|
|
255
458
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
459
|
+
`Tickets.onContinue` fires after the cart is primed. `onSelectSeats` opens the
|
|
460
|
+
seat view; without it the seat-selection button is hidden in a composed
|
|
461
|
+
`Tickets` section. `SeatMap.onContinue` runs after seats are added and priced.
|
|
462
|
+
Without an `onContinue` prop, `BillingInfo` and `AddOns` use their combined-form
|
|
463
|
+
behavior instead of showing a separate Continue button. Match the billing and
|
|
464
|
+
payment email/holder settings, as shown. `AddOns` renders nothing when the
|
|
465
|
+
event has no applicable add-ons; do not skip a required one.
|
|
466
|
+
|
|
467
|
+
### Step-by-step checkout
|
|
468
|
+
|
|
469
|
+
To make billing and payment separate steps, give `BillingInfo` an `onContinue`
|
|
470
|
+
callback. It then validates and saves the buyer details before moving on. This
|
|
471
|
+
example keeps the checkout provider mounted for the whole flow; it does not
|
|
472
|
+
change URLs or assume a browser refresh can resume the in-memory layout.
|
|
473
|
+
|
|
474
|
+
```tsx
|
|
475
|
+
import { useState } from 'react'
|
|
476
|
+
import {
|
|
477
|
+
AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
|
|
478
|
+
Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
|
|
479
|
+
} from 'tf-checkout-react'
|
|
480
|
+
|
|
481
|
+
type Step = 'tickets' | 'seats' | 'details' | 'payment'
|
|
482
|
+
|
|
483
|
+
function StepContents({ eventId }: { eventId: string }) {
|
|
484
|
+
const checkout = useCheckoutContext()
|
|
485
|
+
const [step, setStep] = useState<Step>('tickets')
|
|
486
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
487
|
+
|
|
488
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
489
|
+
|
|
490
|
+
return (
|
|
491
|
+
<main>
|
|
492
|
+
{(step === 'details' || step === 'payment') && (
|
|
493
|
+
<TimerBanner seconds={checkout.secondsLeft} />
|
|
494
|
+
)}
|
|
495
|
+
<div hidden={step !== 'tickets'}>
|
|
496
|
+
<Tickets
|
|
497
|
+
eventId={eventId}
|
|
498
|
+
onContinue={() => setStep('details')}
|
|
499
|
+
onSelectSeats={() => setStep('seats')}
|
|
500
|
+
/>
|
|
501
|
+
</div>
|
|
502
|
+
{step === 'seats' && (
|
|
503
|
+
<>
|
|
504
|
+
<button type="button" onClick={() => setStep('tickets')}>Back to tickets</button>
|
|
505
|
+
<SeatMap eventId={eventId} onContinue={() => setStep('details')} />
|
|
506
|
+
</>
|
|
507
|
+
)}
|
|
508
|
+
{step === 'details' && (
|
|
509
|
+
<BillingInfo
|
|
510
|
+
eventId={eventId}
|
|
511
|
+
requireEmailConfirmation
|
|
512
|
+
collectTicketHolders
|
|
513
|
+
collectHolderContact
|
|
514
|
+
onContinue={() => setStep('payment')}
|
|
515
|
+
/>
|
|
516
|
+
)}
|
|
517
|
+
{step === 'payment' && (
|
|
518
|
+
<>
|
|
519
|
+
<AddOns eventId={eventId} />
|
|
520
|
+
<WaiverSigning eventId={eventId} />
|
|
521
|
+
<Payment
|
|
522
|
+
eventId={eventId}
|
|
523
|
+
requireEmailConfirmation
|
|
524
|
+
collectTicketHolders
|
|
525
|
+
requireHolderContact
|
|
526
|
+
onComplete={setOrder}
|
|
527
|
+
/>
|
|
528
|
+
</>
|
|
529
|
+
)}
|
|
530
|
+
</main>
|
|
531
|
+
)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
export function StepCheckout({ eventId }: { eventId: string }) {
|
|
535
|
+
return <CheckoutProvider><StepContents eventId={eventId} /></CheckoutProvider>
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
For separate routes, keep the provider above the routed pages and connect the
|
|
540
|
+
callbacks to your router. A full page reload is a different session/navigation
|
|
541
|
+
problem: `ResumedCheckout` can attach only to an existing cart in the current
|
|
542
|
+
session, and the old 1.x localStorage state is not a migration format. Handle
|
|
543
|
+
expired reservations, browser Back, buyer changes and unconfirmed payments
|
|
544
|
+
before enabling navigation or a new purchase. Do not unmount or reset an
|
|
545
|
+
in-flight payment merely to move between steps.
|
|
546
|
+
|
|
547
|
+
The step example is a progressive layout: the next step appears after a
|
|
548
|
+
successful callback. A router can replace `setStep`, but the SDK does not
|
|
549
|
+
supply a route-based checkout or implement your browser Back handling. Do not
|
|
550
|
+
assume that a successful TypeScript build verifies route, refresh or payment
|
|
551
|
+
behavior; test those flows with your own backend and providers.
|
|
552
|
+
|
|
553
|
+
### Accordion checkout
|
|
554
|
+
|
|
555
|
+
The SDK does not export a named accordion component. This host-built layout
|
|
556
|
+
uses native HTML disclosures to group the same SDK sections. The payment field
|
|
557
|
+
stays outside the disclosures so it remains visible while the buyer pays.
|
|
558
|
+
It uses the configuration and `QueryClientProvider` from the quick start.
|
|
559
|
+
|
|
560
|
+
```tsx
|
|
561
|
+
import { useState } from 'react'
|
|
562
|
+
import {
|
|
563
|
+
AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
|
|
564
|
+
Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
|
|
565
|
+
} from 'tf-checkout-react'
|
|
566
|
+
|
|
567
|
+
function AccordionContents({ eventId }: { eventId: string }) {
|
|
568
|
+
const checkout = useCheckoutContext()
|
|
569
|
+
const [view, setView] = useState<'tickets' | 'seats' | 'checkout'>('tickets')
|
|
570
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
571
|
+
|
|
572
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
573
|
+
|
|
574
|
+
return (
|
|
575
|
+
<main>
|
|
576
|
+
<div hidden={view !== 'tickets'}>
|
|
577
|
+
<Tickets
|
|
578
|
+
eventId={eventId}
|
|
579
|
+
onContinue={() => setView('checkout')}
|
|
580
|
+
onSelectSeats={() => setView('seats')}
|
|
581
|
+
/>
|
|
582
|
+
</div>
|
|
583
|
+
{view === 'seats' && (
|
|
584
|
+
<>
|
|
585
|
+
<button type="button" onClick={() => setView('tickets')}>Back to tickets</button>
|
|
586
|
+
<SeatMap eventId={eventId} onContinue={() => setView('checkout')} />
|
|
587
|
+
</>
|
|
588
|
+
)}
|
|
589
|
+
{view === 'checkout' && (
|
|
590
|
+
<>
|
|
591
|
+
<TimerBanner seconds={checkout.secondsLeft} />
|
|
592
|
+
<details open>
|
|
593
|
+
<summary>Add-ons</summary>
|
|
594
|
+
<AddOns eventId={eventId} />
|
|
595
|
+
</details>
|
|
596
|
+
<details open>
|
|
597
|
+
<summary>Buyer and ticket holders</summary>
|
|
598
|
+
<BillingInfo
|
|
599
|
+
eventId={eventId}
|
|
600
|
+
requireEmailConfirmation
|
|
601
|
+
collectTicketHolders
|
|
602
|
+
collectHolderContact
|
|
603
|
+
/>
|
|
604
|
+
</details>
|
|
605
|
+
<details open>
|
|
606
|
+
<summary>Waiver</summary>
|
|
607
|
+
<WaiverSigning eventId={eventId} />
|
|
608
|
+
</details>
|
|
609
|
+
<Payment
|
|
610
|
+
eventId={eventId}
|
|
611
|
+
requireEmailConfirmation
|
|
612
|
+
collectTicketHolders
|
|
613
|
+
requireHolderContact
|
|
614
|
+
onComplete={setOrder}
|
|
615
|
+
/>
|
|
616
|
+
</>
|
|
617
|
+
)}
|
|
618
|
+
</main>
|
|
619
|
+
)
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
export function AccordionCheckout({ eventId }: { eventId: string }) {
|
|
623
|
+
return <CheckoutProvider><AccordionContents eventId={eventId} /></CheckoutProvider>
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
The buyer reserves tickets or seats, then can open or close the form groups.
|
|
628
|
+
Closing a `<details>` element hides its contents without unmounting them. In a
|
|
629
|
+
production accordion, open the relevant group when validation needs the buyer's
|
|
630
|
+
attention, and make sure required add-ons, fields and waivers cannot be missed.
|
|
631
|
+
Do not hide or replace the active payment field during a payment attempt.
|
|
632
|
+
As with the other examples, replace the status placeholder with your own
|
|
633
|
+
verified order-status and support flow.
|
|
634
|
+
|
|
635
|
+
`CheckoutProvider` props are `children` (required), `value?: UseCheckout`,
|
|
267
636
|
`theme?: CheckoutTheme`, `locale?: LocaleCode`,
|
|
268
637
|
`messages?: Partial<Messages>`, and `className?: string`. Use
|
|
269
|
-
`useCheckoutContext()` inside the provider
|
|
270
|
-
`
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
ports you need when creating that checkout.
|
|
638
|
+
`useCheckoutContext()` inside the provider to read the current checkout and
|
|
639
|
+
`useCheckoutValidation()` to coordinate validation between sections. The
|
|
640
|
+
provider's default checkout includes the installment picker. If supplying your
|
|
641
|
+
own `value`, wire any custom payment ports you need when creating that checkout.
|
|
274
642
|
|
|
275
643
|
## Checkout lifecycle
|
|
276
644
|
|
|
@@ -309,6 +677,18 @@ error or closed provider page means the charge failed. A custom provider page mu
|
|
|
309
677
|
settle with `{ event: 'dismiss' }` on close/unmount, and other custom payment
|
|
310
678
|
ports must settle, or a waiting reset cannot finish.
|
|
311
679
|
|
|
680
|
+
The beta.26 declaration comments for `reset` and `PAID_ORDER_PENDING_MESSAGE`
|
|
681
|
+
say pressing Pay again finishes an unconfirmed order; the `resetWhenSettled`
|
|
682
|
+
comment also omits retired checkouts as a reason for `false`. Those comments do
|
|
683
|
+
not establish that a retry is safe. Use the session and reconciliation guidance
|
|
684
|
+
above.
|
|
685
|
+
|
|
686
|
+
Stock `Payment` can display an engine message telling the buyer to press Pay
|
|
687
|
+
again when payment is unconfirmed. That wording does not establish that a retry
|
|
688
|
+
is safe. If neutral buyer guidance is required for uncertain outcomes, use a
|
|
689
|
+
custom payment flow with host-controlled error UI, retain the order and reconcile
|
|
690
|
+
the current session and authoritative order/provider status before recovery.
|
|
691
|
+
|
|
312
692
|
### Tickets, codes, seats and waiting lists
|
|
313
693
|
|
|
314
694
|
`Tickets` reads the catalog, presents the event's promo/access-code controls and
|
|
@@ -354,7 +734,7 @@ holder's answers in `ticketDataCapture`, and add-on answers via
|
|
|
354
734
|
the opaque catalog ID. Use backend country/state IDs for `countryId` and
|
|
355
735
|
`stateId`; `countryCode` / `stateCode` are payment billing codes.
|
|
356
736
|
|
|
357
|
-
In beta.
|
|
737
|
+
In beta.26 conditional custom-field requiredness is left to the backend and
|
|
358
738
|
not all hosted-checkout conditional visibility is reproduced. Verify the
|
|
359
739
|
actual event against the deployed checkout, including blanks, images, holder
|
|
360
740
|
scoping and validation errors; do not claim parity from the presence of a
|
|
@@ -362,11 +742,20 @@ field alone. Terms and `additionalConditions` are client-side acceptance gates;
|
|
|
362
742
|
respect the server's own requirements. `Payment` renders condition `content`,
|
|
363
743
|
or `name` as a fallback, as HTML. Only supply trusted or appropriately sanitized
|
|
364
744
|
content, and verify the source and handling of server-provided conditions too.
|
|
365
|
-
|
|
366
|
-
|
|
745
|
+
|
|
746
|
+
During cart priming, failed custom-field, checkout-config, add-on or event
|
|
747
|
+
condition reads fall back to empty/default data. The stock UI cannot show or
|
|
748
|
+
gate requirements it did not load. Do not treat an empty list as proof that no
|
|
749
|
+
requirement exists; verify deployment/failure behavior and add tested host
|
|
750
|
+
safeguards for mandatory fields and acknowledgments. Server validation of
|
|
751
|
+
required answers is not proof that a condition was acknowledged. Only failed
|
|
752
|
+
waiver reads other than a 404 are recorded in `unavailableDetails`. Before money
|
|
753
|
+
may have moved, placement retries an unavailable waiver and blocks if it remains
|
|
754
|
+
unknown; `reloadCheckoutDetails()` can also retry the waiver read. A retained
|
|
755
|
+
order with a possible payment follows separate recovery and needs reconciliation.
|
|
367
756
|
`WaiverSigning` handles the SDK's signing flow.
|
|
368
757
|
|
|
369
|
-
**Consent limitation in beta.
|
|
758
|
+
**Consent limitation in beta.26:** when `privacyPolicy` is supplied, the
|
|
370
759
|
stock `BillingInfo` replaces the Ticket Fairy marketing checkbox with the
|
|
371
760
|
required privacy checkbox, but both use `consent.ttfOptIn`; the order sends
|
|
372
761
|
that value as `ttf_opt_in`. The privacy acknowledgement and Ticket Fairy
|
|
@@ -406,6 +795,19 @@ for authoritative confirmation before showing a paid receipt or fulfilling.
|
|
|
406
795
|
ID verification may still be required after payment. An ID-verification failure
|
|
407
796
|
is not a reason to repeat the charge.
|
|
408
797
|
|
|
798
|
+
The stock in-flow `Confirmation` displays confirmed/ticket-available copy when
|
|
799
|
+
`pending` is absent or false; it does not independently verify final settlement.
|
|
800
|
+
For both paid and free orders, use `confirmationMode="redirect"` with a
|
|
801
|
+
host-owned status page, or a custom composed confirmation gated on authoritative
|
|
802
|
+
order and provider status. Arrange ID verification on the host route when
|
|
803
|
+
`needIdVerification` is true; redirect does not render the inline verification.
|
|
804
|
+
The stock `IDVerification` and routed `OrderIDVerification` verified messages
|
|
805
|
+
say tickets are on their way; they do not check final settlement or issuance.
|
|
806
|
+
Use host-owned neutral verification and status UI when that copy is premature.
|
|
807
|
+
If `onComplete` navigates away or unmounts the checkout, its inline verification
|
|
808
|
+
cannot appear: keep the provider mounted or handle verification at the destination.
|
|
809
|
+
For a custom flow, see [host-owned ID verification](#host-owned-id-verification).
|
|
810
|
+
|
|
409
811
|
**Zero-total orders:** this SDK ignores the free-registration response body and
|
|
410
812
|
reports `needIdVerification: false`. Verification or approval may still be
|
|
411
813
|
required, and `free: true` is not proof tickets were issued. The default inline
|
|
@@ -421,7 +823,8 @@ order's payment status before showing its default confirmed/ticket-availability
|
|
|
421
823
|
copy. Gate it on an authoritative status appropriate for that page. When
|
|
422
824
|
`onComplete` reports `pending`, show a pending page (and any voucher) instead;
|
|
423
825
|
do not route directly to `OrderConfirmation` as a paid receipt. The in-flow
|
|
424
|
-
`Confirmation` component reads the current result and has a pending state
|
|
826
|
+
`Confirmation` component reads the current result and has a pending state, but
|
|
827
|
+
the absence of `pending` is not proof of settlement.
|
|
425
828
|
|
|
426
829
|
`CardInput` renders Stripe Elements and uses the checkout's default card owner;
|
|
427
830
|
`StripePaymentElement` is the deferred Elements option when its server config
|
|
@@ -452,6 +855,24 @@ three only when the provider confirms nothing was charged. An unclassified
|
|
|
452
855
|
error is treated as unknown. Avoid automatic blind retries and never promise
|
|
453
856
|
exactly-once charging across your app, backend and provider.
|
|
454
857
|
|
|
858
|
+
### Host-owned ID verification
|
|
859
|
+
|
|
860
|
+
`runIdVerification(orderHash, options)` does not open the provider on its own.
|
|
861
|
+
Supply `openUrl` to validate the URL against your provider and scheme policy
|
|
862
|
+
and open it in the browser; handle a missing URL or blocked/failed opening in
|
|
863
|
+
your UI. The engine swallows asynchronous `openUrl` rejections, so catch and
|
|
864
|
+
record opening failures inside the callback: polling can otherwise continue
|
|
865
|
+
without a handoff. Use `onPhase` for polling state and handle browser returns;
|
|
866
|
+
`registerForegroundListener` can trigger a recheck on return and must return an
|
|
867
|
+
unsubscribe function.
|
|
868
|
+
|
|
869
|
+
Alternatively, `onRequired` receives the order hash and possibly null URL; if
|
|
870
|
+
it returns `true`, the engine resolves `undefined` without opening or polling,
|
|
871
|
+
and your host owns both steps. A timeout or poll error rejects with a message
|
|
872
|
+
promising that payment is safe and tickets will be emailed. Replace that text
|
|
873
|
+
with neutral status and reconcile authoritative payment, verification and
|
|
874
|
+
issuance. Verification alone does not prove settlement or issuance.
|
|
875
|
+
|
|
455
876
|
## Authentication
|
|
456
877
|
|
|
457
878
|
The embedded checkout supplies the event to its built-in `AuthModal`. A
|
|
@@ -520,7 +941,7 @@ package are the authoritative detail for callback payloads and DTOs.
|
|
|
520
941
|
| `BillingInfo` | `eventId?`, `onContinue?`, `heading?`, `buttonLabel?`, `onLogin?`, `skipWhenProfileComplete?`, `requireEmailConfirmation?`, `collectTicketHolders?`, `collectHolderContact?`, `ttfOptInLabel?`, `brandOptInLabel?`, `privacyPolicy?`, `showPrivacyError?`, `step?`, `className?`. Standalone holder collection follows backend gates unless explicitly enabled. |
|
|
521
942
|
| `WaiverSigning` | `eventId`, `className?`. Render before payment for an event requiring a waiver. |
|
|
522
943
|
| `Payment` | `onComplete?`, `eventId?`, `requireEmailConfirmation?`, `collectTicketHolders?`, `requireHolderContact?`, `additionalConditions?`, `requirePrivacyPolicy?`, `onPrivacyRequired?`, `showTestCardHint?`, `className?`. Match the paired billing policies. |
|
|
523
|
-
| `OrderSummary` | `eventId?`, `className?`. Uses the current checkout's pricing. |
|
|
944
|
+
| `OrderSummary` | `eventId?`, `className?`. Uses the current checkout's pricing. `Payment` already renders it; use it separately when you need a summary elsewhere. |
|
|
524
945
|
| `IDVerification` | `className?`. Uses the current checkout/order. |
|
|
525
946
|
| `Confirmation` | `shareUrl?`, `shareMessage?`, `viewOrderUrl?`, `children?`, `className?`. Uses the current checkout result and handles pending presentation. The default share URL and eligibility have the limitations below. |
|
|
526
947
|
| `OrderConfirmation` | `orderHash`, `title?`, `message?`, `helper?`, `eventTitle?`, `eventDate?`, `eventLocation?`, `viewOrderUrl?` (string or function), `showReferral?`, `showShareButtons?`, `showRewards?`, `snapchat?`, `onLoaded?`, `onError?`, `className?`. Reloads confirmation by hash; the host must gate it on appropriate payment status. The three `show*` options default to true; Snapchat defaults to false. |
|
|
@@ -688,7 +1109,7 @@ as the final order amount.
|
|
|
688
1109
|
| `setAcceptedConditions(map)`, `acceptCondition(id, accepted)`, `setAddonDataCapture(map)` | Record condition acceptance and add-on answers. |
|
|
689
1110
|
| `setWaiverSignature(index, signature, hold?)`, `holdWaiverSigning(index)` | Coordinate a signature save with the cart/holder it belongs to; release a hold when finished. Prefer `WaiverSigning` for standard UI. |
|
|
690
1111
|
| `reloadCheckoutDetails()`, `syncCurrency(eventId, code?, options?)` | Retry unavailable details or switch/seed event currency. Refresh selection and prices after changing currency. |
|
|
691
|
-
| `placeOrder(method?, options?)`, `runIdVerification(orderHash, options?)` | Place/pay; optionally run verification separately. `placeOrder` accepts `autoRunIdVerification`, `idVerification` and `claimCard` options. |
|
|
1112
|
+
| `placeOrder(method?, options?)`, `runIdVerification(orderHash, options?)` | Place/pay; optionally run verification separately with a host URL opener or takeover. See [host-owned ID verification](#host-owned-id-verification). `placeOrder` accepts `autoRunIdVerification`, `idVerification` and `claimCard` options. |
|
|
692
1113
|
| `applyPromoCode(eventId, code)`, `attributeReferrer(eventId, referrer)`, `joinWaitingList(eventId, entry)` | Helpers return promises. Refetch catalog after a code changes availability. |
|
|
693
1114
|
| `reset()`, `resetWhenSettled()` | Restart subject to payment-settlement protection; see [lifecycle](#checkout-lifecycle). |
|
|
694
1115
|
| `snapshot`, `store`, `isLoggedIn` | Entire state, shared store, and whether the hook sees an authenticated or checkout buyer session. The latter does not imply private-account authority. |
|
|
@@ -721,11 +1142,13 @@ for a different gateway.
|
|
|
721
1142
|
|
|
722
1143
|
The package re-exports the shared core: `ttf` is a configured domain facade,
|
|
723
1144
|
`api` contains raw calls, `hooks` contains React bindings, and DTOs, logic,
|
|
724
|
-
`createEngine` and `createCheckoutStore` are named exports.
|
|
725
|
-
promises;
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
1145
|
+
`createEngine` and `createCheckoutStore` are named exports. Network calls usually
|
|
1146
|
+
return promises; `ttf.events.filterAddonsForTickets` and
|
|
1147
|
+
`ttf.order.mapProfileToBilling` are synchronous helpers. They do not render UI
|
|
1148
|
+
or replace the engine's sequencing, payment ownership and preflight. Use them
|
|
1149
|
+
directly only when your application owns the corresponding workflow. The
|
|
1150
|
+
installed `dist/index.d.ts` includes the complete exported signatures. Avoid
|
|
1151
|
+
importing a private shared-core package.
|
|
729
1152
|
|
|
730
1153
|
```tsx
|
|
731
1154
|
import { hooks } from 'tf-checkout-react'
|
|
@@ -819,7 +1242,7 @@ existing 1.x integration pinned until the new flow and backend are verified.
|
|
|
819
1242
|
There is no automatic translation of old URLs, component props, account
|
|
820
1243
|
sessions or persisted 1.x state.
|
|
821
1244
|
|
|
822
|
-
| 1.x integration | 2.0.0-beta.
|
|
1245
|
+
| 1.x integration | 2.0.0-beta.26 approach |
|
|
823
1246
|
| --- | --- |
|
|
824
1247
|
| `setConfigs({ BASE_URL, ... })` | `configureCheckout({ env` or `baseUrl`, `clientId`, `clientSecret: ''`, ... `})`; public client registration and session setup are required. |
|
|
825
1248
|
| `TicketsContainer`, `SeatMapContainer`, `AddOnsContainer` | `EmbeddedCheckout` or `Tickets`, `SeatMap`, `AddOns` under `CheckoutProvider`. Adapt callbacks and navigation. |
|
|
@@ -832,6 +1255,25 @@ sessions or persisted 1.x state.
|
|
|
832
1255
|
| Promo/access, waiting list, pixel and referral behavior | Re-check catalog metadata, code/attribution precedence, waiting-list contract and explicit tracking. Do not infer numeric `?r=`. |
|
|
833
1256
|
| Legacy single-page state in localStorage | Use the 2.x checkout store/engine and server cart; do not copy sensitive state or assume 1.x persisted state can be resumed. |
|
|
834
1257
|
|
|
1258
|
+
### Migrating layout callbacks
|
|
1259
|
+
|
|
1260
|
+
A callback name change can also change what the host receives. In particular,
|
|
1261
|
+
`onContinue` does not pass the old callback's response payload:
|
|
1262
|
+
|
|
1263
|
+
| 1.x usage | 2.x replacement |
|
|
1264
|
+
| --- | --- |
|
|
1265
|
+
| `TicketsContainer`'s `getTicketsLabel` | `Tickets`'s `buttonLabel`. |
|
|
1266
|
+
| `TicketsContainer`'s `onAddToCartSuccess(data)` | `Tickets.onContinue()` after reservation; read the current cart through `useCheckoutContext()` under the provider. |
|
|
1267
|
+
| `BillingInfoContainer`'s `handleSubmit(values, helpers, eventId, response)` | `BillingInfo.onContinue()` after validation and save; read the current billing and holders from the checkout context. Omit the callback for combined-form behavior. |
|
|
1268
|
+
| `AddOnsContainer` timer | Render `TimerBanner` with `useCheckoutContext().secondsLeft` in the host layout. |
|
|
1269
|
+
| Separate 1.x page URLs and localStorage state | Keep the 2.x provider mounted across host steps; implement route/refresh handling and verify any existing server cart in the current session. |
|
|
1270
|
+
|
|
1271
|
+
These are migration starting points, not prop-compatible aliases. In 2.x
|
|
1272
|
+
`eventId` is a string; convert a numeric ID before passing it. Old Material UI
|
|
1273
|
+
theme options, callback payloads and optional page behavior need explicit host
|
|
1274
|
+
work. For the two complete flows see [Choose a checkout layout](#choose-a-checkout-layout);
|
|
1275
|
+
for single-page and stepped alternatives see [Compose sections](#compose-sections).
|
|
1276
|
+
|
|
835
1277
|
Compare the exact event's ticket types, dated pricing, seats, add-ons, holder
|
|
836
1278
|
questions, conditional fields, consent, waivers, fees, currencies, payment
|
|
837
1279
|
methods, account and post-purchase behavior before switching. Backend rollout
|
package/docs/API.md
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# React checkout API reference
|
|
2
2
|
|
|
3
3
|
This reference describes the public surface of `tf-checkout-react` version
|
|
4
|
-
`2.0.0-beta.
|
|
4
|
+
`2.0.0-beta.26`. It supplements the package's npm README with examples and an
|
|
5
5
|
inventory of the shared facade and hooks. The package's installed
|
|
6
6
|
`dist/index.d.ts` is the exact versioned source for complete signatures and
|
|
7
7
|
DTO fields. A named export or a typed payment method does not establish that
|
|
8
8
|
the matching backend feature, account permission or payment provider is enabled.
|
|
9
9
|
|
|
10
|
+
For installation, a complete quick start, and examples of the ready-made,
|
|
11
|
+
single-page and step-by-step layouts, start with the [checkout guide](https://unpkg.com/tf-checkout-react@2.0.0-beta.26/README.md#choose-a-checkout-layout).
|
|
12
|
+
This file is the detailed component, engine and API reference.
|
|
13
|
+
|
|
10
14
|
All examples assume `configureCheckout` has run, and React Query examples are
|
|
11
15
|
under a host `QueryClientProvider`. Use a registered public SDK client ID and
|
|
12
16
|
an empty `clientSecret` in a browser. Never ship a confidential client secret.
|
|
@@ -61,8 +65,11 @@ appropriate authorized logout flow where a backend session must also end.
|
|
|
61
65
|
|
|
62
66
|
`Tickets` and `SeatMap` report when a cart is ready; the host owns navigation
|
|
63
67
|
when composing individual sections. This skeleton connects seated selection to
|
|
64
|
-
its view.
|
|
65
|
-
`QueryClientProvider`.
|
|
68
|
+
its view. This wiring recipe is not a standalone app: configure and mount it
|
|
69
|
+
under `QueryClientProvider`. Its seat Back changes views only; it does not itself
|
|
70
|
+
release held seats or cancel an in-flight reservation or cart priming. Before
|
|
71
|
+
allowing a conflicting selection, coordinate that work and hold expiry or
|
|
72
|
+
release under your deployed backend contract.
|
|
66
73
|
|
|
67
74
|
```tsx
|
|
68
75
|
import { useState } from 'react'
|
|
@@ -75,15 +82,18 @@ export function CheckoutLayout({ eventId }: { eventId: string }) {
|
|
|
75
82
|
const [notice, setNotice] = useState('')
|
|
76
83
|
return (
|
|
77
84
|
<CheckoutProvider>
|
|
78
|
-
{view
|
|
85
|
+
<div hidden={view !== 'tickets'}>
|
|
79
86
|
<Tickets
|
|
80
87
|
eventId={eventId}
|
|
81
88
|
onSelectSeats={() => setView('seats')}
|
|
82
89
|
onContinue={() => setView('checkout')}
|
|
83
90
|
/>
|
|
84
|
-
|
|
91
|
+
</div>
|
|
85
92
|
{view === 'seats' && (
|
|
86
|
-
|
|
93
|
+
<>
|
|
94
|
+
<button type="button" onClick={() => setView('tickets')}>Back to tickets</button>
|
|
95
|
+
<SeatMap eventId={eventId} onContinue={() => setView('checkout')} />
|
|
96
|
+
</>
|
|
87
97
|
)}
|
|
88
98
|
{view === 'checkout' && (
|
|
89
99
|
<>
|
|
@@ -101,10 +111,11 @@ export function CheckoutLayout({ eventId }: { eventId: string }) {
|
|
|
101
111
|
}
|
|
102
112
|
```
|
|
103
113
|
|
|
104
|
-
Real navigation must also
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
114
|
+
Real navigation must also implement checkout Edit/Back, preserve entered
|
|
115
|
+
details, and handle expiry, payment in flight, retained orders and buyer/session
|
|
116
|
+
changes. Do not unconditionally discard or replace a cart on Back during a
|
|
117
|
+
payment. Use `EmbeddedCheckout` for its built-in Back and guarded Edit behavior;
|
|
118
|
+
when building your own, preserve validation and server reservation behavior. The
|
|
108
119
|
host can use `useCheckoutContext()` inside the provider to read the shared
|
|
109
120
|
checkout and `useCheckoutValidation()` to coordinate section validation.
|
|
110
121
|
|
|
@@ -231,8 +242,18 @@ validate on the deployed server too. In this beta the backend owns conditional
|
|
|
231
242
|
requiredness and hosted-checkout conditional visibility is not fully reproduced.
|
|
232
243
|
Test the actual event's branches before release.
|
|
233
244
|
|
|
245
|
+
During priming, failed custom-field, checkout-config, add-on or event-condition
|
|
246
|
+
reads fall back to empty/default data and are not recorded in `unavailableDetails`.
|
|
247
|
+
The engine and stock UI cannot gate requirements they did not load. Do not treat
|
|
248
|
+
an empty list as proof that no requirement exists; verify failure behavior and
|
|
249
|
+
implement tested host safeguards for mandatory fields and acknowledgments. Server
|
|
250
|
+
answer validation is not proof that a condition was acknowledged.
|
|
251
|
+
|
|
234
252
|
If `unavailableDetails` includes `'waiver'`, the read failed without establishing
|
|
235
|
-
whether a waiver exists.
|
|
253
|
+
whether a waiver exists. Before money may have moved, placement retries that
|
|
254
|
+
read and blocks if it remains unknown; `reloadCheckoutDetails()` also retries it.
|
|
255
|
+
A retained order with a possible payment follows separate recovery and needs
|
|
256
|
+
reconciliation. For a custom
|
|
236
257
|
waiver UI, `holdWaiverSigning(index)` returns a hold or `null`; complete or
|
|
237
258
|
cancel the upload, attach via `setWaiverSignature(index, signature, hold)` only
|
|
238
259
|
while the binding remains current, and release the hold. The standard
|
|
@@ -258,7 +279,34 @@ If status is unavailable, contact support. Do not retry payment for a free order
|
|
|
258
279
|
`OrderConfirmation` does not check payment status before rendering its default
|
|
259
280
|
confirmed/ticket-availability copy. Gate it on authoritative appropriate status;
|
|
260
281
|
when the result is pending, show pending UI and any voucher instead. The
|
|
261
|
-
in-flow `Confirmation` component reads the current result's pending state
|
|
282
|
+
in-flow `Confirmation` component reads the current result's pending state but
|
|
283
|
+
shows confirmed copy when `pending` is absent or false, even for paid orders
|
|
284
|
+
whose final settlement has not been independently verified. Use a host-owned
|
|
285
|
+
status route with `confirmationMode="redirect"` or a custom composed
|
|
286
|
+
confirmation gated on authoritative order and provider status. Redirect omits
|
|
287
|
+
inline ID verification; arrange it when `needIdVerification` is true.
|
|
288
|
+
For `EmbeddedCheckout` in redirect mode, provide `onComplete` to route the
|
|
289
|
+
result. `ResumedCheckout` defaults to redirect and likewise needs that callback;
|
|
290
|
+
otherwise its successful flow remains in the loading transition. Inline mode
|
|
291
|
+
has the confirmation and verification-copy limitations described here.
|
|
292
|
+
The stock `IDVerification` and routed `OrderIDVerification` verified messages
|
|
293
|
+
say tickets are on their way but do not verify settlement or issuance. Use a
|
|
294
|
+
host-owned neutral verification and status UI when appropriate. If `onComplete`
|
|
295
|
+
navigates away or unmounts the checkout, inline verification will not appear;
|
|
296
|
+
keep the provider mounted or handle verification at the destination.
|
|
297
|
+
|
|
298
|
+
For custom verification, `runIdVerification(orderHash, options)` does not
|
|
299
|
+
open a URL by itself. Supply `openUrl`, validate the provider URL and open it
|
|
300
|
+
in the browser; handle a missing URL or blocked/failed opening. The engine
|
|
301
|
+
swallows asynchronous `openUrl` rejections, so catch and record failures in
|
|
302
|
+
that callback while showing neutral status. Handle `onPhase` and browser
|
|
303
|
+
returns; `registerForegroundListener` can recheck on return and returns an
|
|
304
|
+
unsubscribe function. Alternatively, return `true` from `onRequired` to take
|
|
305
|
+
over: the engine resolves `undefined` and neither opens nor polls. A timeout or
|
|
306
|
+
poll error rejects with copy promising payment is safe and tickets will be
|
|
307
|
+
emailed; replace it with neutral status and reconcile authoritative payment,
|
|
308
|
+
verification and issuance. Verification alone proves neither settlement nor
|
|
309
|
+
issuance.
|
|
262
310
|
|
|
263
311
|
For a custom Stripe card step, the following demonstrates the boundary between
|
|
264
312
|
host-collected data and SDK placement. Render it only after reserving a cart and
|
|
@@ -350,6 +398,15 @@ no-charge outcomes as `declined`, `cancelled` or `notStarted`, with `unknown`
|
|
|
350
398
|
for uncertainty. `UNSUPPORTED_GATEWAY` indicates the necessary platform
|
|
351
399
|
capability is not available, not that every provider failure is safe to retry.
|
|
352
400
|
|
|
401
|
+
The beta.26 declaration comments for `reset` and `PAID_ORDER_PENDING_MESSAGE`
|
|
402
|
+
say pressing Pay again finishes an unconfirmed order; the `resetWhenSettled`
|
|
403
|
+
comment omits retired checkouts as a reason for `false`. Those comments do not
|
|
404
|
+
establish that a retry is safe; check the current session and reconcile first.
|
|
405
|
+
Stock `Payment` can also display an engine message telling the buyer to press
|
|
406
|
+
Pay again when payment is unconfirmed. That wording does not prove a retry is
|
|
407
|
+
safe. If neutral guidance is required, use a custom payment flow with
|
|
408
|
+
host-controlled error UI, retain the order and reconcile before recovery.
|
|
409
|
+
|
|
353
410
|
## Auth component contracts
|
|
354
411
|
|
|
355
412
|
`AuthModal` owns a complete modal flow. Supply `open`, `onClose` and, for
|
|
@@ -464,6 +521,10 @@ preflight, state and payment coordination. Raw functions are also exported in
|
|
|
464
521
|
the `api` namespace. Calling a low-level endpoint directly does not grant a
|
|
465
522
|
buyer permission or guarantee a safe payment retry.
|
|
466
523
|
|
|
524
|
+
`ttf.events.requiredCustomFieldLabels(eventId)` returns `[]` if its lookup
|
|
525
|
+
fails as well as when no matching required order/ticket labels exist. An empty
|
|
526
|
+
result is not proof that the event has no required custom fields.
|
|
527
|
+
|
|
467
528
|
| Namespace | Methods |
|
|
468
529
|
| --- | --- |
|
|
469
530
|
| `ttf.events` | `featured`, `details`, `tickets`, `ticketsWithMeta`, `bundles`, `startBundlePurchase`, `info`, `conditions`, `timeSlotTickets`, `customFields`, `requiredCustomFieldLabels`, `addons`, `filterAddonsForTickets`, `submitPromoCode`, `setCurrency`, `authenticate`, `track`, `updateOrderDataCapture`, `updateTicketDataCapture`. |
|
package/package.json
CHANGED