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

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 +8195 -282
  3. package/dist/index.d.ts +8195 -282
  4. package/dist/index.js +32346 -7001
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +32586 -7128
  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
@@ -0,0 +1,206 @@
1
+ import React, { type FC } from 'react'
2
+ import { View } from 'react-native'
3
+ import { hooks, type TicketGiftProps } from 'tf-checkout-shared'
4
+ import {
5
+ BodyText,
6
+ Button,
7
+ Card,
8
+ ErrorText,
9
+ Loader,
10
+ SectionHeader,
11
+ } from '../ui/primitives'
12
+ import { Checkbox, Field, Input } from '../ui/Field'
13
+ import { useAccountT } from '../ui/useAccountT'
14
+
15
+ export const TicketGift: FC<TicketGiftProps> = ({
16
+ ticketHash,
17
+ onTicketsChanged,
18
+ onDone,
19
+ locale,
20
+ }) => {
21
+ const t = useAccountT(locale)
22
+ const flow = hooks.useTicketGift(ticketHash, onTicketsChanged)
23
+ const { state, query } = flow
24
+ const command = state.command ?? state.submitted
25
+ if (command)
26
+ return (
27
+ <Card>
28
+ <SectionHeader
29
+ title={t(command.kind === 'send' ? 'Review your gift' : 'Cancel gift')}
30
+ />
31
+ {command.kind === 'send' ? (
32
+ <>
33
+ <BodyText>
34
+ {command.intent.first_name} {command.intent.last_name}
35
+ </BodyText>
36
+ <BodyText>{command.intent.email}</BodyText>
37
+ {query.data?.add_ons
38
+ .filter(
39
+ (item) =>
40
+ !query.data?.select_add_ons ||
41
+ command.intent.add_on_ids.includes(item.id)
42
+ )
43
+ .map((item) => (
44
+ <BodyText key={item.id}>{item.name}</BodyText>
45
+ ))}
46
+ <BodyText>
47
+ {t(
48
+ 'Once the gift is accepted, this ticket will belong to the recipient and you will no longer be able to use it.'
49
+ )}
50
+ </BodyText>
51
+ </>
52
+ ) : (
53
+ <BodyText>
54
+ {t(
55
+ 'Cancel this pending gift so you can keep or send your ticket to someone else?'
56
+ )}
57
+ </BodyText>
58
+ )}
59
+ {state.error && <ErrorText>{t(state.error)}</ErrorText>}
60
+ <Button
61
+ loading={state.busy}
62
+ disabled={state.busy}
63
+ onPress={() => void flow.submit()}
64
+ >
65
+ {t(
66
+ state.submitted
67
+ ? 'Check gift status'
68
+ : command.kind === 'send'
69
+ ? 'Send gift'
70
+ : 'Cancel gift'
71
+ )}
72
+ </Button>
73
+ {!state.submitted && (
74
+ <Button variant="ghost" onPress={flow.back}>
75
+ {t('Back')}
76
+ </Button>
77
+ )}
78
+ </Card>
79
+ )
80
+ if (query.isLoading) return <Loader />
81
+ if (query.error)
82
+ return (
83
+ <Card>
84
+ <ErrorText>{t(query.error.message)}</ErrorText>
85
+ <Button onPress={() => void query.refetch()}>{t('Try again')}</Button>
86
+ </Card>
87
+ )
88
+ const gift = query.data
89
+ if (!gift) return null
90
+ return (
91
+ <Card>
92
+ <SectionHeader title={t('Gift ticket')} />
93
+ {state.result === 'cancelled' && (
94
+ <BodyText>{t('Your gift was cancelled. Your ticket is still yours.')}</BodyText>
95
+ )}
96
+ {gift.status === 'sent' && (
97
+ <BodyText>
98
+ {t('Your ticket has been given to the recipient. You can no longer use it.')}
99
+ </BodyText>
100
+ )}
101
+ {gift.pending && (
102
+ <>
103
+ <BodyText>
104
+ {t(
105
+ gift.status === 'processing'
106
+ ? 'Your gift is being completed.'
107
+ : 'Your gift is waiting for the recipient to accept it.'
108
+ )}
109
+ </BodyText>
110
+ <BodyText>
111
+ {gift.pending.first_name} {gift.pending.last_name}
112
+ </BodyText>
113
+ <BodyText>{gift.pending.email}</BodyText>
114
+ {gift.pending.can_cancel && (
115
+ <Button onPress={flow.confirmCancel}>{t('Cancel gift')}</Button>
116
+ )}
117
+ <Button variant="ghost" onPress={() => void query.refetch()}>
118
+ {t('Check gift status')}
119
+ </Button>
120
+ </>
121
+ )}
122
+ {gift.can_send ? (
123
+ <View style={{ gap: 12 }}>
124
+ <BodyText>
125
+ {t(
126
+ 'Give this ticket to someone else. Once they receive it, you will no longer own it or be able to use it.'
127
+ )}
128
+ </BodyText>
129
+ <Field label={t('First name')}>
130
+ <Input
131
+ value={state.draft.first_name}
132
+ accessibilityLabel={t('First name')}
133
+ maxLength={100}
134
+ onChangeText={(value) => flow.edit({ first_name: value })}
135
+ autoCapitalize="words"
136
+ />
137
+ </Field>
138
+ <Field label={t('Last name')}>
139
+ <Input
140
+ value={state.draft.last_name}
141
+ accessibilityLabel={t('Last name')}
142
+ maxLength={100}
143
+ onChangeText={(value) => flow.edit({ last_name: value })}
144
+ autoCapitalize="words"
145
+ />
146
+ </Field>
147
+ <Field label={t('Email address')}>
148
+ <Input
149
+ value={state.draft.email}
150
+ accessibilityLabel={t('Email address')}
151
+ maxLength={254}
152
+ onChangeText={(value) => flow.edit({ email: value })}
153
+ keyboardType="email-address"
154
+ autoCapitalize="none"
155
+ />
156
+ </Field>
157
+ <Field label={t('Confirm email address')}>
158
+ <Input
159
+ value={state.draft.confirm_email}
160
+ accessibilityLabel={t('Confirm email address')}
161
+ maxLength={254}
162
+ onChangeText={(value) => flow.edit({ confirm_email: value })}
163
+ keyboardType="email-address"
164
+ autoCapitalize="none"
165
+ />
166
+ </Field>
167
+ {gift.add_ons.length > 0 && (
168
+ <BodyText>
169
+ {t(
170
+ gift.select_add_ons
171
+ ? 'Choose add-ons to include'
172
+ : 'These add-ons are included with your gift'
173
+ )}
174
+ </BodyText>
175
+ )}
176
+ {gift.add_ons.map((item) =>
177
+ gift.select_add_ons ? (
178
+ <Checkbox
179
+ key={item.id}
180
+ label={item.name}
181
+ checked={state.draft.add_on_ids.includes(item.id)}
182
+ onChange={() => flow.toggleAddOn(item.id)}
183
+ />
184
+ ) : (
185
+ <BodyText key={item.id}>{item.name}</BodyText>
186
+ )
187
+ )}
188
+ <Checkbox
189
+ checked={state.draft.confirm_terms}
190
+ onChange={(value) => flow.edit({ confirm_terms: value })}
191
+ label={t('I understand that this ticket will belong to the recipient.')}
192
+ />
193
+ {state.error && <ErrorText>{t(state.error)}</ErrorText>}
194
+ <Button onPress={flow.review}>{t('Review gift')}</Button>
195
+ </View>
196
+ ) : gift.status === 'unavailable' ? (
197
+ <BodyText>{t('This ticket cannot be gifted now.')}</BodyText>
198
+ ) : null}
199
+ {onDone && (
200
+ <Button variant="ghost" onPress={onDone}>
201
+ {t('View my tickets')}
202
+ </Button>
203
+ )}
204
+ </Card>
205
+ )
206
+ }
@@ -0,0 +1,104 @@
1
+ import React, { type FC } from 'react'
2
+ import { Pressable, View } from 'react-native'
3
+ import { hooks, ticketRefundConsequences } from 'tf-checkout-shared'
4
+ import {
5
+ BodyText,
6
+ Button,
7
+ Card,
8
+ ErrorText,
9
+ Loader,
10
+ MutedText,
11
+ SectionHeader,
12
+ } from '../ui/primitives'
13
+ import { Checkbox } from '../ui/Field'
14
+ import { FrozenFields } from '../ui/Frozen'
15
+
16
+ export interface TicketRefundProps {
17
+ ticketHash: string
18
+ onSubmitted?: () => void
19
+ onDone?: () => void
20
+ }
21
+ export const TicketRefund: FC<TicketRefundProps> = ({
22
+ ticketHash,
23
+ onSubmitted,
24
+ onDone,
25
+ }) => {
26
+ const refund = hooks.useTicketRefund(ticketHash, onSubmitted)
27
+ if (refund.result)
28
+ return (
29
+ <Card>
30
+ <SectionHeader title="Refund requested" />
31
+ <BodyText>
32
+ Your refund request has been submitted. We’ll email you when it is complete.
33
+ </BodyText>
34
+ {onDone && <Button onPress={onDone}>View my tickets</Button>}
35
+ </Card>
36
+ )
37
+ if (refund.query.isLoading) return <Loader />
38
+ if (refund.query.isError)
39
+ return (
40
+ <Card>
41
+ <ErrorText>{refund.query.error.message}</ErrorText>
42
+ <Button onPress={() => void refund.query.refetch()}>Try again</Button>
43
+ </Card>
44
+ )
45
+ const options = refund.query.data?.options ?? []
46
+ return (
47
+ <Card>
48
+ <SectionHeader title="Refund ticket" />
49
+ {!options.length && (
50
+ <BodyText>
51
+ {refund.query.data?.eligibility_reason ||
52
+ 'No refund choices are available for this ticket.'}
53
+ </BodyText>
54
+ )}
55
+ {options.map((option) => (
56
+ <Pressable
57
+ key={option.option_id}
58
+ accessibilityRole="radio"
59
+ accessibilityState={{
60
+ checked: refund.selected?.option_id === option.option_id,
61
+ disabled: refund.busy || refund.commandPending,
62
+ }}
63
+ disabled={refund.busy || refund.commandPending}
64
+ onPress={() => refund.select(option.option_id)}
65
+ >
66
+ <BodyText>
67
+ {refund.selected?.option_id === option.option_id ? '● ' : '○ '}
68
+ {option.currency} {option.amount}
69
+ </BodyText>
70
+ </Pressable>
71
+ ))}
72
+ {refund.selected && (
73
+ <View style={{ gap: 8 }}>
74
+ <BodyText>
75
+ You’ll receive {refund.selected.currency} {refund.selected.amount}.
76
+ </BodyText>
77
+ <MutedText>
78
+ Amount retained: {refund.selected.currency} {refund.selected.retained_amount}
79
+ </MutedText>
80
+ {ticketRefundConsequences(refund.selected).map((line) => (
81
+ <BodyText key={line}>{line}</BodyText>
82
+ ))}
83
+ <FrozenFields frozen={refund.busy || refund.commandPending}>
84
+ <Checkbox
85
+ label="I have reviewed this refund and its effect on my ticket and add-ons."
86
+ checked={refund.confirmed}
87
+ onChange={refund.confirm}
88
+ />
89
+ </FrozenFields>
90
+ </View>
91
+ )}
92
+ {refund.error && <ErrorText>{refund.error}</ErrorText>}
93
+ {(refund.selected || refund.commandPending) && (
94
+ <Button
95
+ onPress={() => void refund.submit()}
96
+ loading={refund.busy}
97
+ disabled={refund.busy || (!refund.commandPending && !refund.confirmed)}
98
+ >
99
+ {refund.commandPending ? 'Check refund request' : 'Confirm refund'}
100
+ </Button>
101
+ )}
102
+ </Card>
103
+ )
104
+ }