diff --git a/packages/checkout/sdk/src/widgets/definitions/events/bridge.ts b/packages/checkout/sdk/src/widgets/definitions/events/bridge.ts index 60dc3aa9b1..e1ae2c7506 100644 --- a/packages/checkout/sdk/src/widgets/definitions/events/bridge.ts +++ b/packages/checkout/sdk/src/widgets/definitions/events/bridge.ts @@ -6,6 +6,8 @@ export enum BridgeEventType { FAILURE = 'failure', TRANSACTION_SENT = 'transaction-sent', LANGUAGE_CHANGED = 'language-changed', + CLAIM_WITHDRAWAL_SUCCESS = 'claim-withdrawal-success', + CLAIM_WITHDRAWAL_FAILURE = 'claim-withdrawal-failure', } /** @@ -28,3 +30,27 @@ export type BridgeFailed = { /** The timestamp of the failed transaction. */ timestamp: number; }; + +/** + * Represents a successful bridge claim withdrawal. + * @property {string} transactionHash + */ +export type BridgeClaimWithdrawalSuccess = { + /** The hash of the successful transaction. */ + transactionHash: string; +}; + +/** + * Represents a failed bridge claim withdrawal. + * @property {string} transactionHash + * @property {string} reason + * @property {number} timestamp + */ +export type BridgeClaimWithdrawalFailed = { + /** The hash of the failed transaction. */ + transactionHash: string; + /** The reason for the failed transaction. */ + reason: string; + /** The timestamp of the failed transaction. */ + timestamp: number; +}; diff --git a/packages/checkout/sdk/src/widgets/definitions/types.ts b/packages/checkout/sdk/src/widgets/definitions/types.ts index 2a0ce2deca..d2d8345e0e 100644 --- a/packages/checkout/sdk/src/widgets/definitions/types.ts +++ b/packages/checkout/sdk/src/widgets/definitions/types.ts @@ -1,6 +1,8 @@ import { Environment } from '@imtbl/config'; import { Web3Provider } from '@ethersproject/providers'; import { + BridgeClaimWithdrawalFailed, + BridgeClaimWithdrawalSuccess, BridgeEventType, BridgeFailed, BridgeTransactionSent, @@ -142,6 +144,8 @@ export type WidgetEventData = { [BridgeEventType.TRANSACTION_SENT]: BridgeTransactionSent, [BridgeEventType.FAILURE]: BridgeFailed, [BridgeEventType.CLOSE_WIDGET]: {} + [BridgeEventType.CLAIM_WITHDRAWAL_SUCCESS]: BridgeClaimWithdrawalSuccess + [BridgeEventType.CLAIM_WITHDRAWAL_FAILURE]: BridgeClaimWithdrawalFailed } & OrchestrationMapping & ProviderEventMapping, [WidgetType.ONRAMP]: { diff --git a/packages/checkout/widgets-lib/src/components/Transactions/ClaimWithdrawalInProgress.tsx b/packages/checkout/widgets-lib/src/components/Transactions/ClaimWithdrawalInProgress.tsx new file mode 100644 index 0000000000..695cb4ca83 --- /dev/null +++ b/packages/checkout/widgets-lib/src/components/Transactions/ClaimWithdrawalInProgress.tsx @@ -0,0 +1,74 @@ +import { TransactionResponse } from '@ethersproject/providers'; +import { useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; +import { ViewActions, ViewContext } from 'context/view-context/ViewContext'; +import { BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; +import { LoadingView } from 'views/loading/LoadingView'; + +interface ClaimWithdrawalInProgressProps { + transactionResponse: TransactionResponse; +} + +export function ClaimWithdrawalInProgress({ transactionResponse }: ClaimWithdrawalInProgressProps) { + const { t } = useTranslation(); + const { viewDispatch } = useContext(ViewContext); + + const { page } = useAnalytics(); + + useEffect(() => { + page({ + userJourney: UserJourney.BRIDGE, + screen: 'ClaimWithdrawalInProgress', + }); + }, []); + + useEffect(() => { + if (!transactionResponse) return; + + (async () => { + try { + const receipt = await transactionResponse.wait(); + + if (receipt.status === 1) { + viewDispatch({ + payload: { + type: ViewActions.UPDATE_VIEW, + view: { + type: BridgeWidgetViews.CLAIM_WITHDRAWAL_SUCCESS, + transactionHash: receipt.transactionHash, + }, + }, + }); + return; + } + + viewDispatch({ + payload: { + type: ViewActions.UPDATE_VIEW, + view: { + type: BridgeWidgetViews.CLAIM_WITHDRAWAL_FAILURE, + transactionHash: receipt.transactionHash, + reason: 'Transaction failed', + }, + }, + }); + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + viewDispatch({ + payload: { + type: ViewActions.UPDATE_VIEW, + view: { + type: BridgeWidgetViews.CLAIM_WITHDRAWAL_FAILURE, + transactionHash: '', + reason: 'Transaction failed', + }, + }, + }); + } + })(); + }, [transactionResponse]); + + return ; +} diff --git a/packages/checkout/widgets-lib/src/components/Transactions/Transactions.tsx b/packages/checkout/widgets-lib/src/components/Transactions/Transactions.tsx index 37e20c03fa..2bd3b59dbe 100644 --- a/packages/checkout/widgets-lib/src/components/Transactions/Transactions.tsx +++ b/packages/checkout/widgets-lib/src/components/Transactions/Transactions.tsx @@ -38,7 +38,11 @@ import { KnownNetworkMap } from './transactionsType'; import { TransactionList } from './TransactionList'; import { NoTransactions } from './NoTransactions'; -export function Transactions() { +type TransactionsProps = { + onBackButtonClick: () => void; +}; + +export function Transactions({ onBackButtonClick }: TransactionsProps) { const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); const { cryptoFiatDispatch } = useContext(CryptoFiatContext); @@ -292,6 +296,7 @@ export function Transactions() { header={( sendBridgeWidgetCloseEvent(eventTarget)} /> diff --git a/packages/checkout/widgets-lib/src/context/view-context/BridgeViewContextTypes.ts b/packages/checkout/widgets-lib/src/context/view-context/BridgeViewContextTypes.ts index 452b013940..9550b1097a 100644 --- a/packages/checkout/widgets-lib/src/context/view-context/BridgeViewContextTypes.ts +++ b/packages/checkout/widgets-lib/src/context/view-context/BridgeViewContextTypes.ts @@ -1,4 +1,5 @@ import { ApproveBridgeResponse, BridgeTxResponse } from '@imtbl/bridge-sdk'; +import { TransactionResponse } from '@ethersproject/providers'; import { Transaction } from 'lib/clients'; import { ViewType } from './ViewType'; @@ -11,6 +12,9 @@ export enum BridgeWidgetViews { APPROVE_TRANSACTION = 'APPROVE_TRANSACTION', TRANSACTIONS = 'TRANSACTIONS', CLAIM_WITHDRAWAL = 'CLAIM_WITHDRAWAL', + CLAIM_WITHDRAWAL_IN_PROGRESS = 'CLAIM_WITHDRAWAL_IN_PROGRESS', + CLAIM_WITHDRAWAL_SUCCESS = 'CLAIM_WITHDRAWAL_SUCCESS', + CLAIM_WITHDRAWAL_FAILURE = 'CLAIM_WITHDRAWAL_FAILURE', } export type BridgeWidgetView = @@ -21,7 +25,10 @@ export type BridgeWidgetView = | BridgeFailure | BridgeApproveTransaction | BridgeTransactions - | BridgeClaimWithdrawal; + | BridgeClaimWithdrawal + | BridgeClaimWithdrawalInProgress + | BridgeClaimWithdrawalSuccess + | BridgeClaimWithdrawalFailure; interface BridgeCrossWalletSelection extends ViewType { type: BridgeWidgetViews.WALLET_NETWORK_SELECTION, @@ -59,3 +66,19 @@ interface BridgeClaimWithdrawal extends ViewType { type: BridgeWidgetViews.CLAIM_WITHDRAWAL, transaction: Transaction } + +interface BridgeClaimWithdrawalInProgress extends ViewType { + type: BridgeWidgetViews.CLAIM_WITHDRAWAL_IN_PROGRESS, + transactionResponse: TransactionResponse; +} + +export interface BridgeClaimWithdrawalSuccess extends ViewType { + type: BridgeWidgetViews.CLAIM_WITHDRAWAL_SUCCESS, + transactionHash: string; +} + +export interface BridgeClaimWithdrawalFailure extends ViewType { + type: BridgeWidgetViews.CLAIM_WITHDRAWAL_FAILURE, + transactionHash: string; + reason: string; +} diff --git a/packages/checkout/widgets-lib/src/locales/en.json b/packages/checkout/widgets-lib/src/locales/en.json index 0ae3abb3fc..9c6c1127d4 100644 --- a/packages/checkout/widgets-lib/src/locales/en.json +++ b/packages/checkout/widgets-lib/src/locales/en.json @@ -503,6 +503,19 @@ "footer": { "buttonText": "Continue", "retryText": "Try again" + }, + "IN_PROGRESS": { + "loading": { + "text": "Processing" + }, + "success": { + "text": "Success", + "actionText": "Done" + }, + "failure": { + "text": "Transaction failed", + "actionText": "Try again" + } } } }, diff --git a/packages/checkout/widgets-lib/src/locales/ja.json b/packages/checkout/widgets-lib/src/locales/ja.json index 8abd3dd74f..e6f252fc1a 100644 --- a/packages/checkout/widgets-lib/src/locales/ja.json +++ b/packages/checkout/widgets-lib/src/locales/ja.json @@ -506,6 +506,19 @@ "footer": { "buttonText": "続行", "retryText": "もう一度試す" + }, + "IN_PROGRESS": { + "loading": { + "text": "処理中" + }, + "success": { + "text": "成功", + "actionText": "完了" + }, + "failure": { + "text": "取引失敗", + "actionText": "再試行" + } } } }, diff --git a/packages/checkout/widgets-lib/src/locales/ko.json b/packages/checkout/widgets-lib/src/locales/ko.json index 6335b6f3b2..2408b7fb49 100644 --- a/packages/checkout/widgets-lib/src/locales/ko.json +++ b/packages/checkout/widgets-lib/src/locales/ko.json @@ -503,6 +503,19 @@ "footer": { "buttonText": "계속", "retryText": "다시 시도" + }, + "IN_PROGRESS": { + "loading": { + "text": "처리 중" + }, + "success": { + "text": "성공", + "actionText": "완료" + }, + "failure": { + "text": "거래 실패", + "actionText": "다시 시도" + } } } }, diff --git a/packages/checkout/widgets-lib/src/locales/zh.json b/packages/checkout/widgets-lib/src/locales/zh.json index 4a7d656c24..5270ceab42 100644 --- a/packages/checkout/widgets-lib/src/locales/zh.json +++ b/packages/checkout/widgets-lib/src/locales/zh.json @@ -503,6 +503,19 @@ "footer": { "buttonText": "继续", "retryText": "重试" + }, + "IN_PROGRESS": { + "loading": { + "text": "处理中" + }, + "success": { + "text": "成功", + "actionText": "完成" + }, + "failure": { + "text": "交易失败", + "actionText": "请重试" + } } } }, diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx index a084fc82d4..8f11e467b2 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx @@ -13,7 +13,7 @@ import { import { StrongCheckoutWidgetsConfig } from 'lib/withDefaultWidgetConfig'; import { CryptoFiatProvider } from 'context/crypto-fiat-context/CryptoFiatProvider'; import { JsonRpcProvider, Web3Provider } from '@ethersproject/providers'; -import { BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; +import { BridgeClaimWithdrawalFailure, BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; import { StatusView } from 'components/Status/StatusView'; import { StatusType } from 'components/Status/StatusType'; import { ImmutableConfiguration } from '@imtbl/config'; @@ -29,6 +29,7 @@ import { Transactions } from 'components/Transactions/Transactions'; import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; import { TopUpView } from 'views/top-up/TopUpView'; import { useTranslation } from 'react-i18next'; +import { ClaimWithdrawalInProgress } from 'components/Transactions/ClaimWithdrawalInProgress'; import { ViewActions, ViewContext, @@ -49,7 +50,15 @@ import { MoveInProgress } from './views/MoveInProgress'; import { ApproveTransaction } from './views/ApproveTransaction'; import { ErrorView } from '../../views/error/ErrorView'; import { EventTargetContext } from '../../context/event-target-context/EventTargetContext'; -import { sendBridgeFailedEvent, sendBridgeWidgetCloseEvent } from './BridgeWidgetEvents'; +import { + sendBridgeClaimWithdrawalFailedEvent, + sendBridgeClaimWithdrawalSuccessEvent, + sendBridgeFailedEvent, + sendBridgeWidgetCloseEvent, +} from './BridgeWidgetEvents'; +import { + BridgeClaimWithdrawalSuccess, +} from '../../context/view-context/BridgeViewContextTypes'; import { ClaimWithdrawal } from './views/ClaimWithdrawal'; export type BridgeWidgetInputs = BridgeWidgetParams & { @@ -215,7 +224,7 @@ export function BridgeWidget({ /> )} {viewState.view.type === BridgeWidgetViews.TRANSACTIONS && ( - + )} {viewState.view.type === BridgeWidgetViews.CLAIM_WITHDRAWAL && ( @@ -245,6 +254,69 @@ export function BridgeWidget({ onCloseButtonClick={() => sendBridgeWidgetCloseEvent(eventTarget)} /> )} + {viewState.view.type === BridgeWidgetViews.CLAIM_WITHDRAWAL_IN_PROGRESS && ( + + )} + {viewState.view.type === BridgeWidgetViews.CLAIM_WITHDRAWAL_SUCCESS && ( + { + page({ + userJourney: UserJourney.BRIDGE, + screen: 'ClaimWithdrawalSuccess', + }); + sendBridgeClaimWithdrawalSuccessEvent( + eventTarget, + (viewState.view as BridgeClaimWithdrawalSuccess).transactionHash, + ); + }} + onActionClick={() => sendBridgeWidgetCloseEvent(eventTarget)} + statusType={StatusType.SUCCESS} + testId="claim-withdrawal-success-view" + /> + )} + {viewState.view.type === BridgeWidgetViews.CLAIM_WITHDRAWAL_FAILURE && ( + { + let reason = ''; + if (viewState.view.type === BridgeWidgetViews.CLAIM_WITHDRAWAL_FAILURE) { + reason = viewState.view.reason; + } + page({ + userJourney: UserJourney.BRIDGE, + screen: 'ClaimWithdrawalFailure', + extras: { + reason, + }, + }); + sendBridgeClaimWithdrawalFailedEvent( + eventTarget, + (viewState.view as BridgeClaimWithdrawalFailure).transactionHash, + 'Transaction failed', + ); + }} + onActionClick={() => { + if (viewState.view.type === BridgeWidgetViews.CLAIM_WITHDRAWAL_FAILURE) { + viewDispatch({ + payload: { + type: ViewActions.UPDATE_VIEW, + view: { + type: BridgeWidgetViews.TRANSACTIONS, + }, + }, + }); + } + }} + statusType={StatusType.FAILURE} + onCloseClick={() => sendBridgeWidgetCloseEvent(eventTarget)} + testId="claim-withdrawal-fail-view" + /> + )} diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidgetEvents.ts b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidgetEvents.ts index 116df50ec8..1fde897b0a 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidgetEvents.ts +++ b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidgetEvents.ts @@ -54,3 +54,43 @@ export function sendBridgeWidgetCloseEvent(eventTarget: Window | EventTarget) { console.log('bridge close ', eventTarget, closeWidgetEvent); if (eventTarget !== undefined) eventTarget.dispatchEvent(closeWidgetEvent); } + +export const sendBridgeClaimWithdrawalSuccessEvent = (eventTarget: Window | EventTarget, transactionHash: string) => { + const successEvent = new CustomEvent>( + IMTBLWidgetEvents.IMTBL_BRIDGE_WIDGET_EVENT, + { + detail: { + type: BridgeEventType.CLAIM_WITHDRAWAL_SUCCESS, + data: { + transactionHash, + }, + }, + }, + ); + // eslint-disable-next-line no-console + console.log('bridge claim withdrawal success event:', eventTarget, successEvent); + if (eventTarget !== undefined) eventTarget.dispatchEvent(successEvent); +}; + +export const sendBridgeClaimWithdrawalFailedEvent = ( + eventTarget: Window | EventTarget, + transactionHash: string, + reason: string, +) => { + const failedEvent = new CustomEvent>( + IMTBLWidgetEvents.IMTBL_BRIDGE_WIDGET_EVENT, + { + detail: { + type: BridgeEventType.CLAIM_WITHDRAWAL_FAILURE, + data: { + transactionHash, + reason, + timestamp: new Date().getTime(), + }, + }, + }, + ); + // eslint-disable-next-line no-console + console.log('bridge claim withdrawal failed event:', eventTarget, failedEvent); + if (eventTarget !== undefined) eventTarget.dispatchEvent(failedEvent); +}; diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/views/ClaimWithdrawal.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/views/ClaimWithdrawal.tsx index 5ac20d5d41..8f2fc93493 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/views/ClaimWithdrawal.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/views/ClaimWithdrawal.tsx @@ -15,6 +15,7 @@ import { WalletProviderName } from '@imtbl/checkout-sdk'; import { isNativeToken } from 'lib/utils'; import { BigNumber } from 'ethers'; import { FlowRateWithdrawResponse } from '@imtbl/bridge-sdk'; +import { BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { sendBridgeWidgetCloseEvent } from '../BridgeWidgetEvents'; @@ -169,13 +170,20 @@ export function ClaimWithdrawal({ transaction }: ClaimWithdrawalProps) { // send transaction to wallet for signing try { - // TODO: WT-2054 Update view to go to in progress screens and pass through sendTransaction response - - // const response = await checkout.sendTransaction({ - // provider: providerToUse, - // transaction: withdrawalResponse.unsignedTx, - // }); + const response = await checkout.sendTransaction({ + provider: providerToUse, + transaction: withdrawalResponse.unsignedTx, + }); + viewDispatch({ + payload: { + type: ViewActions.UPDATE_VIEW, + view: { + type: BridgeWidgetViews.CLAIM_WITHDRAWAL_IN_PROGRESS, + transactionResponse: response.transactionResponse, + }, + }, + }); } catch (err) { // eslint-disable-next-line no-console console.log(err); diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/views/MoveInProgress.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/views/MoveInProgress.tsx index de5205b909..25a2dba436 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/views/MoveInProgress.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/views/MoveInProgress.tsx @@ -84,8 +84,8 @@ export function MoveInProgress({ transactionHash }: MoveInProgressProps) { variant="guidance" sx={{ position: 'absolute', - right: 'base.spacing.x16', - top: 'base.spacing.x2', + right: 'base.spacing.x14', + top: 'base.spacing.x1', }} />