Skip to content

Commit

Permalink
feat:[CM-708] Checkout Widget Setup (#1993)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwhardwick authored Jul 23, 2024
1 parent 07b182c commit 66a081d
Show file tree
Hide file tree
Showing 14 changed files with 199 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* eslint-disable max-len */
import { WidgetConfiguration } from './widget';

export type CheckoutWidgetConfiguration = {

} & WidgetConfiguration;
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './onramp';
export * from './sale';
export * from './theme';
export * from './widget';
export * from './checkout';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum CheckoutEventType {

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './sale';
export * from './bridge';
export * from './orchestration';
export * from './onramp';
export * from './checkout';
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export enum IMTBLWidgetEvents {
IMTBL_BRIDGE_WIDGET_EVENT = 'imtbl-bridge-widget',
IMTBL_ONRAMP_WIDGET_EVENT = 'imtbl-onramp-widget',
IMTBL_SALE_WIDGET_EVENT = 'imtbl-sale-widget',
IMTBL_CHECKOUT_WIDGET_EVENT = 'imtbl-checkout-widget',
}

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

export type CheckoutWidgetParams = {
/** The language to use for the checkout widget */
language?: WidgetLanguage;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './wallet';
export * from './swap';
export * from './onramp';
export * from './sale';
export * from './checkout';
18 changes: 14 additions & 4 deletions packages/checkout/sdk/src/widgets/definitions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ import {
WalletDisconnect,
WalletEventType,
WalletNetworkSwitch,
CheckoutEventType,
} from './events';
import {
BridgeWidgetParams,
ConnectWidgetParams,
SwapWidgetParams,
WalletWidgetParams,
OnRampWidgetParams,
CheckoutWidgetParams,
} from './parameters';
import { SaleWidgetParams } from './parameters/sale';
import {
Expand All @@ -50,6 +52,7 @@ import {
SaleWidgetConfiguration,
SwapWidgetConfiguration,
WalletWidgetConfiguration,
CheckoutWidgetConfiguration,
} from './configurations';
import { WidgetTheme } from './configurations/theme';

Expand All @@ -63,6 +66,7 @@ export enum WidgetType {
BRIDGE = 'bridge',
ONRAMP = 'onramp',
SALE = 'sale',
CHECKOUT = 'checkout',
}

/**
Expand All @@ -79,7 +83,8 @@ export type WidgetConfigurations = {
[WidgetType.SWAP]: SwapWidgetConfiguration,
[WidgetType.BRIDGE]: BridgeWidgetConfiguration,
[WidgetType.ONRAMP]: OnrampWidgetConfiguration,
[WidgetType.SALE]: SaleWidgetConfiguration
[WidgetType.SALE]: SaleWidgetConfiguration,
[WidgetType.CHECKOUT]: CheckoutWidgetConfiguration,
};

// Mapping each widget type to their parameters
Expand All @@ -89,7 +94,8 @@ export type WidgetParameters = {
[WidgetType.SWAP]: SwapWidgetParams,
[WidgetType.BRIDGE]: BridgeWidgetParams,
[WidgetType.ONRAMP]: OnRampWidgetParams,
[WidgetType.SALE]: SaleWidgetParams
[WidgetType.SALE]: SaleWidgetParams,
[WidgetType.CHECKOUT]: CheckoutWidgetParams,
};

/**
Expand All @@ -101,7 +107,8 @@ export type WidgetEventTypes = {
[WidgetType.SWAP]: SwapEventType | OrchestrationEventType,
[WidgetType.BRIDGE]: BridgeEventType | OrchestrationEventType,
[WidgetType.ONRAMP]: OnRampEventType | OrchestrationEventType,
[WidgetType.SALE]: SaleEventType | OrchestrationEventType
[WidgetType.SALE]: SaleEventType | OrchestrationEventType,
[WidgetType.CHECKOUT]: CheckoutEventType | OrchestrationEventType,
};

// Mapping of Orchestration events to their payloads
Expand Down Expand Up @@ -168,7 +175,10 @@ export type WidgetEventData = {
[SaleEventType.REQUEST_BRIDGE]: {},
[SaleEventType.REQUEST_SWAP]: {},
[SaleEventType.REQUEST_ONRAMP]: {},
} & OrchestrationMapping & ProviderEventMapping
} & OrchestrationMapping & ProviderEventMapping,

[WidgetType.CHECKOUT]: {
} & OrchestrationMapping & ProviderEventMapping,
};

/**
Expand Down
11 changes: 11 additions & 0 deletions packages/checkout/widgets-lib/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
WidgetConfigurations,
} from '@imtbl/checkout-sdk';
import { Web3Provider } from '@ethersproject/providers';
import { Environment } from '@imtbl/config';
import { Connect } from './widgets/connect/ConnectWidgetRoot';
import { Swap } from './widgets/swap/SwapWidgetRoot';
import { OnRamp } from './widgets/on-ramp/OnRampWidgetRoot';
Expand All @@ -21,6 +22,7 @@ import {
DEFAULT_THEME,
} from './lib';
import './i18n';
import { CheckoutWidgetRoot } from './widgets/checkout/CheckoutWidgetRoot';

export class WidgetsFactory implements IWidgetsFactory {
private sdk: Checkout;
Expand Down Expand Up @@ -92,6 +94,15 @@ export class WidgetsFactory implements IWidgetsFactory {
provider,
}) as Widget<WidgetType.SALE> as Widget<T>;
}
case WidgetType.CHECKOUT: {
if (this.sdk.config.environment === Environment.PRODUCTION) {
throw new Error('Checkout widget is not supported in production');
}
return new CheckoutWidgetRoot(this.sdk, {
config: { ...this.widgetConfig, ...(config) },
provider,
}) as Widget<WidgetType.CHECKOUT> as Widget<T>;
}
default:
throw new Error('widget type not supported');
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { CheckoutWidgetParams } from '@imtbl/checkout-sdk';
import {
useContext,
} from 'react';
import { ConnectLoaderContext } from '../../context/connect-loader-context/ConnectLoaderContext';
import { StrongCheckoutWidgetsConfig } from '../../lib/withDefaultWidgetConfig';

export type CheckoutWidgetInputs = CheckoutWidgetParams & {
config: StrongCheckoutWidgetsConfig,
};

export default function CheckoutWidget(props: CheckoutWidgetInputs) {
const {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
config,
} = props;

const {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
connectLoaderState: { checkout, provider },
} = useContext(ConnectLoaderContext);

return (
<div />
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {
ChainId,
IMTBLWidgetEvents,
CheckoutWidgetConfiguration,
CheckoutWidgetParams,
WidgetProperties,
WidgetTheme,
WidgetType,
} from '@imtbl/checkout-sdk';
import React, { Suspense } from 'react';
import { ConnectLoader, ConnectLoaderParams } from '../../components/ConnectLoader/ConnectLoader';
import { ThemeProvider } from '../../components/ThemeProvider/ThemeProvider';
import { CustomAnalyticsProvider } from '../../context/analytics-provider/CustomAnalyticsProvider';
import { HandoverProvider } from '../../context/handover-context/HandoverProvider';
import i18n from '../../i18n';
import { getL1ChainId, getL2ChainId } from '../../lib';
import { LoadingView } from '../../views/loading/LoadingView';
import { Base } from '../BaseWidgetRoot';

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

export class CheckoutWidgetRoot extends Base<WidgetType.CHECKOUT> {
protected eventTopic: IMTBLWidgetEvents = IMTBLWidgetEvents.IMTBL_CHECKOUT_WIDGET_EVENT;

protected getValidatedProperties(
{ config }: WidgetProperties<WidgetType.CHECKOUT>,
): WidgetProperties<WidgetType.CHECKOUT> {
let validatedConfig: CheckoutWidgetConfiguration | 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: CheckoutWidgetParams): CheckoutWidgetParams {
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,
// walletProviderName: this.parameters?.walletProviderName,
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="checkout-container" config={this.strongConfig()}>
<HandoverProvider>
<ConnectLoader
widgetConfig={this.strongConfig()}
params={connectLoaderParams}
closeEvent={() => { }}
>
<Suspense
fallback={
<LoadingView loadingText={t('views.LOADING_VIEW.text')} />
}
>
<CheckoutWidget
config={this.strongConfig()}
/>
</Suspense>
</ConnectLoader>
</HandoverProvider>
</ThemeProvider>
</CustomAnalyticsProvider>
</React.StrictMode>,
);
}
}
4 changes: 4 additions & 0 deletions packages/checkout/widgets-sample-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ function App() {
<a href={"/on-ramp"}>On-ramp Widget</a>
</div>
<br />
<div>
<a href={"/checkout"}>Checkout Widget</a>
</div>
<br />
<div>
<a
href={
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Checkout, WidgetTheme, WidgetType } from '@imtbl/checkout-sdk';
import { WidgetsFactory } from '@imtbl/checkout-widgets';
import { useEffect, useMemo } from 'react';
import { Environment } from '@imtbl/config';

function CheckoutUI() {
const checkout = useMemo(() => new Checkout({ baseConfig: { environment: Environment.SANDBOX } }), []);
const factory = useMemo(() => new WidgetsFactory(checkout, { theme: WidgetTheme.DARK }), [checkout]);
const checkoutWidget = useMemo(() => factory.create(WidgetType.CHECKOUT), [checkout])

const unmount = () => { checkoutWidget.unmount() }
const mount = () => { checkoutWidget.mount('checkout') }
const update = (theme: WidgetTheme) => { checkoutWidget.update({ config: { theme } }) }

useEffect(() => {
mount();
}, []);

return (
<div>
<h1 className="sample-heading">Checkout Widget</h1>
<div id="checkout"></div>
<button onClick={unmount}>Unmount</button>
<button onClick={mount}>Mount</button>
<button onClick={() => update(WidgetTheme.LIGHT)}>Light theme</button>
<button onClick={() => update(WidgetTheme.DARK)}>Dark theme</button>

</div>
);
}

export default CheckoutUI;
5 changes: 5 additions & 0 deletions packages/checkout/widgets-sample-app/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import OnRampUI from "./components/ui/on-ramp/onRamp";
import { PassportLoginCallback } from './components/ui/marketplace-orchestrator/PassportLoginCallback';
import { Marketplace } from './components/ui/marketplace-orchestrator';
import { SaleUI } from './components/ui/sale/sale';
import CheckoutUI from './components/ui/checkout/checkout';

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -41,6 +42,10 @@ const router = createBrowserRouter([
path: '/sale',
element: <SaleUI />,
},
{
path: '/checkout',
element: <CheckoutUI />,
},
{
path: '/marketplace-orchestrator',
element: <Marketplace />
Expand Down

0 comments on commit 66a081d

Please sign in to comment.