tf-checkout-react 2.0.0-beta.25 → 2.0.0-beta.27
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 +550 -102
- package/docs/API.html +1002 -0
- package/docs/API.md +73 -12
- package/docs/GUIDE.html +2194 -0
- package/package.json +1 -1
package/docs/GUIDE.html
ADDED
|
@@ -0,0 +1,2194 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'">
|
|
7
|
+
<title>Ticket Fairy React checkout guide</title>
|
|
8
|
+
<style>
|
|
9
|
+
:root { color-scheme: light; font-family: system-ui, -apple-system, sans-serif; }
|
|
10
|
+
body { color: #1d2032; background: #fff; line-height: 1.55; margin: 0; overflow-wrap: anywhere; }
|
|
11
|
+
main { max-width: 75rem; min-width: 0; margin: 0 auto; padding: 2rem 1.25rem 5rem; }
|
|
12
|
+
h1, h2, h3, h4 { line-height: 1.25; scroll-margin-top: 1rem; }
|
|
13
|
+
h1 { font-size: clamp(1.8rem, 3vw, 2.5rem); }
|
|
14
|
+
h2 { margin-top: 2.5rem; border-bottom: 1px solid #d4d8e4; padding-bottom: .35rem; }
|
|
15
|
+
a { color: #5020b8; text-decoration-thickness: .08em; }
|
|
16
|
+
a:focus-visible { outline: 3px solid #7a51e7; outline-offset: 3px; }
|
|
17
|
+
pre { box-sizing: border-box; max-width: 100%; overflow-x: auto; padding: 1rem; background: #f3f2f8; border-radius: .5rem; }
|
|
18
|
+
code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .9em; overflow-wrap: anywhere; }
|
|
19
|
+
pre code { font-size: .875rem; overflow-wrap: normal; white-space: pre; }
|
|
20
|
+
table { box-sizing: border-box; border-collapse: collapse; display: block; overflow-x: auto; max-width: 100%; }
|
|
21
|
+
th, td { border: 1px solid #d4d8e4; padding: .5rem .65rem; text-align: left; vertical-align: top; }
|
|
22
|
+
th { background: #f3f2f8; }
|
|
23
|
+
.skip { position: absolute; left: -10000px; }
|
|
24
|
+
.skip:focus { position: static; display: inline-block; padding: .5rem; }
|
|
25
|
+
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<a class="skip" href="#main">Skip to content</a>
|
|
30
|
+
<main id="main">
|
|
31
|
+
<h1 id="tf-checkout-react">tf-checkout-react</h1>
|
|
32
|
+
<p>Ticket Fairy's React checkout for the web. Render the complete
|
|
33
|
+
checkout, compose its sections, or build your own UI against the
|
|
34
|
+
checkout engine. The package also exports authentication, confirmation,
|
|
35
|
+
rewards, ticket-management and account components, plus the shared API
|
|
36
|
+
and React Query hooks. Which paths a buyer can actually use depend on
|
|
37
|
+
the event, the deployed API, the buyer's session and the payment
|
|
38
|
+
provider.</p>
|
|
39
|
+
<p>This reference describes <strong>2.0.0-beta.27</strong>. It is a
|
|
40
|
+
prerelease with a different API from 1.x. Pin the version while
|
|
41
|
+
evaluating it. npm's <code>latest</code> and <code>beta</code> tags can
|
|
42
|
+
move independently and an unqualified install may select 1.x:</p>
|
|
43
|
+
<pre class="bash"><code>npm view tf-checkout-react dist-tags
|
|
44
|
+
npm install tf-checkout-react@2.0.0-beta.27 @tanstack/react-query react react-dom</code></pre>
|
|
45
|
+
<p>The <a
|
|
46
|
+
href="https://unpkg.com/tf-checkout-react@2.0.0-beta.27/docs/API.html">API
|
|
47
|
+
reference</a> is included as <code>docs/API.md</code> and
|
|
48
|
+
<code>docs/API.html</code> in this package. A <a
|
|
49
|
+
href="https://unpkg.com/tf-checkout-react@2.0.0-beta.27/docs/GUIDE.html">standalone
|
|
50
|
+
guide</a> is also available.</p>
|
|
51
|
+
<p>If the HTML has not reached the CDN yet, open the packaged
|
|
52
|
+
<code>docs/API.md</code> in a Markdown viewer or read the <a
|
|
53
|
+
href="https://cdn.jsdelivr.net/npm/tf-checkout-react@2.0.0-beta.27/docs/API.md">plain-text
|
|
54
|
+
API Markdown</a>. The full guide is also shown on this npm page.</p>
|
|
55
|
+
<h2 id="choose-a-checkout-layout">Choose a checkout layout</h2>
|
|
56
|
+
<table>
|
|
57
|
+
<thead>
|
|
58
|
+
<tr>
|
|
59
|
+
<th>Your goal</th>
|
|
60
|
+
<th>Start here</th>
|
|
61
|
+
<th>What the SDK renders</th>
|
|
62
|
+
</tr>
|
|
63
|
+
</thead>
|
|
64
|
+
<tbody>
|
|
65
|
+
<tr>
|
|
66
|
+
<td>Add a complete checkout to an event page</td>
|
|
67
|
+
<td><a href="#embeddedcheckout"><code>EmbeddedCheckout</code></a></td>
|
|
68
|
+
<td>A ready-made ticket or seat selection view followed by add-ons,
|
|
69
|
+
buyer details, waiver and payment when applicable.</td>
|
|
70
|
+
</tr>
|
|
71
|
+
<tr>
|
|
72
|
+
<td>Continue a cart created by an earlier flow</td>
|
|
73
|
+
<td><a
|
|
74
|
+
href="#resume-a-server-cart"><code>ResumedCheckout</code></a></td>
|
|
75
|
+
<td>Ready-made buyer details, waiver and payment for the current
|
|
76
|
+
session's existing cart.</td>
|
|
77
|
+
</tr>
|
|
78
|
+
<tr>
|
|
79
|
+
<td>Keep the checkout on one page and arrange the sections yourself</td>
|
|
80
|
+
<td><a href="#single-page-checkout">Single-page composition</a></td>
|
|
81
|
+
<td>Ticket selection, seats, add-ons, billing and payment sections in
|
|
82
|
+
the host's layout.</td>
|
|
83
|
+
</tr>
|
|
84
|
+
<tr>
|
|
85
|
+
<td>Show progressive steps or connect routes</td>
|
|
86
|
+
<td><a href="#step-by-step-checkout">Step-by-step composition</a></td>
|
|
87
|
+
<td>The same sections; your application controls what is visible and how
|
|
88
|
+
the buyer moves between steps.</td>
|
|
89
|
+
</tr>
|
|
90
|
+
<tr>
|
|
91
|
+
<td>Organize the form as an accordion</td>
|
|
92
|
+
<td><a href="#accordion-checkout">Accordion composition</a></td>
|
|
93
|
+
<td>Native HTML disclosure sections around the SDK's checkout
|
|
94
|
+
components.</td>
|
|
95
|
+
</tr>
|
|
96
|
+
<tr>
|
|
97
|
+
<td>Build your own checkout UI</td>
|
|
98
|
+
<td><a href="#headless-apis">Headless APIs</a></td>
|
|
99
|
+
<td>The shared engine, hooks and API; your application owns the UI and
|
|
100
|
+
navigation.</td>
|
|
101
|
+
</tr>
|
|
102
|
+
</tbody>
|
|
103
|
+
</table>
|
|
104
|
+
<p><code>EmbeddedCheckout</code> and <code>ResumedCheckout</code> are
|
|
105
|
+
the ready-made flows in this version. The 1.x <code>*Container</code>
|
|
106
|
+
components and named single-page/accordion examples are not drop-in 2.x
|
|
107
|
+
exports. The <a href="#migrating-from-1x">migration guide</a> shows how
|
|
108
|
+
to reproduce those layouts with the current components.</p>
|
|
109
|
+
<p><a href="#requirements">Requirements</a> · <a
|
|
110
|
+
href="#quick-start">Quick start</a> · <a
|
|
111
|
+
href="#configuration-and-sessions">Configure sessions</a> · <a
|
|
112
|
+
href="#embeddedcheckout">Ready-made checkout</a> · <a
|
|
113
|
+
href="#compose-sections">Custom layouts</a> · <a
|
|
114
|
+
href="#payments">Payments</a> · <a
|
|
115
|
+
href="#authentication">Authentication</a> · <a
|
|
116
|
+
href="#component-reference">Component reference</a> · <a
|
|
117
|
+
href="#styling-and-localization">Styling</a> · <a
|
|
118
|
+
href="#migrating-from-1x">Migration</a> · <a
|
|
119
|
+
href="#testing-and-troubleshooting">Troubleshooting</a></p>
|
|
120
|
+
<h2 id="requirements">Requirements</h2>
|
|
121
|
+
<ul>
|
|
122
|
+
<li>Node.js 18 or newer for tooling; a React browser application and a
|
|
123
|
+
bundler that handles JavaScript and CSS imports.</li>
|
|
124
|
+
<li>Peer dependencies: <code>react >=18</code>,
|
|
125
|
+
<code>react-dom >=18</code> and
|
|
126
|
+
<code>@tanstack/react-query >=5</code>. Supply one compatible copy of
|
|
127
|
+
each in the host. Query-based components and hooks need the host's
|
|
128
|
+
<code>QueryClientProvider</code>.</li>
|
|
129
|
+
<li>A Ticket Fairy event ID and a <strong>public SDK client ID</strong>
|
|
130
|
+
registered for this integration, together with compatible API and
|
|
131
|
+
provider configuration. Ask your Ticket Fairy integration contact for
|
|
132
|
+
the appropriate environment and event setup. Never put a confidential
|
|
133
|
+
OAuth client secret in browser code.</li>
|
|
134
|
+
<li>The shared core and seat renderer are bundled; npm installs the
|
|
135
|
+
package's declared runtime dependencies. No separate shared-core install
|
|
136
|
+
is required. Browser and provider support must be tested for the actual
|
|
137
|
+
event and device.</li>
|
|
138
|
+
</ul>
|
|
139
|
+
<p>The package entry imports
|
|
140
|
+
<code>react-international-phone/style.css</code> and its own checkout
|
|
141
|
+
stylesheet. Your bundler must process both those imports and CSS
|
|
142
|
+
<code>@import</code> rules. The latter is also exported at
|
|
143
|
+
<code>tf-checkout-react/checkout.css</code> for build setups that need
|
|
144
|
+
an explicit import. Its <code>dist/styles</code> files and referenced
|
|
145
|
+
assets are part of the npm package.</p>
|
|
146
|
+
<h2 id="quick-start">Quick start</h2>
|
|
147
|
+
<p>This example puts the ready-made checkout on one event page. You need
|
|
148
|
+
a test event ID and the matching <strong>public</strong> SDK client ID.
|
|
149
|
+
Ask your Ticket Fairy integration contact for these values and the
|
|
150
|
+
appropriate environment.</p>
|
|
151
|
+
<ol type="1">
|
|
152
|
+
<li>Install the package and its peers using the command above.</li>
|
|
153
|
+
<li>Replace <code>EVENT_ID</code> and <code>PUBLIC_SDK_CLIENT_ID</code>
|
|
154
|
+
below. Configure the SDK once in your browser entry, before rendering
|
|
155
|
+
the checkout.</li>
|
|
156
|
+
<li>Mount <code>App</code> in your React application. The package entry
|
|
157
|
+
imports its CSS; the bundler must process CSS imports and their
|
|
158
|
+
assets.</li>
|
|
159
|
+
</ol>
|
|
160
|
+
<pre class="tsx"><code>import { useState } from 'react'
|
|
161
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
162
|
+
import {
|
|
163
|
+
configureCheckout, EmbeddedCheckout, type PlaceOrderResult,
|
|
164
|
+
} from 'tf-checkout-react'
|
|
165
|
+
|
|
166
|
+
configureCheckout({
|
|
167
|
+
env: 'STAG',
|
|
168
|
+
clientId: 'PUBLIC_SDK_CLIENT_ID',
|
|
169
|
+
clientSecret: '',
|
|
170
|
+
cookieAuth: true,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
const queryClient = new QueryClient()
|
|
174
|
+
|
|
175
|
+
export function App() {
|
|
176
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<QueryClientProvider client={queryClient}>
|
|
180
|
+
{order ? (
|
|
181
|
+
<section role="status">
|
|
182
|
+
<h1>Checking your order</h1>
|
|
183
|
+
<p>Check your order status before making another purchase.</p>
|
|
184
|
+
{order.pending && <p>Your payment is pending.</p>}
|
|
185
|
+
{order.needIdVerification && <p>Identity verification may be required.</p>}
|
|
186
|
+
</section>
|
|
187
|
+
) : (
|
|
188
|
+
<EmbeddedCheckout
|
|
189
|
+
eventId="EVENT_ID"
|
|
190
|
+
confirmationMode="redirect"
|
|
191
|
+
onComplete={setOrder}
|
|
192
|
+
/>
|
|
193
|
+
)}
|
|
194
|
+
</QueryClientProvider>
|
|
195
|
+
)
|
|
196
|
+
}</code></pre>
|
|
197
|
+
<p>The buyer first chooses tickets or seats. After reservation, the
|
|
198
|
+
checkout shows applicable add-ons, buyer details, waiver and payment.
|
|
199
|
+
<code>onComplete</code> hands the result to the host; the example
|
|
200
|
+
displays a neutral status instead of claiming that tickets are ready.
|
|
201
|
+
Connect that screen to <strong>your backend's authoritative order
|
|
202
|
+
status</strong> using <code>order.orderHash</code>, handle any required
|
|
203
|
+
ID verification and pending voucher, and provide support if the status
|
|
204
|
+
cannot be established. The callback alone is not proof of settlement or
|
|
205
|
+
ticket issuance.</p>
|
|
206
|
+
<p>Use <code>env: 'PROD'</code> with the matching production public
|
|
207
|
+
client ID when your integration is ready. This beta's stock payment UI
|
|
208
|
+
can ask a buyer to retry an unconfirmed payment; that wording does not
|
|
209
|
+
establish that retrying is safe. See <a href="#payments">Payments</a>
|
|
210
|
+
before using the stock flow in production.</p>
|
|
211
|
+
<h2 id="configuration-and-sessions">Configuration and sessions</h2>
|
|
212
|
+
<p><code>configureCheckout(config: TtfConfig)</code> wraps the shared
|
|
213
|
+
<code>configure</code> function, adds a browser
|
|
214
|
+
<code>localStorage</code> adapter and a browser checkout-auth popup, and
|
|
215
|
+
then applies your supplied options. Call it once at client startup,
|
|
216
|
+
before any SDK hook or <code>ttf</code> call. Calling it again replaces
|
|
217
|
+
the global configuration and can retire existing session state. Do not
|
|
218
|
+
reconfigure from a component render.</p>
|
|
219
|
+
<table>
|
|
220
|
+
<thead>
|
|
221
|
+
<tr>
|
|
222
|
+
<th>Option</th>
|
|
223
|
+
<th>Meaning</th>
|
|
224
|
+
</tr>
|
|
225
|
+
</thead>
|
|
226
|
+
<tbody>
|
|
227
|
+
<tr>
|
|
228
|
+
<td><code>clientId</code>, <code>clientSecret</code></td>
|
|
229
|
+
<td>Required strings. For a public browser integration use its
|
|
230
|
+
registered SDK client ID and an empty <code>clientSecret</code>; a
|
|
231
|
+
confidential secret belongs on a trusted server only.</td>
|
|
232
|
+
</tr>
|
|
233
|
+
<tr>
|
|
234
|
+
<td><code>env</code></td>
|
|
235
|
+
<td><code>PROD</code> (default), <code>STAG</code>, or <code>DEV</code>,
|
|
236
|
+
selecting <code>https://www.ticketfairy.com</code>,
|
|
237
|
+
<code>https://test.ticketfairy.com</code>, or
|
|
238
|
+
<code>https://sandbox.ticketfairy.com</code>.</td>
|
|
239
|
+
</tr>
|
|
240
|
+
<tr>
|
|
241
|
+
<td><code>baseUrl</code></td>
|
|
242
|
+
<td>Explicit host overrides <code>env</code>, including <code>''</code>
|
|
243
|
+
for same origin behind a proxy. A trailing <code>/api</code> is
|
|
244
|
+
normalized; the SDK appends <code>/api</code> for API calls.</td>
|
|
245
|
+
</tr>
|
|
246
|
+
<tr>
|
|
247
|
+
<td><code>sourceOrigin</code></td>
|
|
248
|
+
<td>Optional value of the <code>X-Source-Origin</code> request header
|
|
249
|
+
when required for your integration.</td>
|
|
250
|
+
</tr>
|
|
251
|
+
<tr>
|
|
252
|
+
<td><code>storage</code></td>
|
|
253
|
+
<td>Synchronous <code>StorageAdapter</code> overriding the browser
|
|
254
|
+
default. <code>getItem(key)</code>, <code>setItem(key, value)</code>,
|
|
255
|
+
and <code>removeItem(key)</code> are required; optional
|
|
256
|
+
<code>flush()</code> returns <code>Promise<void></code> for a
|
|
257
|
+
synchronous mirror with asynchronous persistence.</td>
|
|
258
|
+
</tr>
|
|
259
|
+
<tr>
|
|
260
|
+
<td><code>cookieAuth</code></td>
|
|
261
|
+
<td>Enables the header-backed Ticket Fairy session path. Use when the
|
|
262
|
+
integration is set up for a shared session or anonymous cookie cart;
|
|
263
|
+
browser cookie and CORS policies still apply.</td>
|
|
264
|
+
</tr>
|
|
265
|
+
<tr>
|
|
266
|
+
<td><code>withCredentials</code></td>
|
|
267
|
+
<td>Controls automatic HTTP cookie handling; defaults to true in
|
|
268
|
+
browsers. Cross-origin cookies also require correct server CORS/cookie
|
|
269
|
+
configuration and browser permission.</td>
|
|
270
|
+
</tr>
|
|
271
|
+
<tr>
|
|
272
|
+
<td><code>auth</code></td>
|
|
273
|
+
<td>Function returning additional headers or <code>undefined</code>;
|
|
274
|
+
called for each request. Headers normally merge after SDK headers, but
|
|
275
|
+
protected requests enforce session isolation: guest bootstrap strips
|
|
276
|
+
sensitive buyer/session headers after that merge. Use only credentials
|
|
277
|
+
appropriate to the browser.</td>
|
|
278
|
+
</tr>
|
|
279
|
+
<tr>
|
|
280
|
+
<td><code>accountAuth</code></td>
|
|
281
|
+
<td>Opts into first-party account auth routes; default is off. Requires
|
|
282
|
+
the corresponding backend journey and account authority.</td>
|
|
283
|
+
</tr>
|
|
284
|
+
<tr>
|
|
285
|
+
<td><code>sdkCheckoutPhoneAuth</code></td>
|
|
286
|
+
<td>Opts into the first-party phone checkout journey only when its
|
|
287
|
+
matching backend is deployed.</td>
|
|
288
|
+
</tr>
|
|
289
|
+
<tr>
|
|
290
|
+
<td><code>browserAuth</code>, <code>sdkCheckoutBrowserAuth</code></td>
|
|
291
|
+
<td>Browser authorization ports for specialized integrations. The web
|
|
292
|
+
wrapper supplies the checkout popup port when supported; an explicit
|
|
293
|
+
config value overrides it.</td>
|
|
294
|
+
</tr>
|
|
295
|
+
</tbody>
|
|
296
|
+
</table>
|
|
297
|
+
<p><code>localStorageAdapter</code> no-ops outside a browser;
|
|
298
|
+
<code>createMemoryStorage()</code> is an exported non-persistent adapter
|
|
299
|
+
useful for tests. Browser local storage is accessible to scripts in the
|
|
300
|
+
origin. Protect against XSS, avoid logging tokens, order links or
|
|
301
|
+
personal information, and pick an adapter and session lifetime
|
|
302
|
+
appropriate to your application. Logout/session changes need to be
|
|
303
|
+
coordinated with the host: stale UI or a cached profile is not proof of
|
|
304
|
+
authorization.</p>
|
|
305
|
+
<p>The public checkout sign-in path establishes an event-scoped buyer
|
|
306
|
+
identity. It does <strong>not</strong> grant a full account session for
|
|
307
|
+
private tickets or account preferences. A full account experience needs
|
|
308
|
+
the corresponding authorized session and backend routes. Two-factor and
|
|
309
|
+
other proof steps must finish before an authentication flow is complete.
|
|
310
|
+
Do not treat a checkout profile callback as permission to read private
|
|
311
|
+
account data.</p>
|
|
312
|
+
<h3 id="server-rendering">Server rendering</h3>
|
|
313
|
+
<p>The default storage adapter is server-safe, and the checkout hook
|
|
314
|
+
supplies an idle server snapshot. Payment elements, popups, DOM effects
|
|
315
|
+
and browser storage need a browser. In SSR frameworks, mount the
|
|
316
|
+
interactive checkout in a client component; do not run a browser
|
|
317
|
+
checkout on the server or share a configured module/session singleton
|
|
318
|
+
across server requests. Configure the browser before rendering that
|
|
319
|
+
client tree. Confirm that the framework processes the package's CSS
|
|
320
|
+
imports. Static import/SSR compatibility of a particular framework and
|
|
321
|
+
all third-party dependencies should be tested in that framework.</p>
|
|
322
|
+
<h2 id="embeddedcheckout">EmbeddedCheckout</h2>
|
|
323
|
+
<p><code>EmbeddedCheckout</code> owns a <code>CheckoutProvider</code>
|
|
324
|
+
and presents ticket/bundle or seat selection, add-ons, billing, waivers,
|
|
325
|
+
payment and inline completion as the flow requires. It must be under
|
|
326
|
+
<code>QueryClientProvider</code>.</p>
|
|
327
|
+
<p>Only <code>eventId</code> is required. Callbacks and options are
|
|
328
|
+
optional. The component owns its checkout provider; do not wrap it in
|
|
329
|
+
another <code>CheckoutProvider</code> to control its internal steps. The
|
|
330
|
+
host still supplies <code>QueryClientProvider</code>.</p>
|
|
331
|
+
<h3 id="what-the-buyer-sees">What the buyer sees</h3>
|
|
332
|
+
<ol type="1">
|
|
333
|
+
<li><strong>Tickets:</strong> the event's catalog, quantities,
|
|
334
|
+
applicable codes and any organizer-configured waiting list. Seated
|
|
335
|
+
events can open a seat map.</li>
|
|
336
|
+
<li><strong>Checkout:</strong> a selection summary and the applicable
|
|
337
|
+
add-ons, buyer/holder details, waiver and payment. The reservation timer
|
|
338
|
+
is displayed when available.</li>
|
|
339
|
+
<li><strong>Completion:</strong> <code>inline</code> shows the SDK's
|
|
340
|
+
confirmation view; <code>redirect</code> calls <code>onComplete</code>
|
|
341
|
+
and leaves the host to show the next screen. The quick start uses
|
|
342
|
+
<code>redirect</code> so the host can check order status before
|
|
343
|
+
presenting a receipt.</li>
|
|
344
|
+
</ol>
|
|
345
|
+
<p><code>initialView="seats"</code> opens the seat-selection view first
|
|
346
|
+
for an applicable seated event. <code>onViewChange</code> reports
|
|
347
|
+
<code>tickets</code>, <code>seats</code> or <code>checkout</code>; it
|
|
348
|
+
does not turn the component into a controlled router. For custom paths
|
|
349
|
+
or step arrangements, use <a href="#compose-sections">section
|
|
350
|
+
composition</a>.</p>
|
|
351
|
+
<p>When choosing <code>confirmationMode="redirect"</code>, provide
|
|
352
|
+
<code>onComplete</code> to receive the result and navigate to your
|
|
353
|
+
status page. Although the prop is optional in the type, without that
|
|
354
|
+
handoff the checkout remains mounted and no host status page is
|
|
355
|
+
reached.</p>
|
|
356
|
+
<h3 id="options-and-callbacks">Options and callbacks</h3>
|
|
357
|
+
<table>
|
|
358
|
+
<thead>
|
|
359
|
+
<tr>
|
|
360
|
+
<th>Prop</th>
|
|
361
|
+
<th>Type / default</th>
|
|
362
|
+
<th>Description</th>
|
|
363
|
+
</tr>
|
|
364
|
+
</thead>
|
|
365
|
+
<tbody>
|
|
366
|
+
<tr>
|
|
367
|
+
<td><code>eventId</code></td>
|
|
368
|
+
<td><code>string</code></td>
|
|
369
|
+
<td>Event to sell.</td>
|
|
370
|
+
</tr>
|
|
371
|
+
<tr>
|
|
372
|
+
<td><code>onComplete</code></td>
|
|
373
|
+
<td><code>(order: PlaceOrderResult) => void</code></td>
|
|
374
|
+
<td>Result of placement, including an asynchronously pending
|
|
375
|
+
payment.</td>
|
|
376
|
+
</tr>
|
|
377
|
+
<tr>
|
|
378
|
+
<td><code>confirmationMode</code></td>
|
|
379
|
+
<td><code>'inline' | 'redirect'</code>; <code>inline</code></td>
|
|
380
|
+
<td>Inline renders verification/confirmation. Redirect shows a
|
|
381
|
+
transition; use <code>onComplete</code> to navigate.</td>
|
|
382
|
+
</tr>
|
|
383
|
+
<tr>
|
|
384
|
+
<td><code>initialView</code></td>
|
|
385
|
+
<td><code>'tickets' | 'seats'</code>; <code>tickets</code></td>
|
|
386
|
+
<td>Initial selection view.</td>
|
|
387
|
+
</tr>
|
|
388
|
+
<tr>
|
|
389
|
+
<td><code>onViewChange</code></td>
|
|
390
|
+
<td><code>(view: 'tickets' | 'seats' | 'checkout') => void</code></td>
|
|
391
|
+
<td>Reports the visible flow view.</td>
|
|
392
|
+
</tr>
|
|
393
|
+
<tr>
|
|
394
|
+
<td><code>autoScroll</code></td>
|
|
395
|
+
<td><code>boolean</code>; <code>true</code></td>
|
|
396
|
+
<td>Scroll to buyer details after reservation.</td>
|
|
397
|
+
</tr>
|
|
398
|
+
<tr>
|
|
399
|
+
<td><code>requireEmailConfirmation</code></td>
|
|
400
|
+
<td><code>boolean</code>; <code>true</code></td>
|
|
401
|
+
<td>Require guests to repeat their email.</td>
|
|
402
|
+
</tr>
|
|
403
|
+
<tr>
|
|
404
|
+
<td><code>collectTicketHolders</code></td>
|
|
405
|
+
<td><code>boolean</code>; <code>true</code></td>
|
|
406
|
+
<td>Collect one named holder per ticket.</td>
|
|
407
|
+
</tr>
|
|
408
|
+
<tr>
|
|
409
|
+
<td><code>collectHolderContact</code></td>
|
|
410
|
+
<td><code>boolean</code>; <code>true</code></td>
|
|
411
|
+
<td>Collect holder contact details when holders are collected.</td>
|
|
412
|
+
</tr>
|
|
413
|
+
<tr>
|
|
414
|
+
<td><code>skipBillingWhenProfileComplete</code></td>
|
|
415
|
+
<td><code>boolean</code>; <code>false</code></td>
|
|
416
|
+
<td>Skip billing only for an eligible complete signed-in profile and
|
|
417
|
+
compatible holder/custom-field requirements. Payment is not skipped. See
|
|
418
|
+
the privacy and opt-in limitations below.</td>
|
|
419
|
+
</tr>
|
|
420
|
+
<tr>
|
|
421
|
+
<td><code>onLogin</code></td>
|
|
422
|
+
<td><code>(email?: string) => void</code></td>
|
|
423
|
+
<td>Opens host login instead of the built-in modal; the email may be an
|
|
424
|
+
existing-account match.</td>
|
|
425
|
+
</tr>
|
|
426
|
+
<tr>
|
|
427
|
+
<td><code>auth</code></td>
|
|
428
|
+
<td><code>false | EmbeddedCheckoutAuthOptions</code></td>
|
|
429
|
+
<td>Disable or configure the built-in modal; ignored when
|
|
430
|
+
<code>onLogin</code> is supplied.</td>
|
|
431
|
+
</tr>
|
|
432
|
+
<tr>
|
|
433
|
+
<td><code>privacyPolicy</code></td>
|
|
434
|
+
<td><code>CheckoutPrivacyPolicy</code></td>
|
|
435
|
+
<td><code>{ url, brandName, linkLabel? }</code>; adds the host's
|
|
436
|
+
required privacy acknowledgement.</td>
|
|
437
|
+
</tr>
|
|
438
|
+
<tr>
|
|
439
|
+
<td><code>additionalConditions</code></td>
|
|
440
|
+
<td><code>EventCondition[]</code></td>
|
|
441
|
+
<td>Host acknowledgements
|
|
442
|
+
<code>{ id, name, content, isRequired }</code>; required ones gate
|
|
443
|
+
payment. Content is rendered as HTML: supply trusted or sanitized
|
|
444
|
+
HTML.</td>
|
|
445
|
+
</tr>
|
|
446
|
+
<tr>
|
|
447
|
+
<td><code>ttfOptInLabel</code>, <code>brandOptInLabel</code></td>
|
|
448
|
+
<td><code>string</code></td>
|
|
449
|
+
<td>Override the Ticket Fairy opt-in label or add a brand opt-in. The
|
|
450
|
+
privacy-policy option changes the Ticket Fairy control as described
|
|
451
|
+
below.</td>
|
|
452
|
+
</tr>
|
|
453
|
+
<tr>
|
|
454
|
+
<td><code>initialPromoCode</code>, <code>referrer</code>,
|
|
455
|
+
<code>readAttributionFromUrl</code></td>
|
|
456
|
+
<td><code>string</code>, <code>string | number</code>,
|
|
457
|
+
<code>boolean</code></td>
|
|
458
|
+
<td>Apply a code and attribution; URL reading defaults to
|
|
459
|
+
<code>true</code>.</td>
|
|
460
|
+
</tr>
|
|
461
|
+
<tr>
|
|
462
|
+
<td><code>showTestCardHint</code></td>
|
|
463
|
+
<td><code>boolean</code>; <code>false</code></td>
|
|
464
|
+
<td>Demo-only sandbox card copy.</td>
|
|
465
|
+
</tr>
|
|
466
|
+
<tr>
|
|
467
|
+
<td><code>theme</code>, <code>locale</code>, <code>messages</code>,
|
|
468
|
+
<code>className</code></td>
|
|
469
|
+
<td><code>CheckoutTheme</code>, <code>LocaleCode</code>,
|
|
470
|
+
<code>Partial<Messages></code>, <code>string</code></td>
|
|
471
|
+
<td>Appearance, copy and root class.</td>
|
|
472
|
+
</tr>
|
|
473
|
+
</tbody>
|
|
474
|
+
</table>
|
|
475
|
+
<p><code>EmbeddedCheckoutAuthOptions</code> accepts
|
|
476
|
+
<code>allowRegistration</code>, <code>allowPasswordReset</code>,
|
|
477
|
+
<code>requireRegistrationAddress</code>, <code>logoUrl</code>,
|
|
478
|
+
<code>onCheckoutAuthenticated(profile: CheckoutBuyerProfile)</code> and
|
|
479
|
+
<code>onAuthenticated(profile: TfProfile)</code>. The two callbacks
|
|
480
|
+
represent different session authorities; use the one appropriate to your
|
|
481
|
+
configured journey. <code>requireRegistrationAddress={false}</code> does
|
|
482
|
+
not remove the address requirement for the public checkout registration
|
|
483
|
+
or account-completion journey; those paths force it on in this
|
|
484
|
+
version.</p>
|
|
485
|
+
<h3 id="example-brand-the-ready-made-checkout">Example: brand the
|
|
486
|
+
ready-made checkout</h3>
|
|
487
|
+
<p>Use the same <code>QueryClientProvider</code> and one-time
|
|
488
|
+
configuration as the quick start. Here <code>onViewChange</code> can
|
|
489
|
+
update surrounding page content; <code>onComplete</code> passes the
|
|
490
|
+
order result to the host's status screen.</p>
|
|
491
|
+
<pre class="tsx"><code>import { useState } from 'react'
|
|
492
|
+
import { EmbeddedCheckout, type PlaceOrderResult } from 'tf-checkout-react'
|
|
493
|
+
|
|
494
|
+
export function BrandedCheckout() {
|
|
495
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
496
|
+
const [view, setView] = useState('tickets')
|
|
497
|
+
|
|
498
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
499
|
+
|
|
500
|
+
return (
|
|
501
|
+
<main>
|
|
502
|
+
<p>Checkout step: {view}</p>
|
|
503
|
+
<EmbeddedCheckout
|
|
504
|
+
eventId="EVENT_ID"
|
|
505
|
+
confirmationMode="redirect"
|
|
506
|
+
onComplete={setOrder}
|
|
507
|
+
onViewChange={setView}
|
|
508
|
+
initialPromoCode="WELCOME"
|
|
509
|
+
referrer="REFERRER_ID"
|
|
510
|
+
readAttributionFromUrl={false}
|
|
511
|
+
locale="en-US"
|
|
512
|
+
messages={{ 'tickets.getTickets': 'Continue to checkout' }}
|
|
513
|
+
theme={{ colorScheme: 'light', accent: '#6b2bd9', radiusCard: '16px' }}
|
|
514
|
+
className="festival-checkout"
|
|
515
|
+
/>
|
|
516
|
+
</main>
|
|
517
|
+
)
|
|
518
|
+
}</code></pre>
|
|
519
|
+
<p>Use a promo or referral only when it belongs to this visit. Remove
|
|
520
|
+
those props when they do not apply. By default the component also reads
|
|
521
|
+
<code>promo</code> / <code>promo_code</code> and <code>ttf_r</code> /
|
|
522
|
+
<code>referrer_id</code> from the URL. The example disables that
|
|
523
|
+
behavior so the host controls attribution. <code>initialPromoCode</code>
|
|
524
|
+
is applied once when the catalog mounts. It is not a guarantee that a
|
|
525
|
+
code is valid. <code>theme</code> changes SDK design tokens,
|
|
526
|
+
<code>className</code> lets your stylesheet target this instance, and
|
|
527
|
+
<code>messages</code> overrides individual SDK copy keys.
|
|
528
|
+
<code>locale</code> and <code>messages</code> do not automatically
|
|
529
|
+
translate the event's own content or an external payment-provider page.
|
|
530
|
+
See <a href="#styling-and-localization">Styling and localization</a> for
|
|
531
|
+
the available theme tokens and locales.</p>
|
|
532
|
+
<h3 id="example-connect-host-navigation-and-sign-in">Example: connect
|
|
533
|
+
host navigation and sign-in</h3>
|
|
534
|
+
<p>Pass callbacks when the surrounding application owns these actions.
|
|
535
|
+
For example, <code>openSignIn</code> can open your sign-in UI, and
|
|
536
|
+
<code>onOrder</code> can hand the result to your order-status screen.
|
|
537
|
+
<code>onViewChange</code> is a notification, not a way to force the
|
|
538
|
+
checkout to a particular step.</p>
|
|
539
|
+
<pre class="tsx"><code>import { EmbeddedCheckout, type PlaceOrderResult } from 'tf-checkout-react'
|
|
540
|
+
|
|
541
|
+
type View = 'tickets' | 'seats' | 'checkout'
|
|
542
|
+
|
|
543
|
+
export function HostCheckout(props: {
|
|
544
|
+
eventId: string
|
|
545
|
+
openSignIn: (email?: string) => void
|
|
546
|
+
showOrderStatus: (order: PlaceOrderResult) => void
|
|
547
|
+
reportView: (view: View) => void
|
|
548
|
+
}) {
|
|
549
|
+
return (
|
|
550
|
+
<EmbeddedCheckout
|
|
551
|
+
eventId={props.eventId}
|
|
552
|
+
onLogin={props.openSignIn}
|
|
553
|
+
onViewChange={props.reportView}
|
|
554
|
+
confirmationMode="redirect"
|
|
555
|
+
onComplete={props.showOrderStatus}
|
|
556
|
+
/>
|
|
557
|
+
)
|
|
558
|
+
}</code></pre>
|
|
559
|
+
<p>The email passed to <code>openSignIn</code> can be absent. Supplying
|
|
560
|
+
<code>onLogin</code> replaces the built-in login modal; your host must
|
|
561
|
+
complete the appropriate sign-in journey. An event-scoped checkout
|
|
562
|
+
identity is not automatically a full account session.
|
|
563
|
+
<code>showOrderStatus</code> must check the order and provider rather
|
|
564
|
+
than treating the callback as a paid receipt.</p>
|
|
565
|
+
<h3 id="resume-a-server-cart">Resume a server cart</h3>
|
|
566
|
+
<p><code>ResumedCheckout</code> is a ready-made layout for a cart that
|
|
567
|
+
<strong>already exists in the current session</strong>, such as one
|
|
568
|
+
created by a preceding resale flow. It starts with buyer details and
|
|
569
|
+
payment; it does not show ticket selection, create the cart, or accept a
|
|
570
|
+
cart ID. Its <code>confirmationMode</code> defaults to
|
|
571
|
+
<code>redirect</code>. Provide <code>onComplete</code> for the
|
|
572
|
+
redirect/status handoff: without it the successful flow remains on its
|
|
573
|
+
loading transition. Alternatively select <code>inline</code> and account
|
|
574
|
+
for the confirmation and verification-copy limitations below.</p>
|
|
575
|
+
<pre class="tsx"><code>import { useState } from 'react'
|
|
576
|
+
import { ResumedCheckout, type PlaceOrderResult } from 'tf-checkout-react'
|
|
577
|
+
|
|
578
|
+
// Mount only after your preceding flow created a cart in this session.
|
|
579
|
+
export function ResumePage() {
|
|
580
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
581
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
582
|
+
|
|
583
|
+
return (
|
|
584
|
+
<ResumedCheckout
|
|
585
|
+
eventId="EVENT_ID"
|
|
586
|
+
isFromResale
|
|
587
|
+
confirmationMode="redirect"
|
|
588
|
+
onComplete={setOrder}
|
|
589
|
+
/>
|
|
590
|
+
)
|
|
591
|
+
}</code></pre>
|
|
592
|
+
<p>Wrap this page in the same <code>QueryClientProvider</code> as the
|
|
593
|
+
quick start. Set <code>isFromResale</code> only for the resale path.
|
|
594
|
+
Check the result with your backend, including any verification or
|
|
595
|
+
pending-payment requirements. If the preceding flow did not create a
|
|
596
|
+
cart, or the session changed, return the buyer to that flow instead of
|
|
597
|
+
assuming a cart can be resumed.</p>
|
|
598
|
+
<p>Props are <code>eventId</code> (required), <code>isFromResale</code>
|
|
599
|
+
(default <code>false</code>), <code>onComplete</code>,
|
|
600
|
+
<code>confirmationMode</code>, <code>requireEmailConfirmation</code>,
|
|
601
|
+
<code>collectTicketHolders</code>, <code>collectHolderContact</code>
|
|
602
|
+
(each default <code>true</code>), <code>privacyPolicy</code>,
|
|
603
|
+
<code>brandOptInLabel</code>, <code>additionalConditions</code>,
|
|
604
|
+
<code>theme</code> and <code>className</code>. Unlike
|
|
605
|
+
<code>EmbeddedCheckout</code>, this component does not accept
|
|
606
|
+
<code>locale</code>, <code>messages</code>, <code>auth</code> or
|
|
607
|
+
<code>onLogin</code> props in this version.</p>
|
|
608
|
+
<h2 id="compose-sections">Compose sections</h2>
|
|
609
|
+
<p>Use sections when the ready-made flow does not fit your page. Put all
|
|
610
|
+
sections for one checkout inside a single <code>CheckoutProvider</code>,
|
|
611
|
+
under the host's <code>QueryClientProvider</code>. The provider shares
|
|
612
|
+
one checkout instance with its children. The default store is app-wide:
|
|
613
|
+
mounting two flows does not create two independent carts. Configure the
|
|
614
|
+
SDK once, before mounting the provider.</p>
|
|
615
|
+
<p>The examples below assume the quick start's
|
|
616
|
+
<code>configureCheckout</code> and <code>QueryClientProvider</code>
|
|
617
|
+
setup. They demonstrate page layout and section wiring; your host still
|
|
618
|
+
needs to implement order-status reconciliation, expiry and recovery for
|
|
619
|
+
its event and enabled payment methods.</p>
|
|
620
|
+
<p>These are wiring recipes, not complete buyer navigation. Each
|
|
621
|
+
includes a return from the seat view and keeps <code>Tickets</code>
|
|
622
|
+
mounted while switching views. The host still needs to implement Edit
|
|
623
|
+
and Back from checkout (including payment to billing), preserve entered
|
|
624
|
+
details, handle seat holds and cart expiry, and guard event/session
|
|
625
|
+
changes and in-flight or retained payments. Use
|
|
626
|
+
<code>EmbeddedCheckout</code> for its built-in Back and guarded Edit
|
|
627
|
+
behavior. The seat-view Back button only changes views: it does not
|
|
628
|
+
itself release reserved seats or cancel an already-started reservation
|
|
629
|
+
or cart priming. Coordinate any in-flight work and the hold's expiry or
|
|
630
|
+
release under your deployed backend contract before permitting a
|
|
631
|
+
conflicting selection.</p>
|
|
632
|
+
<h3 id="single-page-checkout">Single-page checkout</h3>
|
|
633
|
+
<p>This layout keeps the buyer on one browser page. Selecting tickets or
|
|
634
|
+
seats reveals a single combined form with add-ons, buyer details, waiver
|
|
635
|
+
and payment. The host supplies the status view after
|
|
636
|
+
<code>onComplete</code>.</p>
|
|
637
|
+
<pre class="tsx"><code>import { useState } from 'react'
|
|
638
|
+
import {
|
|
639
|
+
AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
|
|
640
|
+
Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
|
|
641
|
+
} from 'tf-checkout-react'
|
|
642
|
+
|
|
643
|
+
function SinglePageContents({ eventId }: { eventId: string }) {
|
|
644
|
+
const checkout = useCheckoutContext()
|
|
645
|
+
const [view, setView] = useState<'tickets' | 'seats' | 'checkout'>('tickets')
|
|
646
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
647
|
+
|
|
648
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
649
|
+
|
|
650
|
+
return (
|
|
651
|
+
<main>
|
|
652
|
+
<div hidden={view !== 'tickets'}>
|
|
653
|
+
<Tickets
|
|
654
|
+
eventId={eventId}
|
|
655
|
+
onContinue={() => setView('checkout')}
|
|
656
|
+
onSelectSeats={() => setView('seats')}
|
|
657
|
+
/>
|
|
658
|
+
</div>
|
|
659
|
+
{view === 'seats' && (
|
|
660
|
+
<>
|
|
661
|
+
<button type="button" onClick={() => setView('tickets')}>Back to tickets</button>
|
|
662
|
+
<SeatMap eventId={eventId} onContinue={() => setView('checkout')} />
|
|
663
|
+
</>
|
|
664
|
+
)}
|
|
665
|
+
{view === 'checkout' && (
|
|
666
|
+
<>
|
|
667
|
+
<TimerBanner seconds={checkout.secondsLeft} />
|
|
668
|
+
<AddOns eventId={eventId} />
|
|
669
|
+
<BillingInfo
|
|
670
|
+
eventId={eventId}
|
|
671
|
+
requireEmailConfirmation
|
|
672
|
+
collectTicketHolders
|
|
673
|
+
collectHolderContact
|
|
674
|
+
/>
|
|
675
|
+
<WaiverSigning eventId={eventId} />
|
|
676
|
+
<Payment
|
|
677
|
+
eventId={eventId}
|
|
678
|
+
requireEmailConfirmation
|
|
679
|
+
collectTicketHolders
|
|
680
|
+
requireHolderContact
|
|
681
|
+
onComplete={setOrder}
|
|
682
|
+
/>
|
|
683
|
+
</>
|
|
684
|
+
)}
|
|
685
|
+
</main>
|
|
686
|
+
)
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
export function SinglePageCheckout({ eventId }: { eventId: string }) {
|
|
690
|
+
return (
|
|
691
|
+
<CheckoutProvider theme={{ colorScheme: 'light', accent: '#2458d3' }}>
|
|
692
|
+
<SinglePageContents eventId={eventId} />
|
|
693
|
+
</CheckoutProvider>
|
|
694
|
+
)
|
|
695
|
+
}</code></pre>
|
|
696
|
+
<p><code>Tickets.onContinue</code> fires after the cart is primed.
|
|
697
|
+
<code>onSelectSeats</code> opens the seat view; without it the
|
|
698
|
+
seat-selection button is hidden in a composed <code>Tickets</code>
|
|
699
|
+
section. <code>SeatMap.onContinue</code> runs after seats are added and
|
|
700
|
+
priced. Without an <code>onContinue</code> prop,
|
|
701
|
+
<code>BillingInfo</code> and <code>AddOns</code> use their combined-form
|
|
702
|
+
behavior instead of showing a separate Continue button. Match the
|
|
703
|
+
billing and payment email/holder settings, as shown. <code>AddOns</code>
|
|
704
|
+
renders nothing when the event has no applicable add-ons; do not skip a
|
|
705
|
+
required one.</p>
|
|
706
|
+
<h3 id="step-by-step-checkout">Step-by-step checkout</h3>
|
|
707
|
+
<p>To make billing and payment separate steps, give
|
|
708
|
+
<code>BillingInfo</code> an <code>onContinue</code> callback. It then
|
|
709
|
+
validates and saves the buyer details before moving on. This example
|
|
710
|
+
keeps the checkout provider mounted for the whole flow; it does not
|
|
711
|
+
change URLs or assume a browser refresh can resume the in-memory
|
|
712
|
+
layout.</p>
|
|
713
|
+
<pre class="tsx"><code>import { useState } from 'react'
|
|
714
|
+
import {
|
|
715
|
+
AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
|
|
716
|
+
Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
|
|
717
|
+
} from 'tf-checkout-react'
|
|
718
|
+
|
|
719
|
+
type Step = 'tickets' | 'seats' | 'details' | 'payment'
|
|
720
|
+
|
|
721
|
+
function StepContents({ eventId }: { eventId: string }) {
|
|
722
|
+
const checkout = useCheckoutContext()
|
|
723
|
+
const [step, setStep] = useState<Step>('tickets')
|
|
724
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
725
|
+
|
|
726
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
727
|
+
|
|
728
|
+
return (
|
|
729
|
+
<main>
|
|
730
|
+
{(step === 'details' || step === 'payment') && (
|
|
731
|
+
<TimerBanner seconds={checkout.secondsLeft} />
|
|
732
|
+
)}
|
|
733
|
+
<div hidden={step !== 'tickets'}>
|
|
734
|
+
<Tickets
|
|
735
|
+
eventId={eventId}
|
|
736
|
+
onContinue={() => setStep('details')}
|
|
737
|
+
onSelectSeats={() => setStep('seats')}
|
|
738
|
+
/>
|
|
739
|
+
</div>
|
|
740
|
+
{step === 'seats' && (
|
|
741
|
+
<>
|
|
742
|
+
<button type="button" onClick={() => setStep('tickets')}>Back to tickets</button>
|
|
743
|
+
<SeatMap eventId={eventId} onContinue={() => setStep('details')} />
|
|
744
|
+
</>
|
|
745
|
+
)}
|
|
746
|
+
{step === 'details' && (
|
|
747
|
+
<BillingInfo
|
|
748
|
+
eventId={eventId}
|
|
749
|
+
requireEmailConfirmation
|
|
750
|
+
collectTicketHolders
|
|
751
|
+
collectHolderContact
|
|
752
|
+
onContinue={() => setStep('payment')}
|
|
753
|
+
/>
|
|
754
|
+
)}
|
|
755
|
+
{step === 'payment' && (
|
|
756
|
+
<>
|
|
757
|
+
<AddOns eventId={eventId} />
|
|
758
|
+
<WaiverSigning eventId={eventId} />
|
|
759
|
+
<Payment
|
|
760
|
+
eventId={eventId}
|
|
761
|
+
requireEmailConfirmation
|
|
762
|
+
collectTicketHolders
|
|
763
|
+
requireHolderContact
|
|
764
|
+
onComplete={setOrder}
|
|
765
|
+
/>
|
|
766
|
+
</>
|
|
767
|
+
)}
|
|
768
|
+
</main>
|
|
769
|
+
)
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
export function StepCheckout({ eventId }: { eventId: string }) {
|
|
773
|
+
return <CheckoutProvider><StepContents eventId={eventId} /></CheckoutProvider>
|
|
774
|
+
}</code></pre>
|
|
775
|
+
<p>For separate routes, keep the provider above the routed pages and
|
|
776
|
+
connect the callbacks to your router. A full page reload is a different
|
|
777
|
+
session/navigation problem: <code>ResumedCheckout</code> can attach only
|
|
778
|
+
to an existing cart in the current session, and the old 1.x localStorage
|
|
779
|
+
state is not a migration format. Handle expired reservations, browser
|
|
780
|
+
Back, buyer changes and unconfirmed payments before enabling navigation
|
|
781
|
+
or a new purchase. Do not unmount or reset an in-flight payment merely
|
|
782
|
+
to move between steps.</p>
|
|
783
|
+
<p>The step example is a progressive layout: the next step appears after
|
|
784
|
+
a successful callback. A router can replace <code>setStep</code>, but
|
|
785
|
+
the SDK does not supply a route-based checkout or implement your browser
|
|
786
|
+
Back handling. Do not assume that a successful TypeScript build verifies
|
|
787
|
+
route, refresh or payment behavior; test those flows with your own
|
|
788
|
+
backend and providers.</p>
|
|
789
|
+
<h3 id="accordion-checkout">Accordion checkout</h3>
|
|
790
|
+
<p>The SDK does not export a named accordion component. This host-built
|
|
791
|
+
layout uses native HTML disclosures to group the same SDK sections. The
|
|
792
|
+
payment field stays outside the disclosures so it remains visible while
|
|
793
|
+
the buyer pays. It uses the configuration and
|
|
794
|
+
<code>QueryClientProvider</code> from the quick start.</p>
|
|
795
|
+
<pre class="tsx"><code>import { useState } from 'react'
|
|
796
|
+
import {
|
|
797
|
+
AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
|
|
798
|
+
Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
|
|
799
|
+
} from 'tf-checkout-react'
|
|
800
|
+
|
|
801
|
+
function AccordionContents({ eventId }: { eventId: string }) {
|
|
802
|
+
const checkout = useCheckoutContext()
|
|
803
|
+
const [view, setView] = useState<'tickets' | 'seats' | 'checkout'>('tickets')
|
|
804
|
+
const [order, setOrder] = useState<PlaceOrderResult | null>(null)
|
|
805
|
+
|
|
806
|
+
if (order) return <p role="status">Checking your order status…</p>
|
|
807
|
+
|
|
808
|
+
return (
|
|
809
|
+
<main>
|
|
810
|
+
<div hidden={view !== 'tickets'}>
|
|
811
|
+
<Tickets
|
|
812
|
+
eventId={eventId}
|
|
813
|
+
onContinue={() => setView('checkout')}
|
|
814
|
+
onSelectSeats={() => setView('seats')}
|
|
815
|
+
/>
|
|
816
|
+
</div>
|
|
817
|
+
{view === 'seats' && (
|
|
818
|
+
<>
|
|
819
|
+
<button type="button" onClick={() => setView('tickets')}>Back to tickets</button>
|
|
820
|
+
<SeatMap eventId={eventId} onContinue={() => setView('checkout')} />
|
|
821
|
+
</>
|
|
822
|
+
)}
|
|
823
|
+
{view === 'checkout' && (
|
|
824
|
+
<>
|
|
825
|
+
<TimerBanner seconds={checkout.secondsLeft} />
|
|
826
|
+
<details open>
|
|
827
|
+
<summary>Add-ons</summary>
|
|
828
|
+
<AddOns eventId={eventId} />
|
|
829
|
+
</details>
|
|
830
|
+
<details open>
|
|
831
|
+
<summary>Buyer and ticket holders</summary>
|
|
832
|
+
<BillingInfo
|
|
833
|
+
eventId={eventId}
|
|
834
|
+
requireEmailConfirmation
|
|
835
|
+
collectTicketHolders
|
|
836
|
+
collectHolderContact
|
|
837
|
+
/>
|
|
838
|
+
</details>
|
|
839
|
+
<details open>
|
|
840
|
+
<summary>Waiver</summary>
|
|
841
|
+
<WaiverSigning eventId={eventId} />
|
|
842
|
+
</details>
|
|
843
|
+
<Payment
|
|
844
|
+
eventId={eventId}
|
|
845
|
+
requireEmailConfirmation
|
|
846
|
+
collectTicketHolders
|
|
847
|
+
requireHolderContact
|
|
848
|
+
onComplete={setOrder}
|
|
849
|
+
/>
|
|
850
|
+
</>
|
|
851
|
+
)}
|
|
852
|
+
</main>
|
|
853
|
+
)
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
export function AccordionCheckout({ eventId }: { eventId: string }) {
|
|
857
|
+
return <CheckoutProvider><AccordionContents eventId={eventId} /></CheckoutProvider>
|
|
858
|
+
}</code></pre>
|
|
859
|
+
<p>The buyer reserves tickets or seats, then can open or close the form
|
|
860
|
+
groups. Closing a <code><details></code> element hides its
|
|
861
|
+
contents without unmounting them. In a production accordion, open the
|
|
862
|
+
relevant group when validation needs the buyer's attention, and make
|
|
863
|
+
sure required add-ons, fields and waivers cannot be missed. Do not hide
|
|
864
|
+
or replace the active payment field during a payment attempt. As with
|
|
865
|
+
the other examples, replace the status placeholder with your own
|
|
866
|
+
verified order-status and support flow.</p>
|
|
867
|
+
<p><code>CheckoutProvider</code> props are <code>children</code>
|
|
868
|
+
(required), <code>value?: UseCheckout</code>,
|
|
869
|
+
<code>theme?: CheckoutTheme</code>, <code>locale?: LocaleCode</code>,
|
|
870
|
+
<code>messages?: Partial<Messages></code>, and
|
|
871
|
+
<code>className?: string</code>. Use <code>useCheckoutContext()</code>
|
|
872
|
+
inside the provider to read the current checkout and
|
|
873
|
+
<code>useCheckoutValidation()</code> to coordinate validation between
|
|
874
|
+
sections. The provider's default checkout includes the installment
|
|
875
|
+
picker. If supplying your own <code>value</code>, wire any custom
|
|
876
|
+
payment ports you need when creating that checkout.</p>
|
|
877
|
+
<h2 id="checkout-lifecycle">Checkout lifecycle</h2>
|
|
878
|
+
<ol type="1">
|
|
879
|
+
<li>Load the current event catalog and reserve current selections with
|
|
880
|
+
<code>setTickets(eventId, selections)</code>, or reserve seats and call
|
|
881
|
+
<code>setSeats</code> / <code>setSeatsIo</code>. Alternatively
|
|
882
|
+
<code>resumeCart</code> attaches to a cart already owned by this browser
|
|
883
|
+
session. The server owns inventory, expiry and final prices.</li>
|
|
884
|
+
<li>Read <code>customFields</code>, <code>buyerFields</code>,
|
|
885
|
+
conditions, required add-ons, waiver, pricing and payment availability
|
|
886
|
+
from the primed snapshot. Collect the required buyer/holder answers and
|
|
887
|
+
consent. Save them through the corresponding setters. Reprice after
|
|
888
|
+
add-on or currency changes.</li>
|
|
889
|
+
<li>Render only the methods offered for this event and compatible with
|
|
890
|
+
the host. Validate required information, then
|
|
891
|
+
<code>await placeOrder(method)</code> once per buyer action. The engine
|
|
892
|
+
checks preconditions and coordinates concurrent placement.</li>
|
|
893
|
+
<li>Handle the returned <code>PlaceOrderResult</code>, including
|
|
894
|
+
<code>pending</code>, and any ID verification. A result, a redirect, or
|
|
895
|
+
a closed popup alone does not prove that money settled. Reconcile
|
|
896
|
+
authoritative order and provider status before fulfilling or starting a
|
|
897
|
+
new payment when an outcome is uncertain.</li>
|
|
898
|
+
</ol>
|
|
899
|
+
<p><code>status</code> can be <code>idle</code>, <code>priming</code>,
|
|
900
|
+
<code>ready</code>, <code>repricing</code>, <code>placing</code>,
|
|
901
|
+
<code>succeeded</code>, <code>expired</code> or <code>error</code>.
|
|
902
|
+
<code>isBusy</code> includes cart/order operations and an outstanding
|
|
903
|
+
waiver save. <code>secondsLeft</code> is an optional, whole-second
|
|
904
|
+
display countdown derived from <code>expiresAt</code>. When it reaches
|
|
905
|
+
zero the hook expires the cart unless an order is being placed or has
|
|
906
|
+
succeeded. An expired reservation requires the buyer to start again; a
|
|
907
|
+
displayed countdown does not extend a server reservation.</p>
|
|
908
|
+
<p><code>reset()</code> starts a reset and returns <code>void</code>;
|
|
909
|
+
<code>await resetWhenSettled()</code> returns <code>true</code> only
|
|
910
|
+
when reset completed. While a payment is in flight, reset waits for it.
|
|
911
|
+
It returns <code>false</code> if an order must be retained because money
|
|
912
|
+
may have moved, or the checkout is retired. A <code>false</code> result
|
|
913
|
+
does not identify which reason applies. Show neutral guidance and check
|
|
914
|
+
the current session and authoritative order/provider status before
|
|
915
|
+
choosing recovery. <code>PAID_ORDER_PENDING_MESSAGE</code> contains an
|
|
916
|
+
instruction to press Pay again; do not show it for every
|
|
917
|
+
<code>false</code> result or use it as proof that a retry is safe. Do
|
|
918
|
+
not assume a timeout, network error or closed provider page means the
|
|
919
|
+
charge failed. A custom provider page must settle with
|
|
920
|
+
<code>{ event: 'dismiss' }</code> on close/unmount, and other custom
|
|
921
|
+
payment ports must settle, or a waiting reset cannot finish.</p>
|
|
922
|
+
<p>The beta.27 declaration comments for <code>reset</code> and
|
|
923
|
+
<code>PAID_ORDER_PENDING_MESSAGE</code> say pressing Pay again finishes
|
|
924
|
+
an unconfirmed order; the <code>resetWhenSettled</code> comment also
|
|
925
|
+
omits retired checkouts as a reason for <code>false</code>. Those
|
|
926
|
+
comments do not establish that a retry is safe. Use the session and
|
|
927
|
+
reconciliation guidance above.</p>
|
|
928
|
+
<p>Stock <code>Payment</code> can display an engine message telling the
|
|
929
|
+
buyer to press Pay again when payment is unconfirmed. That wording does
|
|
930
|
+
not establish that a retry is safe. If neutral buyer guidance is
|
|
931
|
+
required for uncertain outcomes, use a custom payment flow with
|
|
932
|
+
host-controlled error UI, retain the order and reconcile the current
|
|
933
|
+
session and authoritative order/provider status before recovery.</p>
|
|
934
|
+
<h3 id="tickets-codes-seats-and-waiting-lists">Tickets, codes, seats and
|
|
935
|
+
waiting lists</h3>
|
|
936
|
+
<p><code>Tickets</code> reads the catalog, presents the event's
|
|
937
|
+
promo/access-code controls and waiting-list state, and reserves selected
|
|
938
|
+
ticket lines. <code>initialPromoCode</code> applies once on mount. The
|
|
939
|
+
web picker reads <code>promo</code> / <code>promo_code</code> and
|
|
940
|
+
<code>ttf_r</code> / <code>referrer_id</code> from the URL by default;
|
|
941
|
+
explicit props take precedence. Set
|
|
942
|
+
<code>readAttributionFromUrl={false}</code> to disable this. An
|
|
943
|
+
ambiguous numeric <code>?r=</code> can mean a promotion or referral and
|
|
944
|
+
is not classified by this SDK. Pass a referrer only when its meaning is
|
|
945
|
+
known.</p>
|
|
946
|
+
<p>For headless catalogs, <code>hooks.useTicketsWithMeta(eventId)</code>
|
|
947
|
+
exposes <code>tickets</code>, <code>promo</code>,
|
|
948
|
+
<code>waitingList</code> and <code>bundles</code>. After
|
|
949
|
+
<code>applyPromoCode</code>, refetch the catalog to display changed
|
|
950
|
+
prices or unlocked tickets. Private-event access is a separate server
|
|
951
|
+
operation, <code>ttf.events.authenticate(eventId, password)</code>;
|
|
952
|
+
refetch after success. Do not treat a code or an old catalog as proof
|
|
953
|
+
inventory is reserved. The versioned waiting-list definition controls
|
|
954
|
+
eligibility and choices; <code>waitingList.state</code> can be
|
|
955
|
+
<code>open</code>, <code>closed</code>, <code>hidden</code> or
|
|
956
|
+
<code>unsupported</code>. Use an authoritative offered choice for
|
|
957
|
+
<code>joinWaitingList</code>, or general interest where allowed.
|
|
958
|
+
Unsupported/custom forms may provide an event continuation URL.</p>
|
|
959
|
+
<p>Ticket quantities can survive rotating encrypted IDs <strong>when the
|
|
960
|
+
API supplies a stable canonical <code>selectionKey</code></strong>. Cart
|
|
961
|
+
submissions still use the latest opaque encrypted IDs. For dated
|
|
962
|
+
tickets, deployed canonical keys and numeric price context
|
|
963
|
+
(<code>display_price</code>, <code>price_with_fees</code>,
|
|
964
|
+
<code>fee_included</code>, <code>price_currency</code>,
|
|
965
|
+
<code>price_symbol</code>) must be provided and validated by the API.
|
|
966
|
+
When the optional key is absent, do not assume retention across ID
|
|
967
|
+
rotation.</p>
|
|
968
|
+
<p><code>SeatMap</code> uses the event's configured seat map and server
|
|
969
|
+
reservation. Let the buyer select seats before continuing; availability
|
|
970
|
+
can change. Test the actual map, chart and reservation expiry on the
|
|
971
|
+
target domain and browser. For a headless integration,
|
|
972
|
+
<code>SeatLine</code> uses the server seat reservation key, tier, ticket
|
|
973
|
+
type, option and price; do not manufacture those values from display
|
|
974
|
+
labels. <code>setSeatsIo</code> is a separate path for a seats.io
|
|
975
|
+
selection.</p>
|
|
976
|
+
<h3 id="buyer-fields-consent-and-waivers">Buyer fields, consent and
|
|
977
|
+
waivers</h3>
|
|
978
|
+
<p>The server's checkout configuration determines required buyer fields,
|
|
979
|
+
ticket holders, custom captures, add-ons and waiver.
|
|
980
|
+
<code>buyerFields</code> identifies gated nationality, gender and
|
|
981
|
+
Instagram inputs; <code>customFields</code> contains order, ticket and
|
|
982
|
+
add-on groups. Store order answers in <code>billing.dataCapture</code>,
|
|
983
|
+
each holder's answers in <code>ticketDataCapture</code>, and add-on
|
|
984
|
+
answers via <code>setAddonDataCapture</code>. Holder ticket type IDs
|
|
985
|
+
come from the priced cart, not the opaque catalog ID. Use backend
|
|
986
|
+
country/state IDs for <code>countryId</code> and <code>stateId</code>;
|
|
987
|
+
<code>countryCode</code> / <code>stateCode</code> are payment billing
|
|
988
|
+
codes.</p>
|
|
989
|
+
<p>In beta.27 conditional custom-field requiredness is left to the
|
|
990
|
+
backend and not all hosted-checkout conditional visibility is
|
|
991
|
+
reproduced. Verify the actual event against the deployed checkout,
|
|
992
|
+
including blanks, images, holder scoping and validation errors; do not
|
|
993
|
+
claim parity from the presence of a field alone. Terms and
|
|
994
|
+
<code>additionalConditions</code> are client-side acceptance gates;
|
|
995
|
+
respect the server's own requirements. <code>Payment</code> renders
|
|
996
|
+
condition <code>content</code>, or <code>name</code> as a fallback, as
|
|
997
|
+
HTML. Only supply trusted or appropriately sanitized content, and verify
|
|
998
|
+
the source and handling of server-provided conditions too.</p>
|
|
999
|
+
<p>During cart priming, failed custom-field, checkout-config, add-on or
|
|
1000
|
+
event condition reads fall back to empty/default data. The stock UI
|
|
1001
|
+
cannot show or gate requirements it did not load. Do not treat an empty
|
|
1002
|
+
list as proof that no requirement exists; verify deployment/failure
|
|
1003
|
+
behavior and add tested host safeguards for mandatory fields and
|
|
1004
|
+
acknowledgments. Server validation of required answers is not proof that
|
|
1005
|
+
a condition was acknowledged. Only failed waiver reads other than a 404
|
|
1006
|
+
are recorded in <code>unavailableDetails</code>. Before money may have
|
|
1007
|
+
moved, placement retries an unavailable waiver and blocks if it remains
|
|
1008
|
+
unknown; <code>reloadCheckoutDetails()</code> can also retry the waiver
|
|
1009
|
+
read. A retained order with a possible payment follows separate recovery
|
|
1010
|
+
and needs reconciliation. <code>WaiverSigning</code> handles the SDK's
|
|
1011
|
+
signing flow.</p>
|
|
1012
|
+
<p><strong>Consent limitation in beta.27:</strong> when
|
|
1013
|
+
<code>privacyPolicy</code> is supplied, the stock
|
|
1014
|
+
<code>BillingInfo</code> replaces the Ticket Fairy marketing checkbox
|
|
1015
|
+
with the required privacy checkbox, but both use
|
|
1016
|
+
<code>consent.ttfOptIn</code>; the order sends that value as
|
|
1017
|
+
<code>ttf_opt_in</code>. The privacy acknowledgement and Ticket Fairy
|
|
1018
|
+
marketing choice are therefore not independently captured by this stock
|
|
1019
|
+
path. <code>brandOptIn</code> is a separate value. If your integration
|
|
1020
|
+
requires independent privacy and marketing choices, do not rely on the
|
|
1021
|
+
stock <code>privacyPolicy</code> prop for that requirement; use an
|
|
1022
|
+
alternative whose UI, payload and backend behavior you have
|
|
1023
|
+
verified.</p>
|
|
1024
|
+
<p>Do not combine stock required <code>privacyPolicy</code> with
|
|
1025
|
+
<code>skipBillingWhenProfileComplete</code> /
|
|
1026
|
+
<code>skipWhenProfileComplete</code>. When skipping is eligible, the
|
|
1027
|
+
billing card and its consent controls disappear while
|
|
1028
|
+
<code>Payment</code> can still require the privacy value. The same skip
|
|
1029
|
+
can hide marketing opt-ins; do not assume they remain visible. Keep the
|
|
1030
|
+
billing card available and test both signed-in and guest flows.</p>
|
|
1031
|
+
<h2 id="payments">Payments</h2>
|
|
1032
|
+
<p><code>Payment</code> selects available methods from event/backend
|
|
1033
|
+
configuration and uses the web platform's Stripe, popup and Xendit
|
|
1034
|
+
ports. Supported request shapes in the engine include card, Apple Pay,
|
|
1035
|
+
Google Pay, Stripe redirect methods, OXXO, Xendit card/e-wallets,
|
|
1036
|
+
PayPal, Razorpay, Adyen and payment plans. A type existing in the SDK
|
|
1037
|
+
does <strong>not</strong> mean it is enabled for your event, browser,
|
|
1038
|
+
country, currency, merchant account or deployed backend. Offer the
|
|
1039
|
+
server-returned methods, handle an unavailable or unsupported method,
|
|
1040
|
+
and test each enabled rail with its provider. Wallets require their own
|
|
1041
|
+
provider and domain/device configuration. Redirect/popup methods require
|
|
1042
|
+
allowed popups, return URLs, content security policy and third-party
|
|
1043
|
+
access. Provider configuration and scripts are separate from installing
|
|
1044
|
+
the npm package.</p>
|
|
1045
|
+
<p><code>PlaceOrderResult</code> contains <code>orderHash</code>,
|
|
1046
|
+
<code>free</code>, <code>needIdVerification</code>, and optional
|
|
1047
|
+
<code>currency</code>, <code>paymentIntentId</code>,
|
|
1048
|
+
<code>alreadyPaid</code>, <code>pending</code> and
|
|
1049
|
+
<code>pendingVoucherUrl</code>. <code>alreadyPaid</code> means the
|
|
1050
|
+
server reported a duplicate as already paid; it does not mean this
|
|
1051
|
+
invocation charged again. OXXO vouchers and PayPal can be pending. Show
|
|
1052
|
+
a pending state and voucher link if provided; wait for authoritative
|
|
1053
|
+
confirmation before showing a paid receipt or fulfilling. ID
|
|
1054
|
+
verification may still be required after payment. An ID-verification
|
|
1055
|
+
failure is not a reason to repeat the charge.</p>
|
|
1056
|
+
<p>The stock in-flow <code>Confirmation</code> displays
|
|
1057
|
+
confirmed/ticket-available copy when <code>pending</code> is absent or
|
|
1058
|
+
false; it does not independently verify final settlement. For both paid
|
|
1059
|
+
and free orders, use <code>confirmationMode="redirect"</code> with a
|
|
1060
|
+
host-owned status page, or a custom composed confirmation gated on
|
|
1061
|
+
authoritative order and provider status. Arrange ID verification on the
|
|
1062
|
+
host route when <code>needIdVerification</code> is true; redirect does
|
|
1063
|
+
not render the inline verification. The stock
|
|
1064
|
+
<code>IDVerification</code> and routed <code>OrderIDVerification</code>
|
|
1065
|
+
verified messages say tickets are on their way; they do not check final
|
|
1066
|
+
settlement or issuance. Use host-owned neutral verification and status
|
|
1067
|
+
UI when that copy is premature. If <code>onComplete</code> navigates
|
|
1068
|
+
away or unmounts the checkout, its inline verification cannot appear:
|
|
1069
|
+
keep the provider mounted or handle verification at the destination. For
|
|
1070
|
+
a custom flow, see <a href="#host-owned-id-verification">host-owned ID
|
|
1071
|
+
verification</a>.</p>
|
|
1072
|
+
<p><strong>Zero-total orders:</strong> this SDK ignores the
|
|
1073
|
+
free-registration response body and reports
|
|
1074
|
+
<code>needIdVerification: false</code>. Verification or approval may
|
|
1075
|
+
still be required, and <code>free: true</code> is not proof tickets were
|
|
1076
|
+
issued. The default inline <code>EmbeddedCheckout</code> can
|
|
1077
|
+
nevertheless show confirmed or ticket-available copy while approval or
|
|
1078
|
+
verification is still outstanding. Use
|
|
1079
|
+
<code>confirmationMode="redirect"</code> with host-owned authoritative
|
|
1080
|
+
order and verification status, or a custom composed confirmation gated
|
|
1081
|
+
on that status. If the status is unavailable, contact support. Do not
|
|
1082
|
+
retry payment for a free order.</p>
|
|
1083
|
+
<p><code>OrderConfirmation</code> is a reloadable presentation and does
|
|
1084
|
+
<strong>not</strong> check the order's payment status before showing its
|
|
1085
|
+
default confirmed/ticket-availability copy. Gate it on an authoritative
|
|
1086
|
+
status appropriate for that page. When <code>onComplete</code> reports
|
|
1087
|
+
<code>pending</code>, show a pending page (and any voucher) instead; do
|
|
1088
|
+
not route directly to <code>OrderConfirmation</code> as a paid receipt.
|
|
1089
|
+
The in-flow <code>Confirmation</code> component reads the current result
|
|
1090
|
+
and has a pending state, but the absence of <code>pending</code> is not
|
|
1091
|
+
proof of settlement.</p>
|
|
1092
|
+
<p><code>CardInput</code> renders Stripe Elements and uses the
|
|
1093
|
+
checkout's default card owner; <code>StripePaymentElement</code> is the
|
|
1094
|
+
deferred Elements option when its server config and wallet gates are
|
|
1095
|
+
available. <code>XenditCardInput</code> renders Xendit card fields.
|
|
1096
|
+
<code>Payment</code> wires the right input automatically. When
|
|
1097
|
+
implementing a custom pay step, render the correct input for the
|
|
1098
|
+
selected gateway and keep it mounted and visible for that payment. Do
|
|
1099
|
+
not collect raw card numbers in your own form or logs. Multiple card
|
|
1100
|
+
flows must respect field ownership. With no explicit claim, the web hook
|
|
1101
|
+
claims the default <code>checkout</code> owner's Payment Element if
|
|
1102
|
+
registered, otherwise its <code>CardInput</code>, and refuses if neither
|
|
1103
|
+
is available. For a custom owner, <code>claimCardField(owner)</code>
|
|
1104
|
+
claims a <code>CardInput</code> only; a
|
|
1105
|
+
<code>StripePaymentElement</code> uses
|
|
1106
|
+
<code>cardClaimStep('webPaymentElement', () => webConfirmer.claimPaymentElement(owner))</code>
|
|
1107
|
+
as the <code>placeOrder</code> <code>claimCard</code> step. For a bare
|
|
1108
|
+
card field, the <code>webCard</code> claim step should call
|
|
1109
|
+
<code>webConfirmer.releasePaymentElement()</code> before
|
|
1110
|
+
<code>claimCardField(owner)</code>. The standard <code>Payment</code>
|
|
1111
|
+
component handles these claims and key changes for you.</p>
|
|
1112
|
+
<p><code>useCheckout({ ports, options })</code> reads options on first
|
|
1113
|
+
render. The <code>ports</code> option merges additional compatible web
|
|
1114
|
+
capabilities over the defaults, but its type excludes
|
|
1115
|
+
<code>confirmer</code>; it cannot replace <code>webConfirmer</code>.
|
|
1116
|
+
<code>options</code> includes <code>redirectReturnUrl</code> and
|
|
1117
|
+
merchant/wallet options. A custom confirmer belongs in the lower-level
|
|
1118
|
+
<code>createEngine</code> configuration, not this web hook option.</p>
|
|
1119
|
+
<p>The engine retains the order when it cannot establish whether a
|
|
1120
|
+
charge moved. A custom confirmer should reject using
|
|
1121
|
+
<code>paymentProviderError(message, outcome)</code>;
|
|
1122
|
+
<code>outcome</code> is <code>declined</code>, <code>cancelled</code>,
|
|
1123
|
+
<code>notStarted</code>, or <code>unknown</code>. Use the first three
|
|
1124
|
+
only when the provider confirms nothing was charged. An unclassified
|
|
1125
|
+
error is treated as unknown. Avoid automatic blind retries and never
|
|
1126
|
+
promise exactly-once charging across your app, backend and provider.</p>
|
|
1127
|
+
<h3 id="host-owned-id-verification">Host-owned ID verification</h3>
|
|
1128
|
+
<p><code>runIdVerification(orderHash, options)</code> does not open the
|
|
1129
|
+
provider on its own. Supply <code>openUrl</code> to validate the URL
|
|
1130
|
+
against your provider and scheme policy and open it in the browser;
|
|
1131
|
+
handle a missing URL or blocked/failed opening in your UI. The engine
|
|
1132
|
+
swallows asynchronous <code>openUrl</code> rejections, so catch and
|
|
1133
|
+
record opening failures inside the callback: polling can otherwise
|
|
1134
|
+
continue without a handoff. Use <code>onPhase</code> for polling state
|
|
1135
|
+
and handle browser returns; <code>registerForegroundListener</code> can
|
|
1136
|
+
trigger a recheck on return and must return an unsubscribe function.</p>
|
|
1137
|
+
<p>Alternatively, <code>onRequired</code> receives the order hash and
|
|
1138
|
+
possibly null URL; if it returns <code>true</code>, the engine resolves
|
|
1139
|
+
<code>undefined</code> without opening or polling, and your host owns
|
|
1140
|
+
both steps. A timeout or poll error rejects with a message promising
|
|
1141
|
+
that payment is safe and tickets will be emailed. Replace that text with
|
|
1142
|
+
neutral status and reconcile authoritative payment, verification and
|
|
1143
|
+
issuance. Verification alone does not prove settlement or issuance.</p>
|
|
1144
|
+
<h2 id="authentication">Authentication</h2>
|
|
1145
|
+
<p>The embedded checkout supplies the event to its built-in
|
|
1146
|
+
<code>AuthModal</code>. A standalone modal can do the same. The host
|
|
1147
|
+
must already provide a query client and initialize the SDK. The checkout
|
|
1148
|
+
callback is deliberately narrow.</p>
|
|
1149
|
+
<pre class="tsx"><code>import { useState } from 'react'
|
|
1150
|
+
import { AuthModal } from 'tf-checkout-react'
|
|
1151
|
+
|
|
1152
|
+
export function SignIn() {
|
|
1153
|
+
const [open, setOpen] = useState(false)
|
|
1154
|
+
return (
|
|
1155
|
+
<>
|
|
1156
|
+
<button onClick={() => setOpen(true)}>Sign in</button>
|
|
1157
|
+
<AuthModal
|
|
1158
|
+
open={open}
|
|
1159
|
+
onClose={() => setOpen(false)}
|
|
1160
|
+
checkoutEventId="EVENT_ID"
|
|
1161
|
+
onCheckoutAuthenticated={() => setOpen(false)}
|
|
1162
|
+
/>
|
|
1163
|
+
</>
|
|
1164
|
+
)
|
|
1165
|
+
}</code></pre>
|
|
1166
|
+
<p><code>AuthModal</code> props: <code>open</code> and
|
|
1167
|
+
<code>onClose</code> are required; optional
|
|
1168
|
+
<code>checkoutEventId</code>, <code>onCheckoutAuthenticated</code>,
|
|
1169
|
+
<code>initialView</code>, <code>initialEmail</code>,
|
|
1170
|
+
<code>message</code>, <code>allowRegistration</code> (default
|
|
1171
|
+
<code>true</code>), <code>allowPasswordReset</code> (default
|
|
1172
|
+
<code>true</code>), <code>requireRegistrationAddress</code> (default
|
|
1173
|
+
<code>true</code>), <code>registrationFields</code>,
|
|
1174
|
+
<code>logoUrl</code>, <code>onAuthenticated</code> and
|
|
1175
|
+
<code>className</code>. Public checkout auth requires its registered
|
|
1176
|
+
client and matching deployed server contract. Browser checkout
|
|
1177
|
+
authorization uses a popup with state and PKCE; secure browser crypto
|
|
1178
|
+
and popups must be available. The popup may be blocked or closed, and
|
|
1179
|
+
two-factor or email/phone proof can be required. Surface those outcomes
|
|
1180
|
+
rather than assuming sign-in succeeded. The public checkout registration
|
|
1181
|
+
and account completion paths force address collection even if
|
|
1182
|
+
<code>requireRegistrationAddress</code> is <code>false</code>.</p>
|
|
1183
|
+
<p>For a custom UI, <code>hooks.useAuthFlow(options)</code> owns
|
|
1184
|
+
authentication state, validation and transitions, while
|
|
1185
|
+
<code>LoginForm</code>, <code>RegisterForm</code>,
|
|
1186
|
+
<code>ForgotPasswordForm</code>, <code>ResetPasswordForm</code>,
|
|
1187
|
+
<code>TwoFactorForm</code>, <code>EmailCodeForm</code> and
|
|
1188
|
+
<code>PhoneAuthView</code> provide forms/views. <code>LoginForm</code>
|
|
1189
|
+
requires <code>onSubmit</code>; <code>RegisterForm</code> requires
|
|
1190
|
+
<code>onSubmit</code>; <code>ForgotPasswordForm</code> requires
|
|
1191
|
+
<code>onSubmit</code> and <code>onBackToLogin</code>;
|
|
1192
|
+
<code>ResetPasswordForm</code> requires a reset <code>token</code>.
|
|
1193
|
+
<code>TwoFactorForm</code> and <code>EmailCodeForm</code> are controlled
|
|
1194
|
+
views with required state and callbacks; <code>PhoneAuthView</code>
|
|
1195
|
+
requires a <code>PhoneAuthenticationFlow</code>. Their exported
|
|
1196
|
+
<code>*Props</code> types document every field. The individual
|
|
1197
|
+
controlled forms do not turn an arbitrary callback into a complete
|
|
1198
|
+
authenticated session; use the appropriate flow and handle all its
|
|
1199
|
+
states.</p>
|
|
1200
|
+
<h2 id="component-reference">Component reference</h2>
|
|
1201
|
+
<p>Props shown without <code>?</code> are required. All named
|
|
1202
|
+
<code>*Props</code> types below are exported unless stated otherwise;
|
|
1203
|
+
TypeScript declarations in the installed package are the authoritative
|
|
1204
|
+
detail for callback payloads and DTOs.</p>
|
|
1205
|
+
<h3 id="checkout-sections">Checkout sections</h3>
|
|
1206
|
+
<table>
|
|
1207
|
+
<thead>
|
|
1208
|
+
<tr>
|
|
1209
|
+
<th>Export</th>
|
|
1210
|
+
<th>Props and purpose</th>
|
|
1211
|
+
</tr>
|
|
1212
|
+
</thead>
|
|
1213
|
+
<tbody>
|
|
1214
|
+
<tr>
|
|
1215
|
+
<td><code>Tickets</code></td>
|
|
1216
|
+
<td><code>eventId</code>, <code>title?</code>, <code>onContinue?</code>,
|
|
1217
|
+
<code>buttonLabel?</code>, <code>timeSlotDates?</code> (ISO dates),
|
|
1218
|
+
<code>step?</code>, <code>onSelectSeats?</code>,
|
|
1219
|
+
<code>initialPromoCode?</code>, <code>referrer?</code>,
|
|
1220
|
+
<code>readAttributionFromUrl?</code>, <code>className?</code>.
|
|
1221
|
+
<code>onContinue</code> fires after the cart is primed.</td>
|
|
1222
|
+
</tr>
|
|
1223
|
+
<tr>
|
|
1224
|
+
<td><code>SeatMap</code></td>
|
|
1225
|
+
<td><code>eventId</code>, <code>onContinue?</code>, <code>step?</code>,
|
|
1226
|
+
<code>className?</code>. Callback fires after seats are added and
|
|
1227
|
+
priced.</td>
|
|
1228
|
+
</tr>
|
|
1229
|
+
<tr>
|
|
1230
|
+
<td><code>AddOns</code></td>
|
|
1231
|
+
<td><code>eventId</code>, <code>onContinue?</code>,
|
|
1232
|
+
<code>onSkip?</code>, <code>buttonLabel?</code>, <code>eyebrow?</code>,
|
|
1233
|
+
<code>heading?</code>, <code>className?</code>. Skip is hidden for a
|
|
1234
|
+
required add-on.</td>
|
|
1235
|
+
</tr>
|
|
1236
|
+
<tr>
|
|
1237
|
+
<td><code>Bundles</code></td>
|
|
1238
|
+
<td><code>eventId</code>, <code>onPurchased?(orderHash)</code>,
|
|
1239
|
+
<code>onComplete?(order)</code>, <code>confirmationMode?</code>,
|
|
1240
|
+
<code>visible?</code>, <code>heading?</code>, <code>className?</code>.
|
|
1241
|
+
Bundle purchase is its own flow; hide its card field using
|
|
1242
|
+
<code>visible</code> when the section is hidden.</td>
|
|
1243
|
+
</tr>
|
|
1244
|
+
<tr>
|
|
1245
|
+
<td><code>BillingInfo</code></td>
|
|
1246
|
+
<td><code>eventId?</code>, <code>onContinue?</code>,
|
|
1247
|
+
<code>heading?</code>, <code>buttonLabel?</code>, <code>onLogin?</code>,
|
|
1248
|
+
<code>skipWhenProfileComplete?</code>,
|
|
1249
|
+
<code>requireEmailConfirmation?</code>,
|
|
1250
|
+
<code>collectTicketHolders?</code>, <code>collectHolderContact?</code>,
|
|
1251
|
+
<code>ttfOptInLabel?</code>, <code>brandOptInLabel?</code>,
|
|
1252
|
+
<code>privacyPolicy?</code>, <code>showPrivacyError?</code>,
|
|
1253
|
+
<code>step?</code>, <code>className?</code>. Standalone holder
|
|
1254
|
+
collection follows backend gates unless explicitly enabled.</td>
|
|
1255
|
+
</tr>
|
|
1256
|
+
<tr>
|
|
1257
|
+
<td><code>WaiverSigning</code></td>
|
|
1258
|
+
<td><code>eventId</code>, <code>className?</code>. Render before payment
|
|
1259
|
+
for an event requiring a waiver.</td>
|
|
1260
|
+
</tr>
|
|
1261
|
+
<tr>
|
|
1262
|
+
<td><code>Payment</code></td>
|
|
1263
|
+
<td><code>onComplete?</code>, <code>eventId?</code>,
|
|
1264
|
+
<code>requireEmailConfirmation?</code>,
|
|
1265
|
+
<code>collectTicketHolders?</code>, <code>requireHolderContact?</code>,
|
|
1266
|
+
<code>additionalConditions?</code>, <code>requirePrivacyPolicy?</code>,
|
|
1267
|
+
<code>onPrivacyRequired?</code>, <code>showTestCardHint?</code>,
|
|
1268
|
+
<code>className?</code>. Match the paired billing policies.</td>
|
|
1269
|
+
</tr>
|
|
1270
|
+
<tr>
|
|
1271
|
+
<td><code>OrderSummary</code></td>
|
|
1272
|
+
<td><code>eventId?</code>, <code>className?</code>. Uses the current
|
|
1273
|
+
checkout's pricing. <code>Payment</code> already renders it; use it
|
|
1274
|
+
separately when you need a summary elsewhere.</td>
|
|
1275
|
+
</tr>
|
|
1276
|
+
<tr>
|
|
1277
|
+
<td><code>IDVerification</code></td>
|
|
1278
|
+
<td><code>className?</code>. Uses the current checkout/order.</td>
|
|
1279
|
+
</tr>
|
|
1280
|
+
<tr>
|
|
1281
|
+
<td><code>Confirmation</code></td>
|
|
1282
|
+
<td><code>shareUrl?</code>, <code>shareMessage?</code>,
|
|
1283
|
+
<code>viewOrderUrl?</code>, <code>children?</code>,
|
|
1284
|
+
<code>className?</code>. Uses the current checkout result and handles
|
|
1285
|
+
pending presentation. The default share URL and eligibility have the
|
|
1286
|
+
limitations below.</td>
|
|
1287
|
+
</tr>
|
|
1288
|
+
<tr>
|
|
1289
|
+
<td><code>OrderConfirmation</code></td>
|
|
1290
|
+
<td><code>orderHash</code>, <code>title?</code>, <code>message?</code>,
|
|
1291
|
+
<code>helper?</code>, <code>eventTitle?</code>, <code>eventDate?</code>,
|
|
1292
|
+
<code>eventLocation?</code>, <code>viewOrderUrl?</code> (string or
|
|
1293
|
+
function), <code>showReferral?</code>, <code>showShareButtons?</code>,
|
|
1294
|
+
<code>showRewards?</code>, <code>snapchat?</code>,
|
|
1295
|
+
<code>onLoaded?</code>, <code>onError?</code>, <code>className?</code>.
|
|
1296
|
+
Reloads confirmation by hash; the host must gate it on appropriate
|
|
1297
|
+
payment status. The three <code>show*</code> options default to true;
|
|
1298
|
+
Snapchat defaults to false.</td>
|
|
1299
|
+
</tr>
|
|
1300
|
+
<tr>
|
|
1301
|
+
<td><code>OrderIDVerification</code></td>
|
|
1302
|
+
<td><code>orderHash</code>, <code>onVerified?</code>,
|
|
1303
|
+
<code>className?</code>. For a separately routed order.</td>
|
|
1304
|
+
</tr>
|
|
1305
|
+
<tr>
|
|
1306
|
+
<td><code>Rewards</code></td>
|
|
1307
|
+
<td><code>orderHash?</code>, <code>data?</code>, <code>snapchat?</code>,
|
|
1308
|
+
<code>className?</code>. Supply an order hash or an already loaded
|
|
1309
|
+
<code>RewardsPayload</code>; <code>data</code> avoids a fetch.</td>
|
|
1310
|
+
</tr>
|
|
1311
|
+
<tr>
|
|
1312
|
+
<td><code>TicketChange</code></td>
|
|
1313
|
+
<td><code>ticketHash</code>, <code>orderHash?</code>,
|
|
1314
|
+
<code>onChanged?</code>, <code>openUrl?</code>, <code>onLogin?</code>,
|
|
1315
|
+
<code>className?</code>. Change/upgrade availability and any upgrade
|
|
1316
|
+
waitlist come from server options.</td>
|
|
1317
|
+
</tr>
|
|
1318
|
+
<tr>
|
|
1319
|
+
<td><code>Accommodation</code></td>
|
|
1320
|
+
<td><code>eventId</code>. Renders the accommodation selection for an
|
|
1321
|
+
applicable cart; requires checkout context.</td>
|
|
1322
|
+
</tr>
|
|
1323
|
+
</tbody>
|
|
1324
|
+
</table>
|
|
1325
|
+
<p><code>Confirmation</code> defaults <code>shareUrl</code> to
|
|
1326
|
+
<code>window.location.href</code>, displays generic referral copy for
|
|
1327
|
+
non-pending orders, and does not check organizer referral eligibility.
|
|
1328
|
+
The current URL may include unrelated query parameters or lack a
|
|
1329
|
+
buyer-specific referral. <code>EmbeddedCheckout</code> does not expose a
|
|
1330
|
+
<code>shareUrl</code> prop. For a composed <code>Confirmation</code>,
|
|
1331
|
+
pass a verified buyer-specific URL when eligible, or
|
|
1332
|
+
<code>shareUrl=""</code> to suppress sharing. Alternatively use
|
|
1333
|
+
server-backed <code>OrderConfirmation</code> / <code>Rewards</code>
|
|
1334
|
+
where the appropriate status and response support the experience. Check
|
|
1335
|
+
eligibility and attribution against the deployed backend; don't treat
|
|
1336
|
+
the generic link as evidence of a referral.</p>
|
|
1337
|
+
<p><code>OrderConfirmation</code> includes <code>Rewards</code> when its
|
|
1338
|
+
response has a rewards payload unless <code>showRewards={false}</code>.
|
|
1339
|
+
<code>Rewards</code> can also fetch by hash without a React Query
|
|
1340
|
+
provider. Sharing channels depend on organizer configuration and browser
|
|
1341
|
+
capabilities. Snapchat is opt-in and loads <code>sdk.snapkit.com</code>;
|
|
1342
|
+
allow it in the host's CSP only if used. Clipboard and share operations
|
|
1343
|
+
can be denied by the browser or buyer. <code>RewardsLadder</code>
|
|
1344
|
+
(<code>rows</code>, <code>onSubmitDetails?</code>,
|
|
1345
|
+
<code>className?</code>), <code>RewardsTree</code> (<code>tree</code>,
|
|
1346
|
+
<code>className?</code>), <code>RewardsChannels</code>
|
|
1347
|
+
(<code>channels</code>, <code>shareLink</code>,
|
|
1348
|
+
<code>shareMessage</code>, <code>assertCurrent?</code>,
|
|
1349
|
+
<code>shareCardImageUrl?</code>, <code>snapchat?</code>,
|
|
1350
|
+
<code>className?</code>), and <code>RewardsPackCard</code>
|
|
1351
|
+
(<code>pack</code>, <code>onCreate</code>, <code>onJoin</code>,
|
|
1352
|
+
<code>onLeave</code>, <code>assertCurrent?</code>) are available for
|
|
1353
|
+
custom reward layouts.</p>
|
|
1354
|
+
<p>An upgrade waitlist is a separate server-owned ticket-change
|
|
1355
|
+
contract. Valid change-options targets can expose Join or Leave only
|
|
1356
|
+
when the backend offers that organizer-configured flow. A sold-out row
|
|
1357
|
+
alone does not authorize it; malformed targets or entries are ignored.
|
|
1358
|
+
Verify the deployed contract and confirm the server response before
|
|
1359
|
+
presenting an action as completed.</p>
|
|
1360
|
+
<h3 id="account-post-purchase-and-discovery">Account, post-purchase and
|
|
1361
|
+
discovery</h3>
|
|
1362
|
+
<p>These exports are available in the package, but availability and
|
|
1363
|
+
required account authority vary by endpoint. A public checkout buyer is
|
|
1364
|
+
not automatically a full account user. Supply a host sign-in/route
|
|
1365
|
+
callback where applicable.</p>
|
|
1366
|
+
<table>
|
|
1367
|
+
<thead>
|
|
1368
|
+
<tr>
|
|
1369
|
+
<th>Export</th>
|
|
1370
|
+
<th>Props and purpose</th>
|
|
1371
|
+
</tr>
|
|
1372
|
+
</thead>
|
|
1373
|
+
<tbody>
|
|
1374
|
+
<tr>
|
|
1375
|
+
<td><code>TicketRefund</code></td>
|
|
1376
|
+
<td><code>ticketHash</code>, <code>onSubmitted?</code>,
|
|
1377
|
+
<code>onDone?</code>. Presents offered refund options and
|
|
1378
|
+
submission.</td>
|
|
1379
|
+
</tr>
|
|
1380
|
+
<tr>
|
|
1381
|
+
<td><code>TicketGift</code></td>
|
|
1382
|
+
<td><code>ticketHash</code>, <code>onTicketsChanged?</code>,
|
|
1383
|
+
<code>onDone?</code>, <code>locale?</code>. Gift flow.</td>
|
|
1384
|
+
</tr>
|
|
1385
|
+
<tr>
|
|
1386
|
+
<td><code>Passes</code></td>
|
|
1387
|
+
<td><code>onTicketsChanged?</code>, <code>locale?</code>. Customer
|
|
1388
|
+
passes and booking actions.</td>
|
|
1389
|
+
</tr>
|
|
1390
|
+
<tr>
|
|
1391
|
+
<td><code>Trips</code></td>
|
|
1392
|
+
<td><code>onOpen(url)</code>, <code>onPage(query)</code>,
|
|
1393
|
+
<code>data?</code>, <code>locale?</code>, <code>loading?</code>,
|
|
1394
|
+
<code>errorMessage?</code>, <code>onRetry?</code>. Host supplies data
|
|
1395
|
+
and navigation.</td>
|
|
1396
|
+
</tr>
|
|
1397
|
+
<tr>
|
|
1398
|
+
<td><code>AccountProfile</code></td>
|
|
1399
|
+
<td><code>onSaved?(profile, action)</code>. Profile gender/image
|
|
1400
|
+
actions.</td>
|
|
1401
|
+
</tr>
|
|
1402
|
+
<tr>
|
|
1403
|
+
<td><code>AccountInformationSection</code></td>
|
|
1404
|
+
<td><code>orderId</code>, <code>title?</code>, <code>target?</code>,
|
|
1405
|
+
<code>locale?</code>, <code>active?</code>, <code>onSaved?</code>. Order
|
|
1406
|
+
information/answers.</td>
|
|
1407
|
+
</tr>
|
|
1408
|
+
<tr>
|
|
1409
|
+
<td><code>AccountPaymentPlanSection</code></td>
|
|
1410
|
+
<td><code>plan</code>, <code>orderHash</code>, <code>locale?</code>,
|
|
1411
|
+
<code>onOpen?</code>, <code>onReturn?</code>. Payment-plan management
|
|
1412
|
+
for an existing order.</td>
|
|
1413
|
+
</tr>
|
|
1414
|
+
<tr>
|
|
1415
|
+
<td><code>AccountRewardsSection</code></td>
|
|
1416
|
+
<td><code>locale?</code>, <code>onBrowseEvents?</code>,
|
|
1417
|
+
<code>onViewTickets?</code>. Account rewards summary.</td>
|
|
1418
|
+
</tr>
|
|
1419
|
+
<tr>
|
|
1420
|
+
<td><code>AccountDeletion</code></td>
|
|
1421
|
+
<td><code>showHeader?</code>, <code>showExplanation?</code>,
|
|
1422
|
+
<code>locale?</code>, <code>onSignIn?</code>, <code>onDone?</code>,
|
|
1423
|
+
<code>onOpenTeam?</code>. <code>AccountDeletionView</code> additionally
|
|
1424
|
+
requires a <code>deletion</code> flow.</td>
|
|
1425
|
+
</tr>
|
|
1426
|
+
<tr>
|
|
1427
|
+
<td><code>NotificationPreferences</code></td>
|
|
1428
|
+
<td><code>locale?</code>, <code>onBack?</code>, <code>onSignIn?</code>,
|
|
1429
|
+
<code>onSaved?</code>. <code>NotificationPreferencesView</code>
|
|
1430
|
+
additionally requires a <code>preferences</code> flow.</td>
|
|
1431
|
+
</tr>
|
|
1432
|
+
<tr>
|
|
1433
|
+
<td><code>ProfileSettings</code></td>
|
|
1434
|
+
<td><code>mode: 'links' | 'visibility'</code>, <code>onBack?</code>,
|
|
1435
|
+
<code>onSignIn?</code>. <code>ProfileSettingsView</code> additionally
|
|
1436
|
+
requires a <code>settings</code> flow.</td>
|
|
1437
|
+
</tr>
|
|
1438
|
+
<tr>
|
|
1439
|
+
<td><code>AccountEmailEnrichment</code></td>
|
|
1440
|
+
<td>No props. <code>AccountEmailEnrichmentView</code> requires
|
|
1441
|
+
<code>flow</code>.</td>
|
|
1442
|
+
</tr>
|
|
1443
|
+
<tr>
|
|
1444
|
+
<td><code>PhoneAccountProfile</code></td>
|
|
1445
|
+
<td>No props. Phone account profile view.</td>
|
|
1446
|
+
</tr>
|
|
1447
|
+
<tr>
|
|
1448
|
+
<td><code>Interests</code></td>
|
|
1449
|
+
<td><code>onSignIn?</code>. Interest selection.</td>
|
|
1450
|
+
</tr>
|
|
1451
|
+
<tr>
|
|
1452
|
+
<td><code>Streaming</code></td>
|
|
1453
|
+
<td><code>onSignIn?</code>, <code>onOpenMusic?(url, provider?)</code>.
|
|
1454
|
+
Music connections.</td>
|
|
1455
|
+
</tr>
|
|
1456
|
+
<tr>
|
|
1457
|
+
<td><code>Friends</code></td>
|
|
1458
|
+
<td><code>initialCode?</code>, <code>onSignIn?</code>. Friend
|
|
1459
|
+
flows.</td>
|
|
1460
|
+
</tr>
|
|
1461
|
+
<tr>
|
|
1462
|
+
<td><code>SavedEvents</code></td>
|
|
1463
|
+
<td><code>onSignIn?</code>. Saved-event list.</td>
|
|
1464
|
+
</tr>
|
|
1465
|
+
<tr>
|
|
1466
|
+
<td><code>Recommendations</code></td>
|
|
1467
|
+
<td><code>events</code>, <code>enabled?</code>. Recommendations from the
|
|
1468
|
+
supplied <code>AccountEvent[]</code>.</td>
|
|
1469
|
+
</tr>
|
|
1470
|
+
<tr>
|
|
1471
|
+
<td><code>EventComments</code></td>
|
|
1472
|
+
<td><code>eventId</code>, <code>previewKey?</code>,
|
|
1473
|
+
<code>onSignIn?</code>, <code>className?</code>. Discussion with
|
|
1474
|
+
backend-supplied permissions. <code>EventCommentsView</code> accepts a
|
|
1475
|
+
supplied discussion flow.</td>
|
|
1476
|
+
</tr>
|
|
1477
|
+
<tr>
|
|
1478
|
+
<td><code>PostReaction</code></td>
|
|
1479
|
+
<td><code>postId: string | number</code>, <code>onSignIn?</code>.
|
|
1480
|
+
<code>PostReactionControls</code> accepts <code>flow</code> and
|
|
1481
|
+
<code>onSignIn?</code>.</td>
|
|
1482
|
+
</tr>
|
|
1483
|
+
<tr>
|
|
1484
|
+
<td><code>DiscoveryTravel</code></td>
|
|
1485
|
+
<td><code>searchCities</code>, <code>searchEvents</code>,
|
|
1486
|
+
<code>storage?</code>, <code>locale?</code>. Host supplies search
|
|
1487
|
+
functions; see <code>DiscoveryTravelProps</code> for their
|
|
1488
|
+
signatures.</td>
|
|
1489
|
+
</tr>
|
|
1490
|
+
</tbody>
|
|
1491
|
+
</table>
|
|
1492
|
+
<p>For account orders and ticket lists use <code>hooks.useOrders</code>,
|
|
1493
|
+
<code>hooks.useOrder</code>, <code>ttf.orders.list</code>,
|
|
1494
|
+
<code>ttf.orders.get</code> or <code>ttf.orders.myTickets</code>. In
|
|
1495
|
+
this version <code>ttf.orders.get</code> / <code>useOrder</code> take a
|
|
1496
|
+
<strong>numeric order ID string</strong>, not a public order hash;
|
|
1497
|
+
<code>OrderConfirmation</code> takes a hash. The package does not export
|
|
1498
|
+
1.x <code>MyTicketsContainer</code>, <code>OrdersContainer</code>,
|
|
1499
|
+
<code>OrderDetailsContainer</code> or <code>TicketResaleContainer</code>
|
|
1500
|
+
as drop-in React replacements. Account/resale APIs and hooks can support
|
|
1501
|
+
a host-built screen when the appropriate account session and backend
|
|
1502
|
+
capabilities exist.</p>
|
|
1503
|
+
<h3 id="ui-primitives">UI primitives</h3>
|
|
1504
|
+
<p>Use these within a <code>.tf-checkout</code> styling boundary such as
|
|
1505
|
+
<code>CheckoutProvider</code>; standard HTML attributes apply where the
|
|
1506
|
+
component extends them.</p>
|
|
1507
|
+
<table>
|
|
1508
|
+
<thead>
|
|
1509
|
+
<tr>
|
|
1510
|
+
<th>Export</th>
|
|
1511
|
+
<th>Important props</th>
|
|
1512
|
+
</tr>
|
|
1513
|
+
</thead>
|
|
1514
|
+
<tbody>
|
|
1515
|
+
<tr>
|
|
1516
|
+
<td><code>Card</code></td>
|
|
1517
|
+
<td>HTML <code>div</code> attributes and children.</td>
|
|
1518
|
+
</tr>
|
|
1519
|
+
<tr>
|
|
1520
|
+
<td><code>SectionHeader</code></td>
|
|
1521
|
+
<td><code>title</code>, <code>step?</code>, <code>pills?</code>,
|
|
1522
|
+
<code>className?</code>.</td>
|
|
1523
|
+
</tr>
|
|
1524
|
+
<tr>
|
|
1525
|
+
<td><code>Pill</code></td>
|
|
1526
|
+
<td><code>children</code>, <code>muted?</code>.</td>
|
|
1527
|
+
</tr>
|
|
1528
|
+
<tr>
|
|
1529
|
+
<td><code>Button</code></td>
|
|
1530
|
+
<td>Button attributes,
|
|
1531
|
+
<code>variant?: 'primary' | 'secondary' | 'ghost'</code>,
|
|
1532
|
+
<code>block?</code>, <code>loading?</code>.</td>
|
|
1533
|
+
</tr>
|
|
1534
|
+
<tr>
|
|
1535
|
+
<td><code>Field</code></td>
|
|
1536
|
+
<td><code>children</code>, <code>label?</code>, <code>error?</code>,
|
|
1537
|
+
<code>invalid?</code>, <code>className?</code>; <code>FieldRow</code>
|
|
1538
|
+
takes <code>children</code>, <code>className?</code>.</td>
|
|
1539
|
+
</tr>
|
|
1540
|
+
<tr>
|
|
1541
|
+
<td><code>Input</code>, <code>Textarea</code>, <code>Select</code></td>
|
|
1542
|
+
<td>Corresponding HTML attributes plus <code>invalid?</code>.</td>
|
|
1543
|
+
</tr>
|
|
1544
|
+
<tr>
|
|
1545
|
+
<td><code>Checkbox</code></td>
|
|
1546
|
+
<td>Input attributes plus <code>label?</code>.</td>
|
|
1547
|
+
</tr>
|
|
1548
|
+
<tr>
|
|
1549
|
+
<td><code>CustomFieldInput</code></td>
|
|
1550
|
+
<td><code>field</code>, <code>value</code>, <code>onChange</code>,
|
|
1551
|
+
<code>error?</code>.</td>
|
|
1552
|
+
</tr>
|
|
1553
|
+
<tr>
|
|
1554
|
+
<td><code>CustomFieldGroupFields</code></td>
|
|
1555
|
+
<td><code>group</code>, <code>values</code>,
|
|
1556
|
+
<code>onChange(name, value)</code>, <code>ticketTypeId?</code>;
|
|
1557
|
+
<code>customFieldsComplete</code> is also exported.</td>
|
|
1558
|
+
</tr>
|
|
1559
|
+
<tr>
|
|
1560
|
+
<td><code>PaymentMethods</code></td>
|
|
1561
|
+
<td>Controlled <code>options</code>, <code>selected</code>,
|
|
1562
|
+
<code>onSelect</code>, <code>extraValues</code>,
|
|
1563
|
+
<code>onExtraChange</code>; optional <code>showValidation</code>,
|
|
1564
|
+
<code>children</code>, <code>inputSlotFor</code>,
|
|
1565
|
+
<code>className</code>.</td>
|
|
1566
|
+
</tr>
|
|
1567
|
+
<tr>
|
|
1568
|
+
<td><code>Stepper</code></td>
|
|
1569
|
+
<td><code>value</code>, <code>onChange</code>, <code>min?</code>,
|
|
1570
|
+
<code>max?</code>, <code>step?</code>, <code>disabled?</code>,
|
|
1571
|
+
<code>className?</code>.</td>
|
|
1572
|
+
</tr>
|
|
1573
|
+
<tr>
|
|
1574
|
+
<td><code>QuantitySelect</code></td>
|
|
1575
|
+
<td><code>value</code>, <code>onChange</code>, <code>min?</code>,
|
|
1576
|
+
<code>max?</code>, <code>step?</code>, <code>disabled?</code>,
|
|
1577
|
+
<code>className?</code>, accessible <code>label?</code>.</td>
|
|
1578
|
+
</tr>
|
|
1579
|
+
<tr>
|
|
1580
|
+
<td><code>PriceLine</code></td>
|
|
1581
|
+
<td><code>amount</code>, <code>currency?</code>, <code>original?</code>,
|
|
1582
|
+
<code>note?</code>, <code>className?</code>.</td>
|
|
1583
|
+
</tr>
|
|
1584
|
+
<tr>
|
|
1585
|
+
<td><code>Timer</code></td>
|
|
1586
|
+
<td><code>seconds</code>, <code>urgentAt?</code>, <code>label?</code>,
|
|
1587
|
+
<code>className?</code>. <code>TimerBanner</code> takes
|
|
1588
|
+
<code>seconds?</code>, <code>urgentAt?</code>, <code>message?</code>,
|
|
1589
|
+
<code>className?</code>.</td>
|
|
1590
|
+
</tr>
|
|
1591
|
+
<tr>
|
|
1592
|
+
<td><code>Loader</code></td>
|
|
1593
|
+
<td><code>className?</code>.</td>
|
|
1594
|
+
</tr>
|
|
1595
|
+
<tr>
|
|
1596
|
+
<td><code>SignaturePad</code></td>
|
|
1597
|
+
<td><code>label</code>, <code>clearLabel</code>,
|
|
1598
|
+
<code>onChange(pngDataUrl, inkLength)</code>,
|
|
1599
|
+
<code>disabled?</code>.</td>
|
|
1600
|
+
</tr>
|
|
1601
|
+
<tr>
|
|
1602
|
+
<td><code>FrozenFields</code></td>
|
|
1603
|
+
<td><code>children</code>, <code>frozen?</code>; disables interaction
|
|
1604
|
+
for its nested fields.</td>
|
|
1605
|
+
</tr>
|
|
1606
|
+
</tbody>
|
|
1607
|
+
</table>
|
|
1608
|
+
<p>Additional web exports include <code>themeToVars</code>,
|
|
1609
|
+
<code>cx</code>, <code>I18nProvider</code>, <code>useT</code>,
|
|
1610
|
+
<code>useInstallmentPicker</code>, <code>CardInput</code>,
|
|
1611
|
+
<code>StripePaymentElement</code>, <code>XenditCardInput</code>,
|
|
1612
|
+
<code>claimCardField</code>, <code>webConfirmer</code>,
|
|
1613
|
+
<code>webPorts</code>, <code>webXenditTokenizer</code>, and the
|
|
1614
|
+
<code>createWebStripeConfirmer</code>, <code>createWebPorts</code>,
|
|
1615
|
+
<code>createWebXenditTokenizer</code> factories. Their installed
|
|
1616
|
+
declarations specify complete inputs and outputs. These are lower-level
|
|
1617
|
+
integration points; preserve their payment and session ownership rules
|
|
1618
|
+
when replacing the default flow.</p>
|
|
1619
|
+
<h2 id="headless-apis">Headless APIs</h2>
|
|
1620
|
+
<p><code>useCheckout()</code> returns the snapshot both flat and as
|
|
1621
|
+
<code>snapshot</code>, plus actions. The web version injects browser
|
|
1622
|
+
payment ports; the shared <code>hooks.useCheckout</code> is the
|
|
1623
|
+
lower-level binding and requires an engine configuration. The following
|
|
1624
|
+
example only reserves caller-supplied current catalog selections. It
|
|
1625
|
+
deliberately does not place an order without collecting the event's
|
|
1626
|
+
required data.</p>
|
|
1627
|
+
<pre class="tsx"><code>import { useState } from 'react'
|
|
1628
|
+
import { useCheckout, type TicketSelection } from 'tf-checkout-react'
|
|
1629
|
+
|
|
1630
|
+
export function ReserveButton(props: {
|
|
1631
|
+
eventId: string
|
|
1632
|
+
selections: TicketSelection[]
|
|
1633
|
+
}) {
|
|
1634
|
+
const checkout = useCheckout()
|
|
1635
|
+
const [message, setMessage] = useState('')
|
|
1636
|
+
async function reserve() {
|
|
1637
|
+
try {
|
|
1638
|
+
await checkout.setTickets(props.eventId, props.selections)
|
|
1639
|
+
setMessage('Tickets reserved')
|
|
1640
|
+
} catch (error) {
|
|
1641
|
+
setMessage(error instanceof Error ? error.message : 'Could not reserve tickets')
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
return (
|
|
1645
|
+
<div>
|
|
1646
|
+
<button disabled={checkout.isBusy} onClick={() => void reserve()}>
|
|
1647
|
+
Reserve
|
|
1648
|
+
</button>
|
|
1649
|
+
<p role="status">{message}</p>
|
|
1650
|
+
</div>
|
|
1651
|
+
)
|
|
1652
|
+
}</code></pre>
|
|
1653
|
+
<p>A <code>TicketSelection</code> has <code>id</code> (current encrypted
|
|
1654
|
+
ticket ID), <code>name</code>, <code>optionName</code>,
|
|
1655
|
+
<code>price</code>, <code>quantity</code> and <code>currency</code>.
|
|
1656
|
+
Construct it from the current catalog, not a stale cached display row.
|
|
1657
|
+
Do not trust client-side prices as the final order amount.</p>
|
|
1658
|
+
<h3 id="snapshot-and-actions">Snapshot and actions</h3>
|
|
1659
|
+
<table>
|
|
1660
|
+
<thead>
|
|
1661
|
+
<tr>
|
|
1662
|
+
<th>Field / action</th>
|
|
1663
|
+
<th>Contract</th>
|
|
1664
|
+
</tr>
|
|
1665
|
+
</thead>
|
|
1666
|
+
<tbody>
|
|
1667
|
+
<tr>
|
|
1668
|
+
<td><code>status</code>, <code>error</code>, <code>order</code>,
|
|
1669
|
+
<code>eventId</code>, <code>expiresAt</code>, <code>secondsLeft</code>,
|
|
1670
|
+
<code>isBusy</code></td>
|
|
1671
|
+
<td>Progress, latest error/result and reservation timing.
|
|
1672
|
+
<code>error</code> is a display string; async actions may also
|
|
1673
|
+
reject.</td>
|
|
1674
|
+
</tr>
|
|
1675
|
+
<tr>
|
|
1676
|
+
<td><code>selections</code>, <code>ticketTypeIds</code>,
|
|
1677
|
+
<code>addOns</code>, <code>breakdown</code>,
|
|
1678
|
+
<code>priceBreakdown</code></td>
|
|
1679
|
+
<td>Cart selections, decrypted ticket type IDs and server pricing.
|
|
1680
|
+
Prefer server-priced output for display.</td>
|
|
1681
|
+
</tr>
|
|
1682
|
+
<tr>
|
|
1683
|
+
<td><code>customFields</code>, <code>buyerFields</code>,
|
|
1684
|
+
<code>fieldGates</code>, <code>holderNamesRequired</code>,
|
|
1685
|
+
<code>requiredAddOns</code>, <code>missingRequiredAddonNames</code></td>
|
|
1686
|
+
<td>Inputs and event gates. Required add-ons sold out are exempt from
|
|
1687
|
+
the missing-add-on check.</td>
|
|
1688
|
+
</tr>
|
|
1689
|
+
<tr>
|
|
1690
|
+
<td><code>billing</code>, <code>holders</code>, <code>consent</code>,
|
|
1691
|
+
<code>conditions</code>, <code>acceptedConditions</code>,
|
|
1692
|
+
<code>existingAccountEmail</code></td>
|
|
1693
|
+
<td>Buyer draft and acceptance state.
|
|
1694
|
+
<code>checkBuyerEmail(email)</code> starts an existing-account check and
|
|
1695
|
+
writes the result to the snapshot.</td>
|
|
1696
|
+
</tr>
|
|
1697
|
+
<tr>
|
|
1698
|
+
<td><code>waiver</code>, <code>waiverSignatures</code>,
|
|
1699
|
+
<code>waiverSigningIndexes</code>, <code>unavailableDetails</code>,
|
|
1700
|
+
<code>orderFixed</code></td>
|
|
1701
|
+
<td>Waiver and order-edit state. Forms are frozen while placing or after
|
|
1702
|
+
the order is charged.</td>
|
|
1703
|
+
</tr>
|
|
1704
|
+
<tr>
|
|
1705
|
+
<td><code>gateway</code>, <code>stripe</code>,
|
|
1706
|
+
<code>paymentStripe</code>, <code>paymentPlan</code>,
|
|
1707
|
+
<code>redirectPaymentMethods</code>, <code>walletAvailability</code>,
|
|
1708
|
+
<code>stripeElementsConfig</code>, <code>currency</code></td>
|
|
1709
|
+
<td>Payment/configuration data after priming. Absence does not authorize
|
|
1710
|
+
a method.</td>
|
|
1711
|
+
</tr>
|
|
1712
|
+
<tr>
|
|
1713
|
+
<td><code>extraItems</code>, <code>extraDraft</code>,
|
|
1714
|
+
<code>extraQuotes</code>, <code>extraRejections</code>,
|
|
1715
|
+
<code>extraExpiresAt</code>, <code>reviewedExtraOrderTotal</code></td>
|
|
1716
|
+
<td>Accommodation/extras state and changed authoritative total. Show a
|
|
1717
|
+
changed total before another Pay action.</td>
|
|
1718
|
+
</tr>
|
|
1719
|
+
<tr>
|
|
1720
|
+
<td><code>setTickets(eventId, selections)</code>,
|
|
1721
|
+
<code>setSeats(eventId, lines)</code>,
|
|
1722
|
+
<code>setSeatsIo(eventId, selection)</code>,
|
|
1723
|
+
<code>resumeCart(eventId, options?)</code></td>
|
|
1724
|
+
<td>Build/price or resume a server cart; return promises.</td>
|
|
1725
|
+
</tr>
|
|
1726
|
+
<tr>
|
|
1727
|
+
<td><code>setAddons(addOns)</code>,
|
|
1728
|
+
<code>setExtraItems(items)</code></td>
|
|
1729
|
+
<td>Reprice/reserve selections asynchronously.
|
|
1730
|
+
<code>setExtraDraft(items | undefined)</code> changes the local
|
|
1731
|
+
draft.</td>
|
|
1732
|
+
</tr>
|
|
1733
|
+
<tr>
|
|
1734
|
+
<td><code>setBilling(billing)</code>,
|
|
1735
|
+
<code>setHolders(holders, options?)</code>,
|
|
1736
|
+
<code>setConsent(consent)</code></td>
|
|
1737
|
+
<td>Commit buyer, holder and marketing data. <code>setHolders</code> can
|
|
1738
|
+
mark backfilled holder indexes.</td>
|
|
1739
|
+
</tr>
|
|
1740
|
+
<tr>
|
|
1741
|
+
<td><code>setAcceptedConditions(map)</code>,
|
|
1742
|
+
<code>acceptCondition(id, accepted)</code>,
|
|
1743
|
+
<code>setAddonDataCapture(map)</code></td>
|
|
1744
|
+
<td>Record condition acceptance and add-on answers.</td>
|
|
1745
|
+
</tr>
|
|
1746
|
+
<tr>
|
|
1747
|
+
<td><code>setWaiverSignature(index, signature, hold?)</code>,
|
|
1748
|
+
<code>holdWaiverSigning(index)</code></td>
|
|
1749
|
+
<td>Coordinate a signature save with the cart/holder it belongs to;
|
|
1750
|
+
release a hold when finished. Prefer <code>WaiverSigning</code> for
|
|
1751
|
+
standard UI.</td>
|
|
1752
|
+
</tr>
|
|
1753
|
+
<tr>
|
|
1754
|
+
<td><code>reloadCheckoutDetails()</code>,
|
|
1755
|
+
<code>syncCurrency(eventId, code?, options?)</code></td>
|
|
1756
|
+
<td>Retry unavailable details or switch/seed event currency. Refresh
|
|
1757
|
+
selection and prices after changing currency.</td>
|
|
1758
|
+
</tr>
|
|
1759
|
+
<tr>
|
|
1760
|
+
<td><code>placeOrder(method?, options?)</code>,
|
|
1761
|
+
<code>runIdVerification(orderHash, options?)</code></td>
|
|
1762
|
+
<td>Place/pay; optionally run verification separately with a host URL
|
|
1763
|
+
opener or takeover. See <a href="#host-owned-id-verification">host-owned
|
|
1764
|
+
ID verification</a>. <code>placeOrder</code> accepts
|
|
1765
|
+
<code>autoRunIdVerification</code>, <code>idVerification</code> and
|
|
1766
|
+
<code>claimCard</code> options.</td>
|
|
1767
|
+
</tr>
|
|
1768
|
+
<tr>
|
|
1769
|
+
<td><code>applyPromoCode(eventId, code)</code>,
|
|
1770
|
+
<code>attributeReferrer(eventId, referrer)</code>,
|
|
1771
|
+
<code>joinWaitingList(eventId, entry)</code></td>
|
|
1772
|
+
<td>Helpers return promises. Refetch catalog after a code changes
|
|
1773
|
+
availability.</td>
|
|
1774
|
+
</tr>
|
|
1775
|
+
<tr>
|
|
1776
|
+
<td><code>reset()</code>, <code>resetWhenSettled()</code></td>
|
|
1777
|
+
<td>Restart subject to payment-settlement protection; see <a
|
|
1778
|
+
href="#checkout-lifecycle">lifecycle</a>.</td>
|
|
1779
|
+
</tr>
|
|
1780
|
+
<tr>
|
|
1781
|
+
<td><code>snapshot</code>, <code>store</code>,
|
|
1782
|
+
<code>isLoggedIn</code></td>
|
|
1783
|
+
<td>Entire state, shared store, and whether the hook sees an
|
|
1784
|
+
authenticated or checkout buyer session. The latter does not imply
|
|
1785
|
+
private-account authority.</td>
|
|
1786
|
+
</tr>
|
|
1787
|
+
</tbody>
|
|
1788
|
+
</table>
|
|
1789
|
+
<p><code>checkBuyerEmail</code> is not itself debounced.
|
|
1790
|
+
<code>BillingInfo</code> delays calls, but a headless host should
|
|
1791
|
+
debounce and coordinate in-flight checks. A late response for an earlier
|
|
1792
|
+
email in the same cart can overwrite the snapshot; compare
|
|
1793
|
+
<code>existingAccountEmail</code> with the current trimmed input before
|
|
1794
|
+
prompting and recheck the current value if needed.</p>
|
|
1795
|
+
<p><code>CheckoutBilling</code> requires <code>firstName</code>,
|
|
1796
|
+
<code>lastName</code>, <code>email</code>; optional fields include
|
|
1797
|
+
<code>confirmEmail</code>, <code>phone</code>, address, country/state
|
|
1798
|
+
IDs and codes, date of birth, nationality, gender, Instagram and
|
|
1799
|
+
<code>dataCapture</code>. <code>CheckoutHolder</code> requires
|
|
1800
|
+
<code>firstName</code>, <code>lastName</code>, <code>email</code>;
|
|
1801
|
+
optional <code>phone</code>, <code>ticketTypeId</code>,
|
|
1802
|
+
<code>ticketDataCapture</code>. <code>CheckoutConsent</code> has boolean
|
|
1803
|
+
<code>ttfOptIn</code> and <code>brandOptIn</code>. Event gates may
|
|
1804
|
+
require additional data even where the TypeScript property is optional.
|
|
1805
|
+
<code>confirmEmail</code> is a UI/preflight value; the order request
|
|
1806
|
+
uses the authoritative email.</p>
|
|
1807
|
+
<p><code>PaymentMethod</code> accepts <code>'card'</code>,
|
|
1808
|
+
<code>'applePay'</code> or <code>'googlePay'</code>.
|
|
1809
|
+
<code>PaymentRequest</code> additionally accepts objects with
|
|
1810
|
+
<code>method: 'auto'</code>, <code>'card'</code>,
|
|
1811
|
+
<code>'applePay'</code>, <code>'googlePay'</code>,
|
|
1812
|
+
<code>'redirect'</code> (<code>methodType</code>), <code>'oxxo'</code>,
|
|
1813
|
+
<code>'xenditEWallet'</code> (<code>walletKey</code>, optional
|
|
1814
|
+
<code>extra.cashtag</code> / <code>extra.phoneNumber</code>),
|
|
1815
|
+
<code>'paypal'</code>, <code>'razorpay'</code> (optional
|
|
1816
|
+
<code>description</code>), <code>'adyen'</code>,
|
|
1817
|
+
<code>'xenditCard'</code>, or <code>'paymentPlan'</code> (optional
|
|
1818
|
+
<code>useSavedCard</code>). Availability and necessary ports are
|
|
1819
|
+
provider-specific. <code>placeOrder()</code> defaults to card; do not
|
|
1820
|
+
use that default for a different gateway.</p>
|
|
1821
|
+
<h3 id="react-query-hooks-and-direct-api">React Query hooks and direct
|
|
1822
|
+
API</h3>
|
|
1823
|
+
<p>The package re-exports the shared core: <code>ttf</code> is a
|
|
1824
|
+
configured domain facade, <code>api</code> contains raw calls,
|
|
1825
|
+
<code>hooks</code> contains React bindings, and DTOs, logic,
|
|
1826
|
+
<code>createEngine</code> and <code>createCheckoutStore</code> are named
|
|
1827
|
+
exports. Network calls usually return promises;
|
|
1828
|
+
<code>ttf.events.filterAddonsForTickets</code> and
|
|
1829
|
+
<code>ttf.order.mapProfileToBilling</code> are synchronous helpers. They
|
|
1830
|
+
do not render UI or replace the engine's sequencing, payment ownership
|
|
1831
|
+
and preflight. Use them directly only when your application owns the
|
|
1832
|
+
corresponding workflow. The installed <code>dist/index.d.ts</code>
|
|
1833
|
+
includes the complete exported signatures. Avoid importing a private
|
|
1834
|
+
shared-core package.</p>
|
|
1835
|
+
<pre class="tsx"><code>import { hooks } from 'tf-checkout-react'
|
|
1836
|
+
|
|
1837
|
+
export function CatalogStatus({ eventId }: { eventId: string }) {
|
|
1838
|
+
const catalog = hooks.useTicketsWithMeta(eventId)
|
|
1839
|
+
if (catalog.isPending) return <p>Loading tickets…</p>
|
|
1840
|
+
if (catalog.isError) return <button onClick={() => void catalog.refetch()}>Retry</button>
|
|
1841
|
+
return <p>{catalog.data.tickets.length} ticket types</p>
|
|
1842
|
+
}</code></pre>
|
|
1843
|
+
<p>Useful hook groups, all imported through <code>hooks</code>:</p>
|
|
1844
|
+
<ul>
|
|
1845
|
+
<li>Catalog: <code>useEvent</code>, <code>useTickets</code>,
|
|
1846
|
+
<code>useTicketsWithMeta</code>, <code>useTimeSlotTickets</code>,
|
|
1847
|
+
<code>useEventAddons</code>, <code>useEventBundles</code>,
|
|
1848
|
+
<code>useTicketCatalog</code>, <code>useCountries</code>,
|
|
1849
|
+
<code>useStates</code>.</li>
|
|
1850
|
+
<li>Authentication/session: <code>useAuthFlow</code>,
|
|
1851
|
+
<code>useAuthSession</code>, <code>useLogin</code>,
|
|
1852
|
+
<code>useRegister</code>, <code>useLogout</code>,
|
|
1853
|
+
<code>useProfile</code>, <code>usePhoneAuthentication</code> and
|
|
1854
|
+
verification mutations. Choose the correct public checkout or account
|
|
1855
|
+
path.</li>
|
|
1856
|
+
<li>Checkout/selection: <code>useCheckout</code>,
|
|
1857
|
+
<code>useAddOnSelection</code>, <code>useSeatSelection</code>,
|
|
1858
|
+
<code>useSeatsIoSelection</code>, <code>useWaitingListForm</code>,
|
|
1859
|
+
<code>useWaiverSigning</code>, <code>useAccommodationSelection</code>,
|
|
1860
|
+
<code>useCheckoutPaymentMethods</code>, <code>useBundleFlow</code>.</li>
|
|
1861
|
+
<li>After purchase/account: <code>useOrders</code>,
|
|
1862
|
+
<code>useOrder</code>, <code>useOrderRewards</code>,
|
|
1863
|
+
<code>useTicketChange</code>, <code>useTicketRefund</code>,
|
|
1864
|
+
<code>useTicketGift</code>, <code>useCustomerPasses</code>,
|
|
1865
|
+
<code>useAccountPreferences</code>,
|
|
1866
|
+
<code>useNotificationPreferences</code>,
|
|
1867
|
+
<code>useAccountDeletion</code>, <code>useFriends</code>,
|
|
1868
|
+
<code>useEventComments</code>, <code>useTrips</code>.</li>
|
|
1869
|
+
</ul>
|
|
1870
|
+
<p>Catalog hooks use an event ID and many are disabled until it is
|
|
1871
|
+
present; query results expose standard React Query loading, error, data
|
|
1872
|
+
and <code>refetch</code> states. The account-order query uses a numeric
|
|
1873
|
+
order ID. Account access is scoped to the buyer session; don't reuse
|
|
1874
|
+
private cached data across sign-out or buyer changes.</p>
|
|
1875
|
+
<p>The <code>ttf</code> facade groups calls under <code>auth</code>,
|
|
1876
|
+
<code>profile</code>, <code>events</code>, <code>cart</code>,
|
|
1877
|
+
<code>order</code>, <code>payment</code>, <code>seatmap</code>,
|
|
1878
|
+
<code>engagement</code>, <code>confirmation</code>,
|
|
1879
|
+
<code>rewards</code>, <code>orders</code>, <code>ticketChanges</code>,
|
|
1880
|
+
<code>resale</code>, <code>refunds</code>, <code>gifts</code>,
|
|
1881
|
+
<code>passes</code>, <code>waivers</code>, <code>extras</code>,
|
|
1882
|
+
<code>trips</code>, <code>preferences</code>, <code>friends</code>,
|
|
1883
|
+
<code>savedEvents</code>, <code>comments</code>, <code>word</code>,
|
|
1884
|
+
<code>preRegistration</code> and <code>delegation</code>. For example,
|
|
1885
|
+
<code>ttf.events.ticketsWithMeta</code> loads a catalog,
|
|
1886
|
+
<code>ttf.geo.countries()</code> loads country choices, and
|
|
1887
|
+
<code>ttf.confirmation.get(orderHash)</code> reads a confirmation. The
|
|
1888
|
+
<code>geo</code> group is also available. Check each method's declared
|
|
1889
|
+
input and backend authority before calling it.</p>
|
|
1890
|
+
<p>Transport errors are normalized as <code>TtfError</code>, with
|
|
1891
|
+
<code>message</code>, HTTP <code>status</code> (<code>0</code> for
|
|
1892
|
+
transport failure), optional <code>code</code>, <code>data</code> and
|
|
1893
|
+
<code>retryAfter</code> seconds. Engine validation and provider errors
|
|
1894
|
+
can also be ordinary errors or typed errors such as
|
|
1895
|
+
<code>UNSUPPORTED_GATEWAY</code>; handle unknown errors as well. Avoid
|
|
1896
|
+
logging raw error data if it may contain personal or payment
|
|
1897
|
+
information.</p>
|
|
1898
|
+
<h3 id="tracking">Tracking</h3>
|
|
1899
|
+
<p>For an integration that is authorized to send event tracking, the
|
|
1900
|
+
explicit facade call is
|
|
1901
|
+
<code>ttf.events.track(eventId, { pageUrl?, page?, orderHash? })</code>.
|
|
1902
|
+
The host owns when it fires, consent, deduplication and any additional
|
|
1903
|
+
analytics pixels. No 1.x pixel setup or automatic event equivalence
|
|
1904
|
+
should be assumed. Avoid sending unnecessary buyer data in URLs or
|
|
1905
|
+
analytics.</p>
|
|
1906
|
+
<h2 id="styling-and-localization">Styling and localization</h2>
|
|
1907
|
+
<p>Pass a <code>theme</code> to <code>EmbeddedCheckout</code>,
|
|
1908
|
+
<code>ResumedCheckout</code> or <code>CheckoutProvider</code>. All
|
|
1909
|
+
tokens are optional:</p>
|
|
1910
|
+
<table>
|
|
1911
|
+
<thead>
|
|
1912
|
+
<tr>
|
|
1913
|
+
<th>Group</th>
|
|
1914
|
+
<th><code>CheckoutTheme</code> keys</th>
|
|
1915
|
+
</tr>
|
|
1916
|
+
</thead>
|
|
1917
|
+
<tbody>
|
|
1918
|
+
<tr>
|
|
1919
|
+
<td>Scheme</td>
|
|
1920
|
+
<td><code>colorScheme: 'light' | 'dark'</code>; when omitted CSS follows
|
|
1921
|
+
the browser/OS preference.</td>
|
|
1922
|
+
</tr>
|
|
1923
|
+
<tr>
|
|
1924
|
+
<td>Colors</td>
|
|
1925
|
+
<td><code>accent</code>, <code>accentHover</code>,
|
|
1926
|
+
<code>accentContrast</code>, <code>surface</code>,
|
|
1927
|
+
<code>surfaceMuted</code>, <code>text</code>, <code>muted</code>,
|
|
1928
|
+
<code>border</code>, <code>error</code>, <code>success</code>.</td>
|
|
1929
|
+
</tr>
|
|
1930
|
+
<tr>
|
|
1931
|
+
<td>Shape</td>
|
|
1932
|
+
<td><code>radiusCard</code>, <code>radiusControl</code>,
|
|
1933
|
+
<code>shadow</code>.</td>
|
|
1934
|
+
</tr>
|
|
1935
|
+
<tr>
|
|
1936
|
+
<td>Type/layout</td>
|
|
1937
|
+
<td><code>font</code>, <code>fontSize</code>,
|
|
1938
|
+
<code>maxWidth</code>.</td>
|
|
1939
|
+
</tr>
|
|
1940
|
+
</tbody>
|
|
1941
|
+
</table>
|
|
1942
|
+
<p>Values are CSS strings mapped to <code>--tf-checkout-*</code> custom
|
|
1943
|
+
properties. The provider adds <code>.tf-checkout</code> and optionally
|
|
1944
|
+
<code>.tf-checkout--light</code> or <code>.tf-checkout--dark</code>;
|
|
1945
|
+
section classes use <code>tf-checkout-*</code>. Theme variables and
|
|
1946
|
+
classes can be overridden by your CSS, but test embedded Stripe iframes
|
|
1947
|
+
and third-party phone/seat-map styling separately. Stripe Elements do
|
|
1948
|
+
not inherit page CSS directly. Preserve readable contrast, visible focus
|
|
1949
|
+
and usable error states in custom themes.</p>
|
|
1950
|
+
<p><code>locale</code> defaults to <code>en-GB</code>; accepted
|
|
1951
|
+
<code>LocaleCode</code> values are <code>en-GB</code>,
|
|
1952
|
+
<code>en-US</code>, <code>es-MX</code>, <code>fr</code>,
|
|
1953
|
+
<code>de</code>, <code>ru</code>, and <code>id</code>. Catalogues can be
|
|
1954
|
+
partial and fall back to English; verify all buyer-facing copy for your
|
|
1955
|
+
event. Pass <code>messages</code> for per-key overrides, or use
|
|
1956
|
+
<code>I18nProvider</code> / <code>useT</code> around standalone
|
|
1957
|
+
components. Event-supplied content and provider pages may have their own
|
|
1958
|
+
language. Test keyboard navigation, screen readers, validation focus,
|
|
1959
|
+
small screens, reduced motion, popups, and the entire host page; an SDK
|
|
1960
|
+
control alone cannot guarantee accessibility of the surrounding
|
|
1961
|
+
experience.</p>
|
|
1962
|
+
<h2 id="migrating-from-1x">Migrating from 1.x</h2>
|
|
1963
|
+
<p>2.x is a new shared-core integration, not a prop-compatible update.
|
|
1964
|
+
Keep the existing 1.x integration pinned until the new flow and backend
|
|
1965
|
+
are verified. There is no automatic translation of old URLs, component
|
|
1966
|
+
props, account sessions or persisted 1.x state.</p>
|
|
1967
|
+
<table>
|
|
1968
|
+
<thead>
|
|
1969
|
+
<tr>
|
|
1970
|
+
<th>1.x integration</th>
|
|
1971
|
+
<th>2.0.0-beta.27 approach</th>
|
|
1972
|
+
</tr>
|
|
1973
|
+
</thead>
|
|
1974
|
+
<tbody>
|
|
1975
|
+
<tr>
|
|
1976
|
+
<td><code>setConfigs({ BASE_URL, ... })</code></td>
|
|
1977
|
+
<td><code>configureCheckout({ env</code> or <code>baseUrl</code>,
|
|
1978
|
+
<code>clientId</code>, <code>clientSecret: ''</code>, ...
|
|
1979
|
+
<code>})</code>; public client registration and session setup are
|
|
1980
|
+
required.</td>
|
|
1981
|
+
</tr>
|
|
1982
|
+
<tr>
|
|
1983
|
+
<td><code>TicketsContainer</code>, <code>SeatMapContainer</code>,
|
|
1984
|
+
<code>AddOnsContainer</code></td>
|
|
1985
|
+
<td><code>EmbeddedCheckout</code> or <code>Tickets</code>,
|
|
1986
|
+
<code>SeatMap</code>, <code>AddOns</code> under
|
|
1987
|
+
<code>CheckoutProvider</code>. Adapt callbacks and navigation.</td>
|
|
1988
|
+
</tr>
|
|
1989
|
+
<tr>
|
|
1990
|
+
<td><code>BillingInfoContainer</code>,
|
|
1991
|
+
<code>PaymentContainer</code></td>
|
|
1992
|
+
<td><code>BillingInfo</code> and <code>Payment</code> with matched
|
|
1993
|
+
policies and the current cart; or embedded flow. Old prop
|
|
1994
|
+
names/callbacks are not a contract.</td>
|
|
1995
|
+
</tr>
|
|
1996
|
+
<tr>
|
|
1997
|
+
<td><code>ConfirmationContainer</code></td>
|
|
1998
|
+
<td><code>Confirmation</code> for the active flow or
|
|
1999
|
+
<code>OrderConfirmation</code> for a reloadable order-hash page. Handle
|
|
2000
|
+
<code>pending</code> and ID verification.</td>
|
|
2001
|
+
</tr>
|
|
2002
|
+
<tr>
|
|
2003
|
+
<td>Legacy login/register/forgot-password modals</td>
|
|
2004
|
+
<td><code>AuthModal</code> or <code>hooks.useAuthFlow</code> and
|
|
2005
|
+
controlled forms. Distinguish event-scoped checkout identity from a full
|
|
2006
|
+
account session.</td>
|
|
2007
|
+
</tr>
|
|
2008
|
+
<tr>
|
|
2009
|
+
<td><code>AccountSettings</code></td>
|
|
2010
|
+
<td>No same-named drop-in replacement is established. Evaluate
|
|
2011
|
+
<code>AccountProfile</code>, <code>ProfileSettings</code>,
|
|
2012
|
+
<code>NotificationPreferences</code> and the account APIs against your
|
|
2013
|
+
required authorized account features.</td>
|
|
2014
|
+
</tr>
|
|
2015
|
+
<tr>
|
|
2016
|
+
<td><code>MyTicketsContainer</code>, order/detail and resale
|
|
2017
|
+
containers</td>
|
|
2018
|
+
<td>No same-named drop-in component in this version. Use supported
|
|
2019
|
+
account APIs/hooks and build the host UI after verifying authorization
|
|
2020
|
+
and deployed backend support.</td>
|
|
2021
|
+
</tr>
|
|
2022
|
+
<tr>
|
|
2023
|
+
<td>Webflow/no-code integration</td>
|
|
2024
|
+
<td>No 2.x drop-in Webflow or no-code checkout integration has been
|
|
2025
|
+
established. Integrate the React checkout in a compatible host or verify
|
|
2026
|
+
a separate integration with Ticket Fairy.</td>
|
|
2027
|
+
</tr>
|
|
2028
|
+
<tr>
|
|
2029
|
+
<td>Promo/access, waiting list, pixel and referral behavior</td>
|
|
2030
|
+
<td>Re-check catalog metadata, code/attribution precedence, waiting-list
|
|
2031
|
+
contract and explicit tracking. Do not infer numeric
|
|
2032
|
+
<code>?r=</code>.</td>
|
|
2033
|
+
</tr>
|
|
2034
|
+
<tr>
|
|
2035
|
+
<td>Legacy single-page state in localStorage</td>
|
|
2036
|
+
<td>Use the 2.x checkout store/engine and server cart; do not copy
|
|
2037
|
+
sensitive state or assume 1.x persisted state can be resumed.</td>
|
|
2038
|
+
</tr>
|
|
2039
|
+
</tbody>
|
|
2040
|
+
</table>
|
|
2041
|
+
<h3 id="migrating-layout-callbacks">Migrating layout callbacks</h3>
|
|
2042
|
+
<p>A callback name change can also change what the host receives. In
|
|
2043
|
+
particular, <code>onContinue</code> does not pass the old callback's
|
|
2044
|
+
response payload:</p>
|
|
2045
|
+
<table>
|
|
2046
|
+
<thead>
|
|
2047
|
+
<tr>
|
|
2048
|
+
<th>1.x usage</th>
|
|
2049
|
+
<th>2.x replacement</th>
|
|
2050
|
+
</tr>
|
|
2051
|
+
</thead>
|
|
2052
|
+
<tbody>
|
|
2053
|
+
<tr>
|
|
2054
|
+
<td><code>TicketsContainer</code>'s <code>getTicketsLabel</code></td>
|
|
2055
|
+
<td><code>Tickets</code>'s <code>buttonLabel</code>.</td>
|
|
2056
|
+
</tr>
|
|
2057
|
+
<tr>
|
|
2058
|
+
<td><code>TicketsContainer</code>'s
|
|
2059
|
+
<code>onAddToCartSuccess(data)</code></td>
|
|
2060
|
+
<td><code>Tickets.onContinue()</code> after reservation; read the
|
|
2061
|
+
current cart through <code>useCheckoutContext()</code> under the
|
|
2062
|
+
provider.</td>
|
|
2063
|
+
</tr>
|
|
2064
|
+
<tr>
|
|
2065
|
+
<td><code>BillingInfoContainer</code>'s
|
|
2066
|
+
<code>handleSubmit(values, helpers, eventId, response)</code></td>
|
|
2067
|
+
<td><code>BillingInfo.onContinue()</code> after validation and save;
|
|
2068
|
+
read the current billing and holders from the checkout context. Omit the
|
|
2069
|
+
callback for combined-form behavior.</td>
|
|
2070
|
+
</tr>
|
|
2071
|
+
<tr>
|
|
2072
|
+
<td><code>AddOnsContainer</code> timer</td>
|
|
2073
|
+
<td>Render <code>TimerBanner</code> with
|
|
2074
|
+
<code>useCheckoutContext().secondsLeft</code> in the host layout.</td>
|
|
2075
|
+
</tr>
|
|
2076
|
+
<tr>
|
|
2077
|
+
<td>Separate 1.x page URLs and localStorage state</td>
|
|
2078
|
+
<td>Keep the 2.x provider mounted across host steps; implement
|
|
2079
|
+
route/refresh handling and verify any existing server cart in the
|
|
2080
|
+
current session.</td>
|
|
2081
|
+
</tr>
|
|
2082
|
+
</tbody>
|
|
2083
|
+
</table>
|
|
2084
|
+
<p>These are migration starting points, not prop-compatible aliases. In
|
|
2085
|
+
2.x <code>eventId</code> is a string; convert a numeric ID before
|
|
2086
|
+
passing it. Old Material UI theme options, callback payloads and
|
|
2087
|
+
optional page behavior need explicit host work. For the two complete
|
|
2088
|
+
flows see <a href="#choose-a-checkout-layout">Choose a checkout
|
|
2089
|
+
layout</a>; for single-page and stepped alternatives see <a
|
|
2090
|
+
href="#compose-sections">Compose sections</a>.</p>
|
|
2091
|
+
<p>Compare the exact event's ticket types, dated pricing, seats,
|
|
2092
|
+
add-ons, holder questions, conditional fields, consent, waivers, fees,
|
|
2093
|
+
currencies, payment methods, account and post-purchase behavior before
|
|
2094
|
+
switching. Backend rollout and provider acceptance are independent of
|
|
2095
|
+
the npm package publication.</p>
|
|
2096
|
+
<p>The distribution includes standalone widget JavaScript and CSS
|
|
2097
|
+
bundles for other product surfaces. Their presence alone does not
|
|
2098
|
+
establish a supported public checkout-widget API or a 2.x Webflow
|
|
2099
|
+
integration; use the documented React exports unless a separate
|
|
2100
|
+
integration contract has been verified.</p>
|
|
2101
|
+
<h2 id="testing-and-troubleshooting">Testing and troubleshooting</h2>
|
|
2102
|
+
<p>Use a non-production event and provider test configuration. Exercise
|
|
2103
|
+
at least:</p>
|
|
2104
|
+
<ol type="1">
|
|
2105
|
+
<li>A general-admission purchase, free registration, multi-quantity
|
|
2106
|
+
holders, required and unavailable add-ons, custom questions and waiver;
|
|
2107
|
+
inspect server-priced totals before payment.</li>
|
|
2108
|
+
<li>Seated/time-slot and multi-currency events if used; expiry, sold-out
|
|
2109
|
+
changes, promo/access codes, explicit referral attribution and
|
|
2110
|
+
waiting-list states.</li>
|
|
2111
|
+
<li>Guest, existing-account, sign-in, two-factor and
|
|
2112
|
+
sign-out/buyer-switch flows; verify no prior buyer's cart or private
|
|
2113
|
+
data is shown to the next buyer.</li>
|
|
2114
|
+
<li>Every enabled provider: success, decline, cancellation, blocked
|
|
2115
|
+
popup, redirect return, offline/timeout and asynchronous pending
|
|
2116
|
+
settlement. Check the authoritative order/provider before any retry or
|
|
2117
|
+
fulfilment.</li>
|
|
2118
|
+
<li>Refresh, back navigation, multiple clicks, a delayed response,
|
|
2119
|
+
small-screen and keyboard/screen-reader flows. Test on the actual
|
|
2120
|
+
supported browsers, configured origins and deployment environment.</li>
|
|
2121
|
+
</ol>
|
|
2122
|
+
<table>
|
|
2123
|
+
<thead>
|
|
2124
|
+
<tr>
|
|
2125
|
+
<th>Symptom</th>
|
|
2126
|
+
<th>Check</th>
|
|
2127
|
+
</tr>
|
|
2128
|
+
</thead>
|
|
2129
|
+
<tbody>
|
|
2130
|
+
<tr>
|
|
2131
|
+
<td>"SDK is not configured"</td>
|
|
2132
|
+
<td>Run <code>configureCheckout</code> before mounting any SDK component
|
|
2133
|
+
or calling <code>ttf</code>.</td>
|
|
2134
|
+
</tr>
|
|
2135
|
+
<tr>
|
|
2136
|
+
<td>Query context error</td>
|
|
2137
|
+
<td>Wrap the relevant tree in a <code>QueryClientProvider</code> using
|
|
2138
|
+
the same React Query instance as the SDK.</td>
|
|
2139
|
+
</tr>
|
|
2140
|
+
<tr>
|
|
2141
|
+
<td>No styles / CSS build error</td>
|
|
2142
|
+
<td>Confirm the bundler processes package CSS, nested
|
|
2143
|
+
<code>@import</code>s and assets. Check the package entry and stylesheet
|
|
2144
|
+
export.</td>
|
|
2145
|
+
</tr>
|
|
2146
|
+
<tr>
|
|
2147
|
+
<td>Login fails or popup closes</td>
|
|
2148
|
+
<td>Verify the public client, event, deployed auth route, secure browser
|
|
2149
|
+
crypto, popup permission, origin/cookie/CORS settings and any required
|
|
2150
|
+
proof step.</td>
|
|
2151
|
+
</tr>
|
|
2152
|
+
<tr>
|
|
2153
|
+
<td>Cart or pricing missing</td>
|
|
2154
|
+
<td>Verify the event/environment, current ticket IDs, availability,
|
|
2155
|
+
session, network response and that reservation completed. Re-fetch after
|
|
2156
|
+
a code or currency change.</td>
|
|
2157
|
+
</tr>
|
|
2158
|
+
<tr>
|
|
2159
|
+
<td>No seat button</td>
|
|
2160
|
+
<td>The event must offer seating; a composed <code>Tickets</code> needs
|
|
2161
|
+
<code>onSelectSeats</code> connected to a <code>SeatMap</code>
|
|
2162
|
+
view.</td>
|
|
2163
|
+
</tr>
|
|
2164
|
+
<tr>
|
|
2165
|
+
<td>Pay is disabled / validation error</td>
|
|
2166
|
+
<td>Check buyer and holder rules, required add-ons/answers/conditions,
|
|
2167
|
+
privacy acknowledgement, waiver state and cart expiry. Use matching
|
|
2168
|
+
billing and payment policies.</td>
|
|
2169
|
+
</tr>
|
|
2170
|
+
<tr>
|
|
2171
|
+
<td>Payment method unavailable</td>
|
|
2172
|
+
<td>Check the event's returned method list,
|
|
2173
|
+
merchant/currency/device/provider setup, popup/CSP and backend rollout.
|
|
2174
|
+
A union member alone does not enable a rail.</td>
|
|
2175
|
+
</tr>
|
|
2176
|
+
<tr>
|
|
2177
|
+
<td>Payment is pending or outcome uncertain</td>
|
|
2178
|
+
<td>Show the pending state, retain the order and reconcile with the
|
|
2179
|
+
backend/provider. Do not blindly reset, charge again or fulfil.</td>
|
|
2180
|
+
</tr>
|
|
2181
|
+
<tr>
|
|
2182
|
+
<td>Private account data is unavailable</td>
|
|
2183
|
+
<td>A public checkout buyer session is narrower than a full account
|
|
2184
|
+
session; verify the account journey and authority.</td>
|
|
2185
|
+
</tr>
|
|
2186
|
+
</tbody>
|
|
2187
|
+
</table>
|
|
2188
|
+
<p>Only public/non-secret configuration belongs in client bundles,
|
|
2189
|
+
example <code>.env</code> files and browser logs. Order hashes, buyer
|
|
2190
|
+
data and provider responses should be handled as sensitive application
|
|
2191
|
+
data.</p>
|
|
2192
|
+
</main>
|
|
2193
|
+
</body>
|
|
2194
|
+
</html>
|