@imtbl/checkout-widgets 2.0.0-alpha.9 → 2.0.0

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 (48) hide show
  1. package/dist/browser/{AddTokensWidget-DF8aiUpz.js → AddTokensWidget-C32-7Pge.js} +16 -396
  2. package/dist/browser/{BridgeWidget-DIU9Cxmn.js → BridgeWidget-DHmmZrLe.js} +23 -23
  3. package/dist/browser/{CommerceWidget-CKAKFkix.js → CommerceWidget-DinG6S2H.js} +161 -161
  4. package/dist/browser/{FeesBreakdown-BgEzlEIT.js → FeesBreakdown-CVvm1-Ei.js} +1 -1
  5. package/dist/browser/{OnRampWidget-Bve5vLzE.js → OnRampWidget-B54_6G-f.js} +5 -5
  6. package/dist/browser/{SaleWidget-CKWdID6Y.js → SaleWidget-Cuen5aW7.js} +53 -53
  7. package/dist/browser/{SpendingCapHero-HDVNFS4r.js → SpendingCapHero-DQtmoqNL.js} +1 -1
  8. package/dist/browser/SwapWidget-j_nEgqk4.js +1907 -0
  9. package/dist/browser/{TokenImage-DU_Cg9yk.js → TokenImage-Bc62Xkzv.js} +1 -1
  10. package/dist/browser/{TopUpView-DbE6wlUQ.js → TopUpView-Q4_Glu5-.js} +4 -4
  11. package/dist/browser/{WalletApproveHero-BKgdFRbV.js → WalletApproveHero-B6YvvCmA.js} +25 -5
  12. package/dist/browser/{WalletWidget-D370JeUN.js → WalletWidget-B0Up4Cre.js} +14 -14
  13. package/dist/browser/{auto-track-gJcTpwWh.js → auto-track-CaL-84Ic.js} +1 -1
  14. package/dist/browser/{index-BzdV0KgJ.js → index-BI7vXlHL.js} +1 -1
  15. package/dist/browser/{index-DeP8dLpv.js → index-BVzeDoH7.js} +1 -1
  16. package/dist/browser/{index-CcF1_qRd.js → index-BtnAkpe9.js} +1 -1
  17. package/dist/browser/{index-BB_EeO8_.js → index-CBO9u-8Q.js} +1 -12
  18. package/dist/browser/{index-C_yzaB0L.js → index-Cl7BUGHV.js} +2 -2
  19. package/dist/browser/{index-Q-a_-G_9.js → index-Hh-ME3UA.js} +1 -1
  20. package/dist/browser/{index-CSHKiSiI.js → index-JHffH8Bm.js} +1 -1
  21. package/dist/browser/{index-Bizu61HY.js → index-Skcajiao.js} +14521 -50813
  22. package/dist/browser/index.cdn.js +3262 -39764
  23. package/dist/browser/index.js +1 -1
  24. package/dist/browser/{index.umd-oUBivosK.js → index.umd-C0PZl9Xk.js} +1 -1
  25. package/dist/browser/{useInterval-D7lTeYwU.js → useInterval-D2CM0YwW.js} +1 -1
  26. package/dist/types/widgets/purchase/components/PurchaseRouteOptionsDrawer/RouteOptions.d.ts +2 -1
  27. package/dist/types/widgets/purchase/components/PurchaseRouteOptionsDrawer/RouteOptionsDrawer.d.ts +2 -1
  28. package/dist/types/widgets/swap/GeoblockLoader.d.ts +1 -1
  29. package/dist/types/widgets/swap/SwapWidget.d.ts +1 -1
  30. package/dist/types/widgets/swap/SwapWidgetRoot.d.ts +0 -2
  31. package/package.json +13 -14
  32. package/rollup.config.js +42 -23
  33. package/src/components/CoinSelector/CoinSelector.tsx +63 -16
  34. package/src/lib/metrics.ts +4 -3
  35. package/src/locales/en.json +2 -1
  36. package/src/locales/ja.json +2 -1
  37. package/src/locales/ko.json +1 -0
  38. package/src/locales/zh.json +2 -1
  39. package/src/widgets/purchase/components/PurchaseRouteOptionsDrawer/FiatOption.tsx +0 -1
  40. package/src/widgets/purchase/components/PurchaseRouteOptionsDrawer/RouteOptions.tsx +18 -1
  41. package/src/widgets/purchase/components/PurchaseRouteOptionsDrawer/RouteOptionsDrawer.tsx +8 -1
  42. package/src/widgets/purchase/views/Purchase.tsx +2 -0
  43. package/src/widgets/swap/GeoblockLoader.tsx +3 -1
  44. package/src/widgets/swap/SwapWidget.tsx +216 -153
  45. package/src/widgets/swap/SwapWidgetRoot.tsx +17 -80
  46. package/src/widgets/swap/components/SwapForm.tsx +66 -4
  47. package/dist/browser/SwapWidget-CPcceA1Y.js +0 -1738
  48. package/tsup.config.js +0 -58
@@ -10,6 +10,7 @@ import {
10
10
  TokenFilterTypes, IMTBLWidgetEvents, SwapWidgetParams,
11
11
  SwapDirection,
12
12
  fetchRiskAssessment,
13
+ WalletProviderName,
13
14
  } from '@imtbl/checkout-sdk';
14
15
  import { useTranslation } from 'react-i18next';
15
16
  import { SwapCoins } from './views/SwapCoins';
@@ -52,6 +53,11 @@ import { EventTargetContext } from '../../context/event-target-context/EventTarg
52
53
  import { getAllowedBalances } from '../../lib/balance';
53
54
  import { UserJourney, useAnalytics } from '../../context/analytics-provider/SegmentAnalyticsProvider';
54
55
  import { ServiceUnavailableErrorView } from '../../views/error/ServiceUnavailableErrorView';
56
+ import { ServiceUnavailableToRegionErrorView } from '../../views/error/ServiceUnavailableToRegionErrorView';
57
+ import { ServiceType } from '../../views/error/serviceTypes';
58
+ import { isPassportProvider } from '../../lib/provider';
59
+ import { topUpBridgeOption, topUpOnRampOption } from './helpers';
60
+ import { GeoblockLoader } from './GeoblockLoader';
55
61
 
56
62
  export type SwapWidgetInputs = SwapWidgetParams & {
57
63
  config: StrongCheckoutWidgetsConfig;
@@ -65,6 +71,7 @@ export default function SwapWidget({
65
71
  autoProceed,
66
72
  direction,
67
73
  showBackButton,
74
+ walletProviderName,
68
75
  }: SwapWidgetInputs) {
69
76
  const { t } = useTranslation();
70
77
  const {
@@ -235,160 +242,216 @@ export default function SwapWidget({
235
242
  const fromAmount = direction === SwapDirection.FROM || direction == null ? amount : undefined;
236
243
  const toAmount = direction === SwapDirection.TO ? amount : undefined;
237
244
 
245
+ const topUpOptions: { textKey: string; action: () => void }[] | undefined = useMemo(() => {
246
+ const optionsArray: { textKey: string; action: () => void }[] = [];
247
+
248
+ const isNotPassport = !isPassportProvider(provider)
249
+ || walletProviderName !== WalletProviderName.PASSPORT;
250
+
251
+ const isOnramp = topUpOnRampOption(isOnRampEnabled);
252
+ if (isOnramp) {
253
+ optionsArray.push({ ...isOnramp });
254
+ }
255
+ const isBridge = topUpBridgeOption(
256
+ isBridgeEnabled,
257
+ isNotPassport,
258
+ );
259
+ if (isBridge) {
260
+ optionsArray.push({ ...isBridge });
261
+ }
262
+
263
+ return optionsArray;
264
+ }, []);
265
+
238
266
  return (
239
- <ViewContext.Provider value={viewReducerValues}>
240
- <SwapContext.Provider value={swapReducerValues}>
241
- <CryptoFiatProvider environment={environment}>
242
- {viewState.view.type === SharedViews.LOADING_VIEW && (
243
- <LoadingView loadingText={t('views.LOADING_VIEW.text')} />
244
- )}
245
- {viewState.view.type === SwapWidgetViews.SWAP && (
246
- <SwapCoins
247
- theme={theme}
248
- cancelAutoProceed={cancelAutoProceed}
249
- fromAmount={viewState.view.data?.fromAmount ?? fromAmount}
250
- toAmount={viewState.view.data?.toAmount ?? toAmount}
251
- fromTokenAddress={viewState.view.data?.fromTokenAddress ?? fromTokenAddress}
252
- toTokenAddress={viewState.view.data?.toTokenAddress ?? toTokenAddress}
253
- showBackButton={showBackButton}
254
- />
255
- )}
256
- {viewState.view.type === SwapWidgetViews.IN_PROGRESS && (
257
- <SwapInProgress
258
- transactionResponse={viewState.view.data.transactionResponse}
259
- swapForm={viewState.view.data.swapForm}
260
- />
261
- )}
262
- {viewState.view.type === SwapWidgetViews.APPROVE_ERC20 && (
263
- <ApproveERC20Onboarding data={viewState.view.data} />
264
- )}
265
- {viewState.view.type === SwapWidgetViews.SUCCESS && (
266
- <StatusView
267
- statusText={t('views.SWAP.success.text')}
268
- actionText={t('views.SWAP.success.actionText')}
269
- onRenderEvent={() => {
270
- page({
271
- userJourney: UserJourney.SWAP,
272
- screen: 'SwapSuccess',
273
- extras: {
274
- fromTokenAddress: viewState.view.data?.fromTokenAddress,
275
- fromAmount: viewState.view.data?.fromAmount,
276
- toTokenAddress: viewState.view.data?.toTokenAddress,
277
- toAmount: viewState.view.data?.toAmount,
278
- },
279
- });
280
- sendSwapSuccessEvent(
281
- eventTarget,
282
- (viewState.view as SwapSuccessView).data.transactionHash,
283
- );
284
- }}
285
- onActionClick={() => sendSwapWidgetCloseEvent(eventTarget)}
286
- statusType={StatusType.SUCCESS}
287
- testId="success-view"
288
- />
289
- )}
290
- {viewState.view.type === SwapWidgetViews.FAIL && (
291
- <StatusView
292
- statusText={t('views.SWAP.failed.text')}
293
- actionText={t('views.SWAP.failed.actionText')}
294
- onRenderEvent={() => {
295
- page({
296
- userJourney: UserJourney.SWAP,
297
- screen: 'SwapFailed',
298
- });
299
- sendSwapFailedEvent(eventTarget, 'Transaction failed');
300
- }}
301
- onActionClick={() => {
302
- if (viewState.view.type === SwapWidgetViews.FAIL) {
303
- viewDispatch({
304
- payload: {
305
- type: ViewActions.UPDATE_VIEW,
306
- view: {
307
- type: SwapWidgetViews.SWAP,
308
- data: viewState.view.data,
267
+ <GeoblockLoader
268
+ checkout={checkout}
269
+ widget={
270
+ (
271
+ <ViewContext.Provider value={viewReducerValues}>
272
+ <SwapContext.Provider value={swapReducerValues}>
273
+ <CryptoFiatProvider environment={environment}>
274
+ {viewState.view.type === SharedViews.LOADING_VIEW && (
275
+ <LoadingView loadingText={t('views.LOADING_VIEW.text')} />
276
+ )}
277
+ {viewState.view.type === SwapWidgetViews.SWAP && (
278
+ <SwapCoins
279
+ theme={theme}
280
+ cancelAutoProceed={cancelAutoProceed}
281
+ fromAmount={viewState.view.data?.fromAmount ?? fromAmount}
282
+ toAmount={viewState.view.data?.toAmount ?? toAmount}
283
+ fromTokenAddress={viewState.view.data?.fromTokenAddress ?? fromTokenAddress}
284
+ toTokenAddress={viewState.view.data?.toTokenAddress ?? toTokenAddress}
285
+ showBackButton={showBackButton}
286
+ />
287
+ )}
288
+ {viewState.view.type === SwapWidgetViews.IN_PROGRESS && (
289
+ <SwapInProgress
290
+ transactionResponse={viewState.view.data.transactionResponse}
291
+ swapForm={viewState.view.data.swapForm}
292
+ />
293
+ )}
294
+ {viewState.view.type === SwapWidgetViews.APPROVE_ERC20 && (
295
+ <ApproveERC20Onboarding data={viewState.view.data} />
296
+ )}
297
+ {viewState.view.type === SwapWidgetViews.SUCCESS && (
298
+ <StatusView
299
+ statusText={t('views.SWAP.success.text')}
300
+ actionText={t('views.SWAP.success.actionText')}
301
+ onRenderEvent={() => {
302
+ page({
303
+ userJourney: UserJourney.SWAP,
304
+ screen: 'SwapSuccess',
305
+ extras: {
306
+ fromTokenAddress: viewState.view.data?.fromTokenAddress,
307
+ fromAmount: viewState.view.data?.fromAmount,
308
+ toTokenAddress: viewState.view.data?.toTokenAddress,
309
+ toAmount: viewState.view.data?.toAmount,
309
310
  },
310
- },
311
- });
312
- }
313
- }}
314
- statusType={StatusType.FAILURE}
315
- onCloseClick={() => sendSwapWidgetCloseEvent(eventTarget)}
316
- testId="fail-view"
317
- />
318
- )}
319
- {viewState.view.type === SwapWidgetViews.PRICE_SURGE && (
320
- <StatusView
321
- statusText={t('views.SWAP.rejected.text')}
322
- actionText={t('views.SWAP.rejected.actionText')}
323
- onRenderEvent={() => {
324
- page({
325
- userJourney: UserJourney.SWAP,
326
- screen: 'PriceSurge',
327
- });
328
- sendSwapRejectedEvent(eventTarget, 'Price surge');
329
- }}
330
- onActionClick={() => {
331
- if (viewState.view.type === SwapWidgetViews.PRICE_SURGE) {
332
- viewDispatch({
333
- payload: {
334
- type: ViewActions.UPDATE_VIEW,
335
- view: {
336
- type: SwapWidgetViews.SWAP,
337
- data: viewState.view.data,
338
- },
339
- },
340
- });
341
- }
342
- }}
343
- statusType={StatusType.WARNING}
344
- onCloseClick={() => sendSwapWidgetCloseEvent(eventTarget)}
345
- testId="price-surge-view"
346
- />
347
- )}
348
- {viewState.view.type === SharedViews.ERROR_VIEW && (
349
- <ErrorView
350
- actionText={t('views.ERROR_VIEW.actionText')}
351
- onActionClick={async () => {
352
- setErrorViewLoading(true);
353
- const data = viewState.view as ErrorViewType;
354
-
355
- if (!data.tryAgain) {
356
- showSwapView();
357
- setErrorViewLoading(false);
358
- return;
359
- }
360
-
361
- if (await data.tryAgain()) showSwapView();
362
- setErrorViewLoading(false);
363
- }}
364
- onCloseClick={() => sendSwapWidgetCloseEvent(eventTarget)}
365
- errorEventActionLoading={errorViewLoading}
366
- />
367
- )}
368
- {viewState.view.type === SwapWidgetViews.SERVICE_UNAVAILABLE && (
369
- <ServiceUnavailableErrorView
370
- onCloseClick={() => sendSwapWidgetCloseEvent(eventTarget)}
371
- onBackButtonClick={() => {
372
- viewDispatch({
373
- payload: { type: ViewActions.UPDATE_VIEW, view: { type: SwapWidgetViews.SWAP } },
374
- });
375
- }}
376
- />
377
- )}
378
- {viewState.view.type === SharedViews.TOP_UP_VIEW && (
379
- <TopUpView
380
- analytics={{ userJourney: UserJourney.SWAP }}
381
- checkout={checkout}
382
- provider={provider}
383
- widgetEvent={IMTBLWidgetEvents.IMTBL_SWAP_WIDGET_EVENT}
384
- showOnrampOption={isOnRampEnabled}
385
- showSwapOption={isSwapEnabled}
386
- showBridgeOption={isBridgeEnabled}
387
- onCloseButtonClick={() => sendSwapWidgetCloseEvent(eventTarget)}
388
- />
389
- )}
390
- </CryptoFiatProvider>
391
- </SwapContext.Provider>
392
- </ViewContext.Provider>
311
+ });
312
+ sendSwapSuccessEvent(
313
+ eventTarget,
314
+ (viewState.view as SwapSuccessView).data.transactionHash,
315
+ );
316
+ }}
317
+ onActionClick={() => sendSwapWidgetCloseEvent(eventTarget)}
318
+ statusType={StatusType.SUCCESS}
319
+ testId="success-view"
320
+ />
321
+ )}
322
+ {viewState.view.type === SwapWidgetViews.FAIL && (
323
+ <StatusView
324
+ statusText={t('views.SWAP.failed.text')}
325
+ actionText={t('views.SWAP.failed.actionText')}
326
+ onRenderEvent={() => {
327
+ page({
328
+ userJourney: UserJourney.SWAP,
329
+ screen: 'SwapFailed',
330
+ });
331
+ sendSwapFailedEvent(eventTarget, 'Transaction failed');
332
+ }}
333
+ onActionClick={() => {
334
+ if (viewState.view.type === SwapWidgetViews.FAIL) {
335
+ viewDispatch({
336
+ payload: {
337
+ type: ViewActions.UPDATE_VIEW,
338
+ view: {
339
+ type: SwapWidgetViews.SWAP,
340
+ data: viewState.view.data,
341
+ },
342
+ },
343
+ });
344
+ }
345
+ }}
346
+ statusType={StatusType.FAILURE}
347
+ onCloseClick={() => sendSwapWidgetCloseEvent(eventTarget)}
348
+ testId="fail-view"
349
+ />
350
+ )}
351
+ {viewState.view.type === SwapWidgetViews.PRICE_SURGE && (
352
+ <StatusView
353
+ statusText={t('views.SWAP.rejected.text')}
354
+ actionText={t('views.SWAP.rejected.actionText')}
355
+ onRenderEvent={() => {
356
+ page({
357
+ userJourney: UserJourney.SWAP,
358
+ screen: 'PriceSurge',
359
+ });
360
+ sendSwapRejectedEvent(eventTarget, 'Price surge');
361
+ }}
362
+ onActionClick={() => {
363
+ if (viewState.view.type === SwapWidgetViews.PRICE_SURGE) {
364
+ viewDispatch({
365
+ payload: {
366
+ type: ViewActions.UPDATE_VIEW,
367
+ view: {
368
+ type: SwapWidgetViews.SWAP,
369
+ data: viewState.view.data,
370
+ },
371
+ },
372
+ });
373
+ }
374
+ }}
375
+ statusType={StatusType.WARNING}
376
+ onCloseClick={() => sendSwapWidgetCloseEvent(eventTarget)}
377
+ testId="price-surge-view"
378
+ />
379
+ )}
380
+ {viewState.view.type === SharedViews.ERROR_VIEW && (
381
+ <ErrorView
382
+ actionText={t('views.ERROR_VIEW.actionText')}
383
+ onActionClick={async () => {
384
+ setErrorViewLoading(true);
385
+ const data = viewState.view as ErrorViewType;
386
+
387
+ if (!data.tryAgain) {
388
+ showSwapView();
389
+ setErrorViewLoading(false);
390
+ return;
391
+ }
392
+
393
+ if (await data.tryAgain()) showSwapView();
394
+ setErrorViewLoading(false);
395
+ }}
396
+ onCloseClick={() => sendSwapWidgetCloseEvent(eventTarget)}
397
+ errorEventActionLoading={errorViewLoading}
398
+ />
399
+ )}
400
+ {viewState.view.type === SwapWidgetViews.SERVICE_UNAVAILABLE && (
401
+ <ServiceUnavailableErrorView
402
+ onCloseClick={() => sendSwapWidgetCloseEvent(eventTarget)}
403
+ onBackButtonClick={() => {
404
+ viewDispatch({
405
+ payload: { type: ViewActions.UPDATE_VIEW, view: { type: SwapWidgetViews.SWAP } },
406
+ });
407
+ }}
408
+ />
409
+ )}
410
+ {viewState.view.type === SharedViews.TOP_UP_VIEW && (
411
+ <TopUpView
412
+ analytics={{ userJourney: UserJourney.SWAP }}
413
+ checkout={checkout}
414
+ provider={provider}
415
+ widgetEvent={IMTBLWidgetEvents.IMTBL_SWAP_WIDGET_EVENT}
416
+ showOnrampOption={isOnRampEnabled}
417
+ showSwapOption={isSwapEnabled}
418
+ showBridgeOption={isBridgeEnabled}
419
+ onCloseButtonClick={() => sendSwapWidgetCloseEvent(eventTarget)}
420
+ />
421
+ )}
422
+ </CryptoFiatProvider>
423
+ </SwapContext.Provider>
424
+ </ViewContext.Provider>
425
+ )
426
+ }
427
+ serviceUnavailableView={
428
+ (
429
+ <ServiceUnavailableToRegionErrorView
430
+ service={ServiceType.SWAP}
431
+ onCloseClick={() => sendSwapWidgetCloseEvent(window)}
432
+ primaryActionText={
433
+ topUpOptions && topUpOptions?.length > 0
434
+ ? t(topUpOptions[0].textKey)
435
+ : undefined
436
+ }
437
+ onPrimaryButtonClick={
438
+ topUpOptions && topUpOptions?.length > 0
439
+ ? topUpOptions[0].action
440
+ : undefined
441
+ }
442
+ secondaryActionText={
443
+ topUpOptions?.length === 2
444
+ ? t(topUpOptions[1].textKey)
445
+ : undefined
446
+ }
447
+ onSecondaryButtonClick={
448
+ topUpOptions?.length === 2
449
+ ? topUpOptions[1].action
450
+ : undefined
451
+ }
452
+ />
453
+ )
454
+ }
455
+ />
393
456
  );
394
457
  }
@@ -4,7 +4,6 @@ import {
4
4
  IMTBLWidgetEvents,
5
5
  SwapDirection,
6
6
  SwapWidgetParams,
7
- WalletProviderName,
8
7
  WidgetConfiguration,
9
8
  WidgetProperties,
10
9
  WidgetTheme,
@@ -13,18 +12,13 @@ import {
13
12
  import { Base } from '../BaseWidgetRoot';
14
13
  import { ConnectLoader, ConnectLoaderParams } from '../../components/ConnectLoader/ConnectLoader';
15
14
  import { getL2ChainId } from '../../lib';
16
- import { isPassportProvider } from '../../lib/provider';
17
- import { ServiceUnavailableToRegionErrorView } from '../../views/error/ServiceUnavailableToRegionErrorView';
18
- import { ServiceType } from '../../views/error/serviceTypes';
19
15
  import { isValidAddress, isValidAmount, isValidWalletProvider } from '../../lib/validations/widgetValidators';
20
16
  import { ThemeProvider } from '../../components/ThemeProvider/ThemeProvider';
21
17
  import { CustomAnalyticsProvider } from '../../context/analytics-provider/CustomAnalyticsProvider';
22
18
  import { LoadingView } from '../../views/loading/LoadingView';
23
19
  import { HandoverProvider } from '../../context/handover-context/HandoverProvider';
24
- import { topUpBridgeOption, topUpOnRampOption } from './helpers';
25
20
  import { sendSwapWidgetCloseEvent } from './SwapWidgetEvents';
26
21
  import i18n from '../../i18n';
27
- import { GeoblockLoader } from './GeoblockLoader';
28
22
 
29
23
  const SwapWidget = React.lazy(() => import('./SwapWidget'));
30
24
 
@@ -79,27 +73,6 @@ export class Swap extends Base<WidgetType.SWAP> {
79
73
  return validatedParams;
80
74
  }
81
75
 
82
- private isNotPassport = !isPassportProvider(this.browserProvider)
83
- || this.parameters?.walletProviderName !== WalletProviderName.PASSPORT;
84
-
85
- private topUpOptions(): { textKey: string; action: () => void }[] | undefined {
86
- const optionsArray: { textKey: string; action: () => void }[] = [];
87
-
88
- const isOnramp = topUpOnRampOption(this.strongConfig().isOnRampEnabled);
89
- if (isOnramp) {
90
- optionsArray.push({ ...isOnramp });
91
- }
92
- const isBridge = topUpBridgeOption(
93
- this.strongConfig().isBridgeEnabled,
94
- this.isNotPassport,
95
- );
96
- if (isBridge) {
97
- optionsArray.push({ ...isBridge });
98
- }
99
-
100
- return optionsArray;
101
- }
102
-
103
76
  protected render() {
104
77
  if (!this.reactRoot) return;
105
78
 
@@ -114,65 +87,29 @@ export class Swap extends Base<WidgetType.SWAP> {
114
87
  allowedChains: [getL2ChainId(this.checkout!.config)],
115
88
  };
116
89
 
117
- const topUpOptions = this.topUpOptions();
118
-
119
90
  this.reactRoot!.render(
120
91
  <React.StrictMode>
121
92
  <CustomAnalyticsProvider checkout={this.checkout}>
122
93
  <ThemeProvider id="swap-container" config={this.strongConfig()}>
123
94
  <HandoverProvider>
124
- <GeoblockLoader
125
- checkout={this.checkout}
126
- widget={
127
- (
128
- <ConnectLoader
129
- params={connectLoaderParams}
130
- widgetConfig={this.strongConfig()}
131
- closeEvent={() => sendSwapWidgetCloseEvent(window)}
132
- >
133
- <Suspense fallback={<LoadingView loadingText={t('views.LOADING_VIEW.text')} />}>
134
- <SwapWidget
135
- fromTokenAddress={this.parameters.fromTokenAddress}
136
- toTokenAddress={this.parameters.toTokenAddress}
137
- amount={this.parameters.amount}
138
- config={this.strongConfig()}
139
- autoProceed={this.parameters.autoProceed}
140
- direction={this.parameters.direction ?? SwapDirection.FROM}
141
- showBackButton={this.parameters.showBackButton}
142
- />
143
- </Suspense>
144
- </ConnectLoader>
145
- )
146
- }
147
- serviceUnavailableView={
148
- (
149
- <ServiceUnavailableToRegionErrorView
150
- service={ServiceType.SWAP}
151
- onCloseClick={() => sendSwapWidgetCloseEvent(window)}
152
- primaryActionText={
153
- topUpOptions && topUpOptions?.length > 0
154
- ? t(topUpOptions[0].textKey)
155
- : undefined
156
- }
157
- onPrimaryButtonClick={
158
- topUpOptions && topUpOptions?.length > 0
159
- ? topUpOptions[0].action
160
- : undefined
161
- }
162
- secondaryActionText={
163
- topUpOptions?.length === 2
164
- ? t(topUpOptions[1].textKey)
165
- : undefined
166
- }
167
- onSecondaryButtonClick={
168
- topUpOptions?.length === 2
169
- ? topUpOptions[1].action
170
- : undefined
171
- }
95
+ <ConnectLoader
96
+ params={connectLoaderParams}
97
+ widgetConfig={this.strongConfig()}
98
+ closeEvent={() => sendSwapWidgetCloseEvent(window)}
99
+ >
100
+ <Suspense fallback={<LoadingView loadingText={t('views.LOADING_VIEW.text')} />}>
101
+ <SwapWidget
102
+ fromTokenAddress={this.parameters.fromTokenAddress}
103
+ toTokenAddress={this.parameters.toTokenAddress}
104
+ amount={this.parameters.amount}
105
+ config={this.strongConfig()}
106
+ autoProceed={this.parameters.autoProceed}
107
+ direction={this.parameters.direction ?? SwapDirection.FROM}
108
+ showBackButton={this.parameters.showBackButton}
109
+ walletProviderName={this.parameters.walletProviderName}
172
110
  />
173
- )
174
- }
175
- />
111
+ </Suspense>
112
+ </ConnectLoader>
176
113
  </HandoverProvider>
177
114
  </ThemeProvider>
178
115
  </CustomAnalyticsProvider>
@@ -215,6 +215,24 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
215
215
  network,
216
216
  ]);
217
217
 
218
+ const openUnableToSwapDrawer = useCallback((error: any) => {
219
+ setShowNotEnoughImxDrawer(false);
220
+ setShowUnableToSwapDrawer(true);
221
+ track({
222
+ userJourney: UserJourney.SWAP,
223
+ screen: 'SwapCoins',
224
+ control: 'UnableToSwapDrawer',
225
+ controlType: 'Button',
226
+ extras: {
227
+ fromToken,
228
+ toToken,
229
+ fromAmount,
230
+ toAmount,
231
+ error: 'message' in error ? error.message : error,
232
+ },
233
+ });
234
+ }, [track, fromToken, toToken, fromAmount, toAmount]);
235
+
218
236
  const tokensOptionsTo = useMemo(() => allowedTokens
219
237
  .map(
220
238
  (token) => ({
@@ -329,8 +347,7 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
329
347
  console.error('Error fetching quote.', error);
330
348
 
331
349
  resetQuote();
332
- setShowNotEnoughImxDrawer(false);
333
- setShowUnableToSwapDrawer(true);
350
+ openUnableToSwapDrawer(error);
334
351
  }
335
352
  }
336
353
 
@@ -406,8 +423,7 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
406
423
  } catch (error: any) {
407
424
  if (!error.cancelled) {
408
425
  resetQuote();
409
- setShowNotEnoughImxDrawer(false);
410
- setShowUnableToSwapDrawer(true);
426
+ openUnableToSwapDrawer(error);
411
427
  }
412
428
  }
413
429
 
@@ -542,6 +558,18 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
542
558
  setFromToken(selected.token);
543
559
  setFromBalance(selected.formattedBalance);
544
560
  setFromTokenError('');
561
+
562
+ track({
563
+ userJourney: UserJourney.SWAP,
564
+ screen: 'SwapCoins',
565
+ control: 'SelectFrom',
566
+ controlType: 'Select',
567
+ extras: {
568
+ fromBalance: selected.formattedBalance,
569
+ fromToken: selected.token,
570
+ fromAmount,
571
+ },
572
+ });
545
573
  }, [toToken]);
546
574
 
547
575
  const onFromTextInputFocus = () => {
@@ -559,6 +587,18 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
559
587
  setLoading(true);
560
588
  }
561
589
  setFromAmount(value);
590
+
591
+ track({
592
+ userJourney: UserJourney.SWAP,
593
+ screen: 'SwapCoins',
594
+ control: 'InputFrom',
595
+ controlType: 'TextInput',
596
+ extras: {
597
+ fromBalance,
598
+ fromToken,
599
+ fromAmount: value,
600
+ },
601
+ });
562
602
  };
563
603
 
564
604
  const textInputMaxButtonClick = () => {
@@ -602,6 +642,17 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
602
642
 
603
643
  setToToken(selected);
604
644
  setToTokenError('');
645
+
646
+ track({
647
+ userJourney: UserJourney.SWAP,
648
+ screen: 'SwapCoins',
649
+ control: 'SelectTo',
650
+ controlType: 'Select',
651
+ extras: {
652
+ toToken: selected,
653
+ toAmount,
654
+ },
655
+ });
605
656
  }, [fromToken]);
606
657
 
607
658
  const onToTextInputFocus = () => {
@@ -620,6 +671,17 @@ export function SwapForm({ data, theme, cancelAutoProceed }: SwapFromProps) {
620
671
  setLoading(true);
621
672
  }
622
673
  setToAmount(value);
674
+
675
+ track({
676
+ userJourney: UserJourney.SWAP,
677
+ screen: 'SwapCoins',
678
+ control: 'InputTo',
679
+ controlType: 'TextInput',
680
+ extras: {
681
+ toToken,
682
+ toAmount: value,
683
+ },
684
+ });
623
685
  };
624
686
 
625
687
  const openNotEnoughImxDrawer = () => {