@huma-finance/widgets 0.0.62-beta.624 → 0.0.62-beta.630
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +34 -26
- package/dist/cjs/index.cjs +742 -1110
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.d.ts +33 -9
- package/dist/index.js +997 -1343
- package/dist/index.js.map +1 -1
- package/package.json +12 -5
- package/src/components/CreditLine/paymentV2/1-ChooseAmount.tsx +1 -0
- package/src/components/CreditLine/solanaBorrow/1-ChooseAmount.tsx +2 -21
- package/src/components/CreditLine/solanaBorrow/2-Transfer.tsx +159 -0
- package/src/components/CreditLine/solanaBorrow/3-Done.tsx +38 -0
- package/src/components/CreditLine/solanaBorrow/index.tsx +19 -25
- package/src/components/CreditLine/solanaPayment/1-ChooseAmount.tsx +75 -0
- package/src/components/CreditLine/solanaPayment/2-Transfer.tsx +92 -0
- package/src/components/CreditLine/solanaPayment/3-Done.tsx +59 -0
- package/src/components/CreditLine/solanaPayment/index.tsx +83 -0
- package/src/components/InputAmountModal.tsx +1 -0
- package/src/components/Lend/addRedemptionV2/2-ChooseAmount.tsx +6 -1
- package/src/components/Lend/solanaCancelRedemption/index.tsx +11 -1
- package/src/components/Lend/solanaSupply/5-Success.tsx +10 -8
- package/src/components/Lend/supplyV2/6-Success.tsx +10 -8
- package/src/components/Lend/supplyV2/7-Notifications.tsx +6 -1
- package/src/components/Notifi/NotifiContextWrapper.tsx +57 -0
- package/src/components/Notifi/NotifiSubscriptionModal.tsx +118 -113
- package/src/components/SuperfluidFactoring/index.tsx +12 -46
- package/src/hooks/useNotifi.ts +28 -17
- package/src/index.tsx +31 -9
- package/src/theme/coreThemeConstants.ts +1 -1
- package/src/components/Activity.tsx +0 -128
- package/src/components/CreditLine/solanaBorrow/2-ApproveAllowance.tsx +0 -89
- package/src/components/Factoring/FactoredList.tsx +0 -143
- package/src/components/Factoring/UpcomingList.tsx +0 -90
- package/src/components/Factoring/index.ts +0 -2
- package/src/components/HumaTable.tsx +0 -203
- package/src/components/SuperfluidFactoring/SuperfluidFactoredList.tsx +0 -69
- package/src/components/SuperfluidFactoring/SuperfluidUpcomingList.tsx +0 -169
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { SolanaPoolInfo } from '@huma-finance/shared'
|
|
2
|
+
import { useBorrowerAccounts } from '@huma-finance/web-shared'
|
|
3
|
+
import React, { useEffect } from 'react'
|
|
4
|
+
import { useDispatch } from 'react-redux'
|
|
5
|
+
|
|
6
|
+
import { useAppSelector } from '../../../hooks/useRedux'
|
|
7
|
+
import { selectWidgetState } from '../../../store/widgets.selectors'
|
|
8
|
+
import { WidgetWrapper } from '../../WidgetWrapper'
|
|
9
|
+
import { WIDGET_STEP } from '../../../store/widgets.store'
|
|
10
|
+
import { setStep } from '../../../store/widgets.reducers'
|
|
11
|
+
import { ErrorModal } from '../../ErrorModal'
|
|
12
|
+
import { ChooseAmount } from './1-ChooseAmount'
|
|
13
|
+
import { Transfer } from './2-Transfer'
|
|
14
|
+
import { Done } from './3-Done'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Lend pool supply props
|
|
18
|
+
* @typedef {Object} SolanaPaymentProps
|
|
19
|
+
* @property {SolanaPoolInfo} poolInfo The metadata of the pool.
|
|
20
|
+
* @property {function():void|undefined} handleSuccess Optional function to notify that the lending pool supply action is successful.
|
|
21
|
+
*/
|
|
22
|
+
export interface SolanaPaymentProps {
|
|
23
|
+
poolInfo: SolanaPoolInfo
|
|
24
|
+
handleClose: () => void
|
|
25
|
+
handleSuccess?: () => void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function SolanaPayment({
|
|
29
|
+
poolInfo,
|
|
30
|
+
handleClose,
|
|
31
|
+
handleSuccess,
|
|
32
|
+
}: SolanaPaymentProps): React.ReactElement | null {
|
|
33
|
+
const dispatch = useDispatch()
|
|
34
|
+
const { creditStateAccount, loading: isLoadingBorrowerAccounts } =
|
|
35
|
+
useBorrowerAccounts(poolInfo.chainId, poolInfo.poolName)
|
|
36
|
+
const { step, errorMessage } = useAppSelector(selectWidgetState)
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!step) {
|
|
39
|
+
dispatch(setStep(WIDGET_STEP.ChooseAmount))
|
|
40
|
+
}
|
|
41
|
+
}, [dispatch, step])
|
|
42
|
+
|
|
43
|
+
const title = 'Make Payment'
|
|
44
|
+
if (isLoadingBorrowerAccounts) {
|
|
45
|
+
return (
|
|
46
|
+
<WidgetWrapper
|
|
47
|
+
isOpen
|
|
48
|
+
isLoading
|
|
49
|
+
loadingTitle={title}
|
|
50
|
+
handleClose={handleClose}
|
|
51
|
+
handleSuccess={handleSuccess}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<WidgetWrapper
|
|
58
|
+
isOpen
|
|
59
|
+
loadingTitle={title}
|
|
60
|
+
handleClose={handleClose}
|
|
61
|
+
handleSuccess={handleSuccess}
|
|
62
|
+
>
|
|
63
|
+
{step === WIDGET_STEP.ChooseAmount && creditStateAccount && (
|
|
64
|
+
<ChooseAmount
|
|
65
|
+
poolInfo={poolInfo}
|
|
66
|
+
creditStateAccount={creditStateAccount}
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
69
|
+
{step === WIDGET_STEP.Transfer && <Transfer poolInfo={poolInfo} />}
|
|
70
|
+
{step === WIDGET_STEP.Done && (
|
|
71
|
+
<Done poolInfo={poolInfo} handleAction={handleClose} />
|
|
72
|
+
)}
|
|
73
|
+
{step === WIDGET_STEP.Error && (
|
|
74
|
+
<ErrorModal
|
|
75
|
+
title={title}
|
|
76
|
+
errorReason='Sorry there was an error'
|
|
77
|
+
errorMessage={errorMessage}
|
|
78
|
+
handleOk={handleClose}
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
81
|
+
</WidgetWrapper>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
@@ -68,13 +68,18 @@ export function ChooseAmount({
|
|
|
68
68
|
lpConfig.withdrawalLockoutPeriodInDays * SECONDS_IN_A_DAY
|
|
69
69
|
if (nextEpochStartTime < lockupEndTime) {
|
|
70
70
|
const lockupEndTimeDayjs = dayjs.unix(lockupEndTime).date(1)
|
|
71
|
+
const withdrawTime = lockupEndTimeDayjs.add(1, 'month')
|
|
71
72
|
dispatch(setStep(WIDGET_STEP.Error))
|
|
72
73
|
dispatch(
|
|
73
74
|
setError({
|
|
74
75
|
errorReason: 'Redemption too soon',
|
|
75
76
|
errorMessage: `Your last deposit was on ${timestampToLL(
|
|
76
77
|
depositRecord!.lastDepositTime.toNumber(),
|
|
77
|
-
)}. You can
|
|
78
|
+
)}. You can begin submitting redemption requests on ${timestampToLL(
|
|
79
|
+
lockupEndTimeDayjs.unix(),
|
|
80
|
+
)}, which can be redeemed starting ${timestampToLL(
|
|
81
|
+
withdrawTime.unix(),
|
|
82
|
+
)}.`,
|
|
78
83
|
}),
|
|
79
84
|
)
|
|
80
85
|
}
|
|
@@ -23,12 +23,14 @@ import { Done } from './3-Done'
|
|
|
23
23
|
*/
|
|
24
24
|
export interface SolanaLendCancelRedemptionProps {
|
|
25
25
|
poolInfo: SolanaPoolInfo
|
|
26
|
+
tranche?: TrancheType
|
|
26
27
|
handleClose: () => void
|
|
27
28
|
handleSuccess?: () => void
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export function SolanaLendCancelRedemption({
|
|
31
32
|
poolInfo,
|
|
33
|
+
tranche,
|
|
32
34
|
handleClose,
|
|
33
35
|
handleSuccess,
|
|
34
36
|
}: SolanaLendCancelRedemptionProps): React.ReactElement | null {
|
|
@@ -41,7 +43,9 @@ export function SolanaLendCancelRedemption({
|
|
|
41
43
|
loading: isLoadingLenderAccounts,
|
|
42
44
|
} = useLenderAccounts(poolInfo.chainId, poolInfo.poolName)
|
|
43
45
|
const { step, errorMessage } = useAppSelector(selectWidgetState)
|
|
44
|
-
const [selectedTranche, setSelectedTranche] = useState<
|
|
46
|
+
const [selectedTranche, setSelectedTranche] = useState<
|
|
47
|
+
TrancheType | undefined
|
|
48
|
+
>(tranche)
|
|
45
49
|
|
|
46
50
|
useEffect(() => {
|
|
47
51
|
if (!step && !isLoadingLenderAccounts) {
|
|
@@ -52,6 +56,11 @@ export function SolanaLendCancelRedemption({
|
|
|
52
56
|
juniorLenderStateAccount?.redemptionRecord.numSharesRequested ?? 0,
|
|
53
57
|
)
|
|
54
58
|
|
|
59
|
+
if (selectedTranche) {
|
|
60
|
+
dispatch(setStep(WIDGET_STEP.Transfer))
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
if (
|
|
56
65
|
juniorTrancheSharesRequested.gtn(0) &&
|
|
57
66
|
seniorTrancheSharesRequested.lten(0)
|
|
@@ -83,6 +92,7 @@ export function SolanaLendCancelRedemption({
|
|
|
83
92
|
isLoadingLenderAccounts,
|
|
84
93
|
seniorLenderStateAccount?.redemptionRecord.numSharesRequested,
|
|
85
94
|
juniorLenderStateAccount?.redemptionRecord.numSharesRequested,
|
|
95
|
+
selectedTranche,
|
|
86
96
|
])
|
|
87
97
|
|
|
88
98
|
const title = 'Cancel Redemption'
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { formatMoney, SolanaPoolInfo, timeUtil } from '@huma-finance/shared'
|
|
2
2
|
import { SolanaPoolState } from '@huma-finance/web-shared'
|
|
3
|
-
import moment from 'moment'
|
|
4
3
|
import React from 'react'
|
|
5
4
|
|
|
5
|
+
import dayjs from 'dayjs'
|
|
6
6
|
import { selectWidgetState } from '../../../store/widgets.selectors'
|
|
7
7
|
import { useAppSelector } from '../../../hooks/useRedux'
|
|
8
8
|
import { SolanaTxDoneModal } from '../../SolanaTxDoneModal'
|
|
@@ -26,14 +26,16 @@ export function Success({
|
|
|
26
26
|
]
|
|
27
27
|
|
|
28
28
|
const getSubContent = () => {
|
|
29
|
-
const
|
|
30
|
-
poolState.withdrawalLockupPeriodDays,
|
|
31
|
-
|
|
32
|
-
)
|
|
29
|
+
const lockupEndTime = dayjs()
|
|
30
|
+
.add(poolState.withdrawalLockupPeriodDays ?? 0, 'day')
|
|
31
|
+
.date(1)
|
|
32
|
+
const withdrawTime = lockupEndTime.add(1, 'month')
|
|
33
33
|
return [
|
|
34
|
-
`
|
|
35
|
-
|
|
36
|
-
)}
|
|
34
|
+
`You can begin submitting redemption requests on ${timeUtil.timestampToLL(
|
|
35
|
+
lockupEndTime.unix(),
|
|
36
|
+
)}, which can be redeemed starting ${timeUtil.timestampToLL(
|
|
37
|
+
withdrawTime.unix(),
|
|
38
|
+
)}.`,
|
|
37
39
|
]
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
import { sendTxAtom } from '@huma-finance/web-shared'
|
|
10
10
|
import { useWeb3React } from '@web3-react/core'
|
|
11
11
|
import { useAtom } from 'jotai'
|
|
12
|
-
import moment from 'moment'
|
|
13
12
|
import React, { useCallback, useEffect, useState } from 'react'
|
|
14
13
|
import { useDispatch } from 'react-redux'
|
|
15
14
|
|
|
15
|
+
import dayjs from 'dayjs'
|
|
16
16
|
import { Campaign } from '.'
|
|
17
17
|
import {
|
|
18
18
|
useDoesChainSupportNotifi,
|
|
@@ -90,14 +90,16 @@ export function Success({
|
|
|
90
90
|
]
|
|
91
91
|
|
|
92
92
|
const getSubContent = () => {
|
|
93
|
-
const
|
|
94
|
-
lpConfig.withdrawalLockoutPeriodInDays,
|
|
95
|
-
|
|
96
|
-
)
|
|
93
|
+
const lockupEndTime = dayjs()
|
|
94
|
+
.add(lpConfig.withdrawalLockoutPeriodInDays, 'day')
|
|
95
|
+
.date(1)
|
|
96
|
+
const withdrawTime = lockupEndTime.add(1, 'month')
|
|
97
97
|
return [
|
|
98
|
-
`
|
|
99
|
-
|
|
100
|
-
)}
|
|
98
|
+
`You can begin submitting redemption requests on ${timeUtil.timestampToLL(
|
|
99
|
+
lockupEndTime.unix(),
|
|
100
|
+
)}, which can be redeemed starting ${timeUtil.timestampToLL(
|
|
101
|
+
withdrawTime.unix(),
|
|
102
|
+
)}.`,
|
|
101
103
|
]
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -25,5 +25,10 @@ export function Notifications({
|
|
|
25
25
|
}
|
|
26
26
|
}, [campaign, dispatch, handleAction])
|
|
27
27
|
|
|
28
|
-
return
|
|
28
|
+
return (
|
|
29
|
+
<NotifiSubscriptionModal
|
|
30
|
+
successText={campaign ? 'VIEW POINTS' : undefined}
|
|
31
|
+
handleSuccess={handleUserAction}
|
|
32
|
+
/>
|
|
33
|
+
)
|
|
29
34
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { arrayify } from '@ethersproject/bytes'
|
|
2
|
+
import { ChainEnum, getBlockchainConfigFromChain } from '@huma-finance/shared'
|
|
3
|
+
import { NotifiContextProvider } from '@notifi-network/notifi-react'
|
|
4
|
+
import { useWeb3React } from '@web3-react/core'
|
|
5
|
+
import { providers } from 'ethers'
|
|
6
|
+
import React, { useMemo } from 'react'
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
chainId: number | undefined
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
children?: any
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function NotifiContextWrapper({
|
|
15
|
+
chainId,
|
|
16
|
+
children,
|
|
17
|
+
}: Props): React.ReactElement | null {
|
|
18
|
+
const { account, provider } = useWeb3React()
|
|
19
|
+
const signer = useMemo(() => {
|
|
20
|
+
if (provider instanceof providers.JsonRpcProvider) {
|
|
21
|
+
return provider.getSigner()
|
|
22
|
+
}
|
|
23
|
+
return undefined
|
|
24
|
+
}, [provider])
|
|
25
|
+
|
|
26
|
+
if (account == null || signer == null || chainId == null) {
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let cardId = ''
|
|
31
|
+
if (chainId === ChainEnum.Celo || chainId === ChainEnum.Alfajores) {
|
|
32
|
+
cardId = process.env.REACT_APP_NOTIFI_CONFIG_ID_CELO ?? ''
|
|
33
|
+
} else if (chainId === ChainEnum.Polygon || chainId === ChainEnum.Amoy) {
|
|
34
|
+
cardId = process.env.REACT_APP_NOTIFI_CONFIG_ID_POLYGON ?? ''
|
|
35
|
+
} else if (
|
|
36
|
+
chainId === ChainEnum.Scroll ||
|
|
37
|
+
chainId === ChainEnum.ScrollSepolia
|
|
38
|
+
) {
|
|
39
|
+
cardId = process.env.REACT_APP_NOTIFI_CONFIG_ID_SCROLL ?? ''
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<NotifiContextProvider
|
|
44
|
+
tenantId='humafinanceprod'
|
|
45
|
+
env='Production'
|
|
46
|
+
signMessage={async (message: Uint8Array) => {
|
|
47
|
+
const result = await signer.signMessage(message)
|
|
48
|
+
return arrayify(result)
|
|
49
|
+
}}
|
|
50
|
+
walletPublicKey={account}
|
|
51
|
+
walletBlockchain={getBlockchainConfigFromChain(chainId)}
|
|
52
|
+
cardId={cardId}
|
|
53
|
+
>
|
|
54
|
+
{children}
|
|
55
|
+
</NotifiContextProvider>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
import { getBlockchainConfigFromChain } from '@huma-finance/shared'
|
|
2
1
|
import { txAtom } from '@huma-finance/web-shared'
|
|
3
2
|
import { Box, css, TextField, Typography, useTheme } from '@mui/material'
|
|
4
|
-
import {
|
|
5
|
-
BroadcastEventTypeItem,
|
|
6
|
-
CardConfigItemV1,
|
|
7
|
-
DirectPushEventTypeItem,
|
|
8
|
-
EventTypeItem,
|
|
9
|
-
NotifiFrontendClient,
|
|
10
|
-
SignMessageParams,
|
|
11
|
-
Uint8SignMessageFunction,
|
|
12
|
-
} from '@notifi-network/notifi-frontend-client'
|
|
13
|
-
import { useWeb3React } from '@web3-react/core'
|
|
14
|
-
import { ethers } from 'ethers'
|
|
15
3
|
import { useResetAtom } from 'jotai/utils'
|
|
16
|
-
import React, { useCallback, useState } from 'react'
|
|
4
|
+
import React, { useCallback, useEffect, useState } from 'react'
|
|
17
5
|
|
|
18
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
FtuStage,
|
|
8
|
+
useNotifiFrontendClientContext,
|
|
9
|
+
useNotifiTargetContext,
|
|
10
|
+
useNotifiTenantConfigContext,
|
|
11
|
+
useNotifiTopicContext,
|
|
12
|
+
useNotifiUserSettingContext,
|
|
13
|
+
} from '@notifi-network/notifi-react'
|
|
14
|
+
import { NotifiFrontendClient } from '@notifi-network/notifi-frontend-client'
|
|
19
15
|
import { useAppDispatch } from '../../hooks/useRedux'
|
|
20
16
|
import { resetState } from '../../store/widgets.reducers'
|
|
21
17
|
import { BottomButton } from '../BottomButton'
|
|
@@ -24,83 +20,48 @@ import { LoadingModal } from '../LoadingModal'
|
|
|
24
20
|
import { WrapperModal } from '../WrapperModal'
|
|
25
21
|
|
|
26
22
|
type Props = {
|
|
23
|
+
successText?: string
|
|
27
24
|
handleSuccess: () => void
|
|
28
25
|
}
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
if (eventType.type === 'broadcast') {
|
|
40
|
-
const broadcastEventType = eventType as BroadcastEventTypeItem
|
|
41
|
-
return (
|
|
42
|
-
broadcastEventType.broadcastId as {
|
|
43
|
-
value: string
|
|
44
|
-
}
|
|
45
|
-
).value
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return ''
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async function fetchEventTypes(
|
|
52
|
-
notifiClient: NotifiFrontendClient,
|
|
53
|
-
): Promise<(EventTypeItem & { enabled: boolean })[]> {
|
|
54
|
-
const subscribedAlerts = await notifiClient.getAlerts()
|
|
55
|
-
|
|
56
|
-
const subscriptionConfig = (await notifiClient.fetchSubscriptionCard({
|
|
57
|
-
id: process.env.REACT_APP_NOTIFI_CONFIG_ID ?? '',
|
|
58
|
-
type: 'SUBSCRIPTION_CARD',
|
|
59
|
-
})) as CardConfigItemV1
|
|
60
|
-
|
|
61
|
-
const eventTypes = subscriptionConfig?.eventTypes?.map(
|
|
62
|
-
(eventType): EventTypeItem & { enabled: boolean } => {
|
|
63
|
-
const eventTypeId = getIdFromEventType(eventType)
|
|
64
|
-
let enabled = false
|
|
65
|
-
// Check whether the user is subscribed to the event
|
|
66
|
-
const subscribedAlert = subscribedAlerts?.find(
|
|
67
|
-
(alert) => alert.filterOptions.indexOf(eventTypeId) >= 0,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
if (subscribedAlert) {
|
|
71
|
-
enabled = true
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
...eventType,
|
|
76
|
-
enabled,
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
return eventTypes
|
|
27
|
+
const validateDefaultTargetGroup = async (
|
|
28
|
+
frontendClient: NotifiFrontendClient,
|
|
29
|
+
) => {
|
|
30
|
+
// NOTE: this extra request is necessary as the targetGroupId state in NotifiTargetContext will not be updated constantly right after login
|
|
31
|
+
const targetGroup = (
|
|
32
|
+
await frontendClient?.fetchFusionData()
|
|
33
|
+
)?.targetGroup?.find((group) => group?.name === 'Default')
|
|
34
|
+
return !!targetGroup
|
|
82
35
|
}
|
|
83
36
|
|
|
84
37
|
export function NotifiSubscriptionModal({
|
|
38
|
+
successText,
|
|
85
39
|
handleSuccess,
|
|
86
40
|
}: Props): React.ReactElement {
|
|
87
41
|
const theme = useTheme()
|
|
88
42
|
const reset = useResetAtom(txAtom)
|
|
89
43
|
const dispatch = useAppDispatch()
|
|
90
|
-
const { account, chainId, provider } = useWeb3React()
|
|
91
44
|
const [showSuccessScreen, setShowSuccessScreen] = useState<boolean>(false)
|
|
92
45
|
const [isLoading, setIsLoading] = useState<boolean>(false)
|
|
93
46
|
const [emailAddress, setEmailAddress] = useState<string>('')
|
|
94
47
|
const [emailValid, setEmailValid] = useState<boolean>()
|
|
95
|
-
const {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
48
|
+
const {
|
|
49
|
+
frontendClientStatus: { isInitialized, isAuthenticated, isExpired },
|
|
50
|
+
frontendClient,
|
|
51
|
+
login,
|
|
52
|
+
} = useNotifiFrontendClientContext()
|
|
53
|
+
const { fusionEventTopics } = useNotifiTenantConfigContext()
|
|
54
|
+
const { subscribeAlertsDefault } = useNotifiTopicContext()
|
|
55
|
+
const {
|
|
56
|
+
targetDocument: { targetGroupId },
|
|
57
|
+
updateTargetInputs,
|
|
58
|
+
renewTargetGroup,
|
|
59
|
+
} = useNotifiTargetContext()
|
|
60
|
+
const {
|
|
61
|
+
ftuStage,
|
|
62
|
+
isLoading: isLoadingFtuStage,
|
|
63
|
+
updateFtuStage,
|
|
64
|
+
} = useNotifiUserSettingContext()
|
|
104
65
|
|
|
105
66
|
const handleEmailAddressChange = (
|
|
106
67
|
event: React.ChangeEvent<HTMLInputElement>,
|
|
@@ -110,43 +71,89 @@ export function NotifiSubscriptionModal({
|
|
|
110
71
|
setEmailAddress(event.target.value)
|
|
111
72
|
}
|
|
112
73
|
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
async function subscribe() {
|
|
76
|
+
if (
|
|
77
|
+
!isInitialized ||
|
|
78
|
+
!isAuthenticated ||
|
|
79
|
+
!targetGroupId ||
|
|
80
|
+
isLoadingFtuStage
|
|
81
|
+
) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// If a user is authenticated but already finished with the FTU (First Time User) setup
|
|
86
|
+
// (AKA their login expired and they logged back in), then we can skip the subscription step.
|
|
87
|
+
if (ftuStage !== FtuStage.Done) {
|
|
88
|
+
await updateTargetInputs('email', { value: emailAddress! })
|
|
89
|
+
// Authorize this email address for this wallet
|
|
90
|
+
|
|
91
|
+
if (!targetGroupId) {
|
|
92
|
+
setIsLoading(false)
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await subscribeAlertsDefault(fusionEventTopics, targetGroupId)
|
|
97
|
+
await updateFtuStage(FtuStage.Done)
|
|
98
|
+
|
|
99
|
+
const targetGroup = (
|
|
100
|
+
await frontendClient?.fetchFusionData()
|
|
101
|
+
)?.targetGroup?.find((group) => group?.name === 'Default')
|
|
102
|
+
const emailTarget = targetGroup?.emailTargets?.[0]
|
|
103
|
+
if (emailTarget && !emailTarget.isConfirmed) {
|
|
104
|
+
await frontendClient.sendEmailTargetVerification({
|
|
105
|
+
targetId: emailTarget.id,
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setShowSuccessScreen(true)
|
|
111
|
+
setIsLoading(false)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
subscribe()
|
|
115
|
+
}, [
|
|
116
|
+
isInitialized,
|
|
117
|
+
isAuthenticated,
|
|
118
|
+
targetGroupId,
|
|
119
|
+
updateTargetInputs,
|
|
120
|
+
emailAddress,
|
|
121
|
+
subscribeAlertsDefault,
|
|
122
|
+
fusionEventTopics,
|
|
123
|
+
updateFtuStage,
|
|
124
|
+
isLoadingFtuStage,
|
|
125
|
+
ftuStage,
|
|
126
|
+
frontendClient,
|
|
127
|
+
])
|
|
128
|
+
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
const loginIfExpired = async () => {
|
|
131
|
+
if (isExpired) {
|
|
132
|
+
await login()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
loginIfExpired()
|
|
137
|
+
}, [isExpired, login])
|
|
138
|
+
|
|
113
139
|
const logInAndSubscribe = async (): Promise<void> => {
|
|
114
|
-
if (
|
|
140
|
+
if (!isAuthenticated) {
|
|
115
141
|
setIsLoading(true)
|
|
116
142
|
|
|
117
143
|
// Ask user to sign a message to authenticate
|
|
118
144
|
try {
|
|
119
|
-
await
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
145
|
+
await login()
|
|
146
|
+
|
|
147
|
+
const isDefaultTargetExist = await validateDefaultTargetGroup(
|
|
148
|
+
frontendClient,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if (!isDefaultTargetExist) {
|
|
152
|
+
await renewTargetGroup()
|
|
153
|
+
}
|
|
123
154
|
} catch (e) {
|
|
124
155
|
setIsLoading(false)
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Fetch all event types
|
|
129
|
-
const fetchedEventTypes = await fetchEventTypes(notifiClient)
|
|
130
|
-
|
|
131
|
-
// Authorize this email address for this wallet
|
|
132
|
-
await notifiClient.ensureTargetGroup({
|
|
133
|
-
name: 'Default',
|
|
134
|
-
emailAddress: emailAddress!,
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
// Intentionally running this in serial because the Notifi ensureAlert can't handle
|
|
138
|
-
// multiple calls. Notified their team to fix this.
|
|
139
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
140
|
-
for (const eventType of fetchedEventTypes) {
|
|
141
|
-
// eslint-disable-next-line no-await-in-loop
|
|
142
|
-
await notifiClient.ensureAlert({
|
|
143
|
-
eventType,
|
|
144
|
-
inputs: {},
|
|
145
|
-
})
|
|
146
156
|
}
|
|
147
|
-
|
|
148
|
-
setShowSuccessScreen(true)
|
|
149
|
-
setIsLoading(false)
|
|
150
157
|
}
|
|
151
158
|
}
|
|
152
159
|
|
|
@@ -196,7 +203,7 @@ export function NotifiSubscriptionModal({
|
|
|
196
203
|
<CheckIcon />
|
|
197
204
|
</Box>
|
|
198
205
|
<BottomButton variant='contained' onClick={handleCloseModal}>
|
|
199
|
-
DONE
|
|
206
|
+
{successText ?? 'DONE'}
|
|
200
207
|
</BottomButton>
|
|
201
208
|
</WrapperModal>
|
|
202
209
|
)
|
|
@@ -204,11 +211,7 @@ export function NotifiSubscriptionModal({
|
|
|
204
211
|
|
|
205
212
|
return (
|
|
206
213
|
<WrapperModal title='Connect Your Email'>
|
|
207
|
-
<Typography
|
|
208
|
-
variant='body2'
|
|
209
|
-
textAlign='justify'
|
|
210
|
-
margin={theme.spacing(6, 0, 4, 0)}
|
|
211
|
-
>
|
|
214
|
+
<Typography variant='body2' margin={theme.spacing(6, 0, 4, 0)}>
|
|
212
215
|
Connect your emails to receive important update about your account.
|
|
213
216
|
</Typography>
|
|
214
217
|
<Box css={styles.inputWrapper}>
|
|
@@ -218,7 +221,9 @@ export function NotifiSubscriptionModal({
|
|
|
218
221
|
type='email'
|
|
219
222
|
value={emailAddress}
|
|
220
223
|
onChange={handleEmailAddressChange}
|
|
221
|
-
variant='
|
|
224
|
+
variant='outlined'
|
|
225
|
+
color='primary'
|
|
226
|
+
focused
|
|
222
227
|
/>
|
|
223
228
|
</Box>
|
|
224
229
|
<Box css={styles.disclaimer}>
|
|
@@ -228,7 +233,7 @@ export function NotifiSubscriptionModal({
|
|
|
228
233
|
<BottomButton
|
|
229
234
|
variant='contained'
|
|
230
235
|
onClick={logInAndSubscribe}
|
|
231
|
-
disabled={!emailValid || isLoading}
|
|
236
|
+
disabled={!emailValid || isLoading || !isInitialized}
|
|
232
237
|
>
|
|
233
238
|
CONNECT EMAIL
|
|
234
239
|
</BottomButton>
|
|
@@ -1,37 +1,31 @@
|
|
|
1
1
|
import { Box, useTheme } from '@mui/material'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
CreditEvent,
|
|
5
|
-
POOL_NAME,
|
|
6
|
-
POOL_TYPE,
|
|
7
|
-
PoolMap,
|
|
8
|
-
} from '@huma-finance/shared'
|
|
2
|
+
import { POOL_NAME, POOL_TYPE, PoolMap } from '@huma-finance/shared'
|
|
9
3
|
import { useFactoring } from '@huma-finance/web-shared'
|
|
10
4
|
import React from 'react'
|
|
11
5
|
|
|
12
|
-
import {
|
|
13
|
-
import { Activity } from '../Activity'
|
|
14
|
-
import { ApolloWrapper } from '../ApolloWrapper'
|
|
6
|
+
import { EmotionJSX } from '@emotion/react/types/jsx-namespace'
|
|
15
7
|
import { StreamFactoringBorrow } from '../StreamFactoring/borrow'
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
|
|
9
|
+
export type StreamItem = {
|
|
10
|
+
id: string
|
|
11
|
+
icon: EmotionJSX.Element
|
|
12
|
+
token: string
|
|
13
|
+
tokenId: string
|
|
14
|
+
payer: string
|
|
15
|
+
flowrate: string
|
|
16
|
+
flowrateMonth: string
|
|
17
|
+
}
|
|
18
18
|
|
|
19
19
|
export function SuperfluidFactoring(): React.ReactElement {
|
|
20
20
|
const theme = useTheme()
|
|
21
21
|
const poolName = POOL_NAME.Superfluid
|
|
22
|
-
const { chainId } = useWeb3React()
|
|
23
22
|
const {
|
|
24
|
-
accountStats,
|
|
25
|
-
accountHasActiveLoan,
|
|
26
23
|
actionType,
|
|
27
|
-
loading,
|
|
28
24
|
poolInfo,
|
|
29
25
|
modalIsOpen,
|
|
30
26
|
selectedItem,
|
|
31
27
|
styles,
|
|
32
|
-
handleGetPaid,
|
|
33
28
|
handleGetPaidSuccess,
|
|
34
|
-
handlePayManually,
|
|
35
29
|
handleClose,
|
|
36
30
|
} = useFactoring<StreamItem>(poolName, POOL_TYPE.Stream)
|
|
37
31
|
|
|
@@ -41,34 +35,6 @@ export function SuperfluidFactoring(): React.ReactElement {
|
|
|
41
35
|
<Box css={styles.description} marginBottom={theme.spacing(6)}>
|
|
42
36
|
{PoolMap.Stream[poolName]?.borrowDesc}
|
|
43
37
|
</Box>
|
|
44
|
-
{poolInfo && (
|
|
45
|
-
<SuperfluidFactoredList
|
|
46
|
-
poolInfo={poolInfo}
|
|
47
|
-
handlePayManually={handlePayManually}
|
|
48
|
-
loading={loading && actionType === 'payment'}
|
|
49
|
-
accountStats={accountStats}
|
|
50
|
-
/>
|
|
51
|
-
)}
|
|
52
|
-
<ApolloWrapper uri={poolInfo?.extra?.subgraph!}>
|
|
53
|
-
<SuperfluidUpcomingList
|
|
54
|
-
poolInfo={poolInfo}
|
|
55
|
-
handleGetPaid={handleGetPaid}
|
|
56
|
-
hasActiveLoan={accountHasActiveLoan}
|
|
57
|
-
loading={loading && actionType === 'borrow'}
|
|
58
|
-
/>
|
|
59
|
-
</ApolloWrapper>
|
|
60
|
-
<ApolloWrapper uri={SubgraphService.getSubgraphUrlForChainId(chainId!)}>
|
|
61
|
-
{poolInfo && (
|
|
62
|
-
<Activity
|
|
63
|
-
poolInfo={poolInfo}
|
|
64
|
-
targetEvents={[
|
|
65
|
-
CreditEvent.DrawdownMadeWithReceivable,
|
|
66
|
-
CreditEvent.PaymentMade,
|
|
67
|
-
CreditEvent.ReceivedPaymentProcessed,
|
|
68
|
-
]}
|
|
69
|
-
/>
|
|
70
|
-
)}
|
|
71
|
-
</ApolloWrapper>
|
|
72
38
|
{poolInfo && selectedItem && actionType === 'borrow' && (
|
|
73
39
|
<StreamFactoringBorrow
|
|
74
40
|
poolName={POOL_NAME.Superfluid}
|