Skip to content

Commit

Permalink
Feat: [NO CHANGELOG][Add Funds Widget] Create Add Funds Widget by sur…
Browse files Browse the repository at this point in the history
…facing Top Up View (#2089)

Co-authored-by: Mimi Tran <[email protected]>
  • Loading branch information
jiyounglee and mimi-imtbl authored Aug 16, 2024
1 parent b0b671e commit 549a631
Show file tree
Hide file tree
Showing 16 changed files with 401 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { WidgetConfiguration } from './widget';

/**
* Add Funds Widget Configuration represents the configuration options for the Add Funds Widget.
*/
export type AddFundsWidgetConfiguration = {
// TODO : [ADD_FUNDS] - What are the configuration needed?
} & WidgetConfiguration;
11 changes: 11 additions & 0 deletions packages/checkout/sdk/src/widgets/definitions/events/addFunds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Enum of possible Add Funds Widget event types.
*/
export enum AddFundsEventType {
CLOSE_WIDGET = 'close-widget',
LANGUAGE_CHANGED = 'language-changed',
REQUEST_BRIDGE = 'request-bridge',
REQUEST_ONRAMP = 'request-onramp',
REQUEST_SWAP = 'request-swap',
GO_BACK = 'go-back',
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './bridge';
export * from './orchestration';
export * from './onramp';
export * from './checkout';
export * from './addFunds';
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum OrchestrationEventType {
REQUEST_SWAP = 'request-swap',
REQUEST_BRIDGE = 'request-bridge',
REQUEST_ONRAMP = 'request-onramp',
REQUEST_ADD_FUNDS = 'request-add-funds',
}

/**
Expand Down Expand Up @@ -66,6 +67,12 @@ export type RequestOnrampEvent = {
amount: string;
};

/**
* Represents the add funds event object when the add funds widget is requested.
*/
export type RequestAddFundsEvent = {
};

/*
* Type representing the orchestration events.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export enum IMTBLWidgetEvents {
IMTBL_ONRAMP_WIDGET_EVENT = 'imtbl-onramp-widget',
IMTBL_SALE_WIDGET_EVENT = 'imtbl-sale-widget',
IMTBL_CHECKOUT_WIDGET_EVENT = 'imtbl-checkout-widget',
IMTBL_ADD_FUNDS_WIDGET_EVENT = 'imtbl-add-funds-widget',
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { WidgetLanguage } from '../configurations';

export type AddFundsWidgetParams = {
/** The language to use for the Add Funds widget */
language?: WidgetLanguage;

/** Configure to show on-ramp option */
showOnrampOption?: boolean;

/** Configure to show swap option */
showSwapOption?: boolean;

/** Configure to show on bridge option */
showBridgeOption?: boolean;

/** Token address of the fund to be added */
tokenAddress?: string;

/** Amount of the fund to be added */
amount?: string;
};
18 changes: 18 additions & 0 deletions packages/checkout/sdk/src/widgets/definitions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
CheckoutSuccessEvent,
CheckoutFailureEvent,
CheckoutUserActionEvent,
RequestAddFundsEvent,
} from './events';
import {
BridgeWidgetParams,
Expand All @@ -59,6 +60,9 @@ import {
CheckoutWidgetConfiguration,
} from './configurations';
import { WidgetTheme } from './configurations/theme';
import { AddFundsWidgetConfiguration } from './configurations/addFunds';
import { AddFundsWidgetParams } from './parameters/addFunds';
import { AddFundsEventType } from './events/addFunds';

/**
* Enum representing the list of widget types.
Expand All @@ -71,6 +75,7 @@ export enum WidgetType {
ONRAMP = 'onramp',
SALE = 'sale',
CHECKOUT = 'checkout',
ADD_FUNDS = 'addFunds',
}

/**
Expand All @@ -89,6 +94,7 @@ export type WidgetConfigurations = {
[WidgetType.ONRAMP]: OnrampWidgetConfiguration;
[WidgetType.SALE]: SaleWidgetConfiguration;
[WidgetType.CHECKOUT]: CheckoutWidgetConfiguration;
[WidgetType.ADD_FUNDS]: AddFundsWidgetConfiguration;
};

// Mapping each widget type to their parameters
Expand All @@ -100,6 +106,7 @@ export type WidgetParameters = {
[WidgetType.ONRAMP]: OnRampWidgetParams;
[WidgetType.SALE]: SaleWidgetParams;
[WidgetType.CHECKOUT]: CheckoutWidgetParams;
[WidgetType.ADD_FUNDS]: AddFundsWidgetParams;
};

/**
Expand All @@ -113,6 +120,7 @@ export type WidgetEventTypes = {
[WidgetType.ONRAMP]: OnRampEventType | OrchestrationEventType;
[WidgetType.SALE]: SaleEventType | OrchestrationEventType;
[WidgetType.CHECKOUT]: CheckoutEventType | OrchestrationEventType;
[WidgetType.ADD_FUNDS]: AddFundsEventType | OrchestrationEventType;
};

// Mapping of Orchestration events to their payloads
Expand All @@ -122,6 +130,7 @@ type OrchestrationMapping = {
[OrchestrationEventType.REQUEST_SWAP]: RequestSwapEvent;
[OrchestrationEventType.REQUEST_BRIDGE]: RequestBridgeEvent;
[OrchestrationEventType.REQUEST_ONRAMP]: RequestOnrampEvent;
[OrchestrationEventType.REQUEST_ADD_FUNDS]: RequestAddFundsEvent;
};

type ProviderEventMapping = {
Expand Down Expand Up @@ -196,6 +205,15 @@ export type WidgetEventData = {
[CheckoutEventType.DISCONNECTED]: {};
[CheckoutEventType.USER_ACTION]: CheckoutUserActionEvent;
};

[WidgetType.ADD_FUNDS]: {
[AddFundsEventType.CLOSE_WIDGET]: {};
[AddFundsEventType.GO_BACK]: {};
[AddFundsEventType.REQUEST_BRIDGE]: {};
[AddFundsEventType.REQUEST_SWAP]: {};
[AddFundsEventType.REQUEST_ONRAMP]: {};
} & OrchestrationMapping &
ProviderEventMapping;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum UserJourney {
SWAP = 'Swap',
BRIDGE = 'Bridge',
SALE = 'PrimarySale',
ADD_FUNDS = 'AddFunds',
}

export type AnalyticsControlTypes =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ViewType } from './ViewType';

export enum AddFundsWidgetViews {
ADD_FUNDS = 'ADD_FUNDS',
}

export type AddFundsWidgetView = AddFundsView;

interface AddFundsView extends ViewType {
type: AddFundsWidgetViews.ADD_FUNDS;
}
7 changes: 7 additions & 0 deletions packages/checkout/widgets-lib/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from './lib';
import './i18n';
import { CheckoutWidgetRoot } from './widgets/checkout/CheckoutWidgetRoot';
import { AddFunds } from './widgets/add-funds/AddFundsRoot';

export class WidgetsFactory implements IWidgetsFactory {
private sdk: Checkout;
Expand Down Expand Up @@ -103,6 +104,12 @@ export class WidgetsFactory implements IWidgetsFactory {
provider,
}) as Widget<WidgetType.CHECKOUT> as Widget<T>;
}
case WidgetType.ADD_FUNDS: {
return new AddFunds(this.sdk, {
config: { ...this.widgetConfig, ...(config) },
provider,
}) as Widget<WidgetType.ADD_FUNDS> as Widget<T>;
}
default:
throw new Error('widget type not supported');
}
Expand Down
100 changes: 100 additions & 0 deletions packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsRoot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import {
ChainId,
IMTBLWidgetEvents,
WidgetConfiguration,
WidgetProperties,
WidgetTheme,
WidgetType,
} from '@imtbl/checkout-sdk';
import React, { Suspense } from 'react';
import { AddFundsWidgetParams } from '@imtbl/checkout-sdk/dist/widgets/definitions/parameters/addFunds';
import { Base } from '../BaseWidgetRoot';
import { CustomAnalyticsProvider } from '../../context/analytics-provider/CustomAnalyticsProvider';
import { HandoverProvider } from '../../context/handover-context/HandoverProvider';
import i18n from '../../i18n';
import { LoadingView } from '../../views/loading/LoadingView';
import { ThemeProvider } from '../../components/ThemeProvider/ThemeProvider';
import {
ConnectLoader,
ConnectLoaderParams,
} from '../../components/ConnectLoader/ConnectLoader';
import { getL1ChainId, getL2ChainId } from '../../lib';
import { sendAddFundsCloseEvent } from './AddFundsWidgetEvents';

const AddFundsWidget = React.lazy(() => import('./AddFundsWidget'));

export class AddFunds extends Base<WidgetType.ADD_FUNDS> {
protected eventTopic: IMTBLWidgetEvents = IMTBLWidgetEvents.IMTBL_ADD_FUNDS_WIDGET_EVENT;

protected getValidatedProperties({
config,
}: WidgetProperties<WidgetType.ADD_FUNDS>): WidgetProperties<WidgetType.ADD_FUNDS> {
let validatedConfig: WidgetConfiguration | undefined;

if (config) {
validatedConfig = config;
if (config.theme === WidgetTheme.LIGHT) validatedConfig.theme = WidgetTheme.LIGHT;
else validatedConfig.theme = WidgetTheme.DARK;
}

return {
config: validatedConfig,
};
}

protected getValidatedParameters(
params: AddFundsWidgetParams,
): AddFundsWidgetParams {
const validatedParams = params;
return validatedParams;
}

protected render() {
if (!this.reactRoot) return;

const { t } = i18n;
const connectLoaderParams: ConnectLoaderParams = {
targetChainId: this.checkout.config.isProduction
? ChainId.IMTBL_ZKEVM_MAINNET
: ChainId.IMTBL_ZKEVM_TESTNET,
web3Provider: this.web3Provider,
checkout: this.checkout,
allowedChains: [
getL1ChainId(this.checkout.config),
getL2ChainId(this.checkout.config),
],
};

this.reactRoot.render(
<React.StrictMode>
<CustomAnalyticsProvider checkout={this.checkout}>
<ThemeProvider id="add-funds-container" config={this.strongConfig()}>
<HandoverProvider>
<ConnectLoader
widgetConfig={this.strongConfig()}
params={connectLoaderParams}
closeEvent={() => sendAddFundsCloseEvent(window)}
>
<Suspense
fallback={
<LoadingView loadingText={t('views.LOADING_VIEW.text')} />
}
>
<AddFundsWidget
checkout={this.checkout}
web3Provider={this.web3Provider}
showBridgeOption={this.parameters.showBridgeOption}
showSwapOption={this.parameters.showSwapOption}
showOnrampOption={this.parameters.showOnrampOption}
tokenAddress={this.parameters.tokenAddress}
amount={this.parameters.amount}
/>
</Suspense>
</ConnectLoader>
</HandoverProvider>
</ThemeProvider>
</CustomAnalyticsProvider>
</React.StrictMode>,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { AddFundsWidgetParams } from '@imtbl/checkout-sdk/dist/widgets/definitions/parameters/addFunds';
import { Checkout, IMTBLWidgetEvents } from '@imtbl/checkout-sdk';
import { Web3Provider } from '@ethersproject/providers';
import { useContext, useMemo, useReducer } from 'react';
import { UserJourney } from '../../context/analytics-provider/SegmentAnalyticsProvider';
import { TopUpView } from '../../views/top-up/TopUpView';
import {
sendAddFundsCloseEvent,
sendAddFundsGoBackEvent,
} from './AddFundsWidgetEvents';
import { EventTargetContext } from '../../context/event-target-context/EventTargetContext';
import {
ViewContext,
initialViewState,
viewReducer,
} from '../../context/view-context/ViewContext';

export type AddFundsWidgetInputs = AddFundsWidgetParams & {
checkout: Checkout;
web3Provider?: Web3Provider;
};

export default function AddFundsWidget({
checkout,
web3Provider,
showOnrampOption = true,
showSwapOption = true,
showBridgeOption = true,
tokenAddress,
amount,
}: AddFundsWidgetInputs) {
const [viewState, viewDispatch] = useReducer(viewReducer, initialViewState);

const viewReducerValues = useMemo(
() => ({ viewState, viewDispatch }),
[viewState, viewReducer],
);

const {
eventTargetState: { eventTarget },
} = useContext(EventTargetContext);

return (
<ViewContext.Provider value={viewReducerValues}>
<TopUpView
analytics={{ userJourney: UserJourney.ADD_FUNDS }}
widgetEvent={IMTBLWidgetEvents.IMTBL_ADD_FUNDS_WIDGET_EVENT}
checkout={checkout}
provider={web3Provider}
tokenAddress={tokenAddress}
amount={amount}
showOnrampOption={showOnrampOption}
showSwapOption={showSwapOption}
showBridgeOption={showBridgeOption}
onCloseButtonClick={() => sendAddFundsCloseEvent(eventTarget)}
onBackButtonClick={() => sendAddFundsGoBackEvent(eventTarget)}
/>
</ViewContext.Provider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
WidgetEvent,
WidgetType,
AddFundsEventType,
IMTBLWidgetEvents,
} from '@imtbl/checkout-sdk';

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function sendAddFundsCloseEvent(eventTarget: Window | EventTarget) {
const closeWidgetEvent = new CustomEvent<
WidgetEvent<WidgetType.ADD_FUNDS, AddFundsEventType.CLOSE_WIDGET>
>(IMTBLWidgetEvents.IMTBL_ADD_FUNDS_WIDGET_EVENT, {
detail: {
type: AddFundsEventType.CLOSE_WIDGET,
data: {},
},
});
// TODO: please remove or if necessary keep the eslint ignore
// eslint-disable-next-line no-console
console.log('close widget event:', closeWidgetEvent);
if (eventTarget !== undefined) eventTarget.dispatchEvent(closeWidgetEvent);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function sendAddFundsGoBackEvent(eventTarget: Window | EventTarget) {
const closeWidgetEvent = new CustomEvent<
WidgetEvent<WidgetType.ADD_FUNDS, AddFundsEventType.GO_BACK>
>(IMTBLWidgetEvents.IMTBL_ADD_FUNDS_WIDGET_EVENT, {
detail: {
type: AddFundsEventType.GO_BACK,
data: {},
},
});
// TODO: please remove or if necessary keep the eslint ignore
// eslint-disable-next-line no-console
console.log('go back event:', closeWidgetEvent);
if (eventTarget !== undefined) eventTarget.dispatchEvent(closeWidgetEvent);
}
Loading

0 comments on commit 549a631

Please sign in to comment.