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.
- package/README.md +115 -24
- package/dist/index.d.mts +8194 -282
- package/dist/index.d.ts +8194 -282
- package/dist/index.js +32308 -7001
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32547 -7127
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -11
- package/scripts/build-seat-map.mjs +31 -0
- package/scripts/seat-map-entry.jsx +22 -0
- package/scripts/verify-discussion-support.cjs +131 -0
- package/src/CardInput.tsx +64 -3
- package/src/EmbeddedCheckout.tsx +140 -38
- package/src/auth/AuthModal.tsx +186 -9
- package/src/auth/EmailCodeForm.tsx +91 -0
- package/src/auth/RegisterForm.tsx +91 -5
- package/src/auth/TwoFactorForm.tsx +74 -0
- package/src/auth/index.ts +4 -0
- package/src/configure.ts +19 -14
- package/src/confirmer.ts +112 -20
- package/src/generated/seatMapWidget.ts +3 -0
- package/src/index.tsx +1 -1
- package/src/sections/Accommodation.tsx +57 -0
- package/src/sections/AccountDeletion.tsx +347 -0
- package/src/sections/AccountEmailEnrichment.tsx +122 -0
- package/src/sections/AccountInformation.tsx +139 -0
- package/src/sections/AccountPaymentPlan.tsx +105 -0
- package/src/sections/AccountRewards.tsx +108 -0
- package/src/sections/AddOns.tsx +99 -148
- package/src/sections/BillingInfo.tsx +80 -78
- package/src/sections/Bundles.tsx +467 -0
- package/src/sections/EventDiscussionView.tsx +655 -0
- package/src/sections/NotificationPreferences.tsx +244 -0
- package/src/sections/OrderSummary.tsx +29 -2
- package/src/sections/Passes.tsx +177 -0
- package/src/sections/Payment.tsx +170 -53
- package/src/sections/PhoneAuthentication.tsx +371 -0
- package/src/sections/PostReaction.tsx +122 -0
- package/src/sections/ProfileSettings.tsx +446 -0
- package/src/sections/Rewards.tsx +320 -0
- package/src/sections/SeatMap.tsx +225 -0
- package/src/sections/SeatsIoMap.tsx +110 -0
- package/src/sections/Streaming.tsx +278 -0
- package/src/sections/TicketChange.tsx +379 -0
- package/src/sections/TicketGift.tsx +206 -0
- package/src/sections/TicketRefund.tsx +104 -0
- package/src/sections/Tickets.tsx +289 -208
- package/src/sections/Trips.tsx +87 -0
- package/src/sections/WaiverSigning.tsx +429 -0
- package/src/sections/billing/PhoneIdentity.tsx +169 -0
- package/src/sections/billing/TicketHoldersCard.tsx +4 -0
- package/src/sections/discussion/CommentImages.tsx +366 -0
- package/src/sections/discussion/SwipeReply.tsx +88 -0
- package/src/sections/index.ts +46 -0
- package/src/sections/rewards/RewardsLadder.tsx +167 -0
- package/src/sections/rewards/RewardsTree.tsx +117 -0
- package/src/storage.ts +8 -9
- package/src/ui/CheckoutProvider.tsx +51 -15
- package/src/ui/CustomFields.tsx +48 -12
- package/src/ui/Field.tsx +21 -3
- package/src/ui/Frozen.tsx +22 -0
- package/src/ui/InstallmentPicker.tsx +15 -18
- package/src/ui/PaymentMethods.tsx +6 -3
- package/src/ui/ProviderPages.tsx +214 -0
- package/src/ui/QuantitySelect.tsx +28 -3
- package/src/ui/Select.tsx +4 -1
- package/src/ui/SignaturePad.tsx +218 -0
- package/src/ui/index.ts +3 -0
- package/src/ui/primitives.tsx +13 -2
- package/src/ui/useAccountT.ts +16 -0
- package/src/useCheckout.ts +3 -1
|
@@ -25,6 +25,16 @@ import React, {
|
|
|
25
25
|
import { Linking, Pressable, StyleSheet, Text, View } from 'react-native'
|
|
26
26
|
|
|
27
27
|
import {
|
|
28
|
+
billingDobIso,
|
|
29
|
+
changeBillingPhone,
|
|
30
|
+
changeBillingField,
|
|
31
|
+
billingDraftFrom,
|
|
32
|
+
billingFilledHolderIndexes,
|
|
33
|
+
holderDraftsForSlots,
|
|
34
|
+
holderDraftsFrom,
|
|
35
|
+
holderDraftsReloaded,
|
|
36
|
+
holderDraftsMirroringBuyer,
|
|
37
|
+
patchedHolderDraft,
|
|
28
38
|
hooks,
|
|
29
39
|
mapProfileToBilling,
|
|
30
40
|
missingCheckoutDetails,
|
|
@@ -43,9 +53,11 @@ import {
|
|
|
43
53
|
} from '../ui/CheckoutProvider'
|
|
44
54
|
import { CustomFieldInput } from '../ui/CustomFields'
|
|
45
55
|
import { Checkbox, Field, Input } from '../ui/Field'
|
|
56
|
+
import { FrozenFields } from '../ui/Frozen'
|
|
46
57
|
import { Button, Card, ErrorText, SectionHeader } from '../ui/primitives'
|
|
47
58
|
import type { ResolvedTheme } from '../ui/theme'
|
|
48
59
|
import { BillingAddressFields } from './billing/BillingAddressFields'
|
|
60
|
+
import { BillingPhoneIdentity } from './billing/PhoneIdentity'
|
|
49
61
|
import { BuyerField } from './billing/BuyerField'
|
|
50
62
|
import { TicketHoldersCard } from './billing/TicketHoldersCard'
|
|
51
63
|
import type { BillingDraft, HolderDraft } from './billing/types'
|
|
@@ -110,52 +122,42 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
110
122
|
const validation = useCheckoutValidation()
|
|
111
123
|
const theme = useTheme()
|
|
112
124
|
const s = useStyles(theme)
|
|
113
|
-
const profile = hooks.
|
|
125
|
+
const profile = hooks.useCheckoutBuyerProfile(eventId)
|
|
114
126
|
const event = hooks.useEvent(eventId)
|
|
115
127
|
// No onContinue ⇒ this is one combined form (inside <EmbeddedCheckout/>): mirror the
|
|
116
128
|
// fields into the engine live and drop the "continue" button, so the buyer
|
|
117
129
|
// fills billing + pays with ONE button — the way the old checkout flowed.
|
|
118
130
|
const combined = !onContinue
|
|
119
131
|
|
|
120
|
-
const [billing, setBilling] = useState<BillingDraft>(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
email: checkout.billing?.email ?? '',
|
|
124
|
-
confirmEmail: checkout.billing?.confirmEmail ?? '',
|
|
125
|
-
phone: checkout.billing?.phone,
|
|
126
|
-
streetAddress: checkout.billing?.streetAddress,
|
|
127
|
-
city: checkout.billing?.city,
|
|
128
|
-
zip: checkout.billing?.zip,
|
|
129
|
-
countryId: checkout.billing?.countryId,
|
|
130
|
-
stateId: checkout.billing?.stateId,
|
|
131
|
-
countryCode: checkout.billing?.countryCode,
|
|
132
|
-
stateCode: checkout.billing?.stateCode,
|
|
133
|
-
nationality: checkout.billing?.nationality,
|
|
134
|
-
gender: checkout.billing?.gender,
|
|
135
|
-
instagramHandle: checkout.billing?.instagramHandle,
|
|
136
|
-
})
|
|
132
|
+
const [billing, setBilling] = useState<BillingDraft>(() =>
|
|
133
|
+
billingDraftFrom(checkout.billing)
|
|
134
|
+
)
|
|
137
135
|
const [dataCapture, setDataCapture] = useState<CustomFieldValues>(
|
|
138
136
|
checkout.billing?.dataCapture ?? {}
|
|
139
137
|
)
|
|
140
138
|
const [holders, setHolders] = useState<HolderDraft[]>(() =>
|
|
141
|
-
checkout.holders.
|
|
142
|
-
firstName: holder.firstName,
|
|
143
|
-
lastName: holder.lastName,
|
|
144
|
-
email: holder.email,
|
|
145
|
-
phone: holder.phone ?? '',
|
|
146
|
-
ticketTypeId: holder.ticketTypeId,
|
|
147
|
-
ticketDataCapture: holder.ticketDataCapture ?? {},
|
|
148
|
-
}))
|
|
139
|
+
holderDraftsFrom(checkout.holders, checkout.backfilledHolderIndexes)
|
|
149
140
|
)
|
|
150
141
|
const [consent, setConsent] = useState({ ttfOptIn: false, brandOptIn: false })
|
|
151
|
-
const [dob, setDob] = useState(() =>
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
142
|
+
const [dob, setDob] = useState(() => billingDobIso(checkout.billing)) // ISO yyyy-mm-dd
|
|
143
|
+
// A placement that ended without a charge: show what a retry submits.
|
|
144
|
+
hooks.useOnOrderReleased(checkout.orderFixed, () => {
|
|
145
|
+
setBilling(billingDraftFrom(checkout.billing))
|
|
146
|
+
setDataCapture(checkout.billing?.dataCapture ?? {})
|
|
147
|
+
setDob(billingDobIso(checkout.billing))
|
|
148
|
+
setConsent(checkout.consent)
|
|
149
|
+
setHolders((prev) =>
|
|
150
|
+
holderDraftsReloaded(prev, checkout.holders, checkout.backfilledHolderIndexes)
|
|
151
|
+
)
|
|
152
|
+
})
|
|
158
153
|
const restoredHolders = useRef(checkout.holders)
|
|
154
|
+
// Another event: its holders and custom answers start empty; the buyer's
|
|
155
|
+
// own details stay.
|
|
156
|
+
hooks.useOnEventChange(checkout.eventId, () => {
|
|
157
|
+
restoredHolders.current = []
|
|
158
|
+
setHolders([])
|
|
159
|
+
setDataCapture({})
|
|
160
|
+
})
|
|
159
161
|
const profileSeeded = useRef(false)
|
|
160
162
|
const countryDefaultApplied = useRef(Boolean(checkout.billing?.countryId))
|
|
161
163
|
|
|
@@ -233,38 +235,21 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
233
235
|
|
|
234
236
|
// Resize holders to the slot count, preserving typed values; tag ticket type.
|
|
235
237
|
useEffect(() => {
|
|
236
|
-
setHolders((prev) =>
|
|
237
|
-
slots.map((slot, i) => ({
|
|
238
|
-
firstName: prev[i]?.firstName ?? restoredHolders.current[i]?.firstName ?? '',
|
|
239
|
-
lastName: prev[i]?.lastName ?? restoredHolders.current[i]?.lastName ?? '',
|
|
240
|
-
email: prev[i]?.email ?? restoredHolders.current[i]?.email ?? '',
|
|
241
|
-
phone: prev[i]?.phone ?? restoredHolders.current[i]?.phone ?? '',
|
|
242
|
-
ticketDataCapture:
|
|
243
|
-
prev[i]?.ticketDataCapture ??
|
|
244
|
-
restoredHolders.current[i]?.ticketDataCapture ??
|
|
245
|
-
{},
|
|
246
|
-
ticketTypeId: slot.ticketTypeId,
|
|
247
|
-
ticketName: slot.ticketName,
|
|
248
|
-
}))
|
|
249
|
-
)
|
|
238
|
+
setHolders((prev) => holderDraftsForSlots(prev, slots, restoredHolders.current))
|
|
250
239
|
}, [slots])
|
|
251
240
|
|
|
252
241
|
// Match the storefront: ticket 1 silently starts as the buyer. The legacy
|
|
253
242
|
// checkout has no extra "use buyer details" control.
|
|
254
243
|
useEffect(() => {
|
|
255
244
|
if (!showHolders) return
|
|
245
|
+
// Ticket 1 stops copying the buyer once the buyer edits it.
|
|
256
246
|
setHolders((prev) =>
|
|
257
|
-
prev
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
email: billing.email,
|
|
264
|
-
phone: billing.phone ?? '',
|
|
265
|
-
}
|
|
266
|
-
: holder
|
|
267
|
-
)
|
|
247
|
+
holderDraftsMirroringBuyer(prev, {
|
|
248
|
+
firstName: billing.firstName,
|
|
249
|
+
lastName: billing.lastName,
|
|
250
|
+
email: billing.email,
|
|
251
|
+
phone: billing.phone,
|
|
252
|
+
})
|
|
268
253
|
)
|
|
269
254
|
}, [showHolders, billing.firstName, billing.lastName, billing.email, billing.phone])
|
|
270
255
|
|
|
@@ -357,10 +342,10 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
357
342
|
}, [billing.stateId, billing.stateCode, states])
|
|
358
343
|
|
|
359
344
|
const setB = (k: keyof BillingDraft) => (value: string) =>
|
|
360
|
-
setBilling((b) => (
|
|
345
|
+
setBilling((b) => changeBillingField(b, k, value))
|
|
361
346
|
|
|
362
347
|
const patchHolder = (i: number, patch: Partial<HolderDraft>) =>
|
|
363
|
-
setHolders((hs) => hs.map((h, j) => (j === i ?
|
|
348
|
+
setHolders((hs) => hs.map((h, j) => (j === i ? patchedHolderDraft(h, patch) : h)))
|
|
364
349
|
|
|
365
350
|
const [dobYear, dobMonth, dobDay] = dob ? dob.split('-').map(Number) : []
|
|
366
351
|
const committedBilling: CheckoutBilling = {
|
|
@@ -413,7 +398,11 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
413
398
|
|
|
414
399
|
const commit = () => {
|
|
415
400
|
commitBilling(committedBilling)
|
|
416
|
-
|
|
401
|
+
// Holders that take the buyer's details are marked, so a guardian's
|
|
402
|
+
// signature for a child counts on them (billingFilledHolderIndexes).
|
|
403
|
+
commitHolders(committedHolders, {
|
|
404
|
+
backfilled: billingFilledHolderIndexes(holders, { holderNamesRequired }),
|
|
405
|
+
})
|
|
417
406
|
if (ttfOptInLabel || brandOptInLabel) commitConsent(consent)
|
|
418
407
|
}
|
|
419
408
|
|
|
@@ -477,8 +466,23 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
477
466
|
|
|
478
467
|
const privacyInvalid = (showPrivacyError || showValidation) && !consent.ttfOptIn
|
|
479
468
|
|
|
469
|
+
const continueButton = !combined ? (
|
|
470
|
+
<Button
|
|
471
|
+
onPress={() => {
|
|
472
|
+
if (!complete) {
|
|
473
|
+
validation.requestValidation()
|
|
474
|
+
return
|
|
475
|
+
}
|
|
476
|
+
commit()
|
|
477
|
+
onContinue?.()
|
|
478
|
+
}}
|
|
479
|
+
>
|
|
480
|
+
{buttonLabel}
|
|
481
|
+
</Button>
|
|
482
|
+
) : null
|
|
483
|
+
|
|
480
484
|
return (
|
|
481
|
-
|
|
485
|
+
<FrozenFields frozen={checkout.orderFixed}>
|
|
482
486
|
<Card>
|
|
483
487
|
<SectionHeader title={heading} />
|
|
484
488
|
|
|
@@ -491,6 +495,14 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
491
495
|
</View>
|
|
492
496
|
) : null}
|
|
493
497
|
|
|
498
|
+
{gates.phoneFirstCheckout && !checkout.isLoggedIn ? (
|
|
499
|
+
<BillingPhoneIdentity
|
|
500
|
+
billing={billing}
|
|
501
|
+
setBilling={setBilling}
|
|
502
|
+
eventId={eventId ?? checkout.eventId ?? undefined}
|
|
503
|
+
whatsappAvailable={Boolean(gates.phoneFirstWhatsapp)}
|
|
504
|
+
/>
|
|
505
|
+
) : null}
|
|
494
506
|
<View style={s.row}>
|
|
495
507
|
<View style={s.col}>
|
|
496
508
|
<Field error={fieldError('First name', 'First name is required.')}>
|
|
@@ -598,7 +610,9 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
598
610
|
<Input
|
|
599
611
|
placeholder="Phone number"
|
|
600
612
|
value={billing.phone ?? ''}
|
|
601
|
-
onChangeText={(v) =>
|
|
613
|
+
onChangeText={(v) =>
|
|
614
|
+
setBilling((current) => changeBillingPhone(current, v))
|
|
615
|
+
}
|
|
602
616
|
keyboardType="phone-pad"
|
|
603
617
|
invalid={Boolean(fieldError('Valid phone number'))}
|
|
604
618
|
/>
|
|
@@ -688,20 +702,7 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
688
702
|
/>
|
|
689
703
|
) : null}
|
|
690
704
|
|
|
691
|
-
{!
|
|
692
|
-
<Button
|
|
693
|
-
onPress={() => {
|
|
694
|
-
if (!complete) {
|
|
695
|
-
validation.requestValidation()
|
|
696
|
-
return
|
|
697
|
-
}
|
|
698
|
-
commit()
|
|
699
|
-
onContinue?.()
|
|
700
|
-
}}
|
|
701
|
-
>
|
|
702
|
-
{buttonLabel}
|
|
703
|
-
</Button>
|
|
704
|
-
) : null}
|
|
705
|
+
{!showHolders ? continueButton : null}
|
|
705
706
|
</Card>
|
|
706
707
|
|
|
707
708
|
{showHolders ? (
|
|
@@ -730,7 +731,8 @@ export const BillingInfo: FC<BillingInfoProps> = ({
|
|
|
730
731
|
}
|
|
731
732
|
/>
|
|
732
733
|
) : null}
|
|
733
|
-
|
|
734
|
+
{showHolders ? continueButton : null}
|
|
735
|
+
</FrozenFields>
|
|
734
736
|
)
|
|
735
737
|
}
|
|
736
738
|
|