Skip to content

Commit

Permalink
Sends PROVIDER_UPDATED events to child. (#2105)
Browse files Browse the repository at this point in the history
Co-authored-by: Jhonatan Gonzalez <[email protected]>
  • Loading branch information
jwhardwick and jhesgodi authored Aug 23, 2024
1 parent 12e2a33 commit 19566cb
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 139 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useMemo, useReducer } from 'react';
import { useEffect, useMemo, useReducer } from 'react';
import {
Checkout,
CheckoutWidgetConfiguration,
CheckoutWidgetParams,
} from '@imtbl/checkout-sdk';
import { Web3Provider } from '@ethersproject/providers';
import {
CheckoutActions,
checkoutReducer,
initialCheckoutState,
} from './context/CheckoutContext';
Expand All @@ -16,10 +18,13 @@ export type CheckoutWidgetInputs = {
checkout: Checkout;
params: CheckoutWidgetParams;
config: CheckoutWidgetConfiguration;
provider?: Web3Provider
};

export default function CheckoutWidget(props: CheckoutWidgetInputs) {
const { config, checkout, params } = props;
const {
config, checkout, params, provider,
} = props;
const { environment, publishableKey } = checkout.config;

const [, iframeURL] = useMemo(() => {
Expand All @@ -33,12 +38,23 @@ export default function CheckoutWidget(props: CheckoutWidgetInputs) {
);
const checkoutReducerValues = useMemo(
() => ({
checkoutState: { ...checkoutState, iframeURL, checkout },
checkoutState: {
...checkoutState, iframeURL, checkout,
},
checkoutDispatch,
}),
[checkoutState, checkoutDispatch, iframeURL, checkout],
);

useEffect(() => {
checkoutDispatch({
payload: {
type: CheckoutActions.SET_PROVIDER,
provider,
},
});
}, [provider]);

return (
<CheckoutContextProvider values={checkoutReducerValues}>
<CheckoutAppIframe />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class CheckoutWidgetRoot extends Base<WidgetType.CHECKOUT> {
}
>
<CheckoutWidget
provider={this.web3Provider}
checkout={this.checkout}
config={config}
params={this.parameters}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
Checkout, EIP6963ProviderInfo, PostMessageHandler, WalletProviderName,
} from '@imtbl/checkout-sdk';
import { Passport } from '@imtbl/passport';
import { ProviderRelay } from './ProviderRelay';

export interface CheckoutState {
checkout: Checkout | null;
Expand All @@ -13,7 +12,6 @@ export interface CheckoutState {
iframeURL: string | undefined;
iframeContentWindow: Window | undefined;
postMessageHandler: PostMessageHandler | undefined;
providerRelay: ProviderRelay | undefined;
walletProviderName: WalletProviderName | null;
walletProviderInfo: EIP6963ProviderInfo | null;
sendCloseEvent: () => void;
Expand All @@ -26,7 +24,6 @@ export const initialCheckoutState: CheckoutState = {
iframeURL: undefined,
iframeContentWindow: undefined,
postMessageHandler: undefined,
providerRelay: undefined,
walletProviderInfo: null,
walletProviderName: null,
sendCloseEvent: () => { },
Expand All @@ -47,7 +44,6 @@ type ActionPayload =
| SetIframeURLPayload
| SetPostMessageHandlerPayload
| SetIframeContentWindowPayload
| SetProviderRelayPayload
| SetPassportPayload
| SetProviderNamePayload
| SetSendCloseEventPayload;
Expand All @@ -58,7 +54,6 @@ export enum CheckoutActions {
SET_IFRAME_URL = 'SET_IFRAME_URL',
SET_POST_MESSAGE_HANDLER = 'SET_POST_MESSAGE_HANDLER',
SET_CHECKOUT_APP_IFRAME = 'SET_CHECKOUT_APP_IFRAME',
SET_PROVIDER_RELAY = 'SET_PROVIDER_RELAY',
SET_PASSPORT = 'SET_PASSPORT',
SET_WALLET_PROVIDER_NAME = 'SET_WALLET_PROVIDER_NAME',
SET_SEND_CLOSE_EVENT = 'SET_SEND_CLOSE_EVENT',
Expand All @@ -71,7 +66,7 @@ export interface SetCheckoutPayload {

export interface SetProviderPayload {
type: CheckoutActions.SET_PROVIDER;
provider: Web3Provider;
provider: Web3Provider | undefined;
}

export interface SetIframeURLPayload {
Expand All @@ -89,11 +84,6 @@ export interface SetPostMessageHandlerPayload {
postMessageHandler: PostMessageHandler;
}

export interface SetProviderRelayPayload {
type: CheckoutActions.SET_PROVIDER_RELAY;
providerRelay: ProviderRelay;
}

export interface SetPassportPayload {
type: CheckoutActions.SET_PASSPORT;
passport: Passport;
Expand Down Expand Up @@ -154,11 +144,6 @@ export const checkoutReducer: Reducer<CheckoutState, CheckoutAction> = (
...state,
postMessageHandler: action.payload.postMessageHandler,
};
case CheckoutActions.SET_PROVIDER_RELAY:
return {
...state,
providerRelay: action.payload.providerRelay,
};
case CheckoutActions.SET_WALLET_PROVIDER_NAME:
return {
...state,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PostMessageHandler } from '@imtbl/checkout-sdk';
import { PostMessageHandler, PostMessageHandlerEventType } from '@imtbl/checkout-sdk';
import {
Dispatch, ReactNode, useContext, useEffect,
} from 'react';
Expand All @@ -8,7 +8,6 @@ import {
CheckoutContext,
CheckoutState,
} from './CheckoutContext';
import { ProviderRelay } from './ProviderRelay';

type CheckoutContextProviderProps = {
values: {
Expand Down Expand Up @@ -54,11 +53,9 @@ export function CheckoutContextProvider({
useEffect(() => {
if (!provider || !postMessageHandler) return;

checkoutDispatch({
payload: {
type: CheckoutActions.SET_PROVIDER_RELAY,
providerRelay: new ProviderRelay(postMessageHandler, provider),
},
postMessageHandler.send(PostMessageHandlerEventType.PROVIDER_UPDATED, {
isMetamask: provider.provider.isMetaMask,
isPassport: (provider.provider as any)?.isPassport,
});
}, [provider, postMessageHandler]);

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useCallback, useEffect } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import { EIP6963ProviderDetail, PostMessageHandlerEventType } from '@imtbl/checkout-sdk';
import { useCheckoutContext } from '../context/CheckoutContextProvider';

export function useEip6963Relayer() {
const [checkoutState] = useCheckoutContext();
const { postMessageHandler } = checkoutState;
const unsubscribePostMessageHandler = useRef<() => void>();

const onAnnounce = useCallback((event: CustomEvent<EIP6963ProviderDetail>) => {
postMessageHandler?.send(PostMessageHandlerEventType.EIP_6963_EVENT, {
Expand Down Expand Up @@ -32,8 +33,8 @@ export function useEip6963Relayer() {

useEffect(() => {
if (!postMessageHandler) return;

postMessageHandler.subscribe((message) => {
unsubscribePostMessageHandler.current?.();
unsubscribePostMessageHandler.current = postMessageHandler.subscribe((message) => {
if (message.type === PostMessageHandlerEventType.EIP_6963_EVENT) {
onRequest(message.payload);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import {
EIP6963ProviderInfo,
PostMessageData,
Expand Down Expand Up @@ -28,6 +28,8 @@ type ProviderRelayPayload = {
export function useProviderRelay() {
const [{ checkout, postMessageHandler, provider }, checkoutDispatch] = useCheckoutContext();

const unsubscribePostMessageHandler = useRef<() => void>();

/**
* Execute a request using the provider
* and relay the response back using the postMessageHandler
Expand Down Expand Up @@ -71,39 +73,39 @@ export function useProviderRelay() {

const injectedProviders = checkout.getInjectedProviders();
const targetProvider = injectedProviders.find(
(p) => p.info.uuid === providerRelayPayload.eip6963Info.uuid,
(p) => p.info.uuid === providerRelayPayload?.eip6963Info?.uuid,
);

if (!targetProvider) {
if (!targetProvider && providerRelayPayload.eip6963Info !== undefined) {
// eslint-disable-next-line no-console
console.error(
'PARENT - requested provider not found',
providerRelayPayload.eip6963Info,
providerRelayPayload?.eip6963Info,
injectedProviders,
);
return;
}

// If provider is not defined, connect the target provider
let currentProvider = provider;
if (!currentProvider) {
if (!currentProvider && targetProvider) {
const connectResponse = await checkout.connect({
provider: new Web3Provider(targetProvider.provider),
});
currentProvider = connectResponse.provider;
}

// Set provider and execute the request
checkoutDispatch({
payload: {
type: CheckoutActions.SET_PROVIDER,
provider: currentProvider,
},
});
// Set provider and execute the request
checkoutDispatch({
payload: {
type: CheckoutActions.SET_PROVIDER,
provider: currentProvider,
},
});
}

postMessageHandler.send(PostMessageHandlerEventType.PROVIDER_UPDATED, {
eip6963Info: payload.eip6963Info,
});
if (!currentProvider) {
throw new Error('Provider is not defined');
}

await execute(providerRelayPayload, currentProvider);
},
Expand All @@ -115,7 +117,13 @@ export function useProviderRelay() {
* Subscribe to provider relay messages
*/
useEffect(() => {
// TODO we need to unsubscribe everywhere
if (!postMessageHandler) return;
postMessageHandler.subscribe(onJsonRpcRequestMessage);
}, [provider, postMessageHandler, execute, onJsonRpcRequestMessage]);
unsubscribePostMessageHandler.current?.();
unsubscribePostMessageHandler.current = postMessageHandler?.subscribe(onJsonRpcRequestMessage);
}, [postMessageHandler, onJsonRpcRequestMessage]);
}

// TODO -
// 1 - commit the unsub part
// 2 - add unsubs to all postMessageHandlers subscriptions
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import {
useContext, useEffect, useRef, useState,
} from 'react';
import {
CheckoutEventType,
IMTBLWidgetEvents,
CheckoutEventType, IMTBLWidgetEvents,
PostMessageHandlerEventType,
WidgetEventData,
WidgetType,
Expand All @@ -16,7 +15,10 @@ import { sendCheckoutEvent } from '../CheckoutWidgetEvents';
import { EventTargetContext } from '../../../context/event-target-context/EventTargetContext';
import { LoadingView } from '../../../views/loading/LoadingView';
import { ErrorView } from '../../../views/error/ErrorView';
import { IFRAME_INIT_TIMEOUT_MS, IFRAME_ALLOW_PERMISSIONS } from '../utils/config';
import {
IFRAME_INIT_TIMEOUT_MS,
IFRAME_ALLOW_PERMISSIONS,
} from '../utils/config';
import { useEip6963Relayer } from '../hooks/useEip6963Relayer';
import { useProviderRelay } from '../hooks/useProviderRelay';

Expand All @@ -33,9 +35,12 @@ export function CheckoutAppIframe() {
const [loadingError, setLoadingError] = useState<boolean>(false);
const [initialised, setInitialised] = useState<boolean>(false);
const [
{ iframeURL, postMessageHandler, iframeContentWindow },
{
iframeURL, postMessageHandler, iframeContentWindow,
},
checkoutDispatch,
] = useCheckoutContext();
const unsubscribePostMessageHandler = useRef<() => void>();

useEip6963Relayer();
useProviderRelay();
Expand All @@ -62,9 +67,11 @@ export function CheckoutAppIframe() {

useEffect(() => {
if (!postMessageHandler) return undefined;
unsubscribePostMessageHandler.current?.();

// subscribe to widget events
postMessageHandler.subscribe(({ type, payload }) => {
// TODO: Move to its own hook
unsubscribePostMessageHandler.current = postMessageHandler.subscribe(({ type, payload }) => {
if (type !== PostMessageHandlerEventType.WIDGET_EVENT) return;

// FIXME: improve typing
Expand All @@ -76,6 +83,17 @@ export function CheckoutAppIframe() {
};
} = payload as any;

// TODO: intercept connect success and inject the state provider
// FIXME: events type narrowing is not working properly
if (customEvent.detail.type === CheckoutEventType.DISCONNECTED) {
checkoutDispatch({
payload: {
type: CheckoutActions.SET_PROVIDER,
provider: undefined,
},
});
}

// Forward widget events
sendCheckoutEvent(eventTarget, customEvent.detail);

Expand All @@ -98,7 +116,7 @@ export function CheckoutAppIframe() {
return () => {
clearTimeout(timeoutRef.current!);
};
}, [postMessageHandler]);
}, [postMessageHandler, checkoutDispatch]);

if (loadingError) {
return (
Expand Down
Loading

0 comments on commit 19566cb

Please sign in to comment.