Skip to content

Commit

Permalink
feat(widget-configurator): use @cowprotocol/widget-react for configur…
Browse files Browse the repository at this point in the history
…ator (#3293)
  • Loading branch information
shoom3301 authored Oct 31, 2023
1 parent 0bc7d99 commit d5b7d6f
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
6 changes: 3 additions & 3 deletions apps/widget-configurator/src/app/configurator/embedDialog.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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,
Expand All @@ -33,15 +31,14 @@ export function useWidgetParamsAndSettings(
dynamicHeightEnabled,
} = configuratorState

const params: CowSwapWidgetParams = {
container: widgetContainer,
const params: CowSwapWidgetProps['params'] = {
metaData: { appKey: '<YOUR_APP_ID>', url: '<https://YOUR_APP_URL>' },
width: 400,
height: 640,
provider,
}

const settings: CowSwapWidgetSettings = {
const settings: CowSwapWidgetProps['settings'] = {
theme,
chainId,
env: getEnv(),
Expand All @@ -61,5 +58,5 @@ export function useWidgetParamsAndSettings(
}

return { params, settings }
}, [provider, widgetContainer, configuratorState])
}, [provider, configuratorState])
}
42 changes: 12 additions & 30 deletions apps/widget-configurator/src/app/configurator/index.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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'
Expand Down Expand Up @@ -54,11 +55,7 @@ export function Configurator({ title }: { title: string }) {
const [buyToken] = buyTokenState
const [buyTokenAmount] = buyTokenAmountState

const iframeContainerRef = useRef<HTMLDivElement>(null)
const updateWidgetRef = useRef<UpdateWidgetCallback | null>(null)

const provider = useProvider()
const providerRef = useRef<EthereumProvider | null>()

const state: ConfiguratorState = {
chainId,
Expand All @@ -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])
Expand Down Expand Up @@ -139,9 +117,13 @@ export function Configurator({ title }: { title: string }) {
</Drawer>

<Box sx={ContentStyled}>
{params && settings && <EmbedDialog params={params} settings={settings} />}
<br />
<div ref={iframeContainerRef}></div>
{params && settings && (
<>
<EmbedDialog params={params} settings={settings} />
<br />
<CowSwapWidget provider={provider} settings={settings} params={params} />
</>
)}
</Box>
</Box>
)
Expand Down
2 changes: 1 addition & 1 deletion apps/widget-configurator/src/app/configurator/types.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand Down
6 changes: 3 additions & 3 deletions libs/widget-lib/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
6 changes: 3 additions & 3 deletions libs/widget-lib/src/urlUtils.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
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)

return host + '/#' + path + '?' + query
}

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('/')
Expand Down
17 changes: 8 additions & 9 deletions libs/widget-react/README.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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: '<YOUR_APP_KEY>',
appUrl: '<YOUR_APP_URL>',
},
width: 600,
height: 700,
}

const cowSwapWidgetSettings: CowSwapWidgetSettings = {
urlParams: {
chainId: 1,
tradeType: 'swap',
env: 'local',
},
appParams: {},
tradeType: 'swap',
}
```

Expand Down
1 change: 1 addition & 0 deletions libs/widget-react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './lib/CowSwapWidget'
export type { CowSwapWidgetParams, CowSwapWidgetSettings, EthereumProvider } from '@cowprotocol/widget-lib'
43 changes: 26 additions & 17 deletions libs/widget-react/src/lib/CowSwapWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<CowSwapWidgetParamsAux, 'container'>
export interface CowSwapWidgetProps {
params: CowSwapWidgetParams
params: Omit<CowSwapWidgetParams, 'container'>
settings: CowSwapWidgetSettings
provider?: EthereumProvider
}

export function CowSwapWidget(props: CowSwapWidgetProps) {
const cowWidgetRef = useRef(null)
export function CowSwapWidget({ params, settings, provider }: CowSwapWidgetProps) {
const providerRef = useRef<EthereumProvider | null>()
const iframeContainerRef = useRef<HTMLDivElement>(null)
const updateWidgetRef = useRef<UpdateWidgetCallback | null>(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 <div ref={cowWidgetRef}></div>
return <div ref={iframeContainerRef}></div>
}

0 comments on commit d5b7d6f

Please sign in to comment.