Skip to content

Commit 8ebcca8

Browse files
committed
fixup! feat(ramp): add new plugin architecture for fiat on/off ramps
1 parent 0e87220 commit 8ebcca8

File tree

11 files changed

+92
-91
lines changed

11 files changed

+92
-91
lines changed

eslint.config.mjs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,21 +473,20 @@ export default [
473473
'src/plugins/borrow-plugins/plugins/aave/index.ts',
474474
'src/plugins/gui/amountQuotePlugin.ts',
475475
'src/plugins/gui/components/GuiFormField.tsx',
476-
'src/plugins/gui/fiatPlugin.tsx',
476+
477477
'src/plugins/gui/pluginUtils.ts',
478478
'src/plugins/gui/providers/banxaProvider.ts',
479479
'src/plugins/gui/providers/bityProvider.ts',
480480
'src/plugins/gui/providers/ioniaProvider.ts',
481481
'src/plugins/gui/providers/kadoOtcProvider.ts',
482-
'src/plugins/gui/providers/kadoProvider.ts',
483482
'src/plugins/gui/providers/moonpayProvider.ts',
484483
'src/plugins/gui/providers/mtpelerinProvider.ts',
485484

486485
'src/plugins/gui/providers/revolutProvider.ts',
487486
'src/plugins/gui/providers/simplexProvider.ts',
488487
'src/plugins/gui/RewardsCardPlugin.tsx',
489488
'src/plugins/gui/scenes/FiatPluginEnterAmountScene.tsx',
490-
'src/plugins/gui/scenes/FiatPluginWebView.tsx',
489+
491490
'src/plugins/gui/scenes/InfoDisplayScene.tsx',
492491
'src/plugins/gui/scenes/RewardsCardDashboardScene.tsx',
493492
'src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx',

src/actions/DeepLinkingActions.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,14 +282,13 @@ async function handleLink(
282282
const parseWallets = async (): Promise<void> => {
283283
// Try to parse with all wallets
284284
for (const wallet of Object.values(currencyWallets)) {
285+
const { pluginId } = wallet.currencyInfo
285286
// Ignore disabled wallets:
286-
const { keysOnlyMode = false } = SPECIAL_CURRENCY_INFO
287+
const { keysOnlyMode = false } = SPECIAL_CURRENCY_INFO[pluginId] ?? {}
287288
if (keysOnlyMode) return
288-
289-
const { pluginId } = wallet.currencyInfo
290289
const parsedUri = await wallet
291290
.parseUri(link.uri)
292-
.catch(e => undefined)
291+
.catch((_: unknown) => undefined)
293292
if (parsedUri != null) {
294293
const { tokenId = null } = parsedUri
295294
matchingWalletIdsAndUris.push({

src/components/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const queryClient = new QueryClient({
2222
}
2323
})
2424

25-
function MainApp() {
25+
function MainApp(): React.ReactElement {
2626
const handleBeforeCapture = useHandler((scope: Scope) => {
2727
scope.setLevel('fatal')
2828
scope.setTag('handled', false)

src/components/modals/WalletListModal.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ const keysOnlyModeAssets: EdgeAsset[] = Object.keys(SPECIAL_CURRENCY_INFO)
9393
tokenId: null
9494
}))
9595

96-
export function WalletListModal(props: Props) {
96+
export function WalletListModal(props: Props): React.ReactElement {
9797
const {
9898
bridge,
9999
navigation,
@@ -157,11 +157,7 @@ export function WalletListModal(props: Props) {
157157
bridge.resolve({ type: 'wyre', fiatAccountId })
158158
})
159159
const handleWalletListPress = useHandler(
160-
async (
161-
walletId: string,
162-
tokenId: EdgeTokenId,
163-
customAsset?: CustomAsset
164-
) => {
160+
(walletId: string, tokenId: EdgeTokenId, customAsset?: CustomAsset) => {
165161
if (walletId === '') {
166162
handleCancel()
167163
showError(lstrings.network_alert_title)
@@ -312,7 +308,9 @@ export function WalletListModal(props: Props) {
312308
showCreateWallet={showCreateWallet}
313309
createWalletId={createWalletId}
314310
parentWalletId={parentWalletId}
315-
onPress={handleWalletListPress}
311+
onPress={async (...args) => {
312+
handleWalletListPress(...args)
313+
}}
316314
navigation={navigation}
317315
/>
318316
</EdgeModal>

src/components/scenes/GuiPluginListScene.tsx

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -182,15 +182,15 @@ class GuiPluginList extends React.PureComponent<Props, State> {
182182
this.componentMounted = true
183183
}
184184

185-
async componentDidMount() {
185+
componentDidMount(): void {
186186
this.updatePlugins()
187187
const { developerPluginUri } = getDeviceSettings()
188188
if (developerPluginUri != null) {
189189
this.setState({ developerUri: developerPluginUri })
190190
}
191191
}
192192

193-
componentWillUnmount() {
193+
componentWillUnmount(): void {
194194
this.componentMounted = false
195195
if (this.timeoutId != null) clearTimeout(this.timeoutId)
196196
}
@@ -206,7 +206,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
206206
}
207207
}
208208

209-
updatePlugins() {
209+
updatePlugins(): void {
210210
// Create new array objects so we aren't patching the original JSON
211211
const currentPlugins: BuySellPlugins = {
212212
buy: [...(buySellPlugins.buy ?? [])],
@@ -225,9 +225,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
225225
continue
226226
}
227227
const currentDirection = currentPlugins[direction] ?? []
228-
if (currentPlugins[direction] == null) {
229-
currentPlugins[direction] = currentDirection
230-
}
228+
currentPlugins[direction] ??= currentDirection
231229
for (const patch of patches) {
232230
// Skip comment rows
233231
if (typeof patch === 'string') continue
@@ -268,7 +266,10 @@ class GuiPluginList extends React.PureComponent<Props, State> {
268266
/**
269267
* Launch the provided plugin, including pre-flight checks.
270268
*/
271-
async openPlugin(listRow: GuiPluginRow, longPress: boolean = false) {
269+
async openPlugin(
270+
listRow: GuiPluginRow,
271+
longPress: boolean = false
272+
): Promise<void> {
272273
const {
273274
account,
274275
accountReferral,
@@ -318,9 +319,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
318319
this.setState({ developerUri: deepPath })
319320

320321
// Write to disk lazily:
321-
writeDeveloperPluginUri(deepPath).catch(error => {
322-
showError(error)
323-
})
322+
writeDeveloperPluginUri(deepPath).catch(showError)
324323
}
325324
}
326325
if (plugin.nativePlugin != null) {
@@ -387,7 +386,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
387386
onPluginOpened()
388387
}
389388

390-
renderTitle = (guiPluginRow: GuiPluginRow) => {
389+
renderTitle = (guiPluginRow: GuiPluginRow): React.ReactElement => {
391390
const styles = getStyles(this.props.theme)
392391
const { title, customTitleKey } = guiPluginRow
393392

@@ -426,22 +425,22 @@ class GuiPluginList extends React.PureComponent<Props, State> {
426425
)(error)
427426
if (regionError != null && regionError.length > 0) {
428427
const country = COUNTRY_CODES.find(c => c['alpha-2'] === countryCode)
429-
const countryName = country ? country.name : countryCode // Fallback to countryCode if not found
428+
const countryName = country != null ? country.name : countryCode // Fallback to countryCode if not found
430429

431430
// Attempt to find the stateProvince name if stateProvinceCode is provided
432431
let stateProvinceName = stateProvinceCode
433-
if (country?.stateProvinces && stateProvinceCode) {
432+
if (country?.stateProvinces != null && stateProvinceCode != null) {
434433
const stateProvince = country.stateProvinces.find(
435434
sp => sp['alpha-2'] === stateProvinceCode
436435
)
437-
stateProvinceName = stateProvince
438-
? stateProvince.name
439-
: stateProvinceCode // Fallback to stateProvinceCode if not found
436+
stateProvinceName =
437+
stateProvince != null ? stateProvince.name : stateProvinceCode // Fallback to stateProvinceCode if not found
440438
}
441439

442-
const text = stateProvinceName
443-
? `${stateProvinceName}, ${countryName}`
444-
: countryName
440+
const text =
441+
stateProvinceName != null
442+
? `${stateProvinceName}, ${countryName}`
443+
: countryName
445444
Airship.show<'ok' | undefined>(bridge => (
446445
<ButtonsModal
447446
bridge={bridge}
@@ -454,7 +453,10 @@ class GuiPluginList extends React.PureComponent<Props, State> {
454453
}
455454
}
456455

457-
renderPlugin = ({ item, index }: ListRenderItemInfo<GuiPluginRow>) => {
456+
renderPlugin = ({
457+
item,
458+
index
459+
}: ListRenderItemInfo<GuiPluginRow>): React.ReactElement | null => {
458460
const { theme } = this.props
459461
const { pluginId } = item
460462
const plugin = guiPlugins[pluginId]
@@ -470,9 +472,10 @@ class GuiPluginList extends React.PureComponent<Props, State> {
470472
? undefined
471473
: {
472474
displayName: poweredBy,
473-
icon: partnerLogoThemeKey
474-
? theme[partnerLogoThemeKey]
475-
: { uri: getPartnerIconUri(item.partnerIconPath ?? '') }
475+
icon:
476+
partnerLogoThemeKey != null
477+
? theme[partnerLogoThemeKey]
478+
: { uri: getPartnerIconUri(item.partnerIconPath ?? '') }
476479
}
477480
const [totalAmount, settlementTime] = item.description.split('\n')
478481
return (
@@ -482,7 +485,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
482485
>
483486
<PaymentOptionCard
484487
title={this.renderTitle(item)}
485-
// @ts-expect-error
488+
// @ts-expect-error - we can assume paymentTypeLogoKey exists within paymentTypeLogosById because it comes from static JSON
486489
icon={theme[paymentTypeLogosById[item.paymentTypeLogoKey]]}
487490
totalAmount={totalAmount}
488491
settlementTime={settlementTime}
@@ -491,9 +494,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
491494
await this.openPlugin(item)
492495
}}
493496
onLongPress={async () => {
494-
await this.openPlugin(item, true).catch(error => {
495-
this.handleError(error)
496-
})
497+
await this.openPlugin(item, true).catch(this.handleError)
497498
}}
498499
onProviderPress={async () => {
499500
await this.openPlugin(item)
@@ -503,7 +504,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
503504
)
504505
}
505506

506-
renderTop = () => {
507+
renderTop = (): React.ReactElement => {
507508
const {
508509
account,
509510
countryCode,
@@ -521,7 +522,9 @@ class GuiPluginList extends React.PureComponent<Props, State> {
521522
sp => sp['alpha-2'] === stateProvinceCode
522523
)
523524
const uri = `${FLAG_LOGO_URL}/${
524-
countryData?.filename || countryData?.name.toLowerCase().replace(' ', '-')
525+
countryData?.filename ??
526+
countryData?.name.toLowerCase().replace(' ', '-') ??
527+
''
525528
}.png`
526529
const hasCountryData = countryData != null
527530

@@ -601,7 +604,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
601604
)
602605
}
603606

604-
renderEmptyList = () => {
607+
renderEmptyList = (): React.ReactElement | null => {
605608
const { countryCode, theme } = this.props
606609
const styles = getStyles(theme)
607610
if (countryCode === '') return null
@@ -615,7 +618,7 @@ class GuiPluginList extends React.PureComponent<Props, State> {
615618
)
616619
}
617620

618-
render() {
621+
render(): React.ReactElement {
619622
const {
620623
accountPlugins,
621624
accountReferral,
@@ -823,9 +826,9 @@ const GuiPluginListSceneComponent = React.memo((props: OwnProps) => {
823826
})
824827

825828
// Export separate components for buy and sell routes
826-
export const BuyScene = (props: BuyProps) => (
829+
export const BuyScene = (props: BuyProps): React.ReactElement => (
827830
<GuiPluginListSceneComponent {...props} />
828831
)
829-
export const SellScene = (props: SellProps) => (
832+
export const SellScene = (props: SellProps): React.ReactElement => (
830833
<GuiPluginListSceneComponent {...props} />
831834
)

src/plugins/gui/fiatPlugin.tsx

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const deeplinkListeners: {
7676
} | null
7777
} = { listener: null }
7878

79-
export const fiatProviderDeeplinkHandler = (link: FiatProviderLink) => {
79+
export const fiatProviderDeeplinkHandler = (link: FiatProviderLink): void => {
8080
if (deeplinkListeners.listener == null) {
8181
showError(
8282
`No buy/sell interface currently open to handle fiatProvider deeplink`
@@ -102,7 +102,8 @@ export const fiatProviderDeeplinkHandler = (link: FiatProviderLink) => {
102102
if (Platform.OS === 'ios') {
103103
SafariView.dismiss()
104104
}
105-
deeplinkHandler(link)
105+
const p = deeplinkHandler(link)
106+
if (p != null) p.catch(showError)
106107
}
107108

108109
export const executePlugin = async (params: {
@@ -146,7 +147,7 @@ export const executePlugin = async (params: {
146147

147148
const tabSceneKey = isBuy ? 'buyTab' : 'sellTab'
148149

149-
function maybeNavigateToCorrectTabScene() {
150+
function maybeNavigateToCorrectTabScene(): void {
150151
const navPath = getNavigationAbsolutePath(navigation)
151152
if (!navPath.includes(`/edgeTabs/${tabSceneKey}`)) {
152153
// Navigate to the correct tab first
@@ -193,7 +194,9 @@ export const executePlugin = async (params: {
193194
openExternalWebView: async (params): Promise<void> => {
194195
const { deeplinkHandler, providerId, redirectExternal, url } = params
195196
datelog(
196-
`**** openExternalWebView ${url} deeplinkHandler:${deeplinkHandler}`
197+
`**** openExternalWebView ${url} deeplinkHandler:${JSON.stringify(
198+
deeplinkHandler
199+
)}`
197200
)
198201
if (deeplinkHandler != null) {
199202
if (providerId == null)
@@ -213,17 +216,16 @@ export const executePlugin = async (params: {
213216
const { headerTitle, allowedAssets, showCreateWallet } = params
214217

215218
const result =
216-
forcedWalletResult == null
217-
? await Airship.show<WalletListResult>(bridge => (
218-
<WalletListModal
219-
bridge={bridge}
220-
navigation={navigation}
221-
headerTitle={headerTitle}
222-
allowedAssets={allowedAssets}
223-
showCreateWallet={showCreateWallet}
224-
/>
225-
))
226-
: forcedWalletResult
219+
forcedWalletResult ??
220+
(await Airship.show<WalletListResult>(bridge => (
221+
<WalletListModal
222+
bridge={bridge}
223+
navigation={navigation}
224+
headerTitle={headerTitle}
225+
allowedAssets={allowedAssets}
226+
showCreateWallet={showCreateWallet}
227+
/>
228+
)))
227229

228230
if (result?.type === 'wallet') return result
229231
},
@@ -259,7 +261,7 @@ export const executePlugin = async (params: {
259261
) => {
260262
resolve({ email, firstName, lastName })
261263
},
262-
onClose: async () => {
264+
onClose: () => {
263265
resolve(undefined)
264266
}
265267
})
@@ -277,7 +279,7 @@ export const executePlugin = async (params: {
277279
if (onSubmit != null) await onSubmit(homeAddress)
278280
resolve(homeAddress)
279281
},
280-
onClose: async () => {
282+
onClose: () => {
281283
resolve(undefined)
282284
}
283285
})

src/plugins/gui/fiatPluginTypes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const asFiatPaymentType = asValue(
6363
)
6464
export type FiatPaymentType = ReturnType<typeof asFiatPaymentType>
6565

66-
export type LinkHandler = (url: FiatProviderLink) => void
66+
export type LinkHandler = (url: FiatProviderLink) => void | Promise<void>
6767

6868
export interface FiatPluginSepaTransferInfo {
6969
input: {

0 commit comments

Comments
 (0)