tf-checkout-react 1.0.47 → 1.0.51

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 (33) hide show
  1. package/dist/components/billing-info-container/index.d.ts +1 -1
  2. package/dist/components/billing-info-container/utils.d.ts +6 -0
  3. package/dist/components/common/CheckboxField.d.ts +2 -2
  4. package/dist/components/common/CustomField.d.ts +2 -1
  5. package/dist/components/common/SelectField.d.ts +20 -0
  6. package/dist/components/paymentContainer/index.d.ts +1 -1
  7. package/dist/components/stripePayment/index.d.ts +2 -1
  8. package/dist/tf-checkout-react.cjs.development.css +2 -2
  9. package/dist/tf-checkout-react.cjs.development.js +427 -264
  10. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  11. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  12. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  13. package/dist/tf-checkout-react.esm.js +434 -271
  14. package/dist/tf-checkout-react.esm.js.map +1 -1
  15. package/dist/types/billing-info-data.d.ts +3 -0
  16. package/dist/utils/formikErrorFocus.d.ts +2 -0
  17. package/dist/utils/getQueryVariable.d.ts +1 -0
  18. package/package.json +1 -1
  19. package/src/.DS_Store +0 -0
  20. package/src/components/.DS_Store +0 -0
  21. package/src/components/billing-info-container/index.tsx +124 -133
  22. package/src/components/billing-info-container/style.css +4 -0
  23. package/src/components/billing-info-container/utils.ts +44 -0
  24. package/src/components/common/CheckboxField.tsx +7 -2
  25. package/src/components/common/CustomField.tsx +21 -8
  26. package/src/components/common/SelectField.tsx +89 -0
  27. package/src/components/paymentContainer/index.tsx +31 -3
  28. package/src/components/stripePayment/index.tsx +48 -19
  29. package/src/components/stripePayment/style.css +10 -0
  30. package/src/components/waitingList/index.tsx +36 -25
  31. package/src/types/billing-info-data.ts +3 -0
  32. package/src/utils/formikErrorFocus.ts +24 -0
  33. package/src/utils/getQueryVariable.ts +13 -0
@@ -0,0 +1,89 @@
1
+ import React from 'react'
2
+ import Select from '@mui/material/Select'
3
+ import _map from 'lodash/map'
4
+ import _get from 'lodash/get'
5
+
6
+ import { FieldInputProps, FormikProps } from 'formik'
7
+ import { makeStyles } from '@mui/styles'
8
+ import { FormControl, InputLabel, FormHelperText } from '@mui/material'
9
+
10
+ export interface ISelectOption {
11
+ label: string | number;
12
+ value?: string | number;
13
+ [key: string]: any;
14
+ }
15
+
16
+ export interface ISelectField {
17
+ label: string;
18
+
19
+ field: FieldInputProps<any>;
20
+ form: FormikProps<any>;
21
+ theme: 'dark' | 'light';
22
+
23
+ // optional
24
+ type?: string;
25
+ selectOptions?: ISelectOption[];
26
+ }
27
+
28
+ interface IOtherProps {
29
+ [key: string]: any;
30
+ }
31
+
32
+ const useStyles = makeStyles({
33
+ input: {
34
+ '&::placeholder': {
35
+ color: 'gray',
36
+ },
37
+ },
38
+ })
39
+
40
+ export const SelectField = ({
41
+ label,
42
+ type = 'text',
43
+ field,
44
+ selectOptions = [] as ISelectOption[],
45
+ form: { touched, errors },
46
+ theme,
47
+ }: ISelectField & IOtherProps) => {
48
+ const isTouched = Boolean(_get(touched, field.name))
49
+ const error = _get(errors, field.name)
50
+ const classes = useStyles()
51
+
52
+ return (
53
+ <FormControl fullWidth={true}>
54
+ <InputLabel htmlFor={field.name} error={!!error && isTouched}>
55
+ {label}
56
+ </InputLabel>
57
+ <Select
58
+ id={field.name}
59
+ label={label}
60
+ type={type}
61
+ fullWidth={true}
62
+ error={!!error && isTouched}
63
+ inputProps={{
64
+ id: field.name,
65
+ classes: {
66
+ input: classes.input,
67
+ },
68
+ }}
69
+ native={true}
70
+ className={theme}
71
+ MenuProps={{ className: theme }}
72
+ {...field}
73
+ >
74
+ {_map(selectOptions, option => (
75
+ <option
76
+ key={option.value}
77
+ value={option.value}
78
+ disabled={option.disabled}
79
+ >
80
+ {option.label}
81
+ </option>
82
+ ))}
83
+ </Select>
84
+ {isTouched && error ? (
85
+ <FormHelperText error={!!error && isTouched}>{error}</FormHelperText>
86
+ ) : null}
87
+ </FormControl>
88
+ )
89
+ }
@@ -8,12 +8,14 @@ import _map from 'lodash/map'
8
8
  import _get from 'lodash/get'
9
9
  import _identity from 'lodash/identity'
10
10
  import { ENV } from '../../env'
11
+ import { nanoid } from 'nanoid'
12
+ import { getQueryVariable } from '../../utils/getQueryVariable'
11
13
 
12
14
  import './style.css'
13
15
  import StripePayment from '../stripePayment'
14
16
  import { IOrderData, IPaymentField } from '../../types'
15
17
 
16
- import { getPaymentData, handlePaymentSuccess } from '../../api'
18
+ import { getPaymentData, handlePaymentSuccess, getConditions } from '../../api'
17
19
 
18
20
  const testId = ENV.STRIPE_PUBLISHABLE_KEY || 'pk_test_3Ov1P1oP33A1cxaSjxWE0VjT'
19
21
  const stripePromise = loadStripe(
@@ -47,7 +49,7 @@ const initialReviewValues = {
47
49
  payment_method: {
48
50
  stripe_client_secret: '',
49
51
  },
50
- billing_info: {}
52
+ billing_info: {},
51
53
  }
52
54
 
53
55
  export const PaymentContainer = ({
@@ -59,16 +61,21 @@ export const PaymentContainer = ({
59
61
  onErrorClose = _identity,
60
62
  onGetPaymentDataSuccess = () => {},
61
63
  onGetPaymentDataError = () => {},
62
- onPaymentError = () => {}
64
+ onPaymentError = () => {},
63
65
  }: IPaymentPage) => {
64
66
  const [reviewData, setReviewData] = useState(initialReviewValues)
65
67
  const [orderData, setOrderData] = useState(initialOrderValues)
66
68
  const [error, setError] = useState(null)
67
69
  const [paymentIsLoading, setPaymentIsLoading] = useState(false)
70
+ const [conditions, setConditions] = useState<{ id: string; text: string }[]>(
71
+ []
72
+ )
68
73
 
69
74
  const showFormTitle: boolean = Boolean(formTitle)
70
75
  const showErrorText: boolean = Boolean(errorText)
71
76
 
77
+ const eventId = getQueryVariable('event_id')
78
+
72
79
  useEffect(() => {
73
80
  const { hash } = checkoutData;
74
81
  (async () => {
@@ -99,6 +106,26 @@ export const PaymentContainer = ({
99
106
  })()
100
107
  }, [checkoutData])
101
108
 
109
+ //just once
110
+ useEffect(() => {
111
+ // fetch conditions data
112
+ const fetchConditions = async () => {
113
+ if (eventId) {
114
+ const res = await getConditions(eventId)
115
+ const conditionsInfo = _get(res, 'data.data.attributes')
116
+ setConditions(
117
+ conditionsInfo
118
+ ? conditionsInfo.map((item: string) => ({
119
+ id: nanoid(),
120
+ text: item,
121
+ }))
122
+ : []
123
+ )
124
+ }
125
+ }
126
+ fetchConditions()
127
+ }, [])
128
+
102
129
  // 1. get payment data ---> v1/order/${hash}/review/ done
103
130
  // 2. handle payment ---> v1/order/${orderHash}/pay/
104
131
  // 3. redirect to confirmation page
@@ -163,6 +190,7 @@ export const PaymentContainer = ({
163
190
  billing_info={reviewData.billing_info}
164
191
  isLoading={paymentIsLoading}
165
192
  handleSetLoading={value => setPaymentIsLoading(value)}
193
+ conditions={conditions}
166
194
  />
167
195
  </Elements>
168
196
  </div>
@@ -9,6 +9,7 @@ import {
9
9
  import { StripeCardNumberElementOptions } from '@stripe/stripe-js'
10
10
  import _identity from 'lodash/identity'
11
11
  import _get from 'lodash/get'
12
+ import { CheckboxField } from '../common/CheckboxField'
12
13
 
13
14
  import './style.css'
14
15
  import { getCurrencySymbolByCurrency } from '../../normalizers'
@@ -17,6 +18,7 @@ import CircularProgress from '@mui/material/CircularProgress'
17
18
  const options: StripeCardNumberElementOptions = {
18
19
  style: {
19
20
  base: {
21
+ backgroundColor:'#232323',
20
22
  fontSize: '18px',
21
23
  color: '#ffffff',
22
24
  letterSpacing: '1px',
@@ -42,13 +44,14 @@ export interface ICheckoutForm {
42
44
  billing_info: { [key: string]: any };
43
45
  isLoading: any;
44
46
  handleSetLoading: (loading: any) => void;
47
+ conditions: any;
45
48
  }
46
49
 
47
50
  interface AddressTypes {
48
- city: string,
49
- line1: string,
50
- state: string,
51
- postal_code: string,
51
+ city: string;
52
+ line1: string;
53
+ state: string;
54
+ postal_code: string;
52
55
  }
53
56
 
54
57
  const CheckoutForm = ({
@@ -60,7 +63,8 @@ const CheckoutForm = ({
60
63
  currency,
61
64
  billing_info,
62
65
  isLoading = false,
63
- handleSetLoading = () => {}
66
+ handleSetLoading = () => {},
67
+ conditions = [],
64
68
  }: ICheckoutForm) => {
65
69
  const stripe = useStripe()
66
70
  const elements = useElements()
@@ -71,9 +75,9 @@ const CheckoutForm = ({
71
75
  handleSetLoading(true)
72
76
  try {
73
77
  event.preventDefault()
74
-
75
- if(!postalCode) {
76
- setStripeError("Please enter your zip code.")
78
+
79
+ if (!postalCode) {
80
+ setStripeError('Please enter your zip code.')
77
81
  handleSetLoading(false)
78
82
  return
79
83
  }
@@ -84,7 +88,7 @@ const CheckoutForm = ({
84
88
  handleSetLoading(false)
85
89
  return
86
90
  }
87
-
91
+
88
92
  const card = elements.getElement(CardNumberElement)
89
93
  const address: AddressTypes = {
90
94
  city: billing_info.city,
@@ -100,7 +104,7 @@ const CheckoutForm = ({
100
104
  address,
101
105
  },
102
106
  })
103
-
107
+
104
108
  if (paymentMethodReq.error) {
105
109
  setStripeError(paymentMethodReq.error.message || null)
106
110
  handleSetLoading(false)
@@ -108,7 +112,7 @@ const CheckoutForm = ({
108
112
  }
109
113
 
110
114
  const { error } = await stripe.confirmCardPayment(stripe_client_secret, {
111
- payment_method: paymentMethodReq.paymentMethod.id
115
+ payment_method: paymentMethodReq.paymentMethod.id,
112
116
  })
113
117
 
114
118
  if (error) {
@@ -116,26 +120,29 @@ const CheckoutForm = ({
116
120
  handleSetLoading(false)
117
121
  return
118
122
  }
119
-
120
- onSubmit(null)
121
123
 
122
- } catch(e) {
124
+ onSubmit(null)
125
+ } catch (e) {
123
126
  onSubmit(e)
124
127
  }
125
128
  }
126
129
 
127
130
  const onChangePostalCode = (e: any) => {
128
131
  setPostalCode(e.target.value)
129
- }
132
+ }
130
133
 
131
134
  useEffect(() => {
132
135
  if (typeof window !== 'undefined') {
133
- const userData = JSON.parse(window.localStorage.getItem('user_data') || '')
136
+ const userData = JSON.parse(
137
+ window.localStorage.getItem('user_data') || ''
138
+ )
134
139
  const zipCode = _get(userData, 'zip', '')
135
140
  zipCode && setPostalCode(zipCode)
136
141
  }
137
142
  }, [])
138
143
 
144
+ const buttonIsDiabled = !stripe || !!error || isLoading
145
+
139
146
  return (
140
147
  <div className="stripe_payment_container">
141
148
  {!!stripeError && (
@@ -171,9 +178,31 @@ const CheckoutForm = ({
171
178
  />
172
179
  </label>
173
180
  </div>
174
- <div className="payment_button">
175
- <button disabled={!stripe || !!error || isLoading} type="submit">
176
- {isLoading ? <CircularProgress /> : `Pay ${getCurrencySymbolByCurrency(currency)}${total}`}
181
+ {conditions?.map((checkbox: any) => (
182
+ <div
183
+ className={'billing-info-container__singleField'}
184
+ key={checkbox.id}
185
+ >
186
+ <div className="conditions-block">
187
+ <CheckboxField
188
+ name={checkbox.id}
189
+ label={checkbox.text}
190
+ required={true}
191
+ />
192
+ </div>
193
+ </div>
194
+ ))}
195
+ <div
196
+ className={`payment_button ${
197
+ buttonIsDiabled ? 'disabled-payment-button' : ''
198
+ }`}
199
+ >
200
+ <button disabled={buttonIsDiabled} type="submit">
201
+ {isLoading ? (
202
+ <CircularProgress />
203
+ ) : (
204
+ `Pay ${getCurrencySymbolByCurrency(currency)}${total}`
205
+ )}
177
206
  </button>
178
207
  </div>
179
208
  </form>
@@ -2,6 +2,10 @@
2
2
  background: #232323;
3
3
  border-radius: 8px;
4
4
  padding: 15px;
5
+ width: 50%;
6
+ margin: 0 auto;
7
+ min-width: 325px;
8
+ margin-bottom: 20px;
5
9
  }
6
10
  .card_form_inner .card_label_text {
7
11
  color: #fff;
@@ -30,6 +34,12 @@
30
34
  opacity: 0.7;
31
35
  }
32
36
 
37
+ .disabled-payment-button button{
38
+ user-select: none;
39
+ pointer-events:none;
40
+ opacity: 0.3;
41
+ }
42
+
33
43
  .checkout_error_block {
34
44
  color: #e53935;
35
45
  padding: 15px 0;
@@ -10,6 +10,7 @@ import {
10
10
  emailValidator,
11
11
  } from '../../validators'
12
12
  import { ENV } from '../../env'
13
+ import { ErrorFocus } from '../../utils/formikErrorFocus'
13
14
 
14
15
  import './style.css'
15
16
 
@@ -41,6 +42,8 @@ const WaitingList = ({ tickets = {} }: WaitingListProps) => {
41
42
  value: d.id,
42
43
  }))
43
44
 
45
+ const showTicketsField = Boolean(ticketTypesList.length)
46
+
44
47
  const handleSubmit = async (values: WaitingListFields) => {
45
48
  try {
46
49
  setLoading(true)
@@ -56,7 +59,6 @@ const WaitingList = ({ tickets = {} }: WaitingListProps) => {
56
59
  setShowSuccessMessage(true)
57
60
  }
58
61
  } catch (error) {
59
- console.log(error)
60
62
  } finally {
61
63
  setLoading(false)
62
64
  }
@@ -83,30 +85,39 @@ const WaitingList = ({ tickets = {} }: WaitingListProps) => {
83
85
  onSubmit={handleSubmit}
84
86
  >
85
87
  <Form>
86
- <div className="field-item">
87
- <Field
88
- name="ticketTypeId"
89
- label="Ticket types"
90
- type="select"
91
- component={CustomField}
92
- selectOptions={[
93
- { label: 'Type of Ticket', value: '', disabled: true },
94
- ...ticketTypesList,
95
- ]}
96
- />
97
- </div>
98
- <div className="field-item">
99
- <Field
100
- name="quantity"
101
- label="Quantity"
102
- type="select"
103
- component={CustomField}
104
- selectOptions={[
105
- { label: 'Quantity Requested', value: '', disabled: true },
106
- ...generateQuantity(10),
107
- ]}
108
- />
109
- </div>
88
+ <ErrorFocus />
89
+ {showTicketsField && (
90
+ <>
91
+ <div className="field-item">
92
+ <Field
93
+ name="ticketTypeId"
94
+ label="Ticket types"
95
+ type="select"
96
+ component={CustomField}
97
+ selectOptions={[
98
+ { label: 'Type of Ticket', value: '', disabled: true },
99
+ ...ticketTypesList,
100
+ ]}
101
+ />
102
+ </div>
103
+ <div className="field-item">
104
+ <Field
105
+ name="quantity"
106
+ label="Quantity"
107
+ type="select"
108
+ component={CustomField}
109
+ selectOptions={[
110
+ {
111
+ label: 'Quantity Requested',
112
+ value: '',
113
+ disabled: true,
114
+ },
115
+ ...generateQuantity(10),
116
+ ]}
117
+ />
118
+ </div>
119
+ </>
120
+ )}
110
121
  <div className="field-item">
111
122
  <Field
112
123
  name="firstName"
@@ -10,6 +10,7 @@ export interface IGroupItem {
10
10
  required?: boolean;
11
11
  component?: ReactNode | JSX.Element | HTMLElement;
12
12
  onValidate?: (value: any) => void;
13
+ uniqueId?: string;
13
14
 
14
15
  // aditional props
15
16
  [key: string]: any;
@@ -23,6 +24,7 @@ export interface IFieldData {
23
24
  groupLabel?: string | JSX.Element | HTMLElement;
24
25
  groupLabelClassName?: string;
25
26
  id: number;
27
+ uniqueId?: string;
26
28
  }
27
29
  export interface IBillingInfoData {
28
30
  id: number | string;
@@ -31,4 +33,5 @@ export interface IBillingInfoData {
31
33
  // optional
32
34
  label?: string | JSX.Element;
33
35
  labelClassName?: string;
36
+ uniqueId?: string;
34
37
  }
@@ -0,0 +1,24 @@
1
+ import { connect, FormikContextType } from 'formik'
2
+ import { Component } from 'react'
3
+
4
+ interface IProps {
5
+ formik: FormikContextType<any>;
6
+ }
7
+
8
+ class ErrorFocusInternal extends Component<IProps> {
9
+ public componentDidUpdate(prevProps: IProps) {
10
+ const { isSubmitting, isValidating, errors } = prevProps.formik
11
+ const keys = Object.keys(errors)
12
+ if (keys.length > 0 && isSubmitting && !isValidating) {
13
+ const selector = `[name="${keys[0]}"]`
14
+ const errorElement = document.querySelector(selector) as HTMLElement
15
+ if (errorElement) {
16
+ errorElement.focus()
17
+ }
18
+ }
19
+ }
20
+
21
+ public render = () => null;
22
+ }
23
+
24
+ export const ErrorFocus = connect<{}>(ErrorFocusInternal)
@@ -0,0 +1,13 @@
1
+ export const getQueryVariable = (variable: string) => {
2
+ if (typeof window !== 'undefined') {
3
+ const query = window.location.search.substring(1)
4
+ const vars = query.split('&')
5
+ for (let i = 0; i < vars.length; i++) {
6
+ const pair = vars[i].split('=')
7
+ if (pair[0] === variable) {
8
+ return pair[1]
9
+ }
10
+ }
11
+ }
12
+ return false
13
+ }