@huma-finance/widgets 0.0.31 → 0.0.33

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 (176) hide show
  1. package/.env.example +2 -2
  2. package/.eslintignore +2 -2
  3. package/.eslintrc.js +64 -64
  4. package/.prettierignore +4 -4
  5. package/.prettierrc.js +16 -16
  6. package/API.md +332 -332
  7. package/LICENSE +660 -660
  8. package/README.md +48 -48
  9. package/babel.config.js +15 -15
  10. package/config-overrides.js +9 -9
  11. package/cosmos.config.json +7 -7
  12. package/cypress/e2e/01-invoice-factoring-borrow.test.ts +62 -62
  13. package/cypress/support/e2e.ts +76 -76
  14. package/cypress/support/ethereum.ts +142 -142
  15. package/cypress/tsconfig.json +9 -9
  16. package/cypress/utils/index.ts +54 -54
  17. package/cypress.config.ts +20 -20
  18. package/dist/cjs/index.cjs +1026 -296
  19. package/dist/cjs/index.cjs.map +1 -1
  20. package/dist/index.d.ts +193 -193
  21. package/dist/index.js +1028 -299
  22. package/dist/index.js.map +1 -1
  23. package/jsdoc2md.json +20 -20
  24. package/package.json +4 -4
  25. package/public/index.html +40 -40
  26. package/public/manifest.json +25 -25
  27. package/public/robots.txt +3 -3
  28. package/rollup.config.js +81 -81
  29. package/src/components/Activity.tsx +132 -132
  30. package/src/components/ApolloWrapper.tsx +15 -15
  31. package/src/components/ApproveAllowanceModal.tsx +121 -121
  32. package/src/components/BottomButton.tsx +33 -33
  33. package/src/components/ChainNotSupportedModal.tsx +33 -33
  34. package/src/components/ChooseAmountModal.tsx +322 -322
  35. package/src/components/ConfirmTransferModal.tsx +153 -153
  36. package/src/components/CreditLine/borrow/1-Evaluation.tsx +157 -157
  37. package/src/components/CreditLine/borrow/2-ChooseAmount.tsx +68 -68
  38. package/src/components/CreditLine/borrow/3-Transfer.tsx +44 -44
  39. package/src/components/CreditLine/borrow/4-ApproveAllowance.tsx +29 -29
  40. package/src/components/CreditLine/borrow/5-Success.tsx +38 -30
  41. package/src/components/CreditLine/borrow/6-Notifications.tsx +10 -0
  42. package/src/components/CreditLine/borrow/index.tsx +136 -117
  43. package/src/components/CreditLine/payment/1-ChooseAmount.tsx +67 -67
  44. package/src/components/CreditLine/payment/2-ApproveAllowance.tsx +23 -23
  45. package/src/components/CreditLine/payment/3-Transfer.tsx +34 -34
  46. package/src/components/CreditLine/payment/4-Success.tsx +39 -39
  47. package/src/components/CreditLine/payment/index.tsx +94 -94
  48. package/src/components/ErrorModal.tsx +132 -132
  49. package/src/components/Factoring/FactoredList.tsx +143 -143
  50. package/src/components/Factoring/UpcomingList.tsx +90 -90
  51. package/src/components/Factoring/index.ts +2 -2
  52. package/src/components/HumaLoading.tsx +68 -68
  53. package/src/components/HumaSnackBar.tsx +60 -0
  54. package/src/components/HumaTable.tsx +158 -158
  55. package/src/components/InvoiceFactoring/borrow/1-Evaluation.tsx +49 -49
  56. package/src/components/InvoiceFactoring/borrow/2-ChooseAmount.tsx +88 -88
  57. package/src/components/InvoiceFactoring/borrow/3-ConfirmTransfer.tsx +37 -37
  58. package/src/components/InvoiceFactoring/borrow/4-ApproveNFT.tsx +55 -55
  59. package/src/components/InvoiceFactoring/borrow/5-Transfer.tsx +34 -34
  60. package/src/components/InvoiceFactoring/borrow/6-Success.tsx +20 -20
  61. package/src/components/InvoiceFactoring/borrow/index.tsx +94 -94
  62. package/src/components/InvoiceFactoring/payment/1-ChooseAmount.tsx +67 -67
  63. package/src/components/InvoiceFactoring/payment/2-ApproveAllowance.tsx +23 -23
  64. package/src/components/InvoiceFactoring/payment/3-Transfer.tsx +34 -34
  65. package/src/components/InvoiceFactoring/payment/4-Success.tsx +23 -23
  66. package/src/components/InvoiceFactoring/payment/index.tsx +86 -86
  67. package/src/components/Lend/supply/1-Evaluation/EvaluationEA.tsx +86 -0
  68. package/src/components/Lend/supply/1-Evaluation/EvaluationKYC.tsx +287 -0
  69. package/src/components/Lend/supply/1-Evaluation/index.tsx +31 -0
  70. package/src/components/Lend/supply/2-ChooseAmount.tsx +69 -70
  71. package/src/components/Lend/supply/3-ApproveAllowance.tsx +25 -25
  72. package/src/components/Lend/supply/{6-Transfer.tsx → 4-Transfer.tsx} +32 -32
  73. package/src/components/Lend/supply/{7-Success.tsx → 5-Success.tsx} +60 -49
  74. package/src/components/Lend/supply/6-Notifications.tsx +10 -0
  75. package/src/components/Lend/supply/index.tsx +167 -144
  76. package/src/components/Lend/withdraw/1-CheckWithdrawble.tsx +73 -73
  77. package/src/components/Lend/withdraw/2-ChooseAmount.tsx +50 -50
  78. package/src/components/Lend/withdraw/3-Transfer.tsx +32 -32
  79. package/src/components/Lend/withdraw/4-Success.tsx +49 -49
  80. package/src/components/Lend/withdraw/index.tsx +101 -101
  81. package/src/components/LoadingModal.tsx +49 -49
  82. package/src/components/Notifi/NotifiSubscriptionModal.tsx +264 -0
  83. package/src/components/StreamFactoring/borrow/1-Evaluation.tsx +55 -55
  84. package/src/components/StreamFactoring/borrow/2-ChooseAmount.tsx +127 -127
  85. package/src/components/StreamFactoring/borrow/3-ConfirmTransfer.tsx +42 -42
  86. package/src/components/StreamFactoring/borrow/4-ApproveAllowance.tsx +33 -33
  87. package/src/components/StreamFactoring/borrow/5-Permit.tsx +144 -144
  88. package/src/components/StreamFactoring/borrow/6-Transfer.tsx +37 -37
  89. package/src/components/StreamFactoring/borrow/7-Success.tsx +20 -20
  90. package/src/components/StreamFactoring/borrow/index.tsx +94 -94
  91. package/src/components/StreamFactoring/payment/ChooseAmount.tsx +54 -54
  92. package/src/components/StreamFactoring/payment/Success.tsx +23 -23
  93. package/src/components/StreamFactoring/payment/Transfer.tsx +34 -34
  94. package/src/components/StreamFactoring/payment/index.tsx +66 -66
  95. package/src/components/SuperfluidFactoring/SuperfluidFactoredList.tsx +70 -70
  96. package/src/components/SuperfluidFactoring/SuperfluidUpcomingList.tsx +167 -167
  97. package/src/components/SuperfluidFactoring/index.tsx +85 -85
  98. package/src/components/TxDoneModal.tsx +85 -83
  99. package/src/components/TxSendModal.tsx +59 -59
  100. package/src/components/ViewOnExplorer.tsx +26 -26
  101. package/src/components/WidgetWrapper.tsx +74 -74
  102. package/src/components/WrapperModal.tsx +54 -54
  103. package/src/components/buttons/TableActionButton.tsx +36 -36
  104. package/src/components/buttons/index.ts +1 -1
  105. package/src/components/humaModal/HumaModal.tsx +68 -68
  106. package/src/components/humaModal/HumaModalHeader.tsx +70 -70
  107. package/src/components/humaModal/index.tsx +2 -2
  108. package/src/components/icons/approve-lender.svg +30 -30
  109. package/src/components/icons/auto-payback.svg +40 -40
  110. package/src/components/icons/check-circle.svg +3 -3
  111. package/src/components/icons/check-green.svg +3 -3
  112. package/src/components/icons/check.svg +10 -10
  113. package/src/components/icons/donut.svg +904 -904
  114. package/src/components/icons/ellipse.svg +3 -3
  115. package/src/components/icons/huma-full.svg +22 -22
  116. package/src/components/icons/huma.svg +15 -15
  117. package/src/components/icons/index.tsx +93 -93
  118. package/src/components/icons/loader.svg +229 -229
  119. package/src/components/icons/metamask.svg +31 -31
  120. package/src/components/icons/polygon.svg +16 -16
  121. package/src/components/icons/receipt.svg +3 -3
  122. package/src/components/icons/separator.svg +3 -3
  123. package/src/components/icons/sorry.svg +31 -31
  124. package/src/components/icons/usdc.svg +5 -5
  125. package/src/components/icons/wallet-connect.svg +11 -11
  126. package/src/cosmos/CreditLineBorrow.fixture.tsx +86 -86
  127. package/src/cosmos/CreditLinePayment.fixture.tsx +50 -50
  128. package/src/cosmos/InvoiceFactoringBorrow.fixture.tsx +111 -111
  129. package/src/cosmos/InvoiceFactoringPayment.fixture.tsx +67 -67
  130. package/src/cosmos/LendSupply.fixture.tsx +75 -75
  131. package/src/cosmos/LendWithdraw.fixture.tsx +43 -43
  132. package/src/cosmos/SDKTesting.fixture.tsx +616 -616
  133. package/src/cosmos/SuperfluidFactoringBorrow.fixture.tsx +15 -15
  134. package/src/cosmos/WalletWrapper.tsx +52 -52
  135. package/src/cosmos/abis/InvoiceNFT.json +644 -644
  136. package/src/cosmos/abis/ReceivableFactoringPool.json +1529 -1529
  137. package/src/cosmos/utils/env.ts +6 -6
  138. package/src/cosmos/utils/index.ts +169 -169
  139. package/src/fonts/Recoleta/Recoleta-Black.otf +0 -0
  140. package/src/fonts/Recoleta/Recoleta-Bold.otf +0 -0
  141. package/src/fonts/Recoleta/Recoleta-Light.otf +0 -0
  142. package/src/fonts/Recoleta/Recoleta-Medium.otf +0 -0
  143. package/src/fonts/Recoleta/Recoleta-Regular.otf +0 -0
  144. package/src/fonts/Recoleta/Recoleta-RegularDEMO.otf +0 -0
  145. package/src/fonts/Recoleta/Recoleta-SemiBold.otf +0 -0
  146. package/src/fonts/Recoleta/Recoleta-Thin.otf +0 -0
  147. package/src/hooks/useEA.ts +53 -53
  148. package/src/hooks/useNotifi.ts +71 -0
  149. package/src/hooks/useRedux.ts +6 -6
  150. package/src/index.css +61 -61
  151. package/src/index.tsx +301 -301
  152. package/src/react-app-env.d.ts +1 -1
  153. package/src/reportWebVitals.ts +15 -15
  154. package/src/setupTests.ts +6 -6
  155. package/src/store/index.ts +27 -27
  156. package/src/store/widgets.reducers.ts +120 -120
  157. package/src/store/widgets.selectors.ts +3 -3
  158. package/src/store/widgets.store.ts +55 -54
  159. package/src/theme/breakpoints.ts +10 -10
  160. package/src/theme/components.ts +70 -70
  161. package/src/theme/coreThemeConstants.ts +29 -29
  162. package/src/theme/cssMixins.ts +92 -92
  163. package/src/theme/hooks/useGetSizes.ts +31 -31
  164. package/src/theme/index.ts +24 -24
  165. package/src/theme/palette.ts +150 -150
  166. package/src/theme/shape.ts +7 -7
  167. package/src/theme/theme.types.ts +80 -80
  168. package/src/theme/typography.ts +117 -117
  169. package/src/utilTypes.d.ts +31 -31
  170. package/src/utils/env.ts +10 -10
  171. package/tsconfig.build.json +7 -7
  172. package/tsconfig.json +32 -32
  173. package/webpack.cosmos.js +54 -54
  174. package/src/components/Lend/supply/1-Evaluation.tsx +0 -175
  175. package/src/components/Lend/supply/4-ConfirmTransfer.tsx +0 -104
  176. package/src/components/NotifiSubscriptionModal.tsx +0 -84
@@ -1,23 +1,23 @@
1
- import { PoolInfoType } from '@huma-finance/shared'
2
- import React from 'react'
3
-
4
- import { useAppSelector } from '../../../hooks/useRedux'
5
- import { selectWidgetState } from '../../../store/widgets.selectors'
6
- import { TxDoneModal } from '../../TxDoneModal'
7
-
8
- type Props = {
9
- poolInfo: PoolInfoType
10
- handleAction: () => void
11
- }
12
-
13
- export function Success({ poolInfo, handleAction }: Props): React.ReactElement {
14
- const { symbol } = poolInfo.poolUnderlyingToken
15
- const { paymentAmount, remainDueAmount } = useAppSelector(selectWidgetState)
16
-
17
- const content = [
18
- `You have successfully made a payment of ${paymentAmount} ${symbol}.`,
19
- `The remaining due amount is ${remainDueAmount} ${symbol}.`,
20
- ]
21
-
22
- return <TxDoneModal handleAction={handleAction} content={content} />
23
- }
1
+ import { PoolInfoType } from '@huma-finance/shared'
2
+ import React from 'react'
3
+
4
+ import { useAppSelector } from '../../../hooks/useRedux'
5
+ import { selectWidgetState } from '../../../store/widgets.selectors'
6
+ import { TxDoneModal } from '../../TxDoneModal'
7
+
8
+ type Props = {
9
+ poolInfo: PoolInfoType
10
+ handleAction: () => void
11
+ }
12
+
13
+ export function Success({ poolInfo, handleAction }: Props): React.ReactElement {
14
+ const { symbol } = poolInfo.poolUnderlyingToken
15
+ const { paymentAmount, remainDueAmount } = useAppSelector(selectWidgetState)
16
+
17
+ const content = [
18
+ `You have successfully made a payment of ${paymentAmount} ${symbol}.`,
19
+ `The remaining due amount is ${remainDueAmount} ${symbol}.`,
20
+ ]
21
+
22
+ return <TxDoneModal handleAction={handleAction} content={content} />
23
+ }
@@ -1,86 +1,86 @@
1
- import { useWeb3React } from '@web3-react/core'
2
- import {
3
- POOL_NAME,
4
- POOL_TYPE,
5
- useAccountStats,
6
- usePoolInfo,
7
- } from '@huma-finance/shared'
8
- import React, { useEffect } from 'react'
9
- import { useDispatch } from 'react-redux'
10
-
11
- import { useAppSelector } from '../../../hooks/useRedux'
12
- import { setStep } from '../../../store/widgets.reducers'
13
- import { selectWidgetState } from '../../../store/widgets.selectors'
14
- import { WIDGET_STEP } from '../../../store/widgets.store'
15
- import { ErrorModal } from '../../ErrorModal'
16
- import { WidgetWrapper } from '../../WidgetWrapper'
17
- import { ChooseAmount } from './1-ChooseAmount'
18
- import { ApproveAllowance } from './2-ApproveAllowance'
19
- import { Transfer } from './3-Transfer'
20
- import { Success } from './4-Success'
21
-
22
- /**
23
- * Invoice factoring pool payment props
24
- * @typedef {Object} InvoiceFactoringPaymentProps
25
- * @property {POOL_NAME} poolName The name of the pool.
26
- * @property {POOL_TYPE} poolType The type of the pool.
27
- * @property {function():void} handleClose Function to notify to close the widget modal when user clicks the 'x' close button.
28
- * @property {function((number|undefined)):void|undefined} handleSuccess Optional function to notify that the invoice pool payment action is successful.
29
- */
30
- export type InvoiceFactoringPaymentProps = {
31
- poolName: keyof typeof POOL_NAME
32
- poolType: keyof typeof POOL_TYPE
33
- handleClose: () => void
34
- handleSuccess?: (blockNumber?: number) => void
35
- }
36
-
37
- export function InvoiceFactoringPayment({
38
- poolName: poolNameStr,
39
- poolType: poolTypeStr,
40
- handleClose,
41
- handleSuccess,
42
- }: InvoiceFactoringPaymentProps): React.ReactElement | null {
43
- const dispatch = useDispatch()
44
- const { account } = useWeb3React()
45
- const poolName = POOL_NAME[poolNameStr]
46
- const poolType = POOL_TYPE[poolTypeStr]
47
- const poolInfo = usePoolInfo(poolName, poolType)
48
- const { step, errorMessage } = useAppSelector(selectWidgetState)
49
- const [{ creditRecord }] = useAccountStats(poolName, poolType, account)
50
-
51
- useEffect(() => {
52
- dispatch(setStep(WIDGET_STEP.ChooseAmount))
53
- }, [dispatch])
54
-
55
- if (!poolInfo) {
56
- return null
57
- }
58
-
59
- return (
60
- <WidgetWrapper
61
- isOpen
62
- isLoading={!creditRecord}
63
- loadingTitle='Make Payment'
64
- handleClose={handleClose}
65
- handleSuccess={handleSuccess}
66
- >
67
- {step === WIDGET_STEP.ChooseAmount && (
68
- <ChooseAmount creditRecord={creditRecord!} poolInfo={poolInfo} />
69
- )}
70
- {step === WIDGET_STEP.ApproveAllowance && (
71
- <ApproveAllowance poolInfo={poolInfo} />
72
- )}
73
- {step === WIDGET_STEP.Transfer && <Transfer poolInfo={poolInfo} />}
74
- {step === WIDGET_STEP.Done && (
75
- <Success poolInfo={poolInfo} handleAction={handleClose} />
76
- )}
77
- {step === WIDGET_STEP.Error && (
78
- <ErrorModal
79
- title='Make Payment'
80
- errorMessage={errorMessage}
81
- handleOk={handleClose}
82
- />
83
- )}
84
- </WidgetWrapper>
85
- )
86
- }
1
+ import { useWeb3React } from '@web3-react/core'
2
+ import {
3
+ POOL_NAME,
4
+ POOL_TYPE,
5
+ useAccountStats,
6
+ usePoolInfo,
7
+ } from '@huma-finance/shared'
8
+ import React, { useEffect } from 'react'
9
+ import { useDispatch } from 'react-redux'
10
+
11
+ import { useAppSelector } from '../../../hooks/useRedux'
12
+ import { setStep } from '../../../store/widgets.reducers'
13
+ import { selectWidgetState } from '../../../store/widgets.selectors'
14
+ import { WIDGET_STEP } from '../../../store/widgets.store'
15
+ import { ErrorModal } from '../../ErrorModal'
16
+ import { WidgetWrapper } from '../../WidgetWrapper'
17
+ import { ChooseAmount } from './1-ChooseAmount'
18
+ import { ApproveAllowance } from './2-ApproveAllowance'
19
+ import { Transfer } from './3-Transfer'
20
+ import { Success } from './4-Success'
21
+
22
+ /**
23
+ * Invoice factoring pool payment props
24
+ * @typedef {Object} InvoiceFactoringPaymentProps
25
+ * @property {POOL_NAME} poolName The name of the pool.
26
+ * @property {POOL_TYPE} poolType The type of the pool.
27
+ * @property {function():void} handleClose Function to notify to close the widget modal when user clicks the 'x' close button.
28
+ * @property {function((number|undefined)):void|undefined} handleSuccess Optional function to notify that the invoice pool payment action is successful.
29
+ */
30
+ export type InvoiceFactoringPaymentProps = {
31
+ poolName: keyof typeof POOL_NAME
32
+ poolType: keyof typeof POOL_TYPE
33
+ handleClose: () => void
34
+ handleSuccess?: (blockNumber?: number) => void
35
+ }
36
+
37
+ export function InvoiceFactoringPayment({
38
+ poolName: poolNameStr,
39
+ poolType: poolTypeStr,
40
+ handleClose,
41
+ handleSuccess,
42
+ }: InvoiceFactoringPaymentProps): React.ReactElement | null {
43
+ const dispatch = useDispatch()
44
+ const { account } = useWeb3React()
45
+ const poolName = POOL_NAME[poolNameStr]
46
+ const poolType = POOL_TYPE[poolTypeStr]
47
+ const poolInfo = usePoolInfo(poolName, poolType)
48
+ const { step, errorMessage } = useAppSelector(selectWidgetState)
49
+ const [{ creditRecord }] = useAccountStats(poolName, poolType, account)
50
+
51
+ useEffect(() => {
52
+ dispatch(setStep(WIDGET_STEP.ChooseAmount))
53
+ }, [dispatch])
54
+
55
+ if (!poolInfo) {
56
+ return null
57
+ }
58
+
59
+ return (
60
+ <WidgetWrapper
61
+ isOpen
62
+ isLoading={!creditRecord}
63
+ loadingTitle='Make Payment'
64
+ handleClose={handleClose}
65
+ handleSuccess={handleSuccess}
66
+ >
67
+ {step === WIDGET_STEP.ChooseAmount && (
68
+ <ChooseAmount creditRecord={creditRecord!} poolInfo={poolInfo} />
69
+ )}
70
+ {step === WIDGET_STEP.ApproveAllowance && (
71
+ <ApproveAllowance poolInfo={poolInfo} />
72
+ )}
73
+ {step === WIDGET_STEP.Transfer && <Transfer poolInfo={poolInfo} />}
74
+ {step === WIDGET_STEP.Done && (
75
+ <Success poolInfo={poolInfo} handleAction={handleClose} />
76
+ )}
77
+ {step === WIDGET_STEP.Error && (
78
+ <ErrorModal
79
+ title='Make Payment'
80
+ errorMessage={errorMessage}
81
+ handleOk={handleClose}
82
+ />
83
+ )}
84
+ </WidgetWrapper>
85
+ )
86
+ }
@@ -0,0 +1,86 @@
1
+ import { Box, css, useTheme } from '@mui/material'
2
+ import { useWeb3React } from '@web3-react/core'
3
+ import { EAService, PoolInfoType } from '@huma-finance/shared'
4
+ import React, { useState } from 'react'
5
+
6
+ import { useAppDispatch } from '../../../../hooks/useRedux'
7
+ import { setError, setStep } from '../../../../store/widgets.reducers'
8
+ import { WIDGET_STEP } from '../../../../store/widgets.store'
9
+ import { CustomError } from '../../../../utilTypes'
10
+ import { BottomButton } from '../../../BottomButton'
11
+ import { ApproveLenderIcon } from '../../../icons'
12
+ import { LoadingModal } from '../../../LoadingModal'
13
+ import { WrapperModal } from '../../../WrapperModal'
14
+
15
+ type Props = {
16
+ poolInfo: PoolInfoType
17
+ handleApproveSuccess: () => void
18
+ }
19
+
20
+ export function EvaluationEA({
21
+ poolInfo,
22
+ handleApproveSuccess,
23
+ }: Props): React.ReactElement | null {
24
+ const theme = useTheme()
25
+ const dispatch = useAppDispatch()
26
+ const { account, chainId } = useWeb3React()
27
+ const [loading, setLoading] = useState(false)
28
+
29
+ const styles = {
30
+ iconWrapper: css`
31
+ ${theme.cssMixins.rowCentered};
32
+ margin-top: 30px;
33
+ `,
34
+ description: css`
35
+ ${theme.cssMixins.rowCentered};
36
+ margin-top: 50px;
37
+ font-family: 'Uni-Neue-Regular';
38
+ font-size: 16px;
39
+ color: #a8a1b2;
40
+ `,
41
+ }
42
+
43
+ const approveLender = async () => {
44
+ if (account) {
45
+ try {
46
+ setLoading(true)
47
+ const payload = {
48
+ poolAddress: poolInfo.pool,
49
+ lenderWalletAddress: account,
50
+ }
51
+ await EAService.approveLender(payload, chainId!)
52
+ handleApproveSuccess()
53
+ setLoading(false)
54
+ dispatch(setStep(WIDGET_STEP.ChooseAmount))
55
+ } catch (e: unknown) {
56
+ const error = e as CustomError
57
+ setLoading(false)
58
+ dispatch(setError({ errorMessage: error.message }))
59
+ }
60
+ }
61
+ }
62
+
63
+ if (!loading) {
64
+ return (
65
+ <WrapperModal
66
+ title='Lender Approval'
67
+ subTitle='This pool requires lender approval'
68
+ >
69
+ <Box css={styles.iconWrapper}>
70
+ <ApproveLenderIcon />
71
+ </Box>
72
+ <Box css={styles.description} />
73
+ <BottomButton variant='contained' onClick={approveLender}>
74
+ GET APPROVED
75
+ </BottomButton>
76
+ </WrapperModal>
77
+ )
78
+ }
79
+
80
+ return (
81
+ <LoadingModal
82
+ title='Approval Pending'
83
+ description='Waiting for approval confirmation...'
84
+ />
85
+ )
86
+ }
@@ -0,0 +1,287 @@
1
+ import {
2
+ configUtil,
3
+ DocSignatureStatus,
4
+ IdentityService,
5
+ PoolInfoType,
6
+ timeUtil,
7
+ VerificationStatusResult,
8
+ } from '@huma-finance/shared'
9
+ import { Box, css, useTheme } from '@mui/material'
10
+ import { useWeb3React } from '@web3-react/core'
11
+ import React, { useCallback, useEffect, useMemo, useState } from 'react'
12
+
13
+ import { useAppDispatch } from '../../../../hooks/useRedux'
14
+ import { setError } from '../../../../store/widgets.reducers'
15
+ import { envUtil } from '../../../../utils/env'
16
+ import { BottomButton } from '../../../BottomButton'
17
+ import { HumaSnackBar } from '../../../HumaSnackBar'
18
+ import { ApproveLenderIcon } from '../../../icons'
19
+ import { LoadingModal } from '../../../LoadingModal'
20
+ import { WrapperModal } from '../../../WrapperModal'
21
+
22
+ const KYCProvider = 'Securitize'
23
+
24
+ const KYCCopiesByState: {
25
+ [key: string]: {
26
+ description: string
27
+ buttonText: string
28
+ }
29
+ } = {
30
+ verifyIdentity: {
31
+ description: `Link your ${KYCProvider} account or create a new one to complete identity verification.`,
32
+ buttonText: 'VERIFY MY IDENTITY',
33
+ },
34
+ emailSignatureLink: {
35
+ description: `Final step: Your digital signature on legal documents is required. Click below to email yourself the DocuSign link.`,
36
+ buttonText: 'EMAIL DOCUSIGN LINK',
37
+ },
38
+ resendSignatureLink: {
39
+ description: `DocuSign link sent successfully. Haven't received it? Check your spam folder or click below to resend it.`,
40
+ buttonText: 'RESEND DOCUSIGN LINK',
41
+ },
42
+ docUnderReview: {
43
+ description: `Documents received and under review. You'll be notified upon approval. Your patience is appreciated.`,
44
+ buttonText: 'THANK YOU',
45
+ },
46
+ }
47
+
48
+ const LoadingCopiesByType: {
49
+ [key: string]: {
50
+ description: string
51
+ }
52
+ } = {
53
+ verificationStatus: {
54
+ description: `Checking your verification status...`,
55
+ },
56
+ sendDocSignatureLink: {
57
+ description: `Sending signature link...`,
58
+ },
59
+ }
60
+
61
+ type Props = {
62
+ poolInfo: PoolInfoType
63
+ handleClose: () => void
64
+ }
65
+
66
+ export function EvaluationKYC({
67
+ poolInfo,
68
+ handleClose,
69
+ }: Props): React.ReactElement | null {
70
+ const theme = useTheme()
71
+ const dispatch = useAppDispatch()
72
+ const isDev = envUtil.checkIsDev()
73
+ const { account, chainId } = useWeb3React()
74
+ const [loadingType, setLoadingType] = useState<
75
+ 'verificationStatus' | 'sendDocSignatureLink'
76
+ >()
77
+ const [description, setDescription] = useState<string>(
78
+ KYCCopiesByState.verifyIdentity.description,
79
+ )
80
+ const [buttonText, setButtonText] = useState<string>(
81
+ KYCCopiesByState.verifyIdentity.buttonText,
82
+ )
83
+ const [KYCVerifyStatus, setKYCVerifyStatus] =
84
+ useState<VerificationStatusResult>()
85
+ const [docSignatureStatus, setDocSignatureStatus] =
86
+ useState<DocSignatureStatus['status']>()
87
+ const docSignatureCompleted = docSignatureStatus === 'completed'
88
+ const [openSnackBar, setOpenSnackBar] = useState<boolean>(false)
89
+
90
+ const styles = {
91
+ iconWrapper: css`
92
+ ${theme.cssMixins.rowCentered};
93
+ margin-top: 30px;
94
+ `,
95
+ description: css`
96
+ ${theme.cssMixins.rowCentered};
97
+ margin-top: 50px;
98
+ font-family: 'Uni-Neue-Regular';
99
+ font-size: 16px;
100
+ color: #a8a1b2;
101
+ `,
102
+ }
103
+
104
+ const { envelopeKey, envelopeLastQueryTimeKey } = useMemo(() => {
105
+ const envelopeKey = `${poolInfo.pool.toLowerCase()}-${account?.toLowerCase()}`
106
+ const envelopeLastQueryTimeKey = `${envelopeKey}-last-query-time`
107
+ return {
108
+ envelopeKey,
109
+ envelopeLastQueryTimeKey,
110
+ }
111
+ }, [account, poolInfo.pool])
112
+
113
+ // DocuSign GET requests to any specific URL can be called not more often than once every 15 minutes.
114
+ // https://developers.docusign.com/platform/api-guidelines/#:~:text=Polling,not%20once%20every%2010%20minutes
115
+ const checkGetDocSignatureStatusIsAvailable = useCallback(() => {
116
+ const lastQueryTime = localStorage.getItem(envelopeLastQueryTimeKey)
117
+ if (!lastQueryTime) {
118
+ return true
119
+ }
120
+ const lastQueryTimeNumber = Number(lastQueryTime)
121
+ const now = timeUtil.getUnixTimestamp()
122
+ const diff = now - lastQueryTimeNumber
123
+ const fifteenMinutes = 15 * 60
124
+ return diff > fifteenMinutes
125
+ }, [envelopeLastQueryTimeKey])
126
+
127
+ useEffect(() => {
128
+ const fetchData = async () => {
129
+ if (account && chainId) {
130
+ try {
131
+ setLoadingType('verificationStatus')
132
+ const verificationStatus =
133
+ await IdentityService.getVerificationStatus(
134
+ account,
135
+ poolInfo.pool,
136
+ chainId,
137
+ isDev,
138
+ )
139
+ setKYCVerifyStatus(verificationStatus)
140
+ if (verificationStatus.isVerified) {
141
+ const envelopeId = localStorage.getItem(envelopeKey)
142
+ if (!envelopeId) {
143
+ setDescription(KYCCopiesByState.emailSignatureLink.description)
144
+ setButtonText(KYCCopiesByState.emailSignatureLink.buttonText)
145
+ } else if (!checkGetDocSignatureStatusIsAvailable()) {
146
+ setDescription(KYCCopiesByState.resendSignatureLink.description)
147
+ setButtonText(KYCCopiesByState.resendSignatureLink.buttonText)
148
+ } else {
149
+ const { status } = await IdentityService.getDocSignatureStatus(
150
+ envelopeId,
151
+ chainId,
152
+ isDev,
153
+ )
154
+ localStorage.setItem(
155
+ envelopeLastQueryTimeKey,
156
+ String(timeUtil.getUnixTimestamp()),
157
+ )
158
+ setDocSignatureStatus(status)
159
+ if (status === 'completed') {
160
+ setDescription(KYCCopiesByState.docUnderReview.description)
161
+ setButtonText(KYCCopiesByState.docUnderReview.buttonText)
162
+ // For voided and declined status, we need to send a new link
163
+ } else if (['voided', 'declined'].includes(status)) {
164
+ localStorage.removeItem(envelopeKey)
165
+ localStorage.removeItem(envelopeLastQueryTimeKey)
166
+ setDescription(KYCCopiesByState.emailSignatureLink.description)
167
+ setButtonText(KYCCopiesByState.emailSignatureLink.buttonText)
168
+ } else {
169
+ setDescription(KYCCopiesByState.resendSignatureLink.description)
170
+ setButtonText(KYCCopiesByState.resendSignatureLink.buttonText)
171
+ }
172
+ }
173
+ }
174
+ } catch (e: unknown) {
175
+ console.error(e)
176
+ dispatch(
177
+ setError({
178
+ errorMessage: 'Something went wrong, please try again later.',
179
+ }),
180
+ )
181
+ } finally {
182
+ setLoadingType(undefined)
183
+ }
184
+ }
185
+ }
186
+ fetchData()
187
+ }, [
188
+ account,
189
+ chainId,
190
+ checkGetDocSignatureStatusIsAvailable,
191
+ dispatch,
192
+ envelopeKey,
193
+ envelopeLastQueryTimeKey,
194
+ isDev,
195
+ poolInfo.pool,
196
+ ])
197
+
198
+ const approveLender = async () => {
199
+ if (docSignatureCompleted) {
200
+ handleClose()
201
+ return
202
+ }
203
+
204
+ const { isNotOnboarded, isVerified } = KYCVerifyStatus || {}
205
+
206
+ if (!isVerified) {
207
+ const issuerId = '53a66b32-583e-40e7-ba90-baf516d2cadd'
208
+ const baseUrl = configUtil.getKYCProviderBaseUrl(KYCProvider, isDev)
209
+ const originUrl = window.location.href.split('?')[0]
210
+ const redirectUrl = `${originUrl}?kycProvider=${KYCProvider}&kycPool=${poolInfo.pool}`
211
+ const providerAuthorizeUrl = `${baseUrl}/#/authorize?issuerId=${issuerId}&scope=details&details=verification&redirectUrl=${redirectUrl}`
212
+ const providerUrl = isNotOnboarded ? providerAuthorizeUrl : baseUrl
213
+ window.location.href = providerUrl
214
+ } else {
215
+ const envelopeId = localStorage.getItem(envelopeKey)
216
+ try {
217
+ setLoadingType('sendDocSignatureLink')
218
+ if (!envelopeId) {
219
+ const { envelopeId } = await IdentityService.requestDocSignature(
220
+ account!,
221
+ chainId!,
222
+ isDev,
223
+ )
224
+ localStorage.setItem(envelopeKey, envelopeId)
225
+ localStorage.setItem(
226
+ envelopeLastQueryTimeKey,
227
+ String(timeUtil.getUnixTimestamp()),
228
+ )
229
+ setOpenSnackBar(true)
230
+ setDescription(KYCCopiesByState.resendSignatureLink.description)
231
+ setButtonText(KYCCopiesByState.resendSignatureLink.buttonText)
232
+ } else {
233
+ await IdentityService.resendDocSignatureLink(
234
+ envelopeId,
235
+ chainId!,
236
+ isDev,
237
+ )
238
+ setOpenSnackBar(true)
239
+ }
240
+ } catch (e: unknown) {
241
+ console.error(e)
242
+ dispatch(
243
+ setError({
244
+ errorMessage: 'Something went wrong, please try again later.',
245
+ }),
246
+ )
247
+ } finally {
248
+ setLoadingType(undefined)
249
+ }
250
+ }
251
+ }
252
+
253
+ const getEmailLinkSentSnackbar = () => (
254
+ <HumaSnackBar
255
+ open={openSnackBar}
256
+ title='Signature Link Sent'
257
+ message='The secure signature session link has been sent to your email.'
258
+ severity='success'
259
+ onClose={() => setOpenSnackBar(false)}
260
+ />
261
+ )
262
+
263
+ if (!loadingType) {
264
+ return (
265
+ <WrapperModal
266
+ title='Lender Approval'
267
+ subTitle='This pool requires lender approval'
268
+ >
269
+ <Box css={styles.iconWrapper}>
270
+ <ApproveLenderIcon />
271
+ </Box>
272
+ <Box css={styles.description}>{description}</Box>
273
+ <BottomButton variant='contained' onClick={approveLender}>
274
+ {buttonText}
275
+ </BottomButton>
276
+ {getEmailLinkSentSnackbar()}
277
+ </WrapperModal>
278
+ )
279
+ }
280
+
281
+ return (
282
+ <LoadingModal
283
+ title='Lender Approval'
284
+ description={LoadingCopiesByType[loadingType].description}
285
+ />
286
+ )
287
+ }
@@ -0,0 +1,31 @@
1
+ import { PoolInfoType } from '@huma-finance/shared'
2
+ import React from 'react'
3
+
4
+ import { EvaluationEA } from './EvaluationEA'
5
+ import { EvaluationKYC } from './EvaluationKYC'
6
+
7
+ type Props = {
8
+ poolInfo: PoolInfoType
9
+ handleClose: () => void
10
+ handleApproveSuccess: () => void
11
+ }
12
+
13
+ export function Evaluation({
14
+ poolInfo,
15
+ handleClose,
16
+ handleApproveSuccess,
17
+ }: Props): React.ReactElement | null {
18
+ const lenderApprovalProvider = poolInfo.extra?.lenderApprovalProvider
19
+ const isKYC = lenderApprovalProvider?.type === 'KYC'
20
+
21
+ if (isKYC) {
22
+ return <EvaluationKYC poolInfo={poolInfo} handleClose={handleClose} />
23
+ }
24
+
25
+ return (
26
+ <EvaluationEA
27
+ poolInfo={poolInfo}
28
+ handleApproveSuccess={handleApproveSuccess}
29
+ />
30
+ )
31
+ }