From d5b7d6f83402cc6a8b3589998143f013920b4c62 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Tue, 31 Oct 2023 19:36:17 +0600 Subject: [PATCH] feat(widget-configurator): use @cowprotocol/widget-react for configurator (#3293) --- .../controls/CurrentTradeTypeControl.tsx | 2 +- .../src/app/configurator/embedDialog.tsx | 6 +-- .../hooks/useWidgetParamsAndSettings.ts | 13 +++--- .../src/app/configurator/index.tsx | 42 ++++++------------ .../src/app/configurator/types.ts | 2 +- libs/widget-lib/src/types.ts | 6 +-- libs/widget-lib/src/urlUtils.ts | 6 +-- libs/widget-react/README.md | 17 ++++---- libs/widget-react/src/index.ts | 1 + libs/widget-react/src/lib/CowSwapWidget.tsx | 43 +++++++++++-------- 10 files changed, 63 insertions(+), 75 deletions(-) diff --git a/apps/widget-configurator/src/app/configurator/controls/CurrentTradeTypeControl.tsx b/apps/widget-configurator/src/app/configurator/controls/CurrentTradeTypeControl.tsx index 3f45fbae5c..2620ea2658 100644 --- a/apps/widget-configurator/src/app/configurator/controls/CurrentTradeTypeControl.tsx +++ b/apps/widget-configurator/src/app/configurator/controls/CurrentTradeTypeControl.tsx @@ -1,6 +1,6 @@ import { Dispatch, SetStateAction } from 'react' -import { TradeType } from '@cowprotocol/widget-lib' +import type { TradeType } from '@cowprotocol/widget-lib' import FormControl from '@mui/material/FormControl' import InputLabel from '@mui/material/InputLabel' diff --git a/apps/widget-configurator/src/app/configurator/embedDialog.tsx b/apps/widget-configurator/src/app/configurator/embedDialog.tsx index 3ee4369df7..2f07ff7b60 100644 --- a/apps/widget-configurator/src/app/configurator/embedDialog.tsx +++ b/apps/widget-configurator/src/app/configurator/embedDialog.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react' -import { CowSwapWidgetParams, CowSwapWidgetSettings } from '@cowprotocol/widget-lib' +import { CowSwapWidgetProps } from '@cowprotocol/widget-react' import Button from '@mui/material/Button' import Dialog, { DialogProps } from '@mui/material/Dialog' @@ -12,8 +12,8 @@ import SyntaxHighlighter from 'react-syntax-highlighter' import { nightOwl } from 'react-syntax-highlighter/dist/esm/styles/hljs' export interface EmbedDialogProps { - params: CowSwapWidgetParams - settings: CowSwapWidgetSettings + params: CowSwapWidgetProps['params'] + settings: CowSwapWidgetProps['settings'] } export function EmbedDialog({ params, settings }: EmbedDialogProps) { diff --git a/apps/widget-configurator/src/app/configurator/hooks/useWidgetParamsAndSettings.ts b/apps/widget-configurator/src/app/configurator/hooks/useWidgetParamsAndSettings.ts index c49252c963..4c7e3ebe41 100644 --- a/apps/widget-configurator/src/app/configurator/hooks/useWidgetParamsAndSettings.ts +++ b/apps/widget-configurator/src/app/configurator/hooks/useWidgetParamsAndSettings.ts @@ -1,6 +1,7 @@ import { useMemo } from 'react' -import { CowSwapWidgetEnv, CowSwapWidgetParams, CowSwapWidgetSettings, EthereumProvider } from '@cowprotocol/widget-lib' +import type { CowSwapWidgetEnv, EthereumProvider } from '@cowprotocol/widget-lib' +import { CowSwapWidgetProps } from '@cowprotocol/widget-react' import { isDev, isLocalHost, isVercel } from '../../../env' import { ConfiguratorState } from '../types' @@ -15,12 +16,9 @@ const getEnv = (): CowSwapWidgetEnv => { export function useWidgetParamsAndSettings( provider: EthereumProvider | undefined, - widgetContainer: HTMLDivElement | null, configuratorState: ConfiguratorState ) { return useMemo(() => { - if (!widgetContainer) return null - const { chainId, theme, @@ -33,15 +31,14 @@ export function useWidgetParamsAndSettings( dynamicHeightEnabled, } = configuratorState - const params: CowSwapWidgetParams = { - container: widgetContainer, + const params: CowSwapWidgetProps['params'] = { metaData: { appKey: '', url: '' }, width: 400, height: 640, provider, } - const settings: CowSwapWidgetSettings = { + const settings: CowSwapWidgetProps['settings'] = { theme, chainId, env: getEnv(), @@ -61,5 +58,5 @@ export function useWidgetParamsAndSettings( } return { params, settings } - }, [provider, widgetContainer, configuratorState]) + }, [provider, configuratorState]) } diff --git a/apps/widget-configurator/src/app/configurator/index.tsx b/apps/widget-configurator/src/app/configurator/index.tsx index f09cf3df32..615b6c12a1 100644 --- a/apps/widget-configurator/src/app/configurator/index.tsx +++ b/apps/widget-configurator/src/app/configurator/index.tsx @@ -1,6 +1,7 @@ -import { useContext, useEffect, useRef, useState } from 'react' +import { useContext, useEffect, useState } from 'react' -import { cowSwapWidget, EthereumProvider, TradeType, UpdateWidgetCallback } from '@cowprotocol/widget-lib' +import { TradeType } from '@cowprotocol/widget-lib' +import { CowSwapWidget } from '@cowprotocol/widget-react' import Box from '@mui/material/Box' import Divider from '@mui/material/Divider' @@ -17,7 +18,7 @@ import { TradeModesControl } from './controls/TradeModesControl' import { EmbedDialog } from './embedDialog' import { useProvider } from './hooks/useProvider' import { useWidgetParamsAndSettings } from './hooks/useWidgetParamsAndSettings' -import { DrawerStyled, WrapperStyled, ContentStyled, WalletConnectionWrapper } from './styled' +import { ContentStyled, DrawerStyled, WalletConnectionWrapper, WrapperStyled } from './styled' import { ConfiguratorState } from './types' import { ColorModeContext } from '../../theme/ColorModeContext' @@ -54,11 +55,7 @@ export function Configurator({ title }: { title: string }) { const [buyToken] = buyTokenState const [buyTokenAmount] = buyTokenAmountState - const iframeContainerRef = useRef(null) - const updateWidgetRef = useRef(null) - const provider = useProvider() - const providerRef = useRef() const state: ConfiguratorState = { chainId, @@ -72,28 +69,9 @@ export function Configurator({ title }: { title: string }) { dynamicHeightEnabled: true, } - const paramsAndSettings = useWidgetParamsAndSettings(provider, iframeContainerRef.current, state) + const paramsAndSettings = useWidgetParamsAndSettings(provider, state) const { params, settings } = paramsAndSettings || {} - useEffect(() => { - if (!params?.container || !settings) return - - // Re-initialize widget when provider is changed - if (provider && providerRef.current !== provider) { - updateWidgetRef.current = null - } - - if (updateWidgetRef.current) { - updateWidgetRef.current(settings) - } else { - updateWidgetRef.current = cowSwapWidget(params, settings) - } - }, [provider, params, settings]) - - useEffect(() => { - providerRef.current = provider - }, [provider]) - useEffect(() => { web3Modal.setThemeMode(mode) }, [mode]) @@ -139,9 +117,13 @@ export function Configurator({ title }: { title: string }) { - {params && settings && } -
-
+ {params && settings && ( + <> + +
+ + + )}
) diff --git a/apps/widget-configurator/src/app/configurator/types.ts b/apps/widget-configurator/src/app/configurator/types.ts index 10f0d15522..c4838961c3 100644 --- a/apps/widget-configurator/src/app/configurator/types.ts +++ b/apps/widget-configurator/src/app/configurator/types.ts @@ -1,5 +1,5 @@ import type { SupportedChainId } from '@cowprotocol/cow-sdk' -import { TradeType } from '@cowprotocol/widget-lib' +import type { TradeType } from '@cowprotocol/widget-lib' import { PaletteMode } from '@mui/material' diff --git a/libs/widget-lib/src/types.ts b/libs/widget-lib/src/types.ts index 14ea8a7f59..3ff6b4e030 100644 --- a/libs/widget-lib/src/types.ts +++ b/libs/widget-lib/src/types.ts @@ -32,9 +32,9 @@ export enum TradeType { } export interface CowSwapWidgetUrlParams { - chainId: number - tradeType: TradeType - env: CowSwapWidgetEnv + chainId?: number + tradeType?: TradeType + env?: CowSwapWidgetEnv tradeAssets?: TradeAssets theme?: CowSwapTheme } diff --git a/libs/widget-lib/src/urlUtils.ts b/libs/widget-lib/src/urlUtils.ts index 5765c1fc5b..2277544262 100644 --- a/libs/widget-lib/src/urlUtils.ts +++ b/libs/widget-lib/src/urlUtils.ts @@ -1,8 +1,8 @@ import { COWSWAP_URLS } from './consts' -import { CowSwapWidgetUrlParams } from './types' +import { CowSwapWidgetUrlParams, TradeType } from './types' export function buildWidgetUrl(params: CowSwapWidgetUrlParams): string { - const host = COWSWAP_URLS[params.env] + const host = COWSWAP_URLS[params.env || 'prod'] const path = buildWidgetPath(params) const query = buildTradeAmountsQuery(params) @@ -10,7 +10,7 @@ export function buildWidgetUrl(params: CowSwapWidgetUrlParams): string { } export function buildWidgetPath(params: CowSwapWidgetUrlParams): string { - const { chainId, tradeAssets, tradeType } = params + const { chainId = 1, tradeAssets, tradeType = TradeType.SWAP } = params const assetsPath = tradeAssets ? [tradeAssets.sell.asset, tradeAssets.buy.asset].map(encodeURIComponent).join('/') diff --git a/libs/widget-react/README.md b/libs/widget-react/README.md index 637a2031d7..d5b32025bb 100644 --- a/libs/widget-react/README.md +++ b/libs/widget-react/README.md @@ -1,6 +1,6 @@ # CoW Swap React widget -React component that creates a CoW Swap widget. It is based on [https://npmjs.com/package/@cowprotocol/widget-lib])https://npmjs.com/package/@cowprotocol/widget-lib) +React component that creates a CoW Swap widget. It is based on [https://npmjs.com/package/@cowprotocol/widget-lib](https://npmjs.com/package/@cowprotocol/widget-lib) ## Use it @@ -17,25 +17,24 @@ yarn add @cowprotocol/widget-react Import component and some convenient types ```ts -import { CowSwapWidgetSettings } from '@cowprotocol/widget-lib' -import { CowSwapWidget, CowSwapWidgetParams } from '@cowprotocol/widget-react' +import { CowSwapWidget, CowSwapWidgetParams, CowSwapWidgetSettings } from '@cowprotocol/widget-react' ``` Prepare the config for the widget: ```ts const cowSwapWidgetParams: CowSwapWidgetParams = { + container: document.getElementById('cow-swap-widget'), + metaData: { + appKey: '', + appUrl: '', + }, width: 600, height: 700, } const cowSwapWidgetSettings: CowSwapWidgetSettings = { - urlParams: { - chainId: 1, - tradeType: 'swap', - env: 'local', - }, - appParams: {}, + tradeType: 'swap', } ``` diff --git a/libs/widget-react/src/index.ts b/libs/widget-react/src/index.ts index 14fa5b6d4a..a717a4c133 100644 --- a/libs/widget-react/src/index.ts +++ b/libs/widget-react/src/index.ts @@ -1 +1,2 @@ export * from './lib/CowSwapWidget' +export type { CowSwapWidgetParams, CowSwapWidgetSettings, EthereumProvider } from '@cowprotocol/widget-lib' diff --git a/libs/widget-react/src/lib/CowSwapWidget.tsx b/libs/widget-react/src/lib/CowSwapWidget.tsx index d95f8609f6..4c747ffe01 100644 --- a/libs/widget-react/src/lib/CowSwapWidget.tsx +++ b/libs/widget-react/src/lib/CowSwapWidget.tsx @@ -2,32 +2,41 @@ import { useEffect, useRef } from 'react' import { cowSwapWidget, - CowSwapWidgetParams as CowSwapWidgetParamsAux, + CowSwapWidgetParams, CowSwapWidgetSettings, + EthereumProvider, + UpdateWidgetCallback, } from '@cowprotocol/widget-lib' -export type CowSwapWidgetParams = Omit export interface CowSwapWidgetProps { - params: CowSwapWidgetParams + params: Omit settings: CowSwapWidgetSettings + provider?: EthereumProvider } -export function CowSwapWidget(props: CowSwapWidgetProps) { - const cowWidgetRef = useRef(null) +export function CowSwapWidget({ params, settings, provider }: CowSwapWidgetProps) { + const providerRef = useRef() + const iframeContainerRef = useRef(null) + const updateWidgetRef = useRef(null) useEffect(() => { - if (cowWidgetRef.current) { - const { params, settings } = props - - cowSwapWidget( - { - ...params, - container: cowWidgetRef.current, - }, - settings - ) + if (!iframeContainerRef.current) return + + // Re-initialize widget when provider is changed + if (provider && providerRef.current !== provider) { + updateWidgetRef.current = null + } + + if (updateWidgetRef.current) { + updateWidgetRef.current(settings) + } else { + updateWidgetRef.current = cowSwapWidget({ ...params, container: iframeContainerRef.current }, settings) } - }, [cowWidgetRef, props]) + }, [provider, params, settings]) + + useEffect(() => { + providerRef.current = provider + }, [provider]) - return
+ return
}