tf-checkout-react 1.0.106 → 1.2.1

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 (77) hide show
  1. package/README.md +278 -1
  2. package/dist/api/index.d.ts +40 -28
  3. package/dist/components/account-settings/index.d.ts +3 -0
  4. package/dist/components/billing-info-container/index.d.ts +11 -8
  5. package/dist/components/common/PhoneNumberField.d.ts +9 -0
  6. package/dist/components/common/index.d.ts +1 -0
  7. package/dist/components/confirmationContainer/index.d.ts +2 -1
  8. package/dist/components/countdown/index.d.ts +2 -1
  9. package/dist/components/forgotPasswordModal/index.d.ts +11 -0
  10. package/dist/components/index.d.ts +1 -0
  11. package/dist/components/loginModal/index.d.ts +35 -2
  12. package/dist/components/myTicketsContainer/index.d.ts +2 -1
  13. package/dist/components/myTicketsContainer/tableConfig.d.ts +1 -1
  14. package/dist/components/orderDetailsContainer/index.d.ts +6 -1
  15. package/dist/components/orderDetailsContainer/ticketsTable.d.ts +2 -1
  16. package/dist/components/paymentContainer/index.d.ts +2 -1
  17. package/dist/components/resetPasswordContainer/index.d.ts +10 -0
  18. package/dist/components/signupModal/index.d.ts +14 -0
  19. package/dist/components/ticketsContainer/PromoCodeSection.d.ts +3 -2
  20. package/dist/components/ticketsContainer/TicketsSection.d.ts +1 -2
  21. package/dist/components/ticketsContainer/index.d.ts +7 -3
  22. package/dist/index.d.ts +2 -0
  23. package/dist/tf-checkout-react.cjs.development.js +2177 -1482
  24. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  25. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  26. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  27. package/dist/tf-checkout-react.esm.js +2166 -1473
  28. package/dist/tf-checkout-react.esm.js.map +1 -1
  29. package/dist/tf-checkout-styles.css +1 -1
  30. package/dist/utils/cookies.d.ts +3 -0
  31. package/dist/utils/createCheckoutDataBodyWithDefaultHolder.d.ts +6 -1
  32. package/dist/utils/downloadPDF.d.ts +1 -1
  33. package/dist/utils/getDomain.d.ts +1 -0
  34. package/dist/utils/index.d.ts +2 -0
  35. package/package.json +12 -1
  36. package/src/api/index.ts +100 -29
  37. package/src/components/account-settings/index.tsx +161 -0
  38. package/src/components/account-settings/style.css +200 -0
  39. package/src/components/billing-info-container/index.tsx +145 -99
  40. package/src/components/billing-info-container/style.css +1 -1
  41. package/src/components/billing-info-container/utils.ts +11 -3
  42. package/src/components/common/PhoneNumberField.tsx +68 -0
  43. package/src/components/common/SnackbarAlert.tsx +1 -1
  44. package/src/components/common/dist/PhoneNumberField.js +96 -0
  45. package/src/components/common/index.tsx +1 -0
  46. package/src/components/confirmationContainer/index.tsx +19 -9
  47. package/src/components/countdown/index.tsx +3 -1
  48. package/src/components/forgotPasswordModal/index.tsx +107 -0
  49. package/src/components/forgotPasswordModal/style.css +47 -0
  50. package/src/components/index.ts +1 -0
  51. package/src/components/loginModal/index.tsx +72 -71
  52. package/src/components/myTicketsContainer/index.tsx +99 -95
  53. package/src/components/myTicketsContainer/style.css +2 -2
  54. package/src/components/myTicketsContainer/tableConfig.tsx +3 -6
  55. package/src/components/orderDetailsContainer/index.tsx +80 -21
  56. package/src/components/orderDetailsContainer/style.css +7 -3
  57. package/src/components/orderDetailsContainer/ticketsTable.tsx +130 -83
  58. package/src/components/paymentContainer/index.tsx +114 -49
  59. package/src/components/registerModal/index.tsx +3 -10
  60. package/src/components/resetPasswordContainer/index.tsx +96 -0
  61. package/src/components/resetPasswordContainer/style.css +36 -0
  62. package/src/components/signupModal/index.tsx +195 -0
  63. package/src/components/signupModal/style.css +58 -0
  64. package/src/components/stripePayment/index.tsx +14 -12
  65. package/src/components/stripePayment/style.css +3 -3
  66. package/src/components/ticketResaleModal/index.tsx +12 -14
  67. package/src/components/ticketsContainer/PromoCodeSection.tsx +8 -7
  68. package/src/components/ticketsContainer/TicketRow.tsx +12 -6
  69. package/src/components/ticketsContainer/TicketsSection.tsx +0 -3
  70. package/src/components/ticketsContainer/index.tsx +155 -86
  71. package/src/env.ts +3 -3
  72. package/src/index.ts +3 -1
  73. package/src/utils/cookies.ts +42 -0
  74. package/src/utils/createCheckoutDataBodyWithDefaultHolder.ts +16 -4
  75. package/src/utils/downloadPDF.tsx +28 -6
  76. package/src/utils/getDomain.ts +15 -0
  77. package/src/utils/index.ts +2 -0
@@ -1,12 +1,15 @@
1
- import React, { Fragment } from 'react'
1
+ import Paper from '@mui/material/Paper'
2
2
  import Table from '@mui/material/Table'
3
3
  import TableBody from '@mui/material/TableBody'
4
4
  import TableCell from '@mui/material/TableCell'
5
5
  import TableContainer from '@mui/material/TableContainer'
6
6
  import TableHead from '@mui/material/TableHead'
7
7
  import TableRow from '@mui/material/TableRow'
8
- import Paper from '@mui/material/Paper'
8
+ import _identity from 'lodash/identity'
9
+ import React, { Fragment, useState } from 'react'
10
+
9
11
  import { downloadPDF } from '../../utils'
12
+ import SnackbarAlert from '../common/SnackbarAlert'
10
13
 
11
14
  interface IAddOnTypes {
12
15
  name: string;
@@ -32,99 +35,143 @@ interface TicketsTableTypes {
32
35
  tickets: ITicketTypes[];
33
36
  handleSellTicket: (ticket: ITicketTypes) => void;
34
37
  handleRemoveFromResale: (ticket: ITicketTypes) => void;
38
+
39
+ icon?: string;
35
40
  }
36
41
 
37
42
  const TicketsTable = ({
38
43
  tickets = [],
39
- handleSellTicket = () => {},
40
- handleRemoveFromResale = () => {}
41
- }: TicketsTableTypes) => (
42
- <div className="tickets-box">
43
- <h4 className="sub-title">Your Tickets</h4>
44
- <TableContainer component={Paper}>
45
- <Table aria-label="collapsible table">
46
- <TableHead>
47
- <TableRow>
48
- <TableCell>Ticket ID</TableCell>
49
- <TableCell>Ticket Type</TableCell>
50
- <TableCell>Ticket Holder Name</TableCell>
51
- <TableCell>Status</TableCell>
52
- <TableCell>Download</TableCell>
53
- <TableCell />
54
- </TableRow>
55
- </TableHead>
56
- <TableBody>
57
- {tickets.map((ticket: ITicketTypes, index: number) => (
58
- <Fragment key={index}>
59
- <TableRow>
60
- <TableCell>{ticket.hash}</TableCell>
61
- <TableCell>{ticket.ticket_type}</TableCell>
62
- <TableCell>{ticket.holder_name}</TableCell>
63
- <TableCell>{ticket.status}</TableCell>
44
+ handleSellTicket = _identity,
45
+ handleRemoveFromResale = _identity,
46
+ icon = '',
47
+ }: TicketsTableTypes) => {
48
+ const [pdfError, setPdfError] = useState<string | null>(null)
49
+ return (
50
+ <div className="tickets-box">
51
+ <SnackbarAlert
52
+ type="error"
53
+ isOpen={!!pdfError}
54
+ message={pdfError || ''}
55
+ onClose={() => setPdfError(null)}
56
+ />
57
+ <h4 className="sub-title">Your Tickets</h4>
58
+ <TableContainer component={Paper}>
59
+ <Table aria-label="collapsible table">
60
+ <TableHead>
61
+ <TableRow>
62
+ <TableCell />
63
+ <TableCell />
64
+ <TableCell />
65
+ <TableCell />
66
+ <TableCell />
67
+ <TableCell />
68
+ </TableRow>
69
+ </TableHead>
70
+ <TableBody>
71
+ {tickets.map((ticket: ITicketTypes, index: number) => (
72
+ <Fragment key={index}>
73
+ <TableRow>
74
+ <TableCell>
75
+ <div className="cell-block">
76
+ <span>Ticket ID</span>
77
+ <span>{ticket.hash}</span>
78
+ </div>
79
+ </TableCell>
64
80
  <TableCell>
65
- {
66
- ticket.status !== "Sold" && (
81
+ <div className="cell-block">
82
+ <span>Ticket Type</span>
83
+ <span>{ticket.ticket_type}</span>
84
+ </div>
85
+ </TableCell>
86
+ <TableCell>
87
+ <div className="cell-block">
88
+ <span>Ticket Holder</span>
89
+ <span>{ticket.holder_name}</span>
90
+ </div>
91
+ </TableCell>
92
+ <TableCell>
93
+ <div className="cell-block">
94
+ <span>Status</span>
95
+ <span>{ticket.status}</span>
96
+ </div>
97
+ </TableCell>
98
+ {ticket.pdf_link && ticket.status !== "Sold" ? (
99
+ <TableCell>
100
+ {Boolean(icon) && <img src={icon} alt="nodata" />}
67
101
  <span
68
102
  aria-hidden={true}
69
103
  className="action-button"
70
- onClick={() => downloadPDF(ticket.pdf_link)}
104
+ onClick={async () => {
105
+ try {
106
+ const pdfDownloadError = await downloadPDF(
107
+ ticket.pdf_link
108
+ )
109
+ if (pdfDownloadError) {
110
+ setPdfError(pdfDownloadError?.message)
111
+ }
112
+ } catch (err) {
113
+ if (err && typeof err === 'string') {
114
+ setPdfError(err)
115
+ }
116
+ }
117
+ }}
71
118
  >
72
119
  Download
73
120
  </span>
74
- )
75
- }
76
- </TableCell>
77
- <TableCell>
78
- {ticket.is_sellable && (
79
- <span
80
- aria-hidden={true}
81
- className="action-button"
82
- onClick={() => handleSellTicket(ticket)}
83
- >
84
- Sell Ticket
85
- </span>
86
- )}
87
- {ticket.is_on_sale && (
88
- <span
89
- aria-hidden={true}
90
- className="action-button"
91
- onClick={() => handleRemoveFromResale(ticket)}
92
- >
93
- Remove from Resale
94
- </span>
95
- )}
96
- </TableCell>
97
- </TableRow>
98
- {!!ticket.add_ons?.length && (
99
- <TableRow>
100
- <TableCell colSpan={6}>
101
- <Table className="ticket-add-on-table">
102
- <TableHead>
103
- <TableRow>
104
- <TableCell>Add-On</TableCell>
105
- <TableCell>Status</TableCell>
106
- </TableRow>
107
- </TableHead>
108
- <TableBody>
109
- {ticket.add_ons.map(
110
- (add_on: IAddOnTypes, index: number) => (
111
- <TableRow key={index}>
112
- <TableCell>{add_on.name}</TableCell>
113
- <TableCell>{add_on.status}</TableCell>
114
- </TableRow>
115
- )
116
- )}
117
- </TableBody>
118
- </Table>
121
+ </TableCell>
122
+ ) : null}
123
+ <TableCell>
124
+ {ticket.is_sellable && (
125
+ <span
126
+ aria-hidden={true}
127
+ className="action-button"
128
+ onClick={() => handleSellTicket(ticket)}
129
+ >
130
+ Sell Ticket
131
+ </span>
132
+ )}
133
+ {ticket.is_on_sale && (
134
+ <span
135
+ aria-hidden={true}
136
+ className="action-button"
137
+ onClick={() => handleRemoveFromResale(ticket)}
138
+ >
139
+ Remove from Resale
140
+ </span>
141
+ )}
119
142
  </TableCell>
120
143
  </TableRow>
121
- )}
122
- </Fragment>
123
- ))}
124
- </TableBody>
125
- </Table>
126
- </TableContainer>
127
- </div>
128
- )
144
+ {!!ticket.add_ons?.length && (
145
+ <TableRow>
146
+ <TableCell colSpan={6}>
147
+ <Table className="ticket-add-on-table">
148
+ <TableHead>
149
+ <TableRow>
150
+ <TableCell>Add-On</TableCell>
151
+ <TableCell>Status</TableCell>
152
+ </TableRow>
153
+ </TableHead>
154
+ <TableBody>
155
+ {ticket.add_ons.map(
156
+ (add_on: IAddOnTypes, index: number) => (
157
+ <TableRow key={index}>
158
+ <TableCell>{add_on.name}</TableCell>
159
+ <TableCell>{add_on.status}</TableCell>
160
+ </TableRow>
161
+ )
162
+ )}
163
+ </TableBody>
164
+ </Table>
165
+ </TableCell>
166
+ </TableRow>
167
+ )}
168
+ </Fragment>
169
+ ))}
170
+ </TableBody>
171
+ </Table>
172
+ </TableContainer>
173
+ </div>
174
+ )
175
+ }
129
176
 
130
177
  export default TicketsTable
@@ -20,7 +20,12 @@ import './style.css'
20
20
  import StripePayment from '../stripePayment'
21
21
  import { IOrderData, IPaymentField } from '../../types'
22
22
 
23
- import { getPaymentData, handlePaymentSuccess, getConditions, handleFreeSuccess } from '../../api'
23
+ import {
24
+ getPaymentData,
25
+ handlePaymentSuccess,
26
+ getConditions,
27
+ handleFreeSuccess,
28
+ } from '../../api'
24
29
  import { StripeCardNumberElementOptions } from '@stripe/stripe-js'
25
30
  import { ThemeProvider, createTheme } from '@mui/material/styles'
26
31
  import { ThemeOptions } from '@mui/material'
@@ -65,6 +70,7 @@ export interface IPaymentPage {
65
70
  elementsOptions?: StripeElementsOptions;
66
71
  onCountdownFinish?: () => void;
67
72
  enableTimer?: boolean;
73
+ enablePaymentPlan?: boolean;
68
74
  }
69
75
 
70
76
  const initialOrderValues: IOrderData = {
@@ -101,10 +107,12 @@ export const PaymentContainer = ({
101
107
  elementsOptions,
102
108
  onCountdownFinish = () => {},
103
109
  enableTimer = false,
110
+ enablePaymentPlan = false,
104
111
  }: IPaymentPage) => {
105
112
  const [reviewData, setReviewData] = useState(initialReviewValues)
106
113
  const [orderData, setOrderData] = useState(initialOrderValues)
107
114
  const [error, setError] = useState(null)
115
+ const [showPaymentPlanSection, setShowPaymentPlanSection] = useState(false)
108
116
  const [paymentIsLoading, setPaymentIsLoading] = useState(false)
109
117
  const [paymentDataIsLoading, setPaymentDataIsLoading] = useState(true)
110
118
  const [conditions, setConditions] = useState<{ id: string; text: string }[]>(
@@ -115,7 +123,7 @@ export const PaymentContainer = ({
115
123
  const showErrorText: boolean = Boolean(errorText)
116
124
 
117
125
  const eventId = getQueryVariable('event_id')
118
- const { hash, total } = checkoutData;
126
+ const { hash, total } = checkoutData
119
127
 
120
128
  useEffect(() => {
121
129
  (async () => {
@@ -158,10 +166,10 @@ export const PaymentContainer = ({
158
166
  setConditions(
159
167
  conditionsInfo
160
168
  ? conditionsInfo.map((item: string) => ({
161
- id: nanoid(),
162
- text: item,
163
- checked: false,
164
- }))
169
+ id: nanoid(),
170
+ text: item,
171
+ checked: false,
172
+ }))
165
173
  : []
166
174
  )
167
175
  }
@@ -180,7 +188,10 @@ export const PaymentContainer = ({
180
188
  const {
181
189
  order_details: { order_hash },
182
190
  } = reviewData
183
- const paymentSuccessResponse = total === "0.00" ? (await handleFreeSuccess(order_hash)) : (await handlePaymentSuccess(order_hash))
191
+ const paymentSuccessResponse =
192
+ total === '0.00'
193
+ ? await handleFreeSuccess(order_hash)
194
+ : await handlePaymentSuccess(order_hash)
184
195
  if (paymentSuccessResponse.status === 200) {
185
196
  handlePayment(paymentSuccessResponse)
186
197
  setPaymentIsLoading(false)
@@ -232,51 +243,105 @@ export const PaymentContainer = ({
232
243
  )
233
244
  })}
234
245
  </div>
235
- {total !== "0.00" ? <div className="payment_info">
236
- <div className="payment_info_label">
237
- Please provide your payment information
246
+ {enablePaymentPlan && <div className="payment_toggle">
247
+ <label htmlFor="togBtn" className="switch">
248
+ <input
249
+ type="checkbox"
250
+ id="togBtn"
251
+ disabled={true}
252
+ onChange={() =>
253
+ setShowPaymentPlanSection(!showPaymentPlanSection)
254
+ }
255
+ />
256
+ <div className="slider round"></div>
257
+ <span className="tog_text">
258
+ Click to checkout using Payment Plan
259
+ </span>
260
+ </label>
261
+ </div>}
262
+ {showPaymentPlanSection && (
263
+ <div className="payment_plan">
264
+ <h2>PAYMENT PLAN</h2>
265
+ <div className="plan_block">
266
+ <h3>Mbrand Payment Plan Terms</h3>
267
+ <p>
268
+ By clicking on the “Confirm Payment Plan” button, you are
269
+ starting your payment plan of 2 payments of $115.00, which
270
+ will be drawn from your account every 2 weeks, with the
271
+ first payment taken later today.
272
+ </p>
273
+ <p>
274
+ This includes a non-refundable admin fee of $3.00 per
275
+ payment.
276
+ </p>
277
+ <p className="payment_note">
278
+ NOTE: If today’s payment fails, your payment plan will not
279
+ activate, and your tickets will not be issued until you
280
+ complete your final payment.
281
+ </p>
282
+ <p>
283
+ If you do not complete your payements, your order will be
284
+ canceled. Your first payment of $115.00, plus the
285
+ non-refundable admin fee of $3.00 will not be refunded.
286
+ </p>
287
+ <p>
288
+ Your payment will proceed with the card ending in **** 4242.
289
+ </p>
290
+ </div>
291
+ </div>
292
+ )}
293
+ {total !== '0.00' ? (
294
+ <div className="payment_info">
295
+ <div className="payment_info_label">ORDER CONFIRMATION</div>
296
+ {showErrorText && (
297
+ <p className="payment_info__error">{errorText}</p>
298
+ )}
299
+ <div>
300
+ <Elements
301
+ stripe={getStripePromise(reviewData)}
302
+ options={elementsOptions}
303
+ >
304
+ <StripePayment
305
+ stripe_client_secret={_get(
306
+ reviewData,
307
+ 'payment_method.stripe_client_secret'
308
+ )}
309
+ total={orderData.total}
310
+ onSubmit={handlePaymentMiddleWare}
311
+ error={error}
312
+ currency={orderData.currency}
313
+ billing_info={reviewData.billing_info}
314
+ isLoading={paymentIsLoading}
315
+ handleSetLoading={value => setPaymentIsLoading(value)}
316
+ conditions={conditions}
317
+ stripeCardOptions={stripeCardOptions}
318
+ disableZipSection={disableZipSection}
319
+ />
320
+ </Elements>
321
+ </div>
238
322
  </div>
239
- {showErrorText && (
240
- <p className="payment_info__error">{errorText}</p>
241
- )}
242
- <div>
243
- <Elements
244
- stripe={getStripePromise(reviewData)}
245
- options={elementsOptions}
323
+ ) : (
324
+ <div
325
+ className={`payment_button ${
326
+ paymentIsLoading ? 'disabled-payment-button' : ''
327
+ }`}
328
+ >
329
+ <button
330
+ disabled={paymentIsLoading}
331
+ type="button"
332
+ onClick={() => {
333
+ setPaymentIsLoading(true)
334
+ handlePaymentMiddleWare(null)
335
+ }}
246
336
  >
247
- <StripePayment
248
- stripe_client_secret={_get(
249
- reviewData,
250
- 'payment_method.stripe_client_secret'
251
- )}
252
- total={orderData.total}
253
- onSubmit={handlePaymentMiddleWare}
254
- error={error}
255
- currency={orderData.currency}
256
- billing_info={reviewData.billing_info}
257
- isLoading={paymentIsLoading}
258
- handleSetLoading={value => setPaymentIsLoading(value)}
259
- conditions={conditions}
260
- stripeCardOptions={stripeCardOptions}
261
- disableZipSection={disableZipSection}
262
- />
263
- </Elements>
337
+ {paymentIsLoading ? (
338
+ <CircularProgress size={26} />
339
+ ) : (
340
+ 'Complete Registration'
341
+ )}
342
+ </button>
264
343
  </div>
265
- </div> :
266
- <div
267
- className={`payment_button ${paymentIsLoading ? 'disabled-payment-button' : ''}`}
268
- >
269
- <button disabled={paymentIsLoading} type="button" onClick={() => {
270
- setPaymentIsLoading(true)
271
- handlePaymentMiddleWare(null)
272
- }}>
273
- {paymentIsLoading ? (
274
- <CircularProgress size={26} />
275
- ) : (
276
- "Complete Registration"
277
- )}
278
- </button>
279
- </div>}
344
+ )}
280
345
  </Container>
281
346
  )}
282
347
  </div>
@@ -1,7 +1,7 @@
1
1
  import React, { FC } from 'react'
2
2
  import { AxiosError } from 'axios'
3
3
  import './style.css'
4
- import { getProfileData, handleSetAccessToken, register } from '../../api'
4
+ import { getProfileData, register } from '../../api'
5
5
  import { Field, Form, Formik } from 'formik'
6
6
  import { requiredValidator } from '../../validators'
7
7
  import { TextField } from '@mui/material'
@@ -64,17 +64,11 @@ export const RegisterModal: FC<Props> = ({
64
64
  CONFIGS.CLIENT_SECRET ||
65
65
  'b89c191eff22fdcf84ac9bfd88d005355a151ec2c83b26b9'
66
66
  )
67
- const resRegister = await register(bodyFormData)
68
- const access_token = _get(
69
- resRegister,
70
- 'data.data.attributes.access_token'
71
- )
72
- handleSetAccessToken(access_token)
73
-
67
+ await register(bodyFormData)
74
68
  let profileResponse = null
75
69
 
76
70
  try {
77
- profileResponse = await getProfileData(access_token)
71
+ profileResponse = await getProfileData()
78
72
  onGetProfileDataSuccess(profileResponse.data)
79
73
  } catch (e) {
80
74
  onGetProfileDataError(e.response)
@@ -89,7 +83,6 @@ export const RegisterModal: FC<Props> = ({
89
83
  email: profileSpecifiedData.email,
90
84
  }
91
85
  if (typeof window !== 'undefined') {
92
- window.localStorage.setItem('access_token', access_token)
93
86
  window.localStorage.setItem(
94
87
  'user_data',
95
88
  JSON.stringify(profileDataObj)
@@ -0,0 +1,96 @@
1
+ import React, { FC, useState } from 'react'
2
+ import { Field, Form, Formik } from 'formik'
3
+ import { CircularProgress } from '@mui/material'
4
+ import { CustomField } from '../common/CustomField'
5
+ import axios, { AxiosError } from 'axios'
6
+ import * as Yup from 'yup'
7
+ import { resetPassword } from '../../api'
8
+ import './style.css'
9
+
10
+ interface IResetPasswordProps {
11
+ token?: string
12
+ onResetPasswordSuccess?: (res: any) => void
13
+ onResetPasswordError?: (e: AxiosError) => void
14
+ }
15
+
16
+ const Schema = Yup.object().shape({
17
+ password: Yup.string()
18
+ .min(6, 'Password must have 5+ characters')
19
+ .required('Required'),
20
+ password_confirmation: Yup.string()
21
+ .required('Required')
22
+ .oneOf([Yup.ref('password'), null], 'Passwords must match'),
23
+ })
24
+
25
+ export const ResetPasswordContainer: FC<IResetPasswordProps> = ({
26
+ token: tokenProps = '',
27
+ onResetPasswordSuccess = () => {},
28
+ onResetPasswordError = () => {},
29
+ }) => {
30
+ const [loading, setLoading] = useState(false)
31
+ return (
32
+ <div className="reset-password">
33
+ <div className="title">Change Password</div>
34
+ <Formik
35
+ initialValues={{ password: '', password_confirmation: '' }}
36
+ validationSchema={Schema}
37
+ onSubmit={async (values: any) => {
38
+ try {
39
+ setLoading(true)
40
+ let token
41
+ if (tokenProps) {
42
+ token = tokenProps
43
+ } else {
44
+ if (typeof window !== 'undefined') {
45
+ const params: URLSearchParams = new URL(`${window.location}`)
46
+ .searchParams
47
+ token = params.get('token')
48
+ }
49
+ }
50
+
51
+ const payload = {
52
+ token,
53
+ ...values,
54
+ }
55
+ const res = await resetPassword(payload)
56
+ onResetPasswordSuccess(res)
57
+ } catch (e) {
58
+ if (axios.isAxiosError(e)) {
59
+ onResetPasswordError(e)
60
+ }
61
+ } finally {
62
+ setLoading(false)
63
+ }
64
+ }}
65
+ >
66
+ {({ isValid, dirty }) => (
67
+ <Form>
68
+ <div className="body">
69
+ <div className="field-item">
70
+ <Field
71
+ name="password"
72
+ label="New Password"
73
+ type="password"
74
+ component={CustomField}
75
+ />
76
+ </div>
77
+ <div className="field-item">
78
+ <Field
79
+ name="password_confirmation"
80
+ label="Confirm Password"
81
+ type="password"
82
+ component={CustomField}
83
+ />
84
+ </div>
85
+ </div>
86
+ <div className="action-button">
87
+ <button type="submit" disabled={!(isValid && dirty)}>
88
+ {loading ? <CircularProgress size="22px" /> : 'Submit'}
89
+ </button>
90
+ </div>
91
+ </Form>
92
+ )}
93
+ </Formik>
94
+ </div>
95
+ )
96
+ }
@@ -0,0 +1,36 @@
1
+ .reset-password {
2
+ padding: 14px;
3
+ max-width: 300px;
4
+ margin: 0 auto;
5
+ }
6
+ .reset-password .title {
7
+ font-size: 20px;
8
+ font-weight: bold;
9
+ }
10
+ .reset-password .field-item {
11
+ margin-top: 14px;
12
+ }
13
+ .reset-password .action-button button {
14
+ padding: 10px;
15
+ width: 100%;
16
+ margin-top: 14px;
17
+ border: none;
18
+ border-radius: 0;
19
+ height: 45px;
20
+ font-weight: 600;
21
+ font-size: 26px;
22
+ line-height: 18px;
23
+ color: white;
24
+ cursor: pointer;
25
+ outline: none;
26
+ background-color: #212529;
27
+ text-transform: uppercase;
28
+ }
29
+ .reset-password .action-button button:hover:enabled {
30
+ background-color: #505050;
31
+ border-color: #505050;
32
+ }
33
+ .reset-password .action-button button[disabled] {
34
+ opacity: .7;
35
+ cursor: unset;
36
+ }