Skip to content

Commit dfc43a9

Browse files
CP-10738: create onramp widget (#2911)
1 parent d99979f commit dfc43a9

30 files changed

+1115
-343
lines changed

packages/core-mobile/app/contexts/DeeplinkContext/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ export const ACTIONS = {
3232
WC: 'wc',
3333
StakeComplete: StakeActions.StakeComplete,
3434
Portfolio: 'portfolio',
35-
WatchList: 'watchlist'
35+
WatchList: 'watchlist',
36+
OnrampCompleted: 'onrampCompleted',
37+
OfframpCompleted: 'offrampCompleted'
3638
}
3739

3840
export type NotificationData = { [p: string]: string | number | object }

packages/core-mobile/app/contexts/DeeplinkContext/utils/handleDeeplink.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { showSnackbar } from 'new/common/utils/toast'
88
import { router } from 'expo-router'
99
import { History } from 'store/browser'
1010
import { navigateFromDeeplinkUrl } from 'utils/navigateFromDeeplink'
11+
import { dismissMeldStack } from 'features/buyOnramp/utils'
1112
import { MarketType } from 'store/watchlist'
1213
import { ACTIONS, DeepLink, PROTOCOLS } from '../types'
1314

@@ -54,7 +55,7 @@ export const handleDeeplink = ({
5455
break
5556
}
5657
case PROTOCOLS.CORE: {
57-
const { host: action, pathname } = url
58+
const { host: action, pathname, searchParams } = url
5859
if (action === ACTIONS.WC) {
5960
startWalletConnectSession({ url, dispatch, deeplink })
6061
} else if (action === ACTIONS.Portfolio) {
@@ -70,6 +71,11 @@ export const handleDeeplink = ({
7071
navigateFromDeeplinkUrl(
7172
`/trackTokenDetail?tokenId=${coingeckoId}&marketType=${MarketType.SEARCH}`
7273
)
74+
} else if (
75+
action === ACTIONS.OnrampCompleted ||
76+
action === ACTIONS.OfframpCompleted
77+
) {
78+
dismissMeldStack(action, searchParams)
7379
} else {
7480
const path = deeplink.url.split(':/')[1]
7581
path && navigateFromDeeplinkUrl(path)
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import React from 'react'
2+
import { Icons, Image, useTheme, View } from '@avalabs/k2-alpine'
3+
import { SvgProps } from 'react-native-svg'
4+
import { PaymentMethods } from '../consts'
5+
import { SearchPaymentMethods } from '../types'
6+
7+
const DEFAULT_SIZE = 24
8+
9+
export const PaymentMethodIcon = ({
10+
paymentMethod,
11+
size = DEFAULT_SIZE
12+
}: {
13+
paymentMethod: SearchPaymentMethods
14+
size?: number
15+
}): React.JSX.Element | undefined => {
16+
const {
17+
theme: { colors, isDark }
18+
} = useTheme()
19+
const Icon = paymentMethod.paymentMethod
20+
? PAYMENT_METHOD_TO_ICON[paymentMethod.paymentMethod]
21+
: undefined
22+
return Icon ? (
23+
<View
24+
sx={{
25+
width: size,
26+
height: size,
27+
justifyContent: 'center',
28+
alignItems: 'center'
29+
}}>
30+
<Icon
31+
testID={`icon__${paymentMethod.paymentMethod}`}
32+
width={size}
33+
height={size}
34+
color={colors.$textPrimary}
35+
/>
36+
</View>
37+
) : (
38+
<Image
39+
accessibilityRole="image"
40+
sx={{ width: size, height: size }}
41+
source={{
42+
uri: isDark
43+
? paymentMethod?.logos?.dark ?? ''
44+
: paymentMethod?.logos?.light ?? ''
45+
}}
46+
/>
47+
)
48+
}
49+
50+
const PAYMENT_METHOD_TO_ICON: Record<
51+
PaymentMethods,
52+
React.FC<SvgProps> | undefined
53+
> = {
54+
[PaymentMethods.APPLEPAY_EU]: Icons.Custom.ApplePay,
55+
[PaymentMethods.APPLE_PAY]: Icons.Custom.ApplePay,
56+
[PaymentMethods.PAYPAL]: Icons.Custom.PayPal,
57+
[PaymentMethods.CREDIT_DEBIT_CARD]: Icons.Custom.CreditCard,
58+
[PaymentMethods.GOOGLE_PAY]: Icons.Custom.GooglePay,
59+
[PaymentMethods.BINANCE_CASH_BALANCE]: Icons.Custom.Binance,
60+
[PaymentMethods.BINANCE_P2P]: Icons.Custom.Binance,
61+
[PaymentMethods.COINBASE_CASH_BALANCE]: Icons.Custom.Coinbase,
62+
[PaymentMethods.REVOLUT_PAY]: Icons.Custom.Revolut,
63+
64+
[PaymentMethods.BR_BANK_TRANSFER]: Icons.Custom.BankTransfer,
65+
[PaymentMethods.UAE_BANK_TRANSFER]: Icons.Custom.BankTransfer,
66+
[PaymentMethods.VN_BANK_TRANSFER]: Icons.Custom.BankTransfer,
67+
[PaymentMethods.NG_BANK_TRANSFER]: Icons.Custom.BankTransfer,
68+
[PaymentMethods.TH_BANK_TRANSFER]: Icons.Custom.BankTransfer,
69+
[PaymentMethods.PH_BANK_TRANSFER]: Icons.Custom.BankTransfer,
70+
[PaymentMethods.PE_BANK_TRANSFER]: Icons.Custom.BankTransfer,
71+
[PaymentMethods.MY_BANK_TRANSFER]: Icons.Custom.BankTransfer,
72+
[PaymentMethods.MX_BANK_TRANSFER]: Icons.Custom.BankTransfer,
73+
[PaymentMethods.LOCAL_BANK_TRANSFER]: Icons.Custom.BankTransfer,
74+
[PaymentMethods.ID_BANK_TRANSFER]: Icons.Custom.BankTransfer,
75+
[PaymentMethods.IN_BANK_TRANSFER]: Icons.Custom.BankTransfer,
76+
[PaymentMethods.CO_BANK_TRANSFER]: Icons.Custom.BankTransfer,
77+
[PaymentMethods.CL_BANK_TRANSFER]: Icons.Custom.BankTransfer,
78+
[PaymentMethods.AR_BANK_TRANSFER]: Icons.Custom.BankTransfer,
79+
[PaymentMethods.CH_BANK_TRANSFER]: Icons.Custom.BankTransfer,
80+
[PaymentMethods.DE_BANK_TRANSFER]: Icons.Custom.BankTransfer,
81+
[PaymentMethods.ES_BANK_TRANSFER]: Icons.Custom.BankTransfer,
82+
[PaymentMethods.FR_BANK_TRANSFER]: Icons.Custom.BankTransfer,
83+
[PaymentMethods.IT_BANK_TRANSFER]: Icons.Custom.BankTransfer,
84+
[PaymentMethods.NL_BANK_TRANSFER]: Icons.Custom.BankTransfer,
85+
86+
[PaymentMethods.TODITO_CASH]: Icons.Custom.Cash,
87+
[PaymentMethods.PE_CASH]: Icons.Custom.Cash,
88+
[PaymentMethods.MX_CASH]: Icons.Custom.Cash,
89+
[PaymentMethods.EC_CASH]: Icons.Custom.Cash,
90+
[PaymentMethods.CR_CASH]: Icons.Custom.Cash,
91+
[PaymentMethods.CO_CASH]: Icons.Custom.Cash,
92+
[PaymentMethods.DO_CASH]: Icons.Custom.Cash,
93+
[PaymentMethods.GT_CASH]: Icons.Custom.Cash,
94+
[PaymentMethods.HN_CASH]: Icons.Custom.Cash,
95+
[PaymentMethods.NI_CASH]: Icons.Custom.Cash,
96+
[PaymentMethods.PA_CASH]: Icons.Custom.Cash,
97+
[PaymentMethods.PH_CASH]: Icons.Custom.Cash,
98+
[PaymentMethods.PY_CASH]: Icons.Custom.Cash,
99+
100+
// if there is no custom logo for the payment method, show the default logo provided by Meld
101+
[PaymentMethods.SPEI]: undefined,
102+
[PaymentMethods.PAYMAYA]: undefined,
103+
[PaymentMethods.GCASH]: undefined,
104+
[PaymentMethods.GRABPAY]: undefined,
105+
[PaymentMethods.THAI_QR]: undefined,
106+
[PaymentMethods.FAST]: undefined,
107+
[PaymentMethods.ROBINHOOD_BUYING_POWER]: undefined,
108+
[PaymentMethods.QRIS]: undefined,
109+
[PaymentMethods.OVO]: undefined,
110+
[PaymentMethods.UPI]: undefined,
111+
[PaymentMethods.IMPS]: undefined,
112+
[PaymentMethods.MOBILE_MONEY]: undefined,
113+
[PaymentMethods.SEPA]: undefined,
114+
[PaymentMethods.PIX]: undefined,
115+
[PaymentMethods.ACH]: undefined,
116+
[PaymentMethods.KHIPU]: undefined,
117+
[PaymentMethods.PSE]: undefined,
118+
[PaymentMethods.VIETQR]: undefined,
119+
[PaymentMethods.VIETTELPAY]: undefined,
120+
[PaymentMethods.OPEN_BANKING]: undefined,
121+
[PaymentMethods.INSTAPAY]: undefined,
122+
[PaymentMethods.ASTROPAY]: undefined,
123+
[PaymentMethods.IDEAL]: undefined,
124+
[PaymentMethods.DUITNOW]: undefined,
125+
[PaymentMethods.DANA]: undefined,
126+
[PaymentMethods.SKRILL]: undefined,
127+
[PaymentMethods.SHOPEEPAY]: undefined,
128+
[PaymentMethods.PICPAY]: undefined,
129+
[PaymentMethods.PAYID]: undefined,
130+
[PaymentMethods.BANCONTACT]: undefined,
131+
[PaymentMethods.BRIVA]: undefined,
132+
[PaymentMethods.EPS]: undefined,
133+
[PaymentMethods.COINS_PH]: undefined,
134+
[PaymentMethods.FPX]: undefined,
135+
[PaymentMethods.NETELLER]: undefined,
136+
[PaymentMethods.PAY_NOW]: undefined,
137+
[PaymentMethods.NEFT]: undefined,
138+
[PaymentMethods.MULTIBANCO]: undefined,
139+
[PaymentMethods.MOMO]: undefined,
140+
[PaymentMethods.MPESA]: undefined,
141+
[PaymentMethods.MANDIRIVA]: undefined,
142+
[PaymentMethods.SAME_DAY_ACH]: undefined,
143+
[PaymentMethods.STP]: undefined,
144+
[PaymentMethods.SOFORT]: undefined,
145+
[PaymentMethods.SWIFT]: undefined,
146+
[PaymentMethods.TOUCH_N_GO]: undefined,
147+
[PaymentMethods.UK_FASTER_PAYMENTS]: undefined,
148+
[PaymentMethods.QRPH]: undefined,
149+
[PaymentMethods.INTERAC]: undefined,
150+
[PaymentMethods.ZALOPAY]: undefined,
151+
[PaymentMethods.PROMPTPAY]: undefined,
152+
[PaymentMethods.BLIK]: undefined
153+
}

packages/core-mobile/app/new/features/buyOnramp/components/ServiceProviderIcon.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,13 @@ export const ServiceProviderIcon = ({
2323
borderColor: colors.$borderPrimary,
2424
borderWidth: 1,
2525
borderRadius: 100,
26-
width: DEFAULT_SIZE,
27-
height: DEFAULT_SIZE,
26+
width: size,
27+
height: size,
2828
justifyContent: 'center',
2929
alignItems: 'center',
3030
backgroundColor: colors.$surfaceSecondary
3131
}}>
32-
<Icon
33-
testID={`icon__${serviceProvider}`}
34-
width={size}
35-
height={size}
36-
color={'green'}
37-
/>
32+
<Icon testID={`icon__${serviceProvider}`} width={size} height={size} />
3833
</View>
3934
)
4035
)
Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,72 @@
11
import { useQuery, UseQueryResult } from '@tanstack/react-query'
22
import { ReactQueryKeys } from 'consts/reactQueryKeys'
3+
import { selectSelectedCurrency } from 'store/settings/currency'
4+
import { useSelector } from 'react-redux'
35
import MeldService from '../services/MeldService'
4-
import {
5-
CreateCryptoQuote,
6-
CreateCryptoQuoteWithoutCountryCodeParams
7-
} from '../types'
6+
import { CreateCryptoQuote, CreateCryptoQuoteParams } from '../types'
87
import { ServiceProviderCategories } from '../consts'
9-
import { useLocale } from './useLocale'
8+
import { useOnRampPaymentMethod, useOnRampToken } from '../store'
109
import { useSearchServiceProviders } from './useSearchServiceProviders'
10+
import { useSourceAmount } from './useSourceAmount'
1111

1212
export const useCreateCryptoQuote = ({
13+
countryCode,
1314
walletAddress,
14-
sourceAmount,
1515
destinationCurrencyCode,
1616
sourceCurrencyCode
17-
}: CreateCryptoQuoteWithoutCountryCodeParams): UseQueryResult<
17+
}: CreateCryptoQuoteParams): UseQueryResult<
1818
CreateCryptoQuote | undefined,
1919
Error
2020
> => {
21+
const selectedCurrency = useSelector(selectSelectedCurrency)
22+
const [onRampToken] = useOnRampToken()
23+
const [onRampPaymentMethod] = useOnRampPaymentMethod()
2124
const { data: serviceProvidersData } = useSearchServiceProviders({
2225
categories: [ServiceProviderCategories.CRYPTO_ONRAMP]
2326
})
2427
const serviceProviders = serviceProvidersData?.map(
2528
serviceProvider => serviceProvider.serviceProvider
2629
)
27-
const { countryCode } = useLocale()
30+
const { hasValidSourceAmount, sourceAmount } = useSourceAmount()
2831

2932
return useQuery<CreateCryptoQuote | undefined>({
30-
enabled:
31-
sourceAmount !== undefined &&
32-
sourceAmount > 0 &&
33-
destinationCurrencyCode !== '',
3433
queryKey: [
3534
ReactQueryKeys.MELD_CREATE_CRYPTO_QUOTE,
3635
serviceProviders,
3736
countryCode,
3837
walletAddress,
3938
sourceAmount,
4039
destinationCurrencyCode,
41-
sourceCurrencyCode
40+
sourceCurrencyCode,
41+
selectedCurrency,
42+
onRampToken?.currencyCode,
43+
hasValidSourceAmount,
44+
onRampPaymentMethod
4245
],
43-
queryFn: () =>
44-
MeldService.createCryptoQuote({
45-
serviceProviders,
46-
walletAddress,
47-
sourceAmount,
48-
countryCode,
49-
destinationCurrencyCode,
50-
sourceCurrencyCode
51-
})
46+
queryFn: () => {
47+
const hasValidCountry = countryCode !== undefined
48+
const hasSelectedCurrency = selectedCurrency !== undefined
49+
const hasDestinationCurrencyCode =
50+
onRampToken?.currencyCode !== '' &&
51+
onRampToken?.currencyCode !== undefined
52+
53+
if (
54+
hasValidCountry &&
55+
hasSelectedCurrency &&
56+
hasValidSourceAmount &&
57+
hasDestinationCurrencyCode
58+
) {
59+
return MeldService.createCryptoQuote({
60+
serviceProviders,
61+
walletAddress,
62+
sourceAmount,
63+
countryCode,
64+
destinationCurrencyCode,
65+
sourceCurrencyCode,
66+
paymentMethodType: onRampPaymentMethod
67+
})
68+
}
69+
},
70+
staleTime: 1000 * 60 * 1 // 1 minute
5271
})
5372
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { useCallback } from 'react'
2+
import { CreateSessionWidget, CreateSessionWidgetParams } from '../types'
3+
import MeldService from '../services/MeldService'
4+
import { useOnRampPaymentMethod } from '../store'
5+
import { useLocale } from './useLocale'
6+
import { useSourceAmount } from './useSourceAmount'
7+
8+
export const useCreateSessionWidget = ({
9+
sessionType,
10+
sessionData: {
11+
walletAddress,
12+
sourceAmount,
13+
destinationCurrencyCode,
14+
sourceCurrencyCode,
15+
redirectUrl,
16+
serviceProvider
17+
}
18+
}: CreateSessionWidgetParams): {
19+
createSessionWidget: () => Promise<CreateSessionWidget | undefined>
20+
} => {
21+
const { countryCode } = useLocale()
22+
const [onRampPaymentMethod] = useOnRampPaymentMethod()
23+
const { hasValidSourceAmount } = useSourceAmount()
24+
25+
const hasWalletAddress = walletAddress !== undefined
26+
const hasSourceCurrencyCode = sourceCurrencyCode !== ''
27+
const hasDestinationCurrencyCode = destinationCurrencyCode !== ''
28+
const hasSessionType = sessionType !== undefined
29+
const hasServiceProvider = serviceProvider !== undefined
30+
31+
const shouldCreateSessionWidget =
32+
hasValidSourceAmount &&
33+
hasWalletAddress &&
34+
hasSourceCurrencyCode &&
35+
hasDestinationCurrencyCode &&
36+
hasSessionType &&
37+
hasServiceProvider
38+
39+
const createSessionWidget = useCallback(async () => {
40+
if (shouldCreateSessionWidget === false) {
41+
return undefined
42+
}
43+
44+
return MeldService.createSessionWidget({
45+
sessionType,
46+
sessionData: {
47+
walletAddress,
48+
sourceAmount,
49+
countryCode,
50+
destinationCurrencyCode,
51+
sourceCurrencyCode,
52+
redirectUrl,
53+
serviceProvider,
54+
paymentMethodType: onRampPaymentMethod
55+
}
56+
})
57+
}, [
58+
countryCode,
59+
destinationCurrencyCode,
60+
onRampPaymentMethod,
61+
redirectUrl,
62+
serviceProvider,
63+
sessionType,
64+
shouldCreateSessionWidget,
65+
sourceAmount,
66+
sourceCurrencyCode,
67+
walletAddress
68+
])
69+
70+
return {
71+
createSessionWidget
72+
}
73+
}

0 commit comments

Comments
 (0)