tf-checkout-react 1.4.18 → 1.4.20
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/api/index.d.ts +1 -0
- package/dist/components/confirmationContainer/index.d.ts +3 -0
- package/dist/components/paymentContainer/PaymentPlanSection.d.ts +10 -0
- package/dist/components/stripePayment/index.d.ts +3 -2
- package/dist/tf-checkout-react.cjs.development.js +321 -119
- 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 +321 -119
- package/dist/tf-checkout-react.esm.js.map +1 -1
- package/dist/tf-checkout-styles.css +1 -1
- package/dist/types/payment-plan-configuration.d.ts +18 -0
- package/package.json +2 -2
- package/src/api/index.ts +13 -0
- package/src/components/confirmationContainer/index.tsx +53 -50
- package/src/components/paymentContainer/PaymentPlanSection.tsx +152 -0
- package/src/components/paymentContainer/index.tsx +223 -154
- package/src/components/paymentContainer/style.css +8 -0
- package/src/components/seatMapContainer/SeatMapComponent.tsx +26 -22
- package/src/components/seatMapContainer/TicketsSection.tsx +11 -10
- package/src/components/seatMapContainer/index.tsx +67 -72
- package/src/components/stripePayment/index.tsx +19 -18
- package/src/types/payment-plan-configuration.ts +19 -0
- package/src/types/seatMap.d.ts +1 -0
|
@@ -140,10 +140,7 @@ export const TicketsSection = (
|
|
|
140
140
|
<Button
|
|
141
141
|
className="ticket-delete"
|
|
142
142
|
onClick={() => {
|
|
143
|
-
handleCancelReservation(
|
|
144
|
-
dropdownData.seatId,
|
|
145
|
-
dropdownData.tierId
|
|
146
|
-
)
|
|
143
|
+
handleCancelReservation(dropdownData.seatId, dropdownData.tierId)
|
|
147
144
|
}}
|
|
148
145
|
>
|
|
149
146
|
{ticketDeleteButtonContent}
|
|
@@ -166,7 +163,9 @@ export const TicketsSection = (
|
|
|
166
163
|
{`${currencySymbol} ${finalPrice}`}
|
|
167
164
|
</span>
|
|
168
165
|
<span className="fees">
|
|
169
|
-
{selectedTicketData.fee_included
|
|
166
|
+
{selectedTicketData.fee_included
|
|
167
|
+
? ' (incl. Fees)'
|
|
168
|
+
: ' (excl. Fees)'}
|
|
170
169
|
</span>
|
|
171
170
|
</div>
|
|
172
171
|
{!_isEmpty(selectedTicketData.ticket_type_deposit) && (
|
|
@@ -190,7 +189,7 @@ export const TicketsSection = (
|
|
|
190
189
|
{showDescription && (
|
|
191
190
|
<Tooltip
|
|
192
191
|
title="View Ticket Info"
|
|
193
|
-
placement=
|
|
192
|
+
placement="left"
|
|
194
193
|
arrow
|
|
195
194
|
componentsProps={{
|
|
196
195
|
tooltip: {
|
|
@@ -201,7 +200,7 @@ export const TicketsSection = (
|
|
|
201
200
|
color: 'common.black',
|
|
202
201
|
},
|
|
203
202
|
},
|
|
204
|
-
}
|
|
203
|
+
},
|
|
205
204
|
}}
|
|
206
205
|
>
|
|
207
206
|
<div
|
|
@@ -251,12 +250,14 @@ export const TicketsSection = (
|
|
|
251
250
|
)}
|
|
252
251
|
</div>
|
|
253
252
|
</div>
|
|
254
|
-
{selectedTicketsInfo[dropdownData.seatId] &&
|
|
253
|
+
{selectedTicketsInfo[dropdownData.seatId] && (
|
|
255
254
|
<div
|
|
256
255
|
className="ticket-description-content"
|
|
257
|
-
dangerouslySetInnerHTML={createMarkup(
|
|
256
|
+
dangerouslySetInnerHTML={createMarkup(
|
|
257
|
+
selectedTicketData.description || ''
|
|
258
|
+
)}
|
|
258
259
|
/>
|
|
259
|
-
}
|
|
260
|
+
)}
|
|
260
261
|
</>
|
|
261
262
|
)}
|
|
262
263
|
</div>
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { Alert } from '@mui/material'
|
|
2
2
|
import axios from 'axios'
|
|
3
|
-
import { identity } from 'lodash'
|
|
4
3
|
import _find from 'lodash/find'
|
|
5
4
|
import _forEach from 'lodash/forEach'
|
|
6
5
|
import _get from 'lodash/get'
|
|
6
|
+
import _identity from 'lodash/identity'
|
|
7
7
|
import _isEmpty from 'lodash/isEmpty'
|
|
8
|
+
import _isEqual from 'lodash/isEqual'
|
|
8
9
|
import _keys from 'lodash/keys'
|
|
9
10
|
import _map from 'lodash/map'
|
|
10
11
|
import _values from 'lodash/values'
|
|
11
12
|
import moment from 'moment'
|
|
12
|
-
import React, { useCallback, useEffect, useRef,useState } from 'react'
|
|
13
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
13
14
|
import Countdown from 'react-countdown'
|
|
14
15
|
|
|
15
16
|
import {
|
|
@@ -44,8 +45,8 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
44
45
|
},
|
|
45
46
|
mapContainerId,
|
|
46
47
|
timerMessage = '',
|
|
47
|
-
onAddToCartSuccess =
|
|
48
|
-
onCountdownFinish =
|
|
48
|
+
onAddToCartSuccess = _identity,
|
|
49
|
+
onCountdownFinish = _identity,
|
|
49
50
|
ticketDeleteButtonContent,
|
|
50
51
|
ticketInfoContent,
|
|
51
52
|
} = props
|
|
@@ -65,20 +66,16 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
65
66
|
[seatId: string]: string;
|
|
66
67
|
}>({})
|
|
67
68
|
const [seatMapStatuses, setSeatMapStatuses] = useState('')
|
|
68
|
-
const [reservedSeats, setReservedSeats] = useState<
|
|
69
|
-
Array<SeatReservationData>
|
|
70
|
-
>([])
|
|
69
|
+
const [reservedSeats, setReservedSeats] = useState<Array<SeatReservationData>>([])
|
|
71
70
|
const [isLoadingSeatMapData, setIsLoadingSeatMapData] = useState(true)
|
|
72
|
-
const [isLoadingStatuses, setIsLoadingStatuses] = useState(
|
|
71
|
+
const [isLoadingStatuses, setIsLoadingStatuses] = useState(false)
|
|
73
72
|
const [isReserving, setIsReserving] = useState(false)
|
|
74
73
|
const [isAddingToCart, setIsAddingToCart] = useState(false)
|
|
75
74
|
const [error, setError] = useState<string | null>(null)
|
|
76
75
|
const [showTimer, setShowTimer] = useState(
|
|
77
76
|
Date.now() <= Number(localStorage.getItem(`reservationStart-${eventId}`))
|
|
78
77
|
)
|
|
79
|
-
const [guestCounts, setGuestCounts] = useState<IGuestCounts>(
|
|
80
|
-
{} as IGuestCounts
|
|
81
|
-
)
|
|
78
|
+
const [guestCounts, setGuestCounts] = useState<IGuestCounts>({} as IGuestCounts)
|
|
82
79
|
const isGuestCountsSet = useRef(false)
|
|
83
80
|
|
|
84
81
|
const updateGuestCounts = (data: any) => {
|
|
@@ -87,9 +84,7 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
87
84
|
const seatTicketsArray = _values(tierTickets)
|
|
88
85
|
|
|
89
86
|
setGuestCounts((prevState: any) => ({
|
|
90
|
-
[item.seatId]: Number(
|
|
91
|
-
seatTicketsArray[0].ticket_type_min_number_of_guests
|
|
92
|
-
),
|
|
87
|
+
[item.seatId]: Number(seatTicketsArray[0].ticket_type_min_number_of_guests),
|
|
93
88
|
...prevState,
|
|
94
89
|
}))
|
|
95
90
|
})
|
|
@@ -132,14 +127,12 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
132
127
|
const statusesResponse = await getSeatMapStatuses(eventId)
|
|
133
128
|
const statuses = _get(statusesResponse, 'data.attributes') || {}
|
|
134
129
|
const reservationData: Array<SeatReservationData> = []
|
|
135
|
-
const ownReservations: string[] = getOwnReservationsBasedOnStatuses(
|
|
136
|
-
statuses
|
|
137
|
-
)
|
|
130
|
+
const ownReservations: string[] = getOwnReservationsBasedOnStatuses(statuses)
|
|
138
131
|
|
|
139
132
|
_forEach(ownReservations, reservation => {
|
|
140
133
|
const tierIdOfReservation = getTierIdBasedOnSeatId(
|
|
141
134
|
reservation,
|
|
142
|
-
eventSeatsRef.current
|
|
135
|
+
eventSeatsRef.current
|
|
143
136
|
) as string
|
|
144
137
|
reservationData.push({
|
|
145
138
|
seatId: reservation,
|
|
@@ -149,10 +142,19 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
149
142
|
})
|
|
150
143
|
|
|
151
144
|
localStorage.setItem('reservationData', JSON.stringify(reservationData))
|
|
152
|
-
|
|
153
|
-
|
|
145
|
+
|
|
146
|
+
if (!_isEqual(seatMapStatuses, statusesResponse.data.attributes)) {
|
|
147
|
+
setSeatMapStatuses(statusesResponse.data.attributes)
|
|
148
|
+
}
|
|
149
|
+
if (!_isEqual(reservationData, reservedSeats)) {
|
|
150
|
+
setReservedSeats(reservationData)
|
|
151
|
+
}
|
|
152
|
+
|
|
154
153
|
// automatically set ticket/table type if it's the only one
|
|
155
|
-
if (
|
|
154
|
+
if (
|
|
155
|
+
ticketTypeTierRelationsRef.current &&
|
|
156
|
+
!_isEqual(reservationData, reservedSeats)
|
|
157
|
+
) {
|
|
156
158
|
if (!isGuestCountsSet.current) {
|
|
157
159
|
updateGuestCounts(reservationData)
|
|
158
160
|
isGuestCountsSet.current = true
|
|
@@ -164,9 +166,7 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
164
166
|
setSelectedTickets((prevState: any) => ({
|
|
165
167
|
...prevState,
|
|
166
168
|
[item.seatId]:
|
|
167
|
-
seatTicketsArray.length === 1
|
|
168
|
-
? seatTicketsArray[0].ticket_type_id
|
|
169
|
-
: '',
|
|
169
|
+
seatTicketsArray.length === 1 ? seatTicketsArray[0].ticket_type_id : '',
|
|
170
170
|
}))
|
|
171
171
|
})
|
|
172
172
|
|
|
@@ -177,26 +177,24 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
177
177
|
}
|
|
178
178
|
} catch (error) {
|
|
179
179
|
setError('Something went wrong')
|
|
180
|
-
} finally {
|
|
181
|
-
setIsLoadingStatuses(false)
|
|
182
180
|
}
|
|
183
|
-
}, [eventId])
|
|
181
|
+
}, [eventId, seatMapStatuses, reservedSeats])
|
|
184
182
|
|
|
185
|
-
const startTimer = useCallback(
|
|
186
|
-
|
|
183
|
+
const startTimer = useCallback(
|
|
184
|
+
(duration: number) => {
|
|
185
|
+
setShowTimer(true)
|
|
187
186
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}, [])
|
|
187
|
+
if (!localStorage.getItem(`reservationStart-${eventId}`)) {
|
|
188
|
+
localStorage.setItem(`reservationStart-${eventId}`, String(Date.now() + duration))
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
[eventId]
|
|
192
|
+
)
|
|
195
193
|
|
|
196
194
|
const endTimer = useCallback(() => {
|
|
197
195
|
localStorage.removeItem(`reservationStart-${eventId}`)
|
|
198
196
|
setShowTimer(false)
|
|
199
|
-
}, [])
|
|
197
|
+
}, [eventId])
|
|
200
198
|
|
|
201
199
|
const handleSeatReservation = async (
|
|
202
200
|
eventId: string,
|
|
@@ -209,9 +207,7 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
209
207
|
await fetchSeatMapReservations()
|
|
210
208
|
|
|
211
209
|
startTimer(seatMapData.seatReservationTime * 60000)
|
|
212
|
-
const reservationData = JSON.parse(
|
|
213
|
-
localStorage.getItem('reservationData') || ''
|
|
214
|
-
)
|
|
210
|
+
const reservationData = JSON.parse(localStorage.getItem('reservationData') || '')
|
|
215
211
|
setReservedSeats(reservationData)
|
|
216
212
|
updateGuestCounts(reservationData)
|
|
217
213
|
|
|
@@ -220,9 +216,11 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
220
216
|
const [firstItem] = _keys(ticketTypeTierRelationsRef.current[tierId])
|
|
221
217
|
handleTicketSelect(relations.length === 1 ? firstItem : '', seatId)
|
|
222
218
|
} catch (error) {
|
|
223
|
-
setError(
|
|
224
|
-
|
|
225
|
-
|
|
219
|
+
setError(
|
|
220
|
+
(error as any)?.response?.data?.message === 'Selected seat is not available'
|
|
221
|
+
? // eslint-disable-next-line max-len
|
|
222
|
+
'No more of this ticket type are available right now - they’re either sold out or in people’s shopping carts. Try refreshing the page!'
|
|
223
|
+
: 'Something went wrong'
|
|
226
224
|
)
|
|
227
225
|
} finally {
|
|
228
226
|
setIsReserving(false)
|
|
@@ -238,14 +236,10 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
238
236
|
try {
|
|
239
237
|
await removeSeatReserve(eventId, tierId, [seatId])
|
|
240
238
|
await fetchSeatMapReservations()
|
|
241
|
-
if (
|
|
242
|
-
_isEmpty(JSON.parse(localStorage.getItem('reservationData') as string))
|
|
243
|
-
) {
|
|
239
|
+
if (_isEmpty(JSON.parse(localStorage.getItem('reservationData') as string))) {
|
|
244
240
|
endTimer()
|
|
245
241
|
}
|
|
246
|
-
const reservationData = JSON.parse(
|
|
247
|
-
localStorage.getItem('reservationData') || ''
|
|
248
|
-
)
|
|
242
|
+
const reservationData = JSON.parse(localStorage.getItem('reservationData') || '')
|
|
249
243
|
const currentSelectedTickets = { ...selectedTickets }
|
|
250
244
|
delete currentSelectedTickets[seatId]
|
|
251
245
|
setReservedSeats(reservationData)
|
|
@@ -262,10 +256,9 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
262
256
|
seat: { tierId, seatId, status },
|
|
263
257
|
} = seatInfo
|
|
264
258
|
|
|
265
|
-
const reservationData = JSON.parse(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (status === 'B' || status === 'R' || status === 'BLOCKED' || status === 'RE') return
|
|
259
|
+
const reservationData = JSON.parse(localStorage.getItem('reservationData') || '[]')
|
|
260
|
+
if (status === 'B' || status === 'R' || status === 'BLOCKED' || status === 'RE')
|
|
261
|
+
return
|
|
269
262
|
if (_find(reservationData, data => data.seatId === seatId)) {
|
|
270
263
|
handleCancelSeatReservtion(eventId, tierId, seatId)
|
|
271
264
|
} else if (reservationData.length >= 10) {
|
|
@@ -320,19 +313,20 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
320
313
|
}
|
|
321
314
|
|
|
322
315
|
useEffect(() => {
|
|
323
|
-
if (
|
|
324
|
-
Date.now() > Number(localStorage.getItem(`reservationStart-${eventId}`))
|
|
325
|
-
) {
|
|
316
|
+
if (Date.now() > Number(localStorage.getItem(`reservationStart-${eventId}`))) {
|
|
326
317
|
setSelectedTickets({})
|
|
327
318
|
setReservedSeats([])
|
|
328
319
|
}
|
|
329
320
|
|
|
330
321
|
const makeRequests = async () => {
|
|
331
322
|
try {
|
|
323
|
+
setIsLoadingStatuses(true)
|
|
332
324
|
await fetchSeatMapData()
|
|
333
325
|
await fetchSeatMapReservations()
|
|
334
326
|
} catch (error) {
|
|
335
327
|
setError('Something went wrong')
|
|
328
|
+
} finally {
|
|
329
|
+
setIsLoadingStatuses(false)
|
|
336
330
|
}
|
|
337
331
|
}
|
|
338
332
|
|
|
@@ -341,7 +335,9 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
341
335
|
if (country) {
|
|
342
336
|
localStorage.setItem('eventCountry', country)
|
|
343
337
|
}
|
|
338
|
+
}, [country, eventId, fetchSeatMapData])
|
|
344
339
|
|
|
340
|
+
useEffect(() => {
|
|
345
341
|
const intervalId = setInterval(() => {
|
|
346
342
|
fetchSeatMapReservations()
|
|
347
343
|
}, 3000)
|
|
@@ -349,7 +345,7 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
349
345
|
return () => {
|
|
350
346
|
clearInterval(intervalId)
|
|
351
347
|
}
|
|
352
|
-
}, [
|
|
348
|
+
}, [fetchSeatMapReservations])
|
|
353
349
|
|
|
354
350
|
return (
|
|
355
351
|
<>
|
|
@@ -406,21 +402,20 @@ export const SeatMapContainer = (props: IMapContainerProps) => {
|
|
|
406
402
|
guestCounts={guestCounts}
|
|
407
403
|
setGuestCounts={setGuestCounts}
|
|
408
404
|
/>
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
)}
|
|
405
|
+
<SeatMapComponent
|
|
406
|
+
seatMapProps={{
|
|
407
|
+
seatData: seatMapData.seatMap,
|
|
408
|
+
statuses: seatMapStatuses,
|
|
409
|
+
tierPrices: seatMapData.tierPrices,
|
|
410
|
+
seatMapType: seatMapData.seatMapType,
|
|
411
|
+
ticketTypeTierRelations: ticketTypeTierRelationsRef.current,
|
|
412
|
+
seatMapEvents: { onSeatClick },
|
|
413
|
+
isReserving,
|
|
414
|
+
predefinedSeats: seatMapData.predefinedSeats,
|
|
415
|
+
isLoadingSeatMapData,
|
|
416
|
+
}}
|
|
417
|
+
mapContainerId={mapContainerId}
|
|
418
|
+
/>
|
|
424
419
|
</>
|
|
425
420
|
)
|
|
426
421
|
}
|
|
@@ -39,7 +39,7 @@ const options: StripeCardNumberElementOptions = {
|
|
|
39
39
|
export interface ICheckoutForm {
|
|
40
40
|
total: string;
|
|
41
41
|
currency: string;
|
|
42
|
-
onSubmit: (error: any) => Promise<any>;
|
|
42
|
+
onSubmit: (error: any, data?: object) => Promise<any>;
|
|
43
43
|
error?: string | null;
|
|
44
44
|
stripeCardOptions?: StripeCardNumberElementOptions;
|
|
45
45
|
stripe_client_secret: string;
|
|
@@ -49,6 +49,7 @@ export interface ICheckoutForm {
|
|
|
49
49
|
conditions: any;
|
|
50
50
|
disableZipSection: boolean;
|
|
51
51
|
paymentButtonText?: string;
|
|
52
|
+
forPaymentPlan?: boolean;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
interface AddressTypes {
|
|
@@ -67,10 +68,11 @@ const CheckoutForm = ({
|
|
|
67
68
|
currency,
|
|
68
69
|
billing_info,
|
|
69
70
|
isLoading = false,
|
|
70
|
-
handleSetLoading =
|
|
71
|
+
handleSetLoading = _identity,
|
|
71
72
|
conditions = [],
|
|
72
73
|
disableZipSection,
|
|
73
74
|
paymentButtonText,
|
|
75
|
+
forPaymentPlan = false,
|
|
74
76
|
}: ICheckoutForm) => {
|
|
75
77
|
const stripe = useStripe()
|
|
76
78
|
const elements = useElements()
|
|
@@ -109,6 +111,14 @@ const CheckoutForm = ({
|
|
|
109
111
|
address.postal_code = postalCode
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
if (forPaymentPlan) {
|
|
115
|
+
const setupResponse = await stripe.confirmCardSetup(stripe_client_secret, {
|
|
116
|
+
payment_method: { card: card || { token: '' } },
|
|
117
|
+
})
|
|
118
|
+
onSubmit(null, { paymentMethodId: setupResponse.setupIntent?.payment_method })
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
112
122
|
const paymentMethodReq = await stripe.createPaymentMethod({
|
|
113
123
|
type: 'card',
|
|
114
124
|
card: card || { token: '' },
|
|
@@ -158,9 +168,7 @@ const CheckoutForm = ({
|
|
|
158
168
|
|
|
159
169
|
useEffect(() => {
|
|
160
170
|
if (typeof window !== 'undefined') {
|
|
161
|
-
const userData = JSON.parse(
|
|
162
|
-
window.localStorage.getItem('user_data') || ''
|
|
163
|
-
)
|
|
171
|
+
const userData = JSON.parse(window.localStorage.getItem('user_data') || '')
|
|
164
172
|
const zipCode = _get(userData, 'zip', '')
|
|
165
173
|
zipCode && setPostalCode(zipCode)
|
|
166
174
|
}
|
|
@@ -185,9 +193,7 @@ const CheckoutForm = ({
|
|
|
185
193
|
|
|
186
194
|
return (
|
|
187
195
|
<div className="stripe_payment_container">
|
|
188
|
-
{!!stripeError &&
|
|
189
|
-
<div className="checkout_error_block">{stripeError}</div>
|
|
190
|
-
)}
|
|
196
|
+
{!!stripeError && <div className="checkout_error_block">{stripeError}</div>}
|
|
191
197
|
<form onSubmit={handleSubmit}>
|
|
192
198
|
<div className="card_form_inner">
|
|
193
199
|
<div className="card_number_element">
|
|
@@ -203,9 +209,7 @@ const CheckoutForm = ({
|
|
|
203
209
|
<div className="elements">
|
|
204
210
|
<div className="expiration_element">
|
|
205
211
|
<span className="card_label_text">Expiration date</span>
|
|
206
|
-
<CardExpiryElement
|
|
207
|
-
options={{ ...options, ...stripeCardOptions }}
|
|
208
|
-
/>
|
|
212
|
+
<CardExpiryElement options={{ ...options, ...stripeCardOptions }} />
|
|
209
213
|
</div>
|
|
210
214
|
<div className="cvc_element">
|
|
211
215
|
<span className="card_label_text">CVC</span>
|
|
@@ -225,10 +229,7 @@ const CheckoutForm = ({
|
|
|
225
229
|
)}
|
|
226
230
|
</div>
|
|
227
231
|
{checkboxes?.map((checkbox: any) => (
|
|
228
|
-
<div
|
|
229
|
-
className={'billing-info-container__singleField'}
|
|
230
|
-
key={checkbox.id}
|
|
231
|
-
>
|
|
232
|
+
<div className={'billing-info-container__singleField'} key={checkbox.id}>
|
|
232
233
|
<div className="conditions-block">
|
|
233
234
|
<CheckboxField
|
|
234
235
|
name={checkbox.id}
|
|
@@ -241,13 +242,13 @@ const CheckoutForm = ({
|
|
|
241
242
|
</div>
|
|
242
243
|
))}
|
|
243
244
|
<div
|
|
244
|
-
className={`payment_button ${
|
|
245
|
-
buttonIsDiabled ? 'disabled-payment-button' : ''
|
|
246
|
-
}`}
|
|
245
|
+
className={`payment_button ${buttonIsDiabled ? 'disabled-payment-button' : ''}`}
|
|
247
246
|
>
|
|
248
247
|
<button disabled={buttonIsDiabled} type="submit">
|
|
249
248
|
{isLoading ? (
|
|
250
249
|
<CircularProgress size={26} />
|
|
250
|
+
) : forPaymentPlan ? (
|
|
251
|
+
'Confirm Payment Plan'
|
|
251
252
|
) : (
|
|
252
253
|
`${
|
|
253
254
|
paymentButtonText ? paymentButtonText : 'Pay'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface IPaymentPlanConfig {
|
|
2
|
+
requires_deposit: boolean;
|
|
3
|
+
deposit: number;
|
|
4
|
+
interval: number;
|
|
5
|
+
non_refundable_type: string | null;
|
|
6
|
+
non_refundable_amount: number;
|
|
7
|
+
has_admin_fee: boolean;
|
|
8
|
+
admin_fee: number;
|
|
9
|
+
total_installments: number;
|
|
10
|
+
price_per_installment: number;
|
|
11
|
+
total: number;
|
|
12
|
+
stripe_setup_intent_secret: string;
|
|
13
|
+
saved_card: IPaymentPlanConfigCard;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface IPaymentPlanConfigCard {
|
|
17
|
+
last_4_digits: string | null;
|
|
18
|
+
stripe_payment_method_id: string | null;
|
|
19
|
+
}
|