tf-checkout-react-native 2.0.0-beta.0 → 2.0.0-beta.10

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.
Files changed (71) hide show
  1. package/README.md +115 -24
  2. package/dist/index.d.mts +8194 -282
  3. package/dist/index.d.ts +8194 -282
  4. package/dist/index.js +32308 -7001
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +32547 -7127
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +23 -11
  9. package/scripts/build-seat-map.mjs +31 -0
  10. package/scripts/seat-map-entry.jsx +22 -0
  11. package/scripts/verify-discussion-support.cjs +131 -0
  12. package/src/CardInput.tsx +64 -3
  13. package/src/EmbeddedCheckout.tsx +140 -38
  14. package/src/auth/AuthModal.tsx +186 -9
  15. package/src/auth/EmailCodeForm.tsx +91 -0
  16. package/src/auth/RegisterForm.tsx +91 -5
  17. package/src/auth/TwoFactorForm.tsx +74 -0
  18. package/src/auth/index.ts +4 -0
  19. package/src/configure.ts +19 -14
  20. package/src/confirmer.ts +112 -20
  21. package/src/generated/seatMapWidget.ts +3 -0
  22. package/src/index.tsx +1 -1
  23. package/src/sections/Accommodation.tsx +57 -0
  24. package/src/sections/AccountDeletion.tsx +347 -0
  25. package/src/sections/AccountEmailEnrichment.tsx +122 -0
  26. package/src/sections/AccountInformation.tsx +139 -0
  27. package/src/sections/AccountPaymentPlan.tsx +105 -0
  28. package/src/sections/AccountRewards.tsx +108 -0
  29. package/src/sections/AddOns.tsx +99 -148
  30. package/src/sections/BillingInfo.tsx +80 -78
  31. package/src/sections/Bundles.tsx +467 -0
  32. package/src/sections/EventDiscussionView.tsx +655 -0
  33. package/src/sections/NotificationPreferences.tsx +244 -0
  34. package/src/sections/OrderSummary.tsx +29 -2
  35. package/src/sections/Passes.tsx +177 -0
  36. package/src/sections/Payment.tsx +170 -53
  37. package/src/sections/PhoneAuthentication.tsx +371 -0
  38. package/src/sections/PostReaction.tsx +122 -0
  39. package/src/sections/ProfileSettings.tsx +446 -0
  40. package/src/sections/Rewards.tsx +320 -0
  41. package/src/sections/SeatMap.tsx +225 -0
  42. package/src/sections/SeatsIoMap.tsx +110 -0
  43. package/src/sections/Streaming.tsx +278 -0
  44. package/src/sections/TicketChange.tsx +379 -0
  45. package/src/sections/TicketGift.tsx +206 -0
  46. package/src/sections/TicketRefund.tsx +104 -0
  47. package/src/sections/Tickets.tsx +289 -208
  48. package/src/sections/Trips.tsx +87 -0
  49. package/src/sections/WaiverSigning.tsx +429 -0
  50. package/src/sections/billing/PhoneIdentity.tsx +169 -0
  51. package/src/sections/billing/TicketHoldersCard.tsx +4 -0
  52. package/src/sections/discussion/CommentImages.tsx +366 -0
  53. package/src/sections/discussion/SwipeReply.tsx +88 -0
  54. package/src/sections/index.ts +46 -0
  55. package/src/sections/rewards/RewardsLadder.tsx +167 -0
  56. package/src/sections/rewards/RewardsTree.tsx +117 -0
  57. package/src/storage.ts +8 -9
  58. package/src/ui/CheckoutProvider.tsx +51 -15
  59. package/src/ui/CustomFields.tsx +48 -12
  60. package/src/ui/Field.tsx +21 -3
  61. package/src/ui/Frozen.tsx +22 -0
  62. package/src/ui/InstallmentPicker.tsx +15 -18
  63. package/src/ui/PaymentMethods.tsx +6 -3
  64. package/src/ui/ProviderPages.tsx +214 -0
  65. package/src/ui/QuantitySelect.tsx +28 -3
  66. package/src/ui/Select.tsx +4 -1
  67. package/src/ui/SignaturePad.tsx +218 -0
  68. package/src/ui/index.ts +3 -0
  69. package/src/ui/primitives.tsx +13 -2
  70. package/src/ui/useAccountT.ts +16 -0
  71. package/src/useCheckout.ts +3 -1
package/README.md CHANGED
@@ -4,26 +4,40 @@ The TicketFairy checkout for React Native. Drop in one component and you have
4
4
  ticket selection, add-ons, buyer details, payment, ID verification, and the
5
5
  receipt — or compose the sections yourself.
6
6
 
7
- Same API as [`tf-checkout-react`](../tf-checkout-react/README.md); the flow,
7
+ Same API as [`tf-checkout-react`](https://github.com/theticketfairy/tf-shared-libraries/blob/main/packages/tf-checkout-react/README.md); the flow,
8
8
  validation, and gating rules are literally the same code.
9
9
 
10
+ The 2.x source is maintained in [`tf-shared-libraries/packages/tf-checkout-react-native`](https://github.com/theticketfairy/tf-shared-libraries/tree/main/packages/tf-checkout-react-native).
11
+ The core is private and bundled into both platform packages. Use React 18+ and
12
+ React Query 5 on web; the native requirements below reflect its supported build.
13
+ Never put a confidential OAuth client secret in browser or mobile code. Public
14
+ checkout integrations use registered SDK client IDs and owned buyer sessions.
15
+
10
16
  ## Install
11
17
 
18
+ The 2.0 line is currently a prerelease. Install `@beta` explicitly; the unqualified
19
+ npm package still resolves to stable 1.x until the 2.0 release gates pass. Pin the
20
+ verified exact version in a production app. The current matching pair is
21
+ `2.0.0-beta.9`; see its [registry acceptance record](https://github.com/theticketfairy/tf-shared-libraries/blob/main/docs/releases/2.0.0-beta.9.registry.json).
22
+ The [app integration contract](https://github.com/theticketfairy/tf-shared-libraries/blob/main/docs/integration/app-sdk.md)
23
+ records the shared APIs and remaining deployment/provider acceptance gates.
24
+
12
25
  ```bash
13
- npx expo install tf-checkout-react-native \
26
+ npx expo install tf-checkout-react-native@beta \
14
27
  @tanstack/react-query \
15
28
  @stripe/stripe-react-native \
16
- react-native-mmkv \
17
- @react-native-clipboard/clipboard
29
+ react-native-mmkv@3 \
30
+ @react-native-clipboard/clipboard \
31
+ react-native-webview
18
32
  ```
19
33
 
20
34
  Bare React Native:
21
35
 
22
36
  ```bash
23
- npm install tf-checkout-react-native @tanstack/react-query @stripe/stripe-react-native react-native-mmkv @react-native-clipboard/clipboard
37
+ npm install tf-checkout-react-native@beta @tanstack/react-query @stripe/stripe-react-native react-native-mmkv@3 @react-native-clipboard/clipboard react-native-webview
24
38
  ```
25
39
 
26
- Those four are **peer dependencies** on purpose. React contexts and native
40
+ These are **peer dependencies** on purpose. React contexts and native
27
41
  modules must exist exactly once in an app — a second copy of react-query means
28
42
  your `<QueryClientProvider>` is invisible to our hooks, and a second Stripe
29
43
  means a duplicate pod. As peers there is one copy and no Metro aliasing is ever
@@ -35,7 +49,7 @@ Everything else — the SDK core, the flow, the UI — ships inside the package.
35
49
 
36
50
  - React Native `0.81+` with the New Architecture enabled (required by
37
51
  `react-native-mmkv` 3.x)
38
- - React `19.1+`, Node `20.18.3+`
52
+ - React `19.1+`, Node `20.19.4+`
39
53
  - iOS 15.1+ · Android API 24+ (Stripe SDK minimums)
40
54
  - A development build. **Expo Go will not work** — this package uses native
41
55
  modules.
@@ -62,7 +76,7 @@ npx expo run:ios
62
76
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
63
77
  import { configureCheckout, EmbeddedCheckout } from 'tf-checkout-react-native'
64
78
 
65
- configureCheckout({ env: 'PROD', clientId: '…', clientSecret: '…' })
79
+ configureCheckout({ env: 'PROD', clientId: 'PUBLIC_SDK_CLIENT_ID', clientSecret: '', cookieAuth: true })
66
80
 
67
81
  const queryClient = new QueryClient()
68
82
 
@@ -75,24 +89,23 @@ export default function App() {
75
89
  }
76
90
  ```
77
91
 
78
- `configureCheckout` runs once at app start. It persists tokens to MMKV, so a
79
- signed-in buyer survives a relaunch.
80
-
81
- ### Why native defaults to cookie auth
92
+ `configureCheckout` runs once at app start and defaults SDK-owned storage to
93
+ MMKV. Storage survives a relaunch; the backend still validates the restored
94
+ session.
82
95
 
83
- `configureCheckout` turns on `cookieAuth` by default. This is not cosmetic: the
84
- cart lives in the backend session, and a bearer request without a guest header
85
- gets moved onto a synthetic empty session — so a buyer who reserves tickets and
86
- then signs in mid-checkout would lose the cart to "The cart is expired". On the
87
- cookie flow no bearer is minted, the session holding the cart stays put, and the
88
- rotating `X-TF-ECOMMERCE` ticket is persisted to MMKV.
96
+ ### Checkout sessions and account scope
89
97
 
90
- Pass `cookieAuth: false` to opt into the bearer chain.
98
+ The native wrapper defaults `cookieAuth` to true and disables ambient native
99
+ cookie handling. Owned credentials use the SDK's header-backed session storage.
100
+ Public checkout sign-in preserves the event-bound guest carrier and keeps its
101
+ buyer credential server-side; it does not return a full-account ticket or grant
102
+ private account access. First-party full-account flows explicitly use
103
+ `accountAuth: true`; see the shared identity contract below.
91
104
 
92
105
  ### Environments
93
106
 
94
107
  ```ts
95
- configureCheckout({ env: 'STAG', clientId, clientSecret })
108
+ configureCheckout({ env: 'STAG', clientId: 'PUBLIC_SDK_CLIENT_ID', clientSecret: '', cookieAuth: true })
96
109
  ```
97
110
 
98
111
  `PROD` → `www.ticketfairy.com`, `STAG` → `test.ticketfairy.com`, `DEV` →
@@ -190,13 +203,81 @@ const order = await checkout.placeOrder('card')
190
203
  `placeOrder` is retry-safe: one order, one charge, however many times the button
191
204
  is pressed.
192
205
 
206
+ ### Starting a new checkout
207
+
208
+ `reset()` discards the cart. It returns nothing, so
209
+ `useEffect(() => checkout.reset(), [eventId])` works as it always has. Before
210
+ any money moves it resets at once. While a payment is going through, it waits
211
+ for the payment to finish, so the payment never lands in a new cart. An order
212
+ that is not confirmed yet is kept when it is charged, or when a payment step
213
+ failed without an answer that nothing was charged (a network error, a
214
+ timeout, or a Stripe error that is not a decline or a cancel). A Razorpay or
215
+ redirect payment page the buyer closes is kept only when a check of the order
216
+ fails or finds a payment; otherwise it is a cancel. Pressing Pay again then
217
+ finishes the order, or pays as usual when nothing was paid. A server refusal
218
+ of the order, such as an expired reservation, releases it.
219
+
220
+ To know which happened, await `resetWhenSettled()` instead. It resolves `true`
221
+ once the checkout is reset, or `false` when it kept the order. In that case,
222
+ show the buyer `PAID_ORDER_PENDING_MESSAGE`. While it waits for a payment
223
+ (`status === 'placing'`), tell the buyer, for example "Finishing your
224
+ payment…":
225
+
226
+ ```tsx
227
+ if (checkout.status === 'placing') setNotice('Finishing your payment…')
228
+ if (!(await checkout.resetWhenSettled())) setNotice(PAID_ORDER_PENDING_MESSAGE)
229
+ ```
230
+
231
+ A custom `providerPage` must resolve `'dismiss'` when it closes or unmounts, and
232
+ any other custom port must settle then too, or `resetWhenSettled()` waits for it.
233
+
234
+ A custom confirmer marks a decline or cancel by rejecting with
235
+ `paymentProviderError(message, 'declined' | 'cancelled')`. Any other rejection
236
+ counts as a payment that may have gone through, so the order is kept.
237
+
193
238
  The full SDK is re-exported from this package — `ttf`, `api`, `hooks`, `dtos`,
194
- `logic`, and the engine. See the [SDK reference](../tf-checkout-shared/README.md).
239
+ `logic`, and the engine. See the [SDK reference](https://github.com/theticketfairy/tf-shared-libraries/blob/main/packages/tf-checkout-shared/README.md).
240
+
241
+ ## Rewards
242
+
243
+ The native analogue of the web Rewards section: standing, the referral tree,
244
+ the prize ladder, packs, the share card, and one share button.
245
+
246
+ ```tsx
247
+ import { Confirmation, Rewards } from 'tf-checkout-react-native'
248
+ ;<Confirmation>
249
+ <Rewards orderHash={orderHash} />
250
+ </Confirmation>
251
+ ```
252
+
253
+ When `<EmbeddedCheckout/>` renders the receipt itself, pass the block through
254
+ `confirmationChildren`:
255
+
256
+ ```tsx
257
+ <EmbeddedCheckout eventId={eventId} confirmationChildren={<MyRewards />} />
258
+ ```
259
+
260
+ Native adaptations, and why:
261
+
262
+ - **No SVG.** The tree is positioned `View`s, from the same shared layout the
263
+ web SVG uses. Adding `react-native-svg` would be a new native peer for every
264
+ customer app; a dot-and-line picture does not need one.
265
+ - **One share button.** Per-channel buttons collapse into `Share.share()` — the
266
+ OS sheet already lists every installed app, which is what the web's share
267
+ sheet channel reaches for through the browser.
268
+ - **Copy comes in as props**, this package's idiom. `translate`, or `locale` and
269
+ `messages` for the built-in `rewards.*` catalogue.
270
+
271
+ ## Seat maps
272
+
273
+ `SeatMap` uses the existing WebView peer to render internal charts or the event's
274
+ Seats.io chart, with the shared core owning selection, holds and reservations.
275
+ It requires the matching backend seating/session contracts. Provider-backed hold
276
+ and deployed-cart acceptance remain separate checks; see the
277
+ [seating contract and evidence](https://github.com/theticketfairy/tf-shared-libraries/blob/main/docs/integration/app-sdk.md#seat-chart-and-ticket-refund-checkpoint--25-october-2026).
195
278
 
196
279
  ## Known gaps vs web
197
280
 
198
- - **Seat maps** — the seat-picker view is a placeholder until the native picker
199
- (WebView + seats.io) lands. Non-seated events are unaffected.
200
281
  - **Smooth scroll** — no `scrollIntoView` equivalent, so `autoScroll` has no
201
282
  native counterpart.
202
283
 
@@ -226,4 +307,14 @@ nothing of the sort.
226
307
 
227
308
  ---
228
309
 
229
- Part of the [TicketFairy checkout monorepo](../../README.md).
310
+ Part of the [TicketFairy checkout monorepo](https://github.com/theticketfairy/tf-shared-libraries/blob/main/README.md).
311
+
312
+
313
+ Public checkout sign-in uses event-scoped server-only buyer binding, without a bundled
314
+ client secret. The checkout's auth modal supplies the event automatically; standalone
315
+ `AuthModal` callers pass `checkoutEventId` and can receive the narrow
316
+ `onCheckoutAuthenticated(CheckoutBuyerProfile)` callback. Password/signup/email/phone
317
+ proofs still complete required two-factor verification. These credentials cannot read
318
+ private account preferences or tickets. See the [shared identity contract](https://github.com/theticketfairy/tf-shared-libraries/blob/main/packages/tf-checkout-shared/README.md) for
319
+ scope, retry, logout and configuration ownership. Existing confidential OAuth clients
320
+ are trusted-server integrations; never distribute their secrets in browser/native code.