tf-checkout-react 1.7.8 → 1.7.14
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/dist/components/addonsContainer/index.d.ts +0 -3
- package/dist/components/addonsContainer/useAddons.d.ts +23 -0
- package/dist/components/paymentContainer/index.d.ts +2 -1
- package/dist/index.d.ts +3 -0
- package/dist/tf-checkout-react.cjs.development.js +209 -147
- package/dist/tf-checkout-react.cjs.development.js.map +1 -1
- package/dist/tf-checkout-react.cjs.production.min.js +1 -1
- package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
- package/dist/tf-checkout-react.esm.js +207 -148
- package/dist/tf-checkout-react.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/addonsContainer/index.tsx +26 -230
- package/src/components/addonsContainer/useAddons.ts +248 -0
- package/src/components/billing-info-container/hooks/useStripePayment.ts +14 -16
- package/src/components/billing-info-container/index.tsx +3 -2
- package/src/components/paymentContainer/index.tsx +6 -1
- package/src/index.ts +3 -0
package/package.json
CHANGED
|
@@ -3,36 +3,21 @@
|
|
|
3
3
|
|
|
4
4
|
import { CircularProgress } from '@mui/material'
|
|
5
5
|
import { Form, Formik } from 'formik'
|
|
6
|
-
import _get from 'lodash/get'
|
|
7
6
|
import _identity from 'lodash/identity'
|
|
8
7
|
import _map from 'lodash/map'
|
|
9
|
-
import React, { useEffect,
|
|
8
|
+
import React, { useEffect, useState } from 'react'
|
|
10
9
|
import { Tooltip } from 'react-tooltip'
|
|
11
10
|
|
|
12
|
-
import { getAddons, getCart, getCheckoutPageConfigs, postOnCheckout } from '../../api'
|
|
13
11
|
import { FEES_STYLES } from '../../constants'
|
|
14
12
|
import { currencyNormalizerCreator } from '../../normalizers'
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
CONFIGS,
|
|
18
|
-
createCheckoutDataBodyWithDefaultHolder,
|
|
19
|
-
createMarkup,
|
|
20
|
-
getQueryVariable,
|
|
21
|
-
isBrowser,
|
|
22
|
-
} from '../../utils'
|
|
13
|
+
import { CONFIGS, createMarkup, getQueryVariable, isBrowser } from '../../utils'
|
|
23
14
|
import { VerificationPendingModal } from '../idVerificationContainer/VerificationPendingModal'
|
|
24
15
|
import InfoIcon from '../ticketsContainer/InfoIcon'
|
|
25
16
|
import TimerWidget from '../timerWidget'
|
|
26
|
-
import { addonsWithGroupsAdapter, cartAdapter } from './adapters'
|
|
27
17
|
import AddonComponent from './AddonComponent'
|
|
28
18
|
import { getNormalizedPrice } from './normalizers'
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
getAddonSelectOptions,
|
|
32
|
-
getSortedAddons,
|
|
33
|
-
getTicketRelatedAddons,
|
|
34
|
-
isAtLeastOneAddonSelected,
|
|
35
|
-
} from './utils'
|
|
19
|
+
import { isAtLeastOneAddonSelected } from './utils'
|
|
20
|
+
import { useAddons } from './useAddons'
|
|
36
21
|
|
|
37
22
|
export interface IAddonContainterProps {
|
|
38
23
|
classNamePrefix?: string;
|
|
@@ -54,9 +39,6 @@ export interface IAddonContainterProps {
|
|
|
54
39
|
onAddOnSelect?: (id: string, value: string, addon: any) => void;
|
|
55
40
|
}
|
|
56
41
|
|
|
57
|
-
export interface ObjectLiteral {
|
|
58
|
-
[key: string]: any;
|
|
59
|
-
}
|
|
60
42
|
|
|
61
43
|
export const AddonsContainter = ({
|
|
62
44
|
classNamePrefix = 'add_on',
|
|
@@ -76,15 +58,28 @@ export const AddonsContainter = ({
|
|
|
76
58
|
configs,
|
|
77
59
|
onAddOnSelect = _identity,
|
|
78
60
|
}: IAddonContainterProps) => {
|
|
79
|
-
const eventId = getQueryVariable('event_id')
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
61
|
+
const eventId = getQueryVariable('event_id') || null
|
|
62
|
+
|
|
63
|
+
const {
|
|
64
|
+
addons,
|
|
65
|
+
addonsOptions,
|
|
66
|
+
loading,
|
|
67
|
+
cartExpirationTime,
|
|
68
|
+
pendingVerificationMessage,
|
|
69
|
+
initialValues,
|
|
70
|
+
onFieldChange,
|
|
71
|
+
handleConfirm,
|
|
72
|
+
handleClearAddons,
|
|
73
|
+
} = useAddons(eventId, {
|
|
74
|
+
enableBillingInfoAutoCreate,
|
|
75
|
+
addOnDataWithCustomFields,
|
|
76
|
+
onGetAddonsPageInfoSuccess,
|
|
77
|
+
onGetAddonsPageInfoError,
|
|
78
|
+
onPostCheckoutSuccess,
|
|
79
|
+
onPostCheckoutError,
|
|
80
|
+
onConfirmSelectionSuccess,
|
|
81
|
+
onConfirmSelectionError,
|
|
82
|
+
})
|
|
88
83
|
|
|
89
84
|
const [visibleDescription, setVisibleDescription] = useState<string | null>(null)
|
|
90
85
|
|
|
@@ -96,207 +91,8 @@ export const AddonsContainter = ({
|
|
|
96
91
|
if (samePage) {
|
|
97
92
|
window.localStorage.removeItem('add_ons')
|
|
98
93
|
}
|
|
99
|
-
const getAddonsPageInfo = async () => {
|
|
100
|
-
try {
|
|
101
|
-
if (eventId) {
|
|
102
|
-
setLoading(true)
|
|
103
|
-
|
|
104
|
-
// Get choosed ticket info (id, count) from Cart request for addons options calculations
|
|
105
|
-
const cart = await getCart()
|
|
106
|
-
const { id: choosedTicketID, quantity, expiresAt } = cartAdapter(cart)
|
|
107
|
-
const choosedTicketCount = Number(quantity)
|
|
108
|
-
setCartExpirationTime(expiresAt)
|
|
109
|
-
|
|
110
|
-
// Get and collect addons data
|
|
111
|
-
const addonsData = await getAddons(eventId)
|
|
112
|
-
const adaptedAddons = addonsWithGroupsAdapter(addonsData)
|
|
113
|
-
const ticketRelatedAddons = getTicketRelatedAddons(
|
|
114
|
-
adaptedAddons,
|
|
115
|
-
choosedTicketID
|
|
116
|
-
)
|
|
117
|
-
const sortedTicketAddons = getSortedAddons(ticketRelatedAddons)
|
|
118
|
-
|
|
119
|
-
setAddons(sortedTicketAddons)
|
|
120
|
-
|
|
121
|
-
// Collect addons and addon group options
|
|
122
|
-
const {
|
|
123
|
-
addonsWithOptions,
|
|
124
|
-
groupsWithSelectedVariantsInfo,
|
|
125
|
-
groupsWithVariants,
|
|
126
|
-
} = getAddonSelectOptions(adaptedAddons, choosedTicketCount)
|
|
127
|
-
|
|
128
|
-
setAddonsOptions(addonsWithOptions)
|
|
129
|
-
setGroupsWithSelectedVariants(groupsWithSelectedVariantsInfo)
|
|
130
|
-
setGroupsWithInitialVariantsValues(groupsWithVariants)
|
|
131
|
-
|
|
132
|
-
// Success callback props
|
|
133
|
-
onGetAddonsPageInfoSuccess(addonsData)
|
|
134
|
-
}
|
|
135
|
-
} catch (e) {
|
|
136
|
-
// Callback error props
|
|
137
|
-
onGetAddonsPageInfoError(e)
|
|
138
|
-
} finally {
|
|
139
|
-
setLoading(false)
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
getAddonsPageInfo()
|
|
144
94
|
}, [])
|
|
145
95
|
|
|
146
|
-
const recreateGroupVariantsSelectOptions = (groupId: any, changedGroupd: any) => {
|
|
147
|
-
const { choosedVariants, limit, selectedCount } = changedGroupd
|
|
148
|
-
const remainingGroupStock = limit - selectedCount
|
|
149
|
-
const recreatedVariantsOptions: ObjectLiteral = {}
|
|
150
|
-
|
|
151
|
-
// Regenerate variants allowed stock counts
|
|
152
|
-
for (const variant in choosedVariants) {
|
|
153
|
-
const variantId = variant
|
|
154
|
-
const variantCurrSelectedValue = choosedVariants[variant]
|
|
155
|
-
let allowedOptionCount
|
|
156
|
-
|
|
157
|
-
// Formula for regenerating
|
|
158
|
-
if (
|
|
159
|
-
remainingGroupStock >=
|
|
160
|
-
groupsWithInitialVariantsValues[groupId][variantId] - variantCurrSelectedValue
|
|
161
|
-
) {
|
|
162
|
-
allowedOptionCount = groupsWithInitialVariantsValues[groupId][variantId]
|
|
163
|
-
} else {
|
|
164
|
-
allowedOptionCount = remainingGroupStock + variantCurrSelectedValue
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
recreatedVariantsOptions[variantId] = generateSelectOptions(0, allowedOptionCount)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
setAddonsOptions((prevState: any) =>
|
|
171
|
-
Object.assign({}, prevState, recreatedVariantsOptions)
|
|
172
|
-
)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const onFieldChange = (id: any, value: any, addon: any) => {
|
|
176
|
-
// If changeableGroup exsists it means that group with limitation variant was changed
|
|
177
|
-
const changeableGroup = groupsWithSelectedVariants[addon.id]
|
|
178
|
-
|
|
179
|
-
if (changeableGroup) {
|
|
180
|
-
const currGroupId = addon.id
|
|
181
|
-
const currSelectedVariantId = id
|
|
182
|
-
const currSelectedVariantCount = Number(value)
|
|
183
|
-
const currSelectedVariantPrevCount =
|
|
184
|
-
groupsWithSelectedVariants[currGroupId].choosedVariants[currSelectedVariantId]
|
|
185
|
-
|
|
186
|
-
const currSelectedGroupCount =
|
|
187
|
-
changeableGroup.selectedCount +
|
|
188
|
-
(currSelectedVariantCount - currSelectedVariantPrevCount)
|
|
189
|
-
|
|
190
|
-
// Update Group info
|
|
191
|
-
const updatedGroupsWithSelectedVariants = {
|
|
192
|
-
...groupsWithSelectedVariants,
|
|
193
|
-
[currGroupId]: {
|
|
194
|
-
...groupsWithSelectedVariants[currGroupId],
|
|
195
|
-
selectedCount: currSelectedGroupCount,
|
|
196
|
-
choosedVariants: {
|
|
197
|
-
...groupsWithSelectedVariants[currGroupId].choosedVariants,
|
|
198
|
-
[currSelectedVariantId]: currSelectedVariantCount,
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
}
|
|
202
|
-
setGroupsWithSelectedVariants(updatedGroupsWithSelectedVariants)
|
|
203
|
-
|
|
204
|
-
// Recreate Select Options for Addon Group Variants
|
|
205
|
-
recreateGroupVariantsSelectOptions(
|
|
206
|
-
currGroupId,
|
|
207
|
-
updatedGroupsWithSelectedVariants[currGroupId]
|
|
208
|
-
)
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const handleConfirm = async (values: any, skipAddonPage?: boolean) => {
|
|
213
|
-
try {
|
|
214
|
-
const pageConfigsDataResponse = await getCheckoutPageConfigs()
|
|
215
|
-
const pageConfigsData: ICheckoutPageConfigs =
|
|
216
|
-
_get(pageConfigsDataResponse, 'data.attributes') || {}
|
|
217
|
-
|
|
218
|
-
const skipBillingPage = pageConfigsData.skip_billing_page ?? false
|
|
219
|
-
|
|
220
|
-
if (skipBillingPage && enableBillingInfoAutoCreate) {
|
|
221
|
-
const ticketsQuantity = window.localStorage.getItem('quantity')
|
|
222
|
-
const userData = JSON.parse(window.localStorage.getItem('user_data') || '{}')
|
|
223
|
-
|
|
224
|
-
const checkoutBody = createCheckoutDataBodyWithDefaultHolder(
|
|
225
|
-
Number(ticketsQuantity) || 0,
|
|
226
|
-
userData
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
try {
|
|
230
|
-
const checkoutResponse = await postOnCheckout({
|
|
231
|
-
...checkoutBody,
|
|
232
|
-
attributes: {
|
|
233
|
-
...checkoutBody.attributes,
|
|
234
|
-
...(!skipAddonPage && { add_ons: values }),
|
|
235
|
-
},
|
|
236
|
-
})
|
|
237
|
-
const hash = checkoutResponse?.data?.attributes?.hash || ''
|
|
238
|
-
const total = checkoutResponse?.data?.attributes?.total || ''
|
|
239
|
-
|
|
240
|
-
isBrowser && window.localStorage.removeItem('quantity')
|
|
241
|
-
isBrowser && window.localStorage.removeItem('add_ons')
|
|
242
|
-
|
|
243
|
-
onPostCheckoutSuccess(checkoutResponse?.data.attributes)
|
|
244
|
-
onConfirmSelectionSuccess({
|
|
245
|
-
skip_billing_page: skipBillingPage,
|
|
246
|
-
event_id: String(eventId),
|
|
247
|
-
hash,
|
|
248
|
-
total,
|
|
249
|
-
})
|
|
250
|
-
} catch (error) {
|
|
251
|
-
if ((error as any).response?.data?.data?.hasUnverifiedOrder) {
|
|
252
|
-
setPendingVerificationMessage((error as any).response?.data?.message)
|
|
253
|
-
} else {
|
|
254
|
-
onPostCheckoutError(error)
|
|
255
|
-
onConfirmSelectionError(error)
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
} else {
|
|
259
|
-
if (isBrowser) {
|
|
260
|
-
if (!skipAddonPage) {
|
|
261
|
-
window.localStorage.setItem('add_ons', JSON.stringify(values))
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
onConfirmSelectionSuccess({
|
|
265
|
-
skip_billing_page: skipBillingPage && enableBillingInfoAutoCreate,
|
|
266
|
-
event_id: String(eventId),
|
|
267
|
-
})
|
|
268
|
-
} else {
|
|
269
|
-
onConfirmSelectionError({
|
|
270
|
-
error: true,
|
|
271
|
-
message: 'Window is not defined',
|
|
272
|
-
})
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
} catch (e) {
|
|
276
|
-
onConfirmSelectionError(e)
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const handleClearAddons = () => {
|
|
281
|
-
window.localStorage.removeItem('add_ons')
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const initialValues = useMemo(() => {
|
|
285
|
-
const addOnsData: any = {}
|
|
286
|
-
if (addons?.length > 0 && addOnDataWithCustomFields?.fields?.length > 0) {
|
|
287
|
-
_map(addons, addon => {
|
|
288
|
-
_map(addOnDataWithCustomFields.fields, field => {
|
|
289
|
-
const { id, groupItems } = field
|
|
290
|
-
_map(groupItems, item => {
|
|
291
|
-
addOnsData[`${addon.id}-${id}-${item.name}`] = item.value
|
|
292
|
-
})
|
|
293
|
-
})
|
|
294
|
-
})
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return addOnsData
|
|
298
|
-
}, [addons, addOnDataWithCustomFields])
|
|
299
|
-
|
|
300
96
|
if (loading) {
|
|
301
97
|
return (
|
|
302
98
|
<div className={`${classNamePrefix}_loader`}>
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import _get from 'lodash/get'
|
|
3
|
+
import _identity from 'lodash/identity'
|
|
4
|
+
import _map from 'lodash/map'
|
|
5
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
6
|
+
|
|
7
|
+
import { getAddons, getCart, getCheckoutPageConfigs, postOnCheckout } from '../../api'
|
|
8
|
+
import { ICheckoutPageConfigs } from '../../types'
|
|
9
|
+
import { createCheckoutDataBodyWithDefaultHolder, isBrowser } from '../../utils'
|
|
10
|
+
import { addonsWithGroupsAdapter, cartAdapter } from './adapters'
|
|
11
|
+
import {
|
|
12
|
+
generateSelectOptions,
|
|
13
|
+
getAddonSelectOptions,
|
|
14
|
+
getSortedAddons,
|
|
15
|
+
getTicketRelatedAddons,
|
|
16
|
+
} from './utils'
|
|
17
|
+
|
|
18
|
+
interface ObjectLiteral {
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface IUseAddonsOptions {
|
|
23
|
+
enableBillingInfoAutoCreate?: boolean;
|
|
24
|
+
addOnDataWithCustomFields?: any;
|
|
25
|
+
onGetAddonsPageInfoSuccess?: (res: any) => void;
|
|
26
|
+
onGetAddonsPageInfoError?: (error: any) => void;
|
|
27
|
+
onPostCheckoutSuccess?: (res: any) => void;
|
|
28
|
+
onPostCheckoutError?: (error: any) => void;
|
|
29
|
+
onConfirmSelectionSuccess?: (res: any) => void;
|
|
30
|
+
onConfirmSelectionError?: (error: any) => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const useAddons = (eventId: string | null, options: IUseAddonsOptions = {}) => {
|
|
34
|
+
const {
|
|
35
|
+
enableBillingInfoAutoCreate = true,
|
|
36
|
+
addOnDataWithCustomFields,
|
|
37
|
+
onGetAddonsPageInfoSuccess = _identity,
|
|
38
|
+
onGetAddonsPageInfoError = _identity,
|
|
39
|
+
onPostCheckoutSuccess = _identity,
|
|
40
|
+
onPostCheckoutError = _identity,
|
|
41
|
+
onConfirmSelectionSuccess = _identity,
|
|
42
|
+
onConfirmSelectionError = _identity,
|
|
43
|
+
} = options
|
|
44
|
+
|
|
45
|
+
const [addons, setAddons] = useState<any>([])
|
|
46
|
+
const [addonsOptions, setAddonsOptions] = useState<any>({})
|
|
47
|
+
const [groupsWithSelectedVariants, setGroupsWithSelectedVariants] = useState<any>({})
|
|
48
|
+
const [groupsWithInitialVariantsValues, setGroupsWithInitialVariantsValues] = useState<any>({})
|
|
49
|
+
const [loading, setLoading] = useState(true)
|
|
50
|
+
const [cartExpirationTime, setCartExpirationTime] = useState(0)
|
|
51
|
+
const [pendingVerificationMessage, setPendingVerificationMessage] = useState<any>()
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const getAddonsPageInfo = async () => {
|
|
55
|
+
try {
|
|
56
|
+
if (eventId) {
|
|
57
|
+
setLoading(true)
|
|
58
|
+
|
|
59
|
+
const cart = await getCart()
|
|
60
|
+
const { id: choosedTicketID, quantity, expiresAt } = cartAdapter(cart)
|
|
61
|
+
const choosedTicketCount = Number(quantity)
|
|
62
|
+
setCartExpirationTime(expiresAt)
|
|
63
|
+
|
|
64
|
+
const addonsData = await getAddons(eventId)
|
|
65
|
+
const adaptedAddons = addonsWithGroupsAdapter(addonsData)
|
|
66
|
+
const ticketRelatedAddons = getTicketRelatedAddons(adaptedAddons, choosedTicketID)
|
|
67
|
+
const sortedTicketAddons = getSortedAddons(ticketRelatedAddons)
|
|
68
|
+
|
|
69
|
+
setAddons(sortedTicketAddons)
|
|
70
|
+
|
|
71
|
+
const {
|
|
72
|
+
addonsWithOptions,
|
|
73
|
+
groupsWithSelectedVariantsInfo,
|
|
74
|
+
groupsWithVariants,
|
|
75
|
+
} = getAddonSelectOptions(adaptedAddons, choosedTicketCount)
|
|
76
|
+
|
|
77
|
+
setAddonsOptions(addonsWithOptions)
|
|
78
|
+
setGroupsWithSelectedVariants(groupsWithSelectedVariantsInfo)
|
|
79
|
+
setGroupsWithInitialVariantsValues(groupsWithVariants)
|
|
80
|
+
|
|
81
|
+
onGetAddonsPageInfoSuccess(addonsData)
|
|
82
|
+
}
|
|
83
|
+
} catch (e) {
|
|
84
|
+
onGetAddonsPageInfoError(e)
|
|
85
|
+
} finally {
|
|
86
|
+
setLoading(false)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
getAddonsPageInfo()
|
|
91
|
+
}, [eventId])
|
|
92
|
+
|
|
93
|
+
const recreateGroupVariantsSelectOptions = (groupId: any, changedGroup: any) => {
|
|
94
|
+
const { choosedVariants, limit, selectedCount } = changedGroup
|
|
95
|
+
const remainingGroupStock = limit - selectedCount
|
|
96
|
+
const recreatedVariantsOptions: ObjectLiteral = {}
|
|
97
|
+
|
|
98
|
+
for (const variant in choosedVariants) {
|
|
99
|
+
const variantId = variant
|
|
100
|
+
const variantCurrSelectedValue = choosedVariants[variant]
|
|
101
|
+
let allowedOptionCount
|
|
102
|
+
|
|
103
|
+
if (
|
|
104
|
+
remainingGroupStock >=
|
|
105
|
+
groupsWithInitialVariantsValues[groupId][variantId] - variantCurrSelectedValue
|
|
106
|
+
) {
|
|
107
|
+
allowedOptionCount = groupsWithInitialVariantsValues[groupId][variantId]
|
|
108
|
+
} else {
|
|
109
|
+
allowedOptionCount = remainingGroupStock + variantCurrSelectedValue
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
recreatedVariantsOptions[variantId] = generateSelectOptions(0, allowedOptionCount)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
setAddonsOptions((prevState: any) => Object.assign({}, prevState, recreatedVariantsOptions))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const onFieldChange = (id: any, value: any, addon: any) => {
|
|
119
|
+
const changeableGroup = groupsWithSelectedVariants[addon.id]
|
|
120
|
+
|
|
121
|
+
if (changeableGroup) {
|
|
122
|
+
const currGroupId = addon.id
|
|
123
|
+
const currSelectedVariantId = id
|
|
124
|
+
const currSelectedVariantCount = Number(value)
|
|
125
|
+
const currSelectedVariantPrevCount =
|
|
126
|
+
groupsWithSelectedVariants[currGroupId].choosedVariants[currSelectedVariantId]
|
|
127
|
+
|
|
128
|
+
const currSelectedGroupCount =
|
|
129
|
+
changeableGroup.selectedCount +
|
|
130
|
+
(currSelectedVariantCount - currSelectedVariantPrevCount)
|
|
131
|
+
|
|
132
|
+
const updatedGroupsWithSelectedVariants = {
|
|
133
|
+
...groupsWithSelectedVariants,
|
|
134
|
+
[currGroupId]: {
|
|
135
|
+
...groupsWithSelectedVariants[currGroupId],
|
|
136
|
+
selectedCount: currSelectedGroupCount,
|
|
137
|
+
choosedVariants: {
|
|
138
|
+
...groupsWithSelectedVariants[currGroupId].choosedVariants,
|
|
139
|
+
[currSelectedVariantId]: currSelectedVariantCount,
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
setGroupsWithSelectedVariants(updatedGroupsWithSelectedVariants)
|
|
144
|
+
|
|
145
|
+
recreateGroupVariantsSelectOptions(
|
|
146
|
+
currGroupId,
|
|
147
|
+
updatedGroupsWithSelectedVariants[currGroupId]
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const handleConfirm = async (values: any, skipAddonPage?: boolean) => {
|
|
153
|
+
try {
|
|
154
|
+
const pageConfigsDataResponse = await getCheckoutPageConfigs()
|
|
155
|
+
const pageConfigsData: ICheckoutPageConfigs =
|
|
156
|
+
_get(pageConfigsDataResponse, 'data.attributes') || {}
|
|
157
|
+
|
|
158
|
+
const skipBillingPage = pageConfigsData.skip_billing_page ?? false
|
|
159
|
+
|
|
160
|
+
if (skipBillingPage && enableBillingInfoAutoCreate) {
|
|
161
|
+
const ticketsQuantity = window.localStorage.getItem('quantity')
|
|
162
|
+
const userData = JSON.parse(window.localStorage.getItem('user_data') || '{}')
|
|
163
|
+
|
|
164
|
+
const checkoutBody = createCheckoutDataBodyWithDefaultHolder(
|
|
165
|
+
Number(ticketsQuantity) || 0,
|
|
166
|
+
userData
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
const checkoutResponse = await postOnCheckout({
|
|
171
|
+
...checkoutBody,
|
|
172
|
+
attributes: {
|
|
173
|
+
...checkoutBody.attributes,
|
|
174
|
+
...(!skipAddonPage && { add_ons: values }),
|
|
175
|
+
},
|
|
176
|
+
})
|
|
177
|
+
const hash = checkoutResponse?.data?.attributes?.hash || ''
|
|
178
|
+
const total = checkoutResponse?.data?.attributes?.total || ''
|
|
179
|
+
|
|
180
|
+
isBrowser && window.localStorage.removeItem('quantity')
|
|
181
|
+
isBrowser && window.localStorage.removeItem('add_ons')
|
|
182
|
+
|
|
183
|
+
onPostCheckoutSuccess(checkoutResponse?.data.attributes)
|
|
184
|
+
onConfirmSelectionSuccess({
|
|
185
|
+
skip_billing_page: skipBillingPage,
|
|
186
|
+
event_id: String(eventId),
|
|
187
|
+
hash,
|
|
188
|
+
total,
|
|
189
|
+
})
|
|
190
|
+
} catch (error) {
|
|
191
|
+
if ((error as any).response?.data?.data?.hasUnverifiedOrder) {
|
|
192
|
+
setPendingVerificationMessage((error as any).response?.data?.message)
|
|
193
|
+
} else {
|
|
194
|
+
onPostCheckoutError(error)
|
|
195
|
+
onConfirmSelectionError(error)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
if (isBrowser) {
|
|
200
|
+
if (!skipAddonPage) {
|
|
201
|
+
window.localStorage.setItem('add_ons', JSON.stringify(values))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
onConfirmSelectionSuccess({
|
|
205
|
+
skip_billing_page: skipBillingPage && enableBillingInfoAutoCreate,
|
|
206
|
+
event_id: String(eventId),
|
|
207
|
+
})
|
|
208
|
+
} else {
|
|
209
|
+
onConfirmSelectionError({ error: true, message: 'Window is not defined' })
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} catch (e) {
|
|
213
|
+
onConfirmSelectionError(e)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const handleClearAddons = () => {
|
|
218
|
+
window.localStorage.removeItem('add_ons')
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const initialValues = useMemo(() => {
|
|
222
|
+
const addOnsData: any = {}
|
|
223
|
+
if (addons?.length > 0 && addOnDataWithCustomFields?.fields?.length > 0) {
|
|
224
|
+
_map(addons, addon => {
|
|
225
|
+
_map(addOnDataWithCustomFields.fields, field => {
|
|
226
|
+
const { id, groupItems } = field
|
|
227
|
+
_map(groupItems, item => {
|
|
228
|
+
addOnsData[`${addon.id}-${id}-${item.name}`] = item.value
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
return addOnsData
|
|
234
|
+
}, [addons, addOnDataWithCustomFields])
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
addons,
|
|
238
|
+
addonsOptions,
|
|
239
|
+
loading,
|
|
240
|
+
cartExpirationTime,
|
|
241
|
+
pendingVerificationMessage,
|
|
242
|
+
setPendingVerificationMessage,
|
|
243
|
+
initialValues,
|
|
244
|
+
onFieldChange,
|
|
245
|
+
handleConfirm,
|
|
246
|
+
handleClearAddons,
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -36,20 +36,13 @@ export const useStripePayment = ({
|
|
|
36
36
|
if (!isFreeTickets) {
|
|
37
37
|
if (!stripeRef.current) {
|
|
38
38
|
setError('Stripe is not ready')
|
|
39
|
-
console.log('Stripe is not ready in billing-info-container')
|
|
40
39
|
return null
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
console.log('Stripe confirmPayment in billing-info-container')
|
|
44
|
-
|
|
45
42
|
// Step 1: Submit elements first
|
|
46
43
|
const { error: submitError } = await elementsRef.current.submit()
|
|
47
44
|
if (submitError) {
|
|
48
45
|
setError('' + submitError?.message)
|
|
49
|
-
console.log(
|
|
50
|
-
'Stripe elements.submit() error in billing-info-container',
|
|
51
|
-
submitError
|
|
52
|
-
)
|
|
53
46
|
return null
|
|
54
47
|
}
|
|
55
48
|
|
|
@@ -68,28 +61,33 @@ export const useStripePayment = ({
|
|
|
68
61
|
localStorage.setItem('stripe_payment_context', JSON.stringify(paymentContext))
|
|
69
62
|
|
|
70
63
|
// Step 3: Confirm payment with current page return URL
|
|
64
|
+
const confirmParams: any = {
|
|
65
|
+
return_url:
|
|
66
|
+
window.location.href +
|
|
67
|
+
(window.location.href.includes('?') ? '&' : '?') +
|
|
68
|
+
'payment_return=true',
|
|
69
|
+
}
|
|
70
|
+
if (values?.phone) {
|
|
71
|
+
const rawPhone = String(values.phone).replace(/[\s\-().]/g, '')
|
|
72
|
+
const e164Phone = rawPhone.startsWith('+') ? rawPhone : `+${rawPhone}`
|
|
73
|
+
confirmParams.payment_method_data = {
|
|
74
|
+
billing_details: { phone: e164Phone },
|
|
75
|
+
}
|
|
76
|
+
}
|
|
71
77
|
const { error: confirmError } = await stripeRef.current.confirmPayment({
|
|
72
78
|
clientSecret:
|
|
73
79
|
paymentDataResponse.data.attributes.payment_method.stripe_client_secret,
|
|
74
80
|
elements: elementsRef.current,
|
|
75
|
-
confirmParams
|
|
76
|
-
return_url:
|
|
77
|
-
window.location.href +
|
|
78
|
-
(window.location.href.includes('?') ? '&' : '?') +
|
|
79
|
-
'payment_return=true',
|
|
80
|
-
},
|
|
81
|
+
confirmParams,
|
|
81
82
|
redirect: 'if_required',
|
|
82
83
|
})
|
|
83
84
|
|
|
84
85
|
if (confirmError) {
|
|
85
86
|
setError('' + confirmError?.message)
|
|
86
|
-
console.log('Stripe confirmPayment error in billing-info-container')
|
|
87
87
|
return null
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
console.log('Stripe confirmPayment success in billing-info-container')
|
|
92
|
-
|
|
93
91
|
// Handle payment middleware for non-redirect payments
|
|
94
92
|
let paymentResponse = null
|
|
95
93
|
await handlePaymentMiddleWare(
|
|
@@ -517,7 +517,7 @@ const BillingInfoContainer = React.memo(
|
|
|
517
517
|
const orderIsFree = !Number(checkoutData?.total)
|
|
518
518
|
|
|
519
519
|
useEffect(() => {
|
|
520
|
-
const hasUniqueId = _get(
|
|
520
|
+
const hasUniqueId = _get(data, '[0].uniqueId')
|
|
521
521
|
const isEqualData = _isEqual(prevData.current, data)
|
|
522
522
|
if (!hasUniqueId || !isEqualData) {
|
|
523
523
|
setDataWithUniqueIds(assingUniqueIds(data))
|
|
@@ -525,7 +525,7 @@ const BillingInfoContainer = React.memo(
|
|
|
525
525
|
prevData.current = data
|
|
526
526
|
}
|
|
527
527
|
}
|
|
528
|
-
}, [
|
|
528
|
+
}, [data])
|
|
529
529
|
|
|
530
530
|
const getQuantity = useCallback((cart: any = []) => {
|
|
531
531
|
let qty = 0
|
|
@@ -1575,6 +1575,7 @@ const BillingInfoContainer = React.memo(
|
|
|
1575
1575
|
checkoutData={checkoutData}
|
|
1576
1576
|
elementsOptions={elementsOptions}
|
|
1577
1577
|
paymentElementOptions={{
|
|
1578
|
+
fields: { billingDetails: { phone: 'never' } },
|
|
1578
1579
|
wallets: {
|
|
1579
1580
|
applePay:
|
|
1580
1581
|
checkoutUpdateData?.additional_payment_information
|
|
@@ -43,9 +43,11 @@ import { PaymentPlanSection } from './PaymentPlanSection'
|
|
|
43
43
|
const StripeWrapper = ({
|
|
44
44
|
options,
|
|
45
45
|
onStripeReady,
|
|
46
|
+
onPaymentElementChange,
|
|
46
47
|
}: {
|
|
47
48
|
options?: StripePaymentElementOptions;
|
|
48
49
|
onStripeReady: (stripe: any, elements: any) => void;
|
|
50
|
+
onPaymentElementChange?: (event: any) => void;
|
|
49
51
|
}) => {
|
|
50
52
|
const stripe = useStripe()
|
|
51
53
|
const elements = useElements()
|
|
@@ -56,7 +58,7 @@ const StripeWrapper = ({
|
|
|
56
58
|
}
|
|
57
59
|
}, [stripe, elements, onStripeReady])
|
|
58
60
|
|
|
59
|
-
return <PaymentElement options={options} />
|
|
61
|
+
return <PaymentElement options={options} onChange={onPaymentElementChange} />
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
export interface IPaymentPage {
|
|
@@ -86,6 +88,7 @@ export interface IPaymentPage {
|
|
|
86
88
|
stripePublishableKey?: string;
|
|
87
89
|
stripeAccountId?: string;
|
|
88
90
|
onStripeReady?: (stripe: any, elements: any) => void;
|
|
91
|
+
onPaymentElementChange?: (event: any) => void;
|
|
89
92
|
enablePaymentPlan?: boolean;
|
|
90
93
|
}
|
|
91
94
|
|
|
@@ -166,6 +169,7 @@ export const PaymentContainer = ({
|
|
|
166
169
|
stripePublishableKey,
|
|
167
170
|
stripeAccountId,
|
|
168
171
|
onStripeReady = _identity,
|
|
172
|
+
onPaymentElementChange,
|
|
169
173
|
enablePaymentPlan = true,
|
|
170
174
|
}: IPaymentPage) => {
|
|
171
175
|
const [reviewData, setReviewData] = useState(initialReviewValues)
|
|
@@ -599,6 +603,7 @@ export const PaymentContainer = ({
|
|
|
599
603
|
<StripeWrapper
|
|
600
604
|
onStripeReady={onStripeReady}
|
|
601
605
|
options={paymentElementOptions}
|
|
606
|
+
onPaymentElementChange={onPaymentElementChange}
|
|
602
607
|
/>
|
|
603
608
|
</Elements>
|
|
604
609
|
)}
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,9 @@ export { RsvpContainer } from './components/rsvpContainer'
|
|
|
13
13
|
export { ResetPasswordContainer } from './components/resetPasswordContainer'
|
|
14
14
|
export { ForgotPasswordModal } from './components/forgotPasswordModal'
|
|
15
15
|
export { AddonsContainter } from './components/addonsContainer'
|
|
16
|
+
export { useAddons } from './components/addonsContainer/useAddons'
|
|
17
|
+
export { default as TimerWidget } from './components/timerWidget'
|
|
18
|
+
export { VerificationPendingModal } from './components/idVerificationContainer/VerificationPendingModal'
|
|
16
19
|
export { PreRegistration } from './components/preRegistration'
|
|
17
20
|
export { PreRegistrationComplete } from './components/preRegistration/PreRegistrationComplete'
|
|
18
21
|
export { PreRegistrationInformations } from './components/preRegistration/PreRegistrationInformations'
|