Skip to content

Commit

Permalink
Merge branch 'main' into feature/ID-1897-improve-magic-session-manage…
Browse files Browse the repository at this point in the history
…ment
  • Loading branch information
haydenfowler authored Feb 5, 2025
2 parents 061ecbd + 6396cbd commit d782743
Show file tree
Hide file tree
Showing 17 changed files with 532 additions and 262 deletions.
4 changes: 2 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
/packages/orderbook @immutable/traders
/packages/passport @immutable/passport
/packages/x-provider @immutable/passport
/packages/checkout @immutable/commerce
/packages/checkout/widgets-lib @immutable/commerce
/packages/checkout @immutable/passport
/packages/checkout/widgets-lib @immutable/passport
/packages/blockchain-data @immutable/activation
/packages/minting-backend @shineli1984
/packages/webhook @shineli1984
Expand Down
2 changes: 1 addition & 1 deletion packages/checkout/sdk/src/config/tokensFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class TokensFetcher {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
bridge: null,
bridge: 'native',
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { ViewType } from './ViewType';
export enum PurchaseWidgetViews {
PURCHASE = 'PURCHASE',
REVIEW = 'REVIEW',
PAY_WITH_CARD = 'PAY_WITH_CARD',
GEO_BLOCK_ERROR = 'GEO_BLOCK_ERROR',
}

export type PurchaseWidgetView = PurchaseView | PurchaseReview | GeoBlockErrorView;
export type PurchaseWidgetView = PurchaseView | PurchaseReview | GeoBlockErrorView | PurchaseWithCardView;

interface PurchaseView extends ViewType {
type: PurchaseWidgetViews.PURCHASE;
Expand All @@ -17,6 +18,10 @@ interface PurchaseReview extends ViewType {
data: PurchaseReviewData;
}

interface PurchaseWithCardView extends ViewType {
type: PurchaseWidgetViews.PAY_WITH_CARD;
}

interface GeoBlockErrorView extends ViewType {
type: PurchaseWidgetViews.GEO_BLOCK_ERROR;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/checkout/widgets-lib/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,8 @@
"routeSelection": {
"loadingText": "Finding the best payment route...",
"noRoute": "No routes found, choose a different wallet, token or amount.",
"payWithCard": "No routes found, pay with card available",
"payWithCard": "Pay with card",
"noRoutePayWithCard": "No routes found, pay with card available",
"fastestBadge": "Cheapest & fastest",
"minutesText": "mins",
"minuteText": "min",
Expand Down
3 changes: 2 additions & 1 deletion packages/checkout/widgets-lib/src/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -878,7 +878,8 @@
"routeSelection": {
"loadingText": "最適な支払いルートを検索中...",
"noRoute": "ルートが見つかりません。他のウォレット、トークン、または金額を選択してください。",
"payWithCard": "ルートが見つかりません。カードでの支払いが利用可能です",
"payWithCard": "カードで支払う",
"noRoutePayWithCard": "ルートが見つかりません。カードでの支払いが利用可能です",
"fastestBadge": "最速",
"minutesText": "",
"minuteText": "",
Expand Down
3 changes: 2 additions & 1 deletion packages/checkout/widgets-lib/src/locales/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,8 @@
"routeSelection": {
"loadingText": "최적의 결제 경로를 찾는 중...",
"noRoute": "경로를 찾을 수 없습니다. 다른 지갑, 토큰 또는 금액을 선택하세요.",
"payWithCard": "경로를 찾을 수 없습니다. 카드 결제가 가능합니다",
"payWithCard": "카드로 결제",
"noRoutePayWithCard": "경로를 찾을 수 없습니다. 카드 결제가 가능합니다",
"fastestBadge": "가장 빠름",
"minutesText": "",
"minuteText": "",
Expand Down
5 changes: 3 additions & 2 deletions packages/checkout/widgets-lib/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@
"routeSelection": {
"loadingText": "寻找最佳支付路线中...",
"noRoute": "未找到路线,请选择其他钱包、代币或金额。",
"payWithCard": "未找到路线,可选择用卡支付",
"payWithCard": "用卡支付",
"fastestBadge": "最快",
"minutesText": "分钟",
"minuteText": "分钟",
Expand Down Expand Up @@ -878,7 +878,8 @@
"routeSelection": {
"loadingText": "寻找最佳支付路线中...",
"noRoute": "未找到路线,请选择其他钱包、代币或金额。",
"payWithCard": "未找到路线,可选择用卡支付",
"payWithCard": "用卡支付",
"noRoutePayWithCard": "未找到路线,可选择用卡支付",
"fastestBadge": "最快",
"minutesText": "分钟",
"minuteText": "分钟",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { fetchChains } from '../../lib/squid/functions/fetchChains';
import { useSquid } from '../../lib/squid/hooks/useSquid';
import { useTokens } from '../../lib/squid/hooks/useTokens';
import { useQuoteOrder } from '../../lib/hooks/useQuoteOrder';
import { PayWithCard } from './views/PayWithCard';

export type PurchaseWidgetInputs = PurchaseWidgetParams & {
config: StrongCheckoutWidgetsConfig;
Expand Down Expand Up @@ -200,6 +201,18 @@ export default function PurchaseWidget({
}}
/>
)}
{viewState.view.type === PurchaseWidgetViews.PAY_WITH_CARD && (
<PayWithCard
onCloseButtonClick={() => {
orchestrationEvents.sendRequestGoBackEvent(
eventTarget,
IMTBLWidgetEvents.IMTBL_PURCHASE_WIDGET_EVENT,
{},
);
}}
onError={() => {}}
/>
)}
</Stack>
</CryptoFiatProvider>
</PurchaseContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ReactNode, useRef, useState } from 'react';
import {
ReactNode, useRef, useState,
} from 'react';
import {
EIP6963ProviderDetail,
EIP6963ProviderInfo,
Expand Down Expand Up @@ -66,6 +68,7 @@ export function PurchaseConnectWalletDrawer({
providerInfo: EIP6963ProviderInfo,
) => {
const address = await provider.getSigner().getAddress();

providersDispatch({
payload: {
type: ProvidersContextActions.SET_PROVIDER,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import { getRouteAndTokenBalances } from '../../../lib/squid/functions/getRouteA
import { Chain, RouteData } from '../../../lib/squid/types';
import { getRemoteVideo } from '../../../lib/utils';
import { getRouteAndTokenBalancesForDirectCryptoPay } from '../functions/getRouteAndBalancesForDirectCryptoPay';
import { DirectCryptoPayData } from '../types';
import {
DirectCryptoPayData,
} from '../types';

interface PurchaseSelectedRouteOptionProps {
checkout: Checkout;
Expand Down Expand Up @@ -111,7 +113,7 @@ export function PurchaseSelectedRouteOption({

if (insufficientBalancePayWithCard) {
icon = 'BankCard';
copy = t('views.PURCHASE.routeSelection.payWithCard');
copy = t('views.PURCHASE.routeSelection.noRoutePayWithCard');
}

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useContext, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { WalletProviderRdns } from '@imtbl/checkout-sdk';
import { PurchaseContext } from '../context/PurchaseContext';
import { TransakIframe } from '../../../components/Transak/TransakIframe';
import { TransakNFTData } from '../../../components/Transak/TransakTypes';
import { useProvidersContext } from '../../../context/providers-context/ProvidersContext';

export interface WithCardProps {
onInit?: (data: Record<string, unknown>) => void;
onOpen?: (data: Record<string, unknown>) => void;
onOrderCreated?: (data: Record<string, unknown>) => void;
onOrderProcessing?: (data: Record<string, unknown>) => void;
onOrderCompleted?: (data: Record<string, unknown>) => void;
onOrderFailed?: (data: Record<string, unknown>) => void;
}

export function WithCard(props: WithCardProps) {
const { t } = useTranslation();
const {
onInit,
onOpen,
onOrderCreated,
onOrderProcessing,
onOrderCompleted,
onOrderFailed,
} = props;
const {
purchaseState: {
signResponse,
quote,
},
} = useContext(PurchaseContext);

const onFailedToLoad = () => { };

const {
providersState: {
toProviderInfo,
toAddress,
checkout,
},
} = useProvidersContext();

const recipientEmail = '';
const recipientAddress = toAddress || '';
const isPassportWallet = toProviderInfo?.rdns === WalletProviderRdns.PASSPORT;
const excludeFiatCurrencies = [];
const { environment } = checkout.config;
const executeTxn = signResponse?.transactions.find((txn) => txn.methodCall.startsWith('execute'));

if (!signResponse || !executeTxn) {
return null;
}

const nftData: TransakNFTData[] = useMemo(
() => signResponse.order.products.map((product) => ({
collectionAddress: product.collectionAddress,
imageURL: product.image,
nftName: product.name,
price: product.amount,
quantity: product.qty,
tokenID: product.tokenId,
nftType: product.contractType || 'ERC721',
})),
[signResponse],
);

return (
<TransakIframe
id="transak-iframe"
type="nft-checkout"
email={recipientEmail}
walletAddress={recipientAddress}
isPassportWallet={isPassportWallet}
exchangeScreenTitle={t('views.PAY_WITH_CARD.screenTitle')}
nftData={nftData}
calldata={executeTxn.rawData}
cryptoCurrencyCode={signResponse.order.currency.name}
estimatedGasLimit={executeTxn.gasEstimate}
partnerOrderId={executeTxn.params.reference}
excludeFiatCurrencies={excludeFiatCurrencies}
onInit={onInit}
onOpen={onOpen}
onOrderCreated={onOrderCreated}
onOrderProcessing={onOrderProcessing}
onOrderCompleted={onOrderCompleted}
onOrderFailed={onOrderFailed}
onFailedToLoad={onFailedToLoad}
environment={environment}
contractId={quote?.quote.config.contractId || ''}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Squid } from '@0xsquid/sdk';
import { PurchaseItem, TokenInfo } from '@imtbl/checkout-sdk';
import { createContext } from 'react';
import { createContext, useContext } from 'react';
import { Chain, Token, RouteData } from '../../../lib/squid/types';
import { OrderQuoteResponse } from '../../../lib/primary-sales';
import { OrderQuoteResponse, SignResponse } from '../../../lib/primary-sales';

export interface PurchaseState {
id: string;
Expand All @@ -15,6 +15,7 @@ export interface PurchaseState {
selectedToken: TokenInfo | undefined;
selectedRouteData: RouteData | undefined;
quote: OrderQuoteResponse | null;
signResponse: SignResponse | undefined;
}

export const initialPurchaseState: PurchaseState = {
Expand All @@ -28,6 +29,7 @@ export const initialPurchaseState: PurchaseState = {
selectedToken: undefined,
selectedRouteData: undefined,
quote: null,
signResponse: undefined,
};

export interface PurchaseContextState {
Expand All @@ -48,7 +50,8 @@ type ActionPayload =
| SetSquidChains
| SetSquidTokens
| SetItems
| SetQuote;
| SetQuote
| SetSignResponse;

export enum PurchaseActions {
SET_ID = 'SET_ID',
Expand All @@ -59,6 +62,7 @@ export enum PurchaseActions {
SET_SELECTED_TOKEN = 'SET_SELECTED_TOKEN',
SET_SELECTED_ROUTE_DATA = 'SET_SELECTED_ROUTE_DATA',
SET_QUOTE = 'SET_QUOTE',
SET_SIGN_RESPONSE = 'SET_SIGN_RESPONSE',
}

export interface SetId {
Expand Down Expand Up @@ -86,6 +90,11 @@ export interface SetItems {
items: PurchaseItem[];
}

export interface SetSignResponse {
type: PurchaseActions.SET_SIGN_RESPONSE;
signResponse: SignResponse;
}

export interface SetSelectedToken {
type: PurchaseActions.SET_SELECTED_TOKEN;
selectedToken: TokenInfo;
Expand All @@ -95,6 +104,7 @@ export interface SetSelectedRouteData {
type: PurchaseActions.SET_SELECTED_ROUTE_DATA;
selectedRouteData: RouteData;
}

export interface SetQuote {
type: PurchaseActions.SET_QUOTE;
quote: OrderQuoteResponse;
Expand Down Expand Up @@ -164,7 +174,16 @@ export const purchaseReducer: Reducer<PurchaseState, PurchaseAction> = (
...state,
quote: action.payload.quote,
};
case PurchaseActions.SET_SIGN_RESPONSE:
return {
...state,
signResponse: action.payload.signResponse,
};
default:
return state;
}
};

export function usePurchaseContext() {
return useContext(PurchaseContext);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useState } from 'react';
import { Box, LoadingOverlay } from '@biom3/react';

import { useTranslation } from 'react-i18next';
import { HeaderNavigation } from '../../../components/Header/HeaderNavigation';
import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout';
import { WithCard } from '../components/WithCard';

interface PayWithCardProps {
onCloseButtonClick?: () => void;
onError?: () => void;
}

export function PayWithCard({
onCloseButtonClick,
onError,
}: PayWithCardProps) {
const [initialised, setInitialised] = useState(false);
const { t } = useTranslation();

const onInit = () => setInitialised(true);

const onOrderFailed = () => {
onError?.();
};

return (
<SimpleLayout
header={
initialised && (
<HeaderNavigation
onCloseButtonClick={() => onCloseButtonClick?.()}
/>
)
}
>
<>
<LoadingOverlay visible={!initialised}>
<LoadingOverlay.Content>
<LoadingOverlay.Content.LoopingText
text={[t('views.PAY_WITH_CARD.loading')]}
/>
</LoadingOverlay.Content>
</LoadingOverlay>
<Box
style={{
display: 'block',
position: 'relative',
maxWidth: '420px',
height: '565px',
borderRadius: '1%',
overflow: 'hidden',
margin: '0 auto',
width: '100%',
}}
>
<WithCard
onInit={onInit}
onOrderFailed={onOrderFailed}
/>
</Box>
</>
</SimpleLayout>
);
}
Loading

0 comments on commit d782743

Please sign in to comment.