@huma-finance/widgets 0.0.59-beta.494 → 0.0.59-beta.511

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 (31) hide show
  1. package/API.md +2 -0
  2. package/dist/cjs/index.cjs +967 -191
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/index.d.ts +8 -0
  5. package/dist/index.js +968 -193
  6. package/dist/index.js.map +1 -1
  7. package/package.json +6 -4
  8. package/src/components/ChooseAmountModal.tsx +2 -3
  9. package/src/components/ConfirmTransferModal.tsx +1 -1
  10. package/src/components/ErrorModal.tsx +1 -1
  11. package/src/components/InputAmountModal.tsx +2 -2
  12. package/src/components/Lend/supplyV2/2-Evaluation.tsx +31 -329
  13. package/src/components/Lend/supplyV2/3-ChooseAmount.tsx +58 -9
  14. package/src/components/Lend/supplyV2/6-Success.tsx +49 -6
  15. package/src/components/Lend/supplyV2/7-Notifications.tsx +22 -3
  16. package/src/components/Lend/supplyV2/8-PointsEarned.tsx +231 -0
  17. package/src/components/Lend/supplyV2/components/PersonaEvaluation.tsx +442 -0
  18. package/src/components/Lend/supplyV2/components/SecuritizeEvaluation.tsx +345 -0
  19. package/src/components/Lend/supplyV2/index.tsx +67 -5
  20. package/src/components/Lend/withdrawV2/1-ConfirmTransfer.tsx +1 -1
  21. package/src/components/SignIn.tsx +7 -2
  22. package/src/components/TxDoneModal.tsx +21 -2
  23. package/src/components/humaModal/HumaModal.tsx +1 -0
  24. package/src/components/humaModal/HumaModalHeader.tsx +1 -0
  25. package/src/components/icons/congratulations.svg +54 -0
  26. package/src/components/icons/huma-points.svg +15 -0
  27. package/src/components/icons/index.tsx +15 -0
  28. package/src/components/icons/ribbon.svg +9 -0
  29. package/src/store/widgets.reducers.ts +0 -1
  30. package/src/store/widgets.store.ts +1 -0
  31. package/src/theme/palette.ts +1 -1
@@ -1,10 +1,29 @@
1
- import React from 'react'
1
+ import React, { useCallback } from 'react'
2
+ import { useDispatch } from 'react-redux'
3
+
4
+ import { Campaign } from '.'
2
5
  import { NotifiSubscriptionModal } from '../../Notifi/NotifiSubscriptionModal'
6
+ import { setStep } from '../../../store/widgets.reducers'
7
+ import { WIDGET_STEP } from '../../../store/widgets.store'
3
8
 
4
9
  type Props = {
10
+ campaign?: Campaign
5
11
  handleAction: () => void
6
12
  }
7
13
 
8
- export function Notifications({ handleAction }: Props): React.ReactElement {
9
- return <NotifiSubscriptionModal handleSuccess={handleAction} />
14
+ export function Notifications({
15
+ campaign,
16
+ handleAction,
17
+ }: Props): React.ReactElement {
18
+ const dispatch = useDispatch()
19
+
20
+ const handleUserAction = useCallback(() => {
21
+ if (campaign) {
22
+ dispatch(setStep(WIDGET_STEP.PointsEarned))
23
+ } else {
24
+ handleAction()
25
+ }
26
+ }, [campaign, dispatch, handleAction])
27
+
28
+ return <NotifiSubscriptionModal handleSuccess={handleUserAction} />
10
29
  }
@@ -0,0 +1,231 @@
1
+ import {
2
+ CampaignService,
3
+ checkIsDev,
4
+ formatNumber,
5
+ useAuthErrorHandling,
6
+ } from '@huma-finance/shared'
7
+ import { Box, css, useTheme } from '@mui/material'
8
+ import { useWeb3React } from '@web3-react/core'
9
+ import React, { useEffect, useState } from 'react'
10
+ import { useDispatch } from 'react-redux'
11
+
12
+ import { setError } from '../../../store/widgets.reducers'
13
+ import { BottomButton } from '../../BottomButton'
14
+ import { CongratulationsIcon, HumaPointsIcon, RibbonIcon } from '../../icons'
15
+ import { LoadingModal } from '../../LoadingModal'
16
+ import { SignIn } from '../../SignIn'
17
+
18
+ enum STATE {
19
+ Loading = 'Loading',
20
+ SignIn = 'SignIn',
21
+ Congrats = 'Congrats',
22
+ }
23
+
24
+ const ERROR_MESSAGE =
25
+ 'Failed to update wallet points. Be assured that your points will be added later.'
26
+
27
+ type Props = {
28
+ transactionHash: string
29
+ lpConfig: { withdrawalLockoutPeriodInDays: number }
30
+ pointsTestnetExperience: boolean
31
+ handleAction: () => void
32
+ }
33
+
34
+ export function PointsEarned({
35
+ transactionHash,
36
+ lpConfig,
37
+ pointsTestnetExperience,
38
+ handleAction,
39
+ }: Props): React.ReactElement {
40
+ const theme = useTheme()
41
+ const isDev = checkIsDev()
42
+ const dispatch = useDispatch()
43
+ const { account, chainId } = useWeb3React()
44
+ const [pointsAccumulated, setPointsAccumulated] = useState<
45
+ number | undefined
46
+ >()
47
+ const lockupMonths = Math.round(lpConfig.withdrawalLockoutPeriodInDays / 30)
48
+ const monthText =
49
+ lockupMonths > 1 ? `${lockupMonths} months` : `${lockupMonths} month`
50
+
51
+ const {
52
+ errorType,
53
+ setError: setAuthError,
54
+ isWalletOwnershipVerified,
55
+ isWalletOwnershipVerificationRequired,
56
+ } = useAuthErrorHandling(isDev)
57
+ const [walletOwnership, setWalletOwnership] = useState<boolean | undefined>()
58
+ const [state, setState] = useState<STATE>(STATE.Loading)
59
+
60
+ useEffect(() => {
61
+ if (isWalletOwnershipVerificationRequired) {
62
+ setState(STATE.Loading)
63
+ }
64
+ }, [isWalletOwnershipVerificationRequired])
65
+
66
+ useEffect(() => {
67
+ if (isWalletOwnershipVerified) {
68
+ setWalletOwnership(true)
69
+ }
70
+ }, [isWalletOwnershipVerified])
71
+
72
+ useEffect(() => {
73
+ const checkWalletOwnership = async () => {
74
+ const ownership = await CampaignService.checkWalletOwnership(
75
+ account!,
76
+ isDev,
77
+ pointsTestnetExperience,
78
+ )
79
+ setWalletOwnership(ownership)
80
+ if (!ownership) {
81
+ setAuthError('WalletNotSignInException')
82
+ }
83
+ }
84
+ checkWalletOwnership()
85
+ }, [account, isDev, pointsTestnetExperience, setAuthError])
86
+
87
+ useEffect(() => {
88
+ if (errorType === 'NotSignedIn') {
89
+ setState(STATE.SignIn)
90
+ } else if (errorType === 'UserRejected') {
91
+ dispatch(
92
+ setError({
93
+ errorMessage: 'User has rejected the transaction.',
94
+ }),
95
+ )
96
+ } else if (errorType === 'Other') {
97
+ dispatch(
98
+ setError({
99
+ errorMessage: ERROR_MESSAGE,
100
+ }),
101
+ )
102
+ }
103
+ }, [dispatch, errorType])
104
+
105
+ useEffect(() => {
106
+ const updateWalletPoints = async () => {
107
+ if (walletOwnership) {
108
+ try {
109
+ const result = await CampaignService.updateWalletPoints(
110
+ account!,
111
+ transactionHash,
112
+ chainId!,
113
+ isDev,
114
+ pointsTestnetExperience,
115
+ )
116
+ if (!result.pointsAccumulated) {
117
+ dispatch(
118
+ setError({
119
+ errorMessage: ERROR_MESSAGE,
120
+ }),
121
+ )
122
+ }
123
+ setPointsAccumulated(result.pointsAccumulated)
124
+ setState(STATE.Congrats)
125
+ } catch (error) {
126
+ dispatch(
127
+ setError({
128
+ errorMessage: ERROR_MESSAGE,
129
+ }),
130
+ )
131
+ }
132
+ }
133
+ }
134
+ updateWalletPoints()
135
+ }, [
136
+ account,
137
+ chainId,
138
+ dispatch,
139
+ isDev,
140
+ pointsTestnetExperience,
141
+ transactionHash,
142
+ walletOwnership,
143
+ ])
144
+
145
+ const styles = {
146
+ wrapper: css`
147
+ height: 518px;
148
+ position: relative;
149
+ `,
150
+ congrats: css`
151
+ margin: ${theme.spacing(-4, -4.5, 0, -4.5)};
152
+ `,
153
+ ribbon: css`
154
+ position: relative;
155
+ ${theme.cssMixins.rowHCentered};
156
+ font-weight: 700;
157
+ margin-top: ${theme.spacing(-8)};
158
+ color: ${theme.palette.text.primary};
159
+ font-size: 20px;
160
+ line-height: 160%;
161
+ letter-spacing: 0.15px;
162
+ `,
163
+ ribbonContent: css`
164
+ ${theme.cssMixins.rowVCentered};
165
+ position: absolute;
166
+ top: ${theme.spacing(1)};
167
+
168
+ svg {
169
+ margin-right: ${theme.spacing(1)};
170
+ }
171
+ `,
172
+ entirePoints: css`
173
+ color: ${theme.palette.text.tertiary};
174
+ text-align: center;
175
+ font-weight: 700;
176
+ font-size: 20px;
177
+ line-height: 160%;
178
+ letter-spacing: 0.15px;
179
+ margin-top: ${theme.spacing(7)};
180
+ `,
181
+ entirePointsDetails: css`
182
+ color: ${theme.palette.text.tertiary};
183
+ text-align: center;
184
+ font-weight: 400;
185
+ font-size: 16px;
186
+ line-height: 150%;
187
+ letter-spacing: 0.15px;
188
+ margin-top: ${theme.spacing(4)};
189
+ `,
190
+ everyday: css`
191
+ font-weight: 700;
192
+ `,
193
+ }
194
+
195
+ if (state === STATE.SignIn) {
196
+ return (
197
+ <SignIn description='Please sign in to check the points that you earned.' />
198
+ )
199
+ }
200
+
201
+ if (state === STATE.Congrats) {
202
+ return (
203
+ <Box css={styles.wrapper}>
204
+ <Box css={styles.congrats}>
205
+ <CongratulationsIcon />
206
+ </Box>
207
+ <Box css={styles.ribbon}>
208
+ <RibbonIcon />
209
+ <Box css={styles.ribbonContent}>
210
+ <HumaPointsIcon />
211
+ <Box>{formatNumber(pointsAccumulated)} Points</Box>
212
+ </Box>
213
+ </Box>
214
+ <Box css={styles.entirePoints}>
215
+ <Box>Congratulations,</Box>
216
+ <Box>you've earned {pointsAccumulated} points</Box>
217
+ </Box>
218
+ <Box css={styles.entirePointsDetails}>
219
+ You'll earn points <span css={styles.everyday}>everyday</span> for{' '}
220
+ {monthText} straight. Plus, If you keep your investment till after{' '}
221
+ {monthText}, you’ll gain extra points daily.
222
+ </Box>
223
+ <BottomButton variant='contained' onClick={handleAction}>
224
+ GREAT
225
+ </BottomButton>
226
+ </Box>
227
+ )
228
+ }
229
+
230
+ return <LoadingModal title='SUPPLY' />
231
+ }
@@ -0,0 +1,442 @@
1
+ import {
2
+ CAMPAIGN_REFERENCE_CODE,
3
+ CampaignService,
4
+ checkIsDev,
5
+ formatNumber,
6
+ IdentityServiceV2,
7
+ IdentityVerificationStatusV2,
8
+ KYCCopy,
9
+ PoolInfoV2,
10
+ TrancheType,
11
+ useAuthErrorHandling,
12
+ VerificationStatusResultV2,
13
+ } from '@huma-finance/shared'
14
+ import { Box, css, useTheme } from '@mui/material'
15
+ import { useWeb3React } from '@web3-react/core'
16
+ import { BigNumber } from 'ethers'
17
+ import Persona, { Client } from 'persona'
18
+ import React, { useCallback, useEffect, useRef, useState } from 'react'
19
+
20
+ import { Campaign } from '..'
21
+ import { useAppDispatch } from '../../../../hooks/useRedux'
22
+ import { setError, setStep } from '../../../../store/widgets.reducers'
23
+ import { WIDGET_STEP } from '../../../../store/widgets.store'
24
+ import { BottomButton } from '../../../BottomButton'
25
+ import { ApproveLenderImg } from '../../../images'
26
+ import { LoadingModal } from '../../../LoadingModal'
27
+ import { WrapperModal } from '../../../WrapperModal'
28
+
29
+ type LoadingType = 'verificationStatus' | 'startKYC' | 'approveLender'
30
+
31
+ const LoadingCopiesByType: {
32
+ [key: string]: {
33
+ description: string
34
+ }
35
+ } = {
36
+ verificationStatus: {
37
+ description: `Checking your verification status...`,
38
+ },
39
+ startKYC: {
40
+ description: `Starting KYC...`,
41
+ },
42
+ approveLender: {
43
+ description: `Approving as lender...`,
44
+ },
45
+ }
46
+
47
+ type Props = {
48
+ poolInfo: PoolInfoV2
49
+ isUniTranche: boolean
50
+ minDepositAmount: BigNumber
51
+ pointsTestnetExperience: boolean
52
+ campaign?: Campaign
53
+ changeTranche: (tranche: TrancheType) => void
54
+ handleClose: () => void
55
+ }
56
+
57
+ export function PersonaEvaluation({
58
+ poolInfo,
59
+ isUniTranche,
60
+ minDepositAmount: minDepositAmountBN,
61
+ campaign,
62
+ pointsTestnetExperience,
63
+ changeTranche,
64
+ handleClose,
65
+ }: Props): React.ReactElement | null {
66
+ const theme = useTheme()
67
+ const isDev = checkIsDev()
68
+ const dispatch = useAppDispatch()
69
+ const { account, chainId } = useWeb3React()
70
+ const {
71
+ errorType,
72
+ setError: setAuthError,
73
+ isWalletOwnershipVerified,
74
+ isWalletOwnershipVerificationRequired,
75
+ } = useAuthErrorHandling(isDev)
76
+ const KYCCopies = poolInfo.KYC!.Persona!
77
+ const [loadingType, setLoadingType] = useState<LoadingType>()
78
+ const [kycCopy, setKYCCopy] = useState<KYCCopy>(KYCCopies.verifyIdentity)
79
+ const [inquiryId, setInquiryId] = useState<string>()
80
+ const [sessionToken, setSessionToken] = useState<string>()
81
+ const [verificationStatus, setVerificationStatus] =
82
+ useState<VerificationStatusResultV2>()
83
+ const [showPersonaClient, setShowPersonaClient] = useState<boolean>(false)
84
+ const [campaignBasePoints, setCampaignBasePoints] = useState<number>(0)
85
+ const isKYCCompletedRef = useRef<boolean>(false)
86
+ const isActionOngoingRef = useRef<boolean>(false)
87
+ const isKYCResumedRef = useRef<boolean>(false)
88
+
89
+ useEffect(() => {
90
+ const createNewWallet = async () => {
91
+ if (isWalletOwnershipVerified && campaign && account) {
92
+ await CampaignService.createNewWallet(
93
+ account,
94
+ localStorage.getItem(CAMPAIGN_REFERENCE_CODE) ?? undefined,
95
+ isDev,
96
+ pointsTestnetExperience,
97
+ )
98
+ }
99
+ }
100
+ createNewWallet()
101
+ }, [
102
+ account,
103
+ campaign,
104
+ isDev,
105
+ isWalletOwnershipVerified,
106
+ pointsTestnetExperience,
107
+ ])
108
+
109
+ useEffect(() => {
110
+ const getBasePoints = async () => {
111
+ if (campaign) {
112
+ const estimatedPoints = await CampaignService.getEstimatedPoints(
113
+ campaign.campaignGroupId,
114
+ minDepositAmountBN.toString(),
115
+ isDev,
116
+ pointsTestnetExperience,
117
+ )
118
+ const campaignPoints = estimatedPoints.find(
119
+ (item) => item.campaignId === campaign.id,
120
+ )
121
+ if (campaignPoints) {
122
+ const { juniorTranchePoints, seniorTranchePoints } = campaignPoints
123
+ if (isUniTranche) {
124
+ setCampaignBasePoints(juniorTranchePoints ?? 0)
125
+ } else {
126
+ setCampaignBasePoints(
127
+ juniorTranchePoints < seniorTranchePoints
128
+ ? juniorTranchePoints
129
+ : seniorTranchePoints,
130
+ )
131
+ }
132
+ }
133
+ }
134
+ }
135
+ getBasePoints()
136
+ }, [
137
+ campaign,
138
+ isDev,
139
+ isUniTranche,
140
+ minDepositAmountBN,
141
+ pointsTestnetExperience,
142
+ ])
143
+
144
+ const approveLender = useCallback(async () => {
145
+ try {
146
+ isActionOngoingRef.current = true
147
+ setLoadingType('approveLender')
148
+ await IdentityServiceV2.approveLender(
149
+ account!,
150
+ chainId!,
151
+ poolInfo.juniorTrancheVault,
152
+ isDev,
153
+ )
154
+ if (!isUniTranche) {
155
+ await IdentityServiceV2.approveLender(
156
+ account!,
157
+ chainId!,
158
+ poolInfo.seniorTrancheVault,
159
+ isDev,
160
+ )
161
+ }
162
+ if (isUniTranche) {
163
+ changeTranche('junior')
164
+ dispatch(setStep(WIDGET_STEP.ChooseAmount))
165
+ } else {
166
+ dispatch(setStep(WIDGET_STEP.ChooseTranche))
167
+ }
168
+ } finally {
169
+ isActionOngoingRef.current = false
170
+ setLoadingType(undefined)
171
+ }
172
+ }, [
173
+ account,
174
+ chainId,
175
+ changeTranche,
176
+ dispatch,
177
+ isDev,
178
+ isUniTranche,
179
+ poolInfo.juniorTrancheVault,
180
+ poolInfo.seniorTrancheVault,
181
+ ])
182
+
183
+ const checkVerificationStatus = useCallback(async () => {
184
+ if (isActionOngoingRef.current || isKYCResumedRef.current) {
185
+ return
186
+ }
187
+ try {
188
+ if (account && chainId) {
189
+ isActionOngoingRef.current = true
190
+ setLoadingType('verificationStatus')
191
+ const verificationStatus =
192
+ await IdentityServiceV2.getVerificationStatusV2(
193
+ account,
194
+ chainId,
195
+ isDev,
196
+ )
197
+ setVerificationStatus(verificationStatus)
198
+ setInquiryId(verificationStatus.personaInquiryId)
199
+
200
+ switch (verificationStatus.status) {
201
+ case IdentityVerificationStatusV2.NOT_STARTED: {
202
+ const startVerificationResult =
203
+ await IdentityServiceV2.startVerification(account, chainId, isDev)
204
+ setInquiryId(startVerificationResult.personaInquiryId)
205
+ setKYCCopy(KYCCopies.verifyIdentity)
206
+ setLoadingType(undefined)
207
+ break
208
+ }
209
+
210
+ case IdentityVerificationStatusV2.CREATED: {
211
+ setKYCCopy(KYCCopies.verifyIdentity)
212
+ setLoadingType(undefined)
213
+ break
214
+ }
215
+
216
+ case IdentityVerificationStatusV2.PENDING: {
217
+ if (!isKYCCompletedRef.current) {
218
+ const resumeVerificationResult =
219
+ await IdentityServiceV2.resumeVerification(
220
+ account,
221
+ chainId,
222
+ isDev,
223
+ )
224
+ verificationStatus.status = resumeVerificationResult.status
225
+ setVerificationStatus(verificationStatus)
226
+ setSessionToken(resumeVerificationResult.sessionToken)
227
+ setLoadingType(undefined)
228
+ isKYCResumedRef.current = true
229
+ } else {
230
+ setLoadingType('verificationStatus')
231
+ }
232
+ setKYCCopy(KYCCopies.verifyIdentity)
233
+ break
234
+ }
235
+
236
+ case IdentityVerificationStatusV2.EXPIRED: {
237
+ const resumeVerificationResult =
238
+ await IdentityServiceV2.resumeVerification(
239
+ account,
240
+ chainId,
241
+ isDev,
242
+ )
243
+ verificationStatus.status = resumeVerificationResult.status
244
+ setVerificationStatus(verificationStatus)
245
+ setSessionToken(resumeVerificationResult.sessionToken)
246
+ setKYCCopy(KYCCopies.verifyIdentity)
247
+ setLoadingType(undefined)
248
+ isKYCResumedRef.current = true
249
+ break
250
+ }
251
+
252
+ case IdentityVerificationStatusV2.APPROVED: {
253
+ await approveLender()
254
+ break
255
+ }
256
+
257
+ case IdentityVerificationStatusV2.DECLINED: {
258
+ setKYCCopy(KYCCopies.verificationDeclined)
259
+ setLoadingType(undefined)
260
+ break
261
+ }
262
+
263
+ case IdentityVerificationStatusV2.NEEDS_REVIEW: {
264
+ setKYCCopy(KYCCopies.verificationNeedsReview)
265
+ setLoadingType(undefined)
266
+ break
267
+ }
268
+
269
+ default:
270
+ break
271
+ }
272
+ }
273
+ } catch (e: unknown) {
274
+ setAuthError(e)
275
+ } finally {
276
+ isActionOngoingRef.current = false
277
+ }
278
+ }, [KYCCopies, account, approveLender, chainId, isDev, setAuthError])
279
+
280
+ useEffect(() => {
281
+ checkVerificationStatus()
282
+ }, [checkVerificationStatus])
283
+
284
+ useEffect(() => {
285
+ if (isWalletOwnershipVerificationRequired && isWalletOwnershipVerified) {
286
+ checkVerificationStatus()
287
+ }
288
+ }, [
289
+ checkVerificationStatus,
290
+ isWalletOwnershipVerificationRequired,
291
+ isWalletOwnershipVerified,
292
+ ])
293
+
294
+ useEffect(() => {
295
+ const interval = setInterval(() => {
296
+ if (
297
+ verificationStatus?.status &&
298
+ [
299
+ IdentityVerificationStatusV2.CREATED,
300
+ IdentityVerificationStatusV2.PENDING,
301
+ ].includes(verificationStatus.status)
302
+ ) {
303
+ checkVerificationStatus()
304
+ }
305
+ }, 10 * 1000)
306
+ // eslint-disable-next-line consistent-return
307
+ return () => clearInterval(interval)
308
+ }, [checkVerificationStatus, verificationStatus?.status])
309
+
310
+ useEffect(() => {
311
+ if (errorType === 'NotSignedIn') {
312
+ setLoadingType(undefined)
313
+ setKYCCopy(KYCCopies.signInRequired)
314
+ } else if (errorType === 'UserRejected') {
315
+ dispatch(
316
+ setError({
317
+ errorMessage: 'User has rejected the transaction.',
318
+ }),
319
+ )
320
+ } else if (errorType === 'Other') {
321
+ dispatch(
322
+ setError({
323
+ errorMessage: 'Something went wrong. Please try again later.',
324
+ }),
325
+ )
326
+ }
327
+ }, [KYCCopies.signInRequired, dispatch, errorType])
328
+
329
+ useEffect(() => {
330
+ const modalElement = document.getElementById('huma-modal')
331
+ if (modalElement) {
332
+ modalElement.style.visibility = showPersonaClient ? 'hidden' : 'visible'
333
+ }
334
+ }, [showPersonaClient])
335
+
336
+ const startKYC = async () => {
337
+ isActionOngoingRef.current = true
338
+ isKYCResumedRef.current = false
339
+ setLoadingType('startKYC')
340
+ const client: Client = new Persona.Client({
341
+ inquiryId,
342
+ sessionToken,
343
+ onReady: () => {
344
+ client.open()
345
+ setShowPersonaClient(true)
346
+ },
347
+ onComplete: () => {
348
+ isKYCCompletedRef.current = true
349
+ isActionOngoingRef.current = false
350
+ setShowPersonaClient(false)
351
+ checkVerificationStatus()
352
+ },
353
+ onCancel: () => {
354
+ isActionOngoingRef.current = false
355
+ setShowPersonaClient(false)
356
+ setLoadingType(undefined)
357
+ },
358
+ onError: () => {
359
+ isActionOngoingRef.current = false
360
+ setShowPersonaClient(false)
361
+ setLoadingType(undefined)
362
+ },
363
+ })
364
+ }
365
+
366
+ const handleAction = () => {
367
+ if (verificationStatus) {
368
+ switch (verificationStatus.status) {
369
+ case IdentityVerificationStatusV2.NOT_STARTED:
370
+ case IdentityVerificationStatusV2.CREATED:
371
+ case IdentityVerificationStatusV2.PENDING:
372
+ case IdentityVerificationStatusV2.EXPIRED:
373
+ startKYC()
374
+ break
375
+
376
+ case IdentityVerificationStatusV2.DECLINED:
377
+ case IdentityVerificationStatusV2.NEEDS_REVIEW:
378
+ handleClose()
379
+ break
380
+
381
+ default:
382
+ break
383
+ }
384
+ }
385
+ }
386
+
387
+ const styles = {
388
+ iconWrapper: css`
389
+ ${theme.cssMixins.rowCentered};
390
+ margin-top: ${theme.spacing(8)};
391
+ & > img {
392
+ width: 144px;
393
+ }
394
+ `,
395
+ description: css`
396
+ margin-top: ${theme.spacing(10)};
397
+ padding: ${theme.spacing(0, 2)};
398
+ font-weight: 400;
399
+ font-size: 16px;
400
+ color: ${theme.palette.text.primary};
401
+ `,
402
+ points: css`
403
+ color: ${theme.palette.primary.main};
404
+ font-weight: 700;
405
+ `,
406
+ }
407
+
408
+ if (!loadingType) {
409
+ return (
410
+ <WrapperModal title={kycCopy.title}>
411
+ <Box css={styles.iconWrapper}>
412
+ <img src={ApproveLenderImg} alt='approve-lender' />
413
+ </Box>
414
+ {campaign && kycCopy === KYCCopies.verifyIdentity ? (
415
+ <Box css={styles.description}>
416
+ <span>You'll be rewarded with a minimum of</span>
417
+ <span css={styles.points}>
418
+ {' '}
419
+ {formatNumber(campaignBasePoints)} Huma points{' '}
420
+ </span>
421
+ <span>after completing KYC and your first investment.</span>
422
+ </Box>
423
+ ) : (
424
+ <Box css={styles.description}>{kycCopy.description}</Box>
425
+ )}
426
+
427
+ {Boolean(kycCopy.buttonText) && (
428
+ <BottomButton variant='contained' onClick={handleAction}>
429
+ {kycCopy.buttonText}
430
+ </BottomButton>
431
+ )}
432
+ </WrapperModal>
433
+ )
434
+ }
435
+
436
+ return (
437
+ <LoadingModal
438
+ title='Lender Approval'
439
+ description={LoadingCopiesByType[loadingType].description}
440
+ />
441
+ )
442
+ }