From 3acbd26cb85f0d1346b6b242a34b7b32240039ec Mon Sep 17 00:00:00 2001 From: Todd Kao Date: Tue, 20 Aug 2024 15:32:04 -0400 Subject: [PATCH 1/8] Add Router, errorAtom ad renderLogic --- packages/widget-v2/package.json | 1 + .../src/components/AssetChainInput.tsx | 2 +- .../ManualAddressModal/ManualAddressModal.tsx | 4 +-- .../TokenAndChainSelectorModal.tsx | 2 +- .../TokenAndChainSelectorModalRowItem.tsx | 2 +- .../TokenAndChainSelectorModalSearchInput.tsx | 2 +- .../TransactionHistoryModalItem.tsx | 2 +- .../src/pages/ErrorPage/ErrorPage.tsx | 13 ++++++++ .../SwapExecutionPage/SwapExecutionPage.tsx | 14 ++++----- .../SwapExecutionPageRouteDetailedRow.tsx | 2 +- .../SwapExecutionPageRouteSimple.tsx | 2 +- .../SwapExecutionPageRouteSimpleRow.tsx | 2 +- .../widget-v2/src/pages/SwapPage/SwapPage.tsx | 4 +-- .../src/pages/SwapPage/swapPageState.ts | 15 +++++++++ packages/widget-v2/src/state/errorPage.ts | 7 +++++ packages/widget-v2/src/state/router.ts | 8 +++++ .../src/state/{skip.ts => skipClient.ts} | 0 .../src/state/{swap.ts => swapPage.ts} | 2 +- .../stories/ManualAddressModals.stories.tsx | 4 +-- ...ries.tsx => SwapExecutionPage.stories.tsx} | 13 +++----- packages/widget-v2/src/utils/useUsdValue.ts | 2 +- packages/widget-v2/src/widget/Router.tsx | 31 +++++++++++++++++++ packages/widget-v2/src/widget/Widget.tsx | 6 ++-- packages/widget-v2/tsconfig.app.json | 2 +- yarn.lock | 12 +++++++ 25 files changed, 119 insertions(+), 35 deletions(-) create mode 100644 packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx create mode 100644 packages/widget-v2/src/pages/SwapPage/swapPageState.ts create mode 100644 packages/widget-v2/src/state/errorPage.ts create mode 100644 packages/widget-v2/src/state/router.ts rename packages/widget-v2/src/state/{skip.ts => skipClient.ts} (100%) rename packages/widget-v2/src/state/{swap.ts => swapPage.ts} (89%) rename packages/widget-v2/src/stories/{SwapExecutionFlow.stories.tsx => SwapExecutionPage.stories.tsx} (82%) create mode 100644 packages/widget-v2/src/widget/Router.tsx diff --git a/packages/widget-v2/package.json b/packages/widget-v2/package.json index cfbd31211..14a923098 100644 --- a/packages/widget-v2/package.json +++ b/packages/widget-v2/package.json @@ -56,6 +56,7 @@ "lodash.debounce": "^4.0.8", "pluralize": "^8.0.0", "rc-virtual-list": "^3.14.5", + "react-error-boundary": "^4.0.13", "react-shadow-scope": "^1.0.5", "zod": "^3.23.8" } diff --git a/packages/widget-v2/src/components/AssetChainInput.tsx b/packages/widget-v2/src/components/AssetChainInput.tsx index c553c625b..7dad04173 100644 --- a/packages/widget-v2/src/components/AssetChainInput.tsx +++ b/packages/widget-v2/src/components/AssetChainInput.tsx @@ -6,7 +6,7 @@ import { useTheme } from 'styled-components'; import { CogIcon } from '@/icons/CogIcon'; import { Button, GhostButton } from '@/components/Button'; import { useAtom } from 'jotai'; -import { skipAssets } from '@/state/skip'; +import { skipAssets } from '@/state/skipClient'; import { useUsdValue } from '@/utils/useUsdValue'; import { formatUSD } from '@/utils/intl'; diff --git a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx index 5d69fb2a1..743fa32d2 100644 --- a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx +++ b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx @@ -12,9 +12,9 @@ import { import { WALLET_LIST } from '@/modals/WalletSelectorModal/WalletSelectorFlow'; import { Button } from '@/components/Button'; import { SmallText, Text } from '@/components/Typography'; -import { destinationAssetAtom, destinationWalletAtom } from '@/state/swap'; +import { destinationAssetAtom, destinationWalletAtom } from '@/state/swapPage'; import { useAtom } from 'jotai'; -import { getChain } from '@/state/skip'; +import { getChain } from '@/state/skipClient'; export const ManualAddressModal = NiceModal.create((modalProps: ModalProps) => { const { theme } = modalProps; diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx index e8d104692..94e2e1f48 100644 --- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx +++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx @@ -3,7 +3,7 @@ import { Modal, ModalProps } from '@/components/Modal'; import { Column } from '@/components/Layout'; import { styled } from 'styled-components'; import { useAtom } from 'jotai'; -import { ChainWithAsset, ClientAsset, skipAssets } from '@/state/skip'; +import { ChainWithAsset, ClientAsset, skipAssets } from '@/state/skipClient'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { VirtualList } from '@/components/VirtualList'; import { diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalRowItem.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalRowItem.tsx index 2dbce565f..56c678933 100644 --- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalRowItem.tsx +++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalRowItem.tsx @@ -1,7 +1,7 @@ import { Row } from '@/components/Layout'; import { ModalRowItem } from '@/components/ModalRowItem'; import { SmallText, Text } from '@/components/Typography'; -import { ChainWithAsset, ClientAsset } from '@/state/skip'; +import { ChainWithAsset, ClientAsset } from '@/state/skipClient'; import { CircleSkeletonElement, SkeletonElement } from '@/components/Skeleton'; import { styled } from 'styled-components'; import { Chain } from '@chain-registry/types'; diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalSearchInput.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalSearchInput.tsx index b9bb35633..52b13e58a 100644 --- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalSearchInput.tsx +++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalSearchInput.tsx @@ -5,7 +5,7 @@ import { SkipLogoIcon } from '@/icons/SkipLogoIcon'; import { SmallText } from '@/components/Typography'; import { SearchIcon } from '@/icons/SearchIcon'; import { StyledAssetLabel } from '@/components/AssetChainInput'; -import { ClientAsset } from '@/state/skip'; +import { ClientAsset } from '@/state/skipClient'; import { LeftArrowIcon } from '@/icons/ArrowIcon'; import { useModal } from '@ebay/nice-modal-react'; import { Button } from '@/components/Button'; diff --git a/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModalItem.tsx b/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModalItem.tsx index 507903cc7..0b00404ca 100644 --- a/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModalItem.tsx +++ b/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModalItem.tsx @@ -1,7 +1,7 @@ import { RouteResponse } from '@skip-go/client'; import { SmallText } from '@/components/Typography'; import { useAtom } from 'jotai'; -import { skipAssets, getChain, ClientAsset } from '@/state/skip'; +import { skipAssets, getChain, ClientAsset } from '@/state/skipClient'; import { Column, Row } from '@/components/Layout'; import styled, { useTheme } from 'styled-components'; import { getFormattedAssetAmount } from '@/utils/crypto'; diff --git a/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx b/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx new file mode 100644 index 000000000..a0e672a40 --- /dev/null +++ b/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx @@ -0,0 +1,13 @@ +import { errorAtom } from '@/state/errorPage'; +import { useResetAtom } from 'jotai/utils'; + +export const ErrorPage = () => { + const resetError = useResetAtom(errorAtom); + + return ( +
+ error page + +
+ ); +}; diff --git a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx index 322852e32..2dba7da34 100644 --- a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx +++ b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx @@ -8,7 +8,7 @@ import { useModal } from '@ebay/nice-modal-react'; import { ManualAddressModal } from '@/modals/ManualAddressModal/ManualAddressModal'; import styled, { useTheme } from 'styled-components'; import { useAtom } from 'jotai'; -import { destinationWalletAtom } from '@/state/swap'; +import { destinationWalletAtom } from '@/state/swapPage'; import { SwapExecutionPageRouteSimple } from './SwapExecutionPageRouteSimple'; import { SwapExecutionPageRouteDetailed } from './SwapExecutionPageRouteDetailed'; @@ -17,6 +17,7 @@ import { Operation, txState } from './SwapExecutionPageRouteDetailedRow'; import { SmallText } from '@/components/Typography'; import { SignatureIcon } from '@/icons/SignatureIcon'; import pluralize from 'pluralize'; +import operations from './operations.json'; enum SwapExecutionState { destinationAddressUnset, @@ -25,14 +26,10 @@ enum SwapExecutionState { confirmed, } -export type SwapExecutionPageProps = { - operations: Operation[]; -}; - const SIGNATURES_REQUIRED = 2; const TX_DELAY_MS = 5_000; // 5 seconds -export const SwapExecutionPage = ({ operations }: SwapExecutionPageProps) => { +export const SwapExecutionPage = () => { const theme = useTheme(); const [destinationWallet] = useAtom(destinationWalletAtom); @@ -157,7 +154,10 @@ export const SwapExecutionPage = ({ operations }: SwapExecutionPageProps) => { onClick: () => setSimpleRoute(!simpleRoute), }} /> - + {renderMainButton} & { + amount?: string; +}; + +export const sourceAssetAtom = atom(); + +export const destinationAssetAtom = atom(); + +export const connectedWalletAtom = atom(); + +export const destinationWalletAtom = atom(); diff --git a/packages/widget-v2/src/state/errorPage.ts b/packages/widget-v2/src/state/errorPage.ts new file mode 100644 index 000000000..ddb34fedc --- /dev/null +++ b/packages/widget-v2/src/state/errorPage.ts @@ -0,0 +1,7 @@ +import { atomWithReset } from 'jotai/utils'; + +export const errorAtom = atomWithReset< + ExpectedErrorDetails | Error | undefined +>(undefined); + +type ExpectedErrorDetails = {}; diff --git a/packages/widget-v2/src/state/router.ts b/packages/widget-v2/src/state/router.ts new file mode 100644 index 000000000..635be0787 --- /dev/null +++ b/packages/widget-v2/src/state/router.ts @@ -0,0 +1,8 @@ +import { atom } from 'jotai'; + +export enum Routes { + SwapPage, + SwapExecutionPage, +} + +export const currentPageAtom = atom(Routes.SwapPage); diff --git a/packages/widget-v2/src/state/skip.ts b/packages/widget-v2/src/state/skipClient.ts similarity index 100% rename from packages/widget-v2/src/state/skip.ts rename to packages/widget-v2/src/state/skipClient.ts diff --git a/packages/widget-v2/src/state/swap.ts b/packages/widget-v2/src/state/swapPage.ts similarity index 89% rename from packages/widget-v2/src/state/swap.ts rename to packages/widget-v2/src/state/swapPage.ts index 7331e976c..ebd689647 100644 --- a/packages/widget-v2/src/state/swap.ts +++ b/packages/widget-v2/src/state/swapPage.ts @@ -1,5 +1,5 @@ import { atom } from 'jotai'; -import { ClientAsset } from './skip'; +import { ClientAsset } from './skipClient'; import { Wallet } from '@/components/RenderWalletList'; export type AssetAtom = Partial & { diff --git a/packages/widget-v2/src/stories/ManualAddressModals.stories.tsx b/packages/widget-v2/src/stories/ManualAddressModals.stories.tsx index 1168e0c33..7a4e02d5c 100644 --- a/packages/widget-v2/src/stories/ManualAddressModals.stories.tsx +++ b/packages/widget-v2/src/stories/ManualAddressModals.stories.tsx @@ -4,8 +4,8 @@ import { Row } from '@/components/Layout'; import { defaultTheme, lightTheme } from '@/widget/theme'; import { ManualAddressModal } from '@/modals/ManualAddressModal/ManualAddressModal'; import { useEffect, useState } from 'react'; -import { skipAssets } from '@/state/skip'; -import { destinationAssetAtom } from '@/state/swap'; +import { skipAssets } from '@/state/skipClient'; +import { destinationAssetAtom } from '@/state/swapPage'; import { useAtom } from 'jotai'; const meta = { diff --git a/packages/widget-v2/src/stories/SwapExecutionFlow.stories.tsx b/packages/widget-v2/src/stories/SwapExecutionPage.stories.tsx similarity index 82% rename from packages/widget-v2/src/stories/SwapExecutionFlow.stories.tsx rename to packages/widget-v2/src/stories/SwapExecutionPage.stories.tsx index 230a3c11b..9146e19d5 100644 --- a/packages/widget-v2/src/stories/SwapExecutionFlow.stories.tsx +++ b/packages/widget-v2/src/stories/SwapExecutionPage.stories.tsx @@ -2,12 +2,11 @@ import type { Meta, StoryObj } from '@storybook/react'; import { renderLightAndDarkTheme } from './renderLightAndDarkTheme'; import { SwapExecutionPage } from '@/pages/SwapExecutionPage/SwapExecutionPage'; import NiceModal from '@ebay/nice-modal-react'; -import { destinationAssetAtom } from '@/state/swap'; +import { destinationAssetAtom } from '@/state/swapPage'; import { useAtom } from 'jotai'; import operations from '@/pages/SwapExecutionPage/operations.json'; -import { skipAssets } from '@/state/skip'; +import { skipAssets } from '@/state/skipClient'; import { useEffect, useState } from 'react'; -import { Operation } from '@/pages/SwapExecutionPage/SwapExecutionPageRouteDetailedRow'; const meta = { title: 'Pages/SwapExecutionPage', @@ -16,8 +15,8 @@ const meta = { const [_destinationAsset, setDestinationAsset] = useAtom(destinationAssetAtom); const [shouldRender, setShouldRender] = useState(false); - const firstOperation = props.operations[0]; - const lastOperation = props.operations[props.operations.length - 1]; + const firstOperation = operations[0]; + const lastOperation = operations[operations.length - 1]; const [{ data: assets }] = useAtom(skipAssets); @@ -57,7 +56,5 @@ type Story = StoryObj; export default meta; export const SwapExecutionPageExample: Story = { - args: { - operations: operations as Operation[], - }, + args: {}, }; diff --git a/packages/widget-v2/src/utils/useUsdValue.ts b/packages/widget-v2/src/utils/useUsdValue.ts index f080fe4d8..cc036b169 100644 --- a/packages/widget-v2/src/utils/useUsdValue.ts +++ b/packages/widget-v2/src/utils/useUsdValue.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; import { z } from 'zod'; -import { getAssets } from '@/state/skip'; +import { getAssets } from '@/state/skipClient'; interface Args { coingeckoID: string; diff --git a/packages/widget-v2/src/widget/Router.tsx b/packages/widget-v2/src/widget/Router.tsx new file mode 100644 index 000000000..65c918d28 --- /dev/null +++ b/packages/widget-v2/src/widget/Router.tsx @@ -0,0 +1,31 @@ +import { ErrorPage } from '@/pages/ErrorPage/ErrorPage'; +import { SwapExecutionPage } from '@/pages/SwapExecutionPage/SwapExecutionPage'; +import { SwapPage } from '@/pages/SwapPage/SwapPage'; +import { errorAtom } from '@/state/errorPage'; +import { Routes, currentPageAtom } from '@/state/router'; +import { useAtom } from 'jotai'; +import { ErrorBoundary } from 'react-error-boundary'; + +export const Router = () => { + const [currentPage] = useAtom(currentPageAtom); + const [error, setError] = useAtom(errorAtom); + + if (error) { + return ; + } + + switch (currentPage) { + case Routes.SwapPage: + return ( + setError(error)}> + + + ); + case Routes.SwapExecutionPage: + return ( + setError(error)}> + + + ); + } +}; diff --git a/packages/widget-v2/src/widget/Widget.tsx b/packages/widget-v2/src/widget/Widget.tsx index 7f828b53a..db7b8fc5b 100644 --- a/packages/widget-v2/src/widget/Widget.tsx +++ b/packages/widget-v2/src/widget/Widget.tsx @@ -1,10 +1,10 @@ import { ShadowDomAndProviders } from './ShadowDomAndProviders'; -import { SwapPage } from '@/pages/SwapPage/SwapPage'; import NiceModal, { useModal } from '@ebay/nice-modal-react'; import { styled } from 'styled-components'; import { Modal } from '@/components/Modal'; import { cloneElement, ReactElement } from 'react'; import { PartialTheme } from './theme'; +import { Router } from './Router'; export type SwapWidgetProps = { theme?: PartialTheme; @@ -15,7 +15,7 @@ export const SwapWidget = (props: SwapWidgetProps) => { - + @@ -26,7 +26,7 @@ const SwapWidgetWithoutNiceModalProvider = (props: SwapWidgetProps) => { return ( - + ); diff --git a/packages/widget-v2/tsconfig.app.json b/packages/widget-v2/tsconfig.app.json index 50f728991..2b65b1b31 100644 --- a/packages/widget-v2/tsconfig.app.json +++ b/packages/widget-v2/tsconfig.app.json @@ -26,7 +26,7 @@ /* Aliases */ "baseUrl": ".", "paths": { - "@*": ["src/*"] + "@/*": ["src/*"] } }, "include": ["src"] diff --git a/yarn.lock b/yarn.lock index 25d554dba..6f8d0f155 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24160,6 +24160,17 @@ __metadata: languageName: node linkType: hard +"react-error-boundary@npm:^4.0.13": + version: 4.0.13 + resolution: "react-error-boundary@npm:4.0.13" + dependencies: + "@babel/runtime": ^7.12.5 + peerDependencies: + react: ">=16.13.1" + checksum: 50398d080015d51d22c6f94c56f4ea336d10232d72345b36ee6f15b6b643666d20b072829b02f091a80e5af68fe67f68a62ef0d2b649dbd759ead929304449af + languageName: node + linkType: hard + "react-hot-toast@npm:^2.4.1": version: 2.4.1 resolution: "react-hot-toast@npm:2.4.1" @@ -28495,6 +28506,7 @@ __metadata: lodash.debounce: ^4.0.8 pluralize: ^8.0.0 rc-virtual-list: ^3.14.5 + react-error-boundary: ^4.0.13 react-shadow-scope: ^1.0.5 storybook: ^8.2.6 styled-components: ^6.0.0 From 8fad0d93bb335f87965e1abccc27d190f9cba3c5 Mon Sep 17 00:00:00 2001 From: Todd Kao Date: Wed, 21 Aug 2024 14:18:41 -0400 Subject: [PATCH 2/8] Refactor modals to wrap with ErrorBoundary and auto pass theme --- packages/widget-v2/src/components/Modal.tsx | 46 +++++++- .../ManualAddressModal/ManualAddressModal.tsx | 6 +- .../TokenAndChainSelectorModal.tsx | 6 +- .../TransactionHistoryModal.tsx | 5 +- .../WalletSelectorFlow.tsx | 6 +- .../src/pages/ErrorPage/ErrorPage.tsx | 18 ++- .../SwapExecutionPage/SwapExecutionPage.tsx | 14 +-- .../widget-v2/src/pages/SwapPage/SwapPage.tsx | 11 +- .../src/pages/SwapPage/SwapPageSettings.tsx | 107 +++++++++--------- 9 files changed, 129 insertions(+), 90 deletions(-) diff --git a/packages/widget-v2/src/components/Modal.tsx b/packages/widget-v2/src/components/Modal.tsx index f2913a52d..feaf77f01 100644 --- a/packages/widget-v2/src/components/Modal.tsx +++ b/packages/widget-v2/src/components/Modal.tsx @@ -1,10 +1,15 @@ -import { css, styled } from 'styled-components'; +import { css, styled, useTheme } from 'styled-components'; import * as Dialog from '@radix-ui/react-dialog'; import { ShadowDomAndProviders } from '@/widget/ShadowDomAndProviders'; -import { useModal } from '@ebay/nice-modal-react'; -import { useEffect } from 'react'; +import NiceModal, { useModal } from '@ebay/nice-modal-react'; +import { ComponentProps, ComponentType, FC, useEffect } from 'react'; import { PartialTheme } from '@/widget/theme'; +import { ErrorBoundary } from 'react-error-boundary'; +import { useAtom } from 'jotai'; +import { errorAtom } from '@/state/errorPage'; +import { ErrorPage } from '@/pages/ErrorPage/ErrorPage'; + export type ModalProps = { children: React.ReactNode; drawer?: boolean; @@ -42,6 +47,41 @@ export const Modal = ({ ); }; +export const createModal = (component: ComponentType) => { + const Component = component; + + const WrappedComponent = (props: any) => { + const [, setError] = useAtom(errorAtom); + + return ( + + setError(error)} + > + + + + ); + }; + + return NiceModal.create(WrappedComponent); +}; + +export const useThemedModal = >( + modal: T, + args?: Partial> +) => { + const theme = useTheme(); + const modalInstance = NiceModal.useModal(modal, { theme, ...args }); + + return { + ...modalInstance, + show: (showArgs?: Partial>) => + modalInstance.show({ theme, ...showArgs }), + }; +}; + const StyledOverlay = styled(Dialog.Overlay)<{ drawer?: boolean }>` background: rgba(0 0 0 / 0.5); position: fixed; diff --git a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx index 743fa32d2..5c018b77f 100644 --- a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx +++ b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx @@ -1,5 +1,5 @@ -import NiceModal, { useModal } from '@ebay/nice-modal-react'; -import { Modal, ModalProps } from '@/components/Modal'; +import { useModal } from '@ebay/nice-modal-react'; +import { createModal, Modal, ModalProps } from '@/components/Modal'; import { Column, Row } from '@/components/Layout'; import { css, styled } from 'styled-components'; import { useCallback, useMemo, useState } from 'react'; @@ -16,7 +16,7 @@ import { destinationAssetAtom, destinationWalletAtom } from '@/state/swapPage'; import { useAtom } from 'jotai'; import { getChain } from '@/state/skipClient'; -export const ManualAddressModal = NiceModal.create((modalProps: ModalProps) => { +export const ManualAddressModal = createModal((modalProps: ModalProps) => { const { theme } = modalProps; const modal = useModal(); const [destinationAsset] = useAtom(destinationAssetAtom); diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx index 94e2e1f48..46dda1026 100644 --- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx +++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx @@ -1,5 +1,5 @@ -import NiceModal, { useModal } from '@ebay/nice-modal-react'; -import { Modal, ModalProps } from '@/components/Modal'; +import { useModal } from '@ebay/nice-modal-react'; +import { createModal, Modal, ModalProps } from '@/components/Modal'; import { Column } from '@/components/Layout'; import { styled } from 'styled-components'; import { useAtom } from 'jotai'; @@ -19,7 +19,7 @@ export type TokenAndChainSelectorModalProps = ModalProps & { asset?: Partial; }; -export const TokenAndChainSelectorModal = NiceModal.create( +export const TokenAndChainSelectorModal = createModal( (modalProps: TokenAndChainSelectorModalProps) => { const modal = useModal(); const { onSelect, chainsContainingAsset, asset } = modalProps; diff --git a/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModal.tsx b/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModal.tsx index a1e73059f..dd1cd1801 100644 --- a/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModal.tsx +++ b/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModal.tsx @@ -1,5 +1,4 @@ -import NiceModal from '@ebay/nice-modal-react'; -import { Modal, ModalProps } from '@/components/Modal'; +import { createModal, Modal, ModalProps } from '@/components/Modal'; import { Column } from '@/components/Layout'; import { styled } from 'styled-components'; import { SwapPageHeader } from '@/pages/SwapPage/SwapPageHeader'; @@ -21,7 +20,7 @@ export type TransactionHistoryModalProps = ModalProps & { txHistory: TxHistoryItem[]; }; -export const TransactionHistoryModal = NiceModal.create( +export const TransactionHistoryModal = createModal( ({ txHistory, ...modalProps }: TransactionHistoryModalProps) => { const [itemIndexToShowDetail, setItemIndexToShowDetail] = useState< number | undefined diff --git a/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx b/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx index 8fec1823b..cb0e3e2fb 100644 --- a/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx +++ b/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx @@ -1,5 +1,5 @@ -import NiceModal, { useModal } from '@ebay/nice-modal-react'; -import { Modal, ModalProps } from '@/components/Modal'; +import { useModal } from '@ebay/nice-modal-react'; +import { createModal, Modal, ModalProps } from '@/components/Modal'; import { RenderWalletList, Wallet } from '@/components/RenderWalletList'; export type WalletSelectorModalProps = ModalProps & { @@ -26,7 +26,7 @@ export const WALLET_LIST: Wallet[] = [ }, ]; -export const WalletSelectorModal = NiceModal.create( +export const WalletSelectorModal = createModal( (modalProps: WalletSelectorModalProps) => { const { onSelect } = modalProps; const modal = useModal(); diff --git a/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx b/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx index a0e672a40..1edd6e58f 100644 --- a/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx +++ b/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx @@ -1,13 +1,27 @@ import { errorAtom } from '@/state/errorPage'; +import NiceModal from '@ebay/nice-modal-react'; import { useResetAtom } from 'jotai/utils'; -export const ErrorPage = () => { +export const ErrorPage = ({ + error, + componentStack, + resetErrorBoundary, +}: { + error?: Error; + componentStack?: string; + resetErrorBoundary?: () => void; +}) => { const resetError = useResetAtom(errorAtom); + const handleReset = () => { + resetError(); + resetErrorBoundary?.(); + }; + return (
error page - +
); }; diff --git a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx index 2dba7da34..108fecb62 100644 --- a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx +++ b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx @@ -4,7 +4,6 @@ import { SwapPageFooter } from '@/pages/SwapPage/SwapPageFooter'; import { SwapPageHeader } from '@/pages/SwapPage/SwapPageHeader'; import { useEffect, useMemo, useState } from 'react'; import { ICONS } from '@/icons'; -import { useModal } from '@ebay/nice-modal-react'; import { ManualAddressModal } from '@/modals/ManualAddressModal/ManualAddressModal'; import styled, { useTheme } from 'styled-components'; import { useAtom } from 'jotai'; @@ -18,6 +17,7 @@ import { SmallText } from '@/components/Typography'; import { SignatureIcon } from '@/icons/SignatureIcon'; import pluralize from 'pluralize'; import operations from './operations.json'; +import { useThemedModal } from '@/components/Modal'; enum SwapExecutionState { destinationAddressUnset, @@ -45,7 +45,7 @@ export const SwapExecutionPage = () => { } }, [destinationWallet]); const [simpleRoute, setSimpleRoute] = useState(true); - const modal = useModal(ManualAddressModal); + const modal = useThemedModal(ManualAddressModal); const [txStateMap, setTxStateMap] = useState<{ [index: number]: txState }>({ 0: 'pending', @@ -92,11 +92,7 @@ export const SwapExecutionPage = () => { - modal.show({ - theme, - }) - } + onClick={() => modal.show()} /> ); case SwapExecutionState.unconfirmed: @@ -133,9 +129,7 @@ export const SwapExecutionPage = () => { const SwapExecutionPageRoute = simpleRoute ? withBoundProps(SwapExecutionPageRouteSimple, { onClickEditDestinationWallet: () => { - modal.show({ - theme, - }); + modal.show(); }, }) : SwapExecutionPageRouteDetailed; diff --git a/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx b/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx index 44013787f..fd74a1412 100644 --- a/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx +++ b/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx @@ -14,19 +14,19 @@ import { SwapPageSettings } from './SwapPageSettings'; import { SwapPageFooter } from './SwapPageFooter'; import { SwapPageBridge } from './SwapPageBridge'; import { SwapPageHeader } from './SwapPageHeader'; +import { useThemedModal } from '@/components/Modal'; const sourceAssetBalance = 125; export const SwapPage = () => { - const theme = useTheme(); const [container, setContainer] = useState(); const [drawerOpen, setDrawerOpen] = useState(false); const [sourceAsset, setSourceAsset] = useAtom(sourceAssetAtom); const [{ data: assets }] = useAtom(skipAssets); const [destinationAsset, setDestinationAsset] = useAtom(destinationAssetAtom); - const swapFlowSettings = useModal(SwapPageSettings); - const tokenAndChainSelectorFlow = useModal(TokenAndChainSelectorModal); + const swapFlowSettings = useThemedModal(SwapPageSettings); + const tokenAndChainSelectorFlow = useThemedModal(TokenAndChainSelectorModal); const chainsContainingSourceAsset = useMemo(() => { if (!assets || !sourceAsset?.symbol) return; @@ -42,7 +42,6 @@ export const SwapPage = () => { const handleChangeSourceAsset = useCallback(() => { tokenAndChainSelectorFlow.show({ - theme, onSelect: (asset) => { setSourceAsset((old) => ({ ...old, @@ -57,7 +56,6 @@ export const SwapPage = () => { if (!chainsContainingSourceAsset) return; return tokenAndChainSelectorFlow.show({ - theme, onSelect: (asset) => { setSourceAsset((old) => ({ ...old, @@ -74,7 +72,6 @@ export const SwapPage = () => { const handleChangeDestinationAsset = useCallback(() => { tokenAndChainSelectorFlow.show({ - theme, onSelect: (asset) => { setDestinationAsset((old) => ({ ...old, @@ -89,7 +86,6 @@ export const SwapPage = () => { if (!chainsContainingDestinationAsset) return; return tokenAndChainSelectorFlow.show({ - theme, onSelect: (asset) => { setDestinationAsset((old) => ({ ...old, @@ -153,7 +149,6 @@ export const SwapPage = () => { showRouteInfo onClick={() => swapFlowSettings.show({ - theme, drawer: true, container, onOpenChange: (open: boolean) => diff --git a/packages/widget-v2/src/pages/SwapPage/SwapPageSettings.tsx b/packages/widget-v2/src/pages/SwapPage/SwapPageSettings.tsx index a23fa573a..6282b20ef 100644 --- a/packages/widget-v2/src/pages/SwapPage/SwapPageSettings.tsx +++ b/packages/widget-v2/src/pages/SwapPage/SwapPageSettings.tsx @@ -1,10 +1,11 @@ import { css, styled } from 'styled-components'; -import { Modal, ModalProps } from '@/components/Modal'; +import { createModal, Modal, ModalProps } from '@/components/Modal'; import { Column, Row } from '@/components/Layout'; import NiceModal from '@ebay/nice-modal-react'; import { SmallText } from '@/components/Typography'; import { RouteArrow } from '@/icons/RouteArrow'; import { SwapPageFooterItems } from './SwapPageFooter'; +import { useEffect } from 'react'; const SLIPPAGE_OPTIONS = [ { @@ -31,65 +32,61 @@ const bridgeFee = '0.001 XYZ ($0.1)'; const selectedOption = SLIPPAGE_OPTIONS[0]; const route = ['COSMOS', 'OSMOSIS', 'AXELAR']; -export const SwapPageSettings = NiceModal.create((modalProps: ModalProps) => { +export const SwapPageSettings = createModal((modalProps: ModalProps) => { return ( - - - - - Route - - {route.map((_path, index) => ( - <> - - {index !== route.length - 1 && ( - - )} - - ))} - + + + + Route + + {route.map((_path, index) => ( + <> + + {index !== route.length - 1 && ( + + )} + + ))} - - Max Slippage - - {SLIPPAGE_OPTIONS.map(({ label }) => ( - - {label} - - ))} - + + + Max Slippage + + {SLIPPAGE_OPTIONS.map(({ label }) => ( + + {label} + + ))} - + + - - - Total Gas - {totalGas} - - - Router Fee - {routerFee} - - - Bridge Fee - {bridgeFee} - - + + + Total Gas + {totalGas} + + + Router Fee + {routerFee} + + + Bridge Fee + {bridgeFee} + + - - - - - + + + + ); }); From 946284301dc20602b7fbd1e53830b26428a8494f Mon Sep 17 00:00:00 2001 From: Todd Kao Date: Wed, 21 Aug 2024 14:21:15 -0400 Subject: [PATCH 3/8] Remove manual usages of Modal within createModal --- .../ManualAddressModal/ManualAddressModal.tsx | 6 +-- .../TokenAndChainSelectorModal.tsx | 54 +++++++++---------- .../TransactionHistoryModal.tsx | 6 +-- .../WalletSelectorFlow.tsx | 16 +++--- .../src/pages/SwapPage/SwapPageSettings.tsx | 4 +- 5 files changed, 40 insertions(+), 46 deletions(-) diff --git a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx index 5c018b77f..45e0c87c0 100644 --- a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx +++ b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx @@ -1,5 +1,5 @@ import { useModal } from '@ebay/nice-modal-react'; -import { createModal, Modal, ModalProps } from '@/components/Modal'; +import { createModal, ModalProps } from '@/components/Modal'; import { Column, Row } from '@/components/Layout'; import { css, styled } from 'styled-components'; import { useCallback, useMemo, useState } from 'react'; @@ -62,7 +62,7 @@ export const ManualAddressModal = createModal((modalProps: ModalProps) => { }, [manualWalletAddress]); return ( - + <> {showManualAddressInput ? ( { onClickBackButton={() => modal.remove()} /> )} - + ); }); diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx index 46dda1026..a2c9be2e2 100644 --- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx +++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx @@ -1,5 +1,5 @@ import { useModal } from '@ebay/nice-modal-react'; -import { createModal, Modal, ModalProps } from '@/components/Modal'; +import { createModal, ModalProps } from '@/components/Modal'; import { Column } from '@/components/Layout'; import { styled } from 'styled-components'; import { useAtom } from 'jotai'; @@ -78,34 +78,32 @@ export const TokenAndChainSelectorModal = createModal( ); return ( - - - + + {showSkeleton || (!filteredAssets && !filteredChains) ? ( + + {Array.from({ length: 10 }, (_, index) => ( + + ))} + + ) : ( + { + if (isChainWithAsset(item)) { + return `${item.chain_id}${item.chain_name}`; + } + return `${item.chainID}${item.denom}`; + }} /> - {showSkeleton || (!filteredAssets && !filteredChains) ? ( - - {Array.from({ length: 10 }, (_, index) => ( - - ))} - - ) : ( - { - if (isChainWithAsset(item)) { - return `${item.chain_id}${item.chain_name}`; - } - return `${item.chainID}${item.denom}`; - }} - /> - )} - - + )} + ); } ); diff --git a/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModal.tsx b/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModal.tsx index dd1cd1801..447d26ccb 100644 --- a/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModal.tsx +++ b/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModal.tsx @@ -1,4 +1,4 @@ -import { createModal, Modal, ModalProps } from '@/components/Modal'; +import { createModal, ModalProps } from '@/components/Modal'; import { Column } from '@/components/Layout'; import { styled } from 'styled-components'; import { SwapPageHeader } from '@/pages/SwapPage/SwapPageHeader'; @@ -26,7 +26,7 @@ export const TransactionHistoryModal = createModal( number | undefined >(); return ( - + <> - + ); } ); diff --git a/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx b/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx index cb0e3e2fb..334fcdc87 100644 --- a/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx +++ b/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx @@ -1,5 +1,5 @@ import { useModal } from '@ebay/nice-modal-react'; -import { createModal, Modal, ModalProps } from '@/components/Modal'; +import { createModal, ModalProps } from '@/components/Modal'; import { RenderWalletList, Wallet } from '@/components/RenderWalletList'; export type WalletSelectorModalProps = ModalProps & { @@ -32,14 +32,12 @@ export const WalletSelectorModal = createModal( const modal = useModal(); return ( - - modal.remove()} - /> - + modal.remove()} + /> ); } ); diff --git a/packages/widget-v2/src/pages/SwapPage/SwapPageSettings.tsx b/packages/widget-v2/src/pages/SwapPage/SwapPageSettings.tsx index 6282b20ef..98d862534 100644 --- a/packages/widget-v2/src/pages/SwapPage/SwapPageSettings.tsx +++ b/packages/widget-v2/src/pages/SwapPage/SwapPageSettings.tsx @@ -1,11 +1,9 @@ import { css, styled } from 'styled-components'; -import { createModal, Modal, ModalProps } from '@/components/Modal'; +import { createModal, ModalProps } from '@/components/Modal'; import { Column, Row } from '@/components/Layout'; -import NiceModal from '@ebay/nice-modal-react'; import { SmallText } from '@/components/Typography'; import { RouteArrow } from '@/icons/RouteArrow'; import { SwapPageFooterItems } from './SwapPageFooter'; -import { useEffect } from 'react'; const SLIPPAGE_OPTIONS = [ { From dbdb0ae0da87066a169eb1add7d3d54f87bf5e14 Mon Sep 17 00:00:00 2001 From: Todd Kao Date: Wed, 21 Aug 2024 14:23:16 -0400 Subject: [PATCH 4/8] Update ErrorBoundary in modal to simply setError --- packages/widget-v2/src/components/Modal.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/widget-v2/src/components/Modal.tsx b/packages/widget-v2/src/components/Modal.tsx index feaf77f01..6d4d20a9b 100644 --- a/packages/widget-v2/src/components/Modal.tsx +++ b/packages/widget-v2/src/components/Modal.tsx @@ -55,10 +55,7 @@ export const createModal = (component: ComponentType) => { return ( - setError(error)} - > + setError(error)}> From 0b52aa392fb6f7b120bb94ec52ff1f2d7a26023c Mon Sep 17 00:00:00 2001 From: Todd Kao Date: Wed, 21 Aug 2024 14:42:18 -0400 Subject: [PATCH 5/8] Update createModal types --- packages/widget-v2/src/components/Modal.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/widget-v2/src/components/Modal.tsx b/packages/widget-v2/src/components/Modal.tsx index 6d4d20a9b..648ec9192 100644 --- a/packages/widget-v2/src/components/Modal.tsx +++ b/packages/widget-v2/src/components/Modal.tsx @@ -47,10 +47,12 @@ export const Modal = ({ ); }; -export const createModal = (component: ComponentType) => { +export const createModal = ( + component: ComponentType +) => { const Component = component; - const WrappedComponent = (props: any) => { + const WrappedComponent = (props: T) => { const [, setError] = useAtom(errorAtom); return ( From ef0cf9cf530e54dbf8a3173a6fc9bdbec0de35e7 Mon Sep 17 00:00:00 2001 From: Todd Kao Date: Wed, 21 Aug 2024 15:47:11 -0400 Subject: [PATCH 6/8] Add not rendering stacked modal overlays if multiple modals are open --- packages/widget-v2/src/components/Modal.tsx | 68 +++++++++++++++---- .../ManualAddressModal/ManualAddressModal.tsx | 3 +- .../TokenAndChainSelectorModal.tsx | 3 +- .../TokenAndChainSelectorModalSearchInput.tsx | 2 +- .../WalletSelectorFlow.tsx | 3 +- .../SwapExecutionPage/SwapExecutionPage.tsx | 4 +- .../widget-v2/src/pages/SwapPage/SwapPage.tsx | 8 +-- packages/widget-v2/src/state/modal.ts | 3 + packages/widget-v2/src/widget/Widget.tsx | 4 +- 9 files changed, 67 insertions(+), 31 deletions(-) create mode 100644 packages/widget-v2/src/state/modal.ts diff --git a/packages/widget-v2/src/components/Modal.tsx b/packages/widget-v2/src/components/Modal.tsx index 648ec9192..a7190aef3 100644 --- a/packages/widget-v2/src/components/Modal.tsx +++ b/packages/widget-v2/src/components/Modal.tsx @@ -1,20 +1,28 @@ import { css, styled, useTheme } from 'styled-components'; import * as Dialog from '@radix-ui/react-dialog'; import { ShadowDomAndProviders } from '@/widget/ShadowDomAndProviders'; -import NiceModal, { useModal } from '@ebay/nice-modal-react'; -import { ComponentProps, ComponentType, FC, useEffect } from 'react'; +import NiceModal, { useModal as useNiceModal } from '@ebay/nice-modal-react'; +import { + ComponentProps, + ComponentType, + FC, + useCallback, + useEffect, + useMemo, +} from 'react'; import { PartialTheme } from '@/widget/theme'; import { ErrorBoundary } from 'react-error-boundary'; import { useAtom } from 'jotai'; import { errorAtom } from '@/state/errorPage'; -import { ErrorPage } from '@/pages/ErrorPage/ErrorPage'; +import { numberOfModalsOpenAtom } from '@/state/modal'; export type ModalProps = { children: React.ReactNode; drawer?: boolean; container?: HTMLElement; onOpenChange?: (open: boolean) => void; + stackedModal?: boolean; theme?: PartialTheme; }; @@ -23,6 +31,7 @@ export const Modal = ({ drawer, container, onOpenChange, + stackedModal, theme, }: ModalProps) => { const modal = useModal(); @@ -38,7 +47,7 @@ export const Modal = ({ modal.remove()}> - + {children} @@ -67,22 +76,51 @@ export const createModal = ( return NiceModal.create(WrappedComponent); }; -export const useThemedModal = >( - modal: T, - args?: Partial> +export const useModal = >( + modal?: T, + initialArgs?: Partial> ) => { const theme = useTheme(); - const modalInstance = NiceModal.useModal(modal, { theme, ...args }); + const [numberOfModalsOpen, setNumberOfModalsOpen] = useAtom( + numberOfModalsOpenAtom + ); - return { - ...modalInstance, - show: (showArgs?: Partial>) => - modalInstance.show({ theme, ...showArgs }), - }; + const modalInstance = modal + ? useNiceModal(modal, initialArgs) + : useNiceModal(); + + const show = useCallback( + (showArgs?: any) => { + setNumberOfModalsOpen((prev) => prev + 1); + modalInstance.show({ + theme, + stackedModal: numberOfModalsOpen > 0, + ...showArgs, + }); + }, + [modalInstance, setNumberOfModalsOpen] + ); + + const remove = useCallback(() => { + setNumberOfModalsOpen((prev) => Math.max(0, prev - 1)); + modalInstance.remove(); + }, [modalInstance, setNumberOfModalsOpen]); + + return useMemo( + () => ({ + ...modalInstance, + show, + remove, + }), + [modalInstance, show, remove] + ); }; -const StyledOverlay = styled(Dialog.Overlay)<{ drawer?: boolean }>` - background: rgba(0 0 0 / 0.5); +const StyledOverlay = styled(Dialog.Overlay)<{ + drawer?: boolean; + invisible?: boolean; +}>` + ${({ invisible }) => (invisible ? '' : 'background: rgba(0 0 0 / 0.5);')} position: fixed; top: 0; left: 0; diff --git a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx index 45e0c87c0..d920ea7df 100644 --- a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx +++ b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx @@ -1,5 +1,4 @@ -import { useModal } from '@ebay/nice-modal-react'; -import { createModal, ModalProps } from '@/components/Modal'; +import { createModal, ModalProps, useModal } from '@/components/Modal'; import { Column, Row } from '@/components/Layout'; import { css, styled } from 'styled-components'; import { useCallback, useMemo, useState } from 'react'; diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx index a2c9be2e2..c81b2f831 100644 --- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx +++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx @@ -1,5 +1,4 @@ -import { useModal } from '@ebay/nice-modal-react'; -import { createModal, ModalProps } from '@/components/Modal'; +import { createModal, ModalProps, useModal } from '@/components/Modal'; import { Column } from '@/components/Layout'; import { styled } from 'styled-components'; import { useAtom } from 'jotai'; diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalSearchInput.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalSearchInput.tsx index 52b13e58a..bc95503d2 100644 --- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalSearchInput.tsx +++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalSearchInput.tsx @@ -7,9 +7,9 @@ import { SearchIcon } from '@/icons/SearchIcon'; import { StyledAssetLabel } from '@/components/AssetChainInput'; import { ClientAsset } from '@/state/skipClient'; import { LeftArrowIcon } from '@/icons/ArrowIcon'; -import { useModal } from '@ebay/nice-modal-react'; import { Button } from '@/components/Button'; import { Text } from '@/components/Typography'; +import { useModal } from '@/components/Modal'; type TokenAndChainSelectorModalSearchInputProps = { onSearch: (term: string) => void; diff --git a/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx b/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx index 334fcdc87..61c8022de 100644 --- a/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx +++ b/packages/widget-v2/src/modals/WalletSelectorModal/WalletSelectorFlow.tsx @@ -1,5 +1,4 @@ -import { useModal } from '@ebay/nice-modal-react'; -import { createModal, ModalProps } from '@/components/Modal'; +import { createModal, ModalProps, useModal } from '@/components/Modal'; import { RenderWalletList, Wallet } from '@/components/RenderWalletList'; export type WalletSelectorModalProps = ModalProps & { diff --git a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx index 108fecb62..c790053a9 100644 --- a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx +++ b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPage.tsx @@ -17,7 +17,7 @@ import { SmallText } from '@/components/Typography'; import { SignatureIcon } from '@/icons/SignatureIcon'; import pluralize from 'pluralize'; import operations from './operations.json'; -import { useThemedModal } from '@/components/Modal'; +import { useModal } from '@/components/Modal'; enum SwapExecutionState { destinationAddressUnset, @@ -45,7 +45,7 @@ export const SwapExecutionPage = () => { } }, [destinationWallet]); const [simpleRoute, setSimpleRoute] = useState(true); - const modal = useThemedModal(ManualAddressModal); + const modal = useModal(ManualAddressModal); const [txStateMap, setTxStateMap] = useState<{ [index: number]: txState }>({ 0: 'pending', diff --git a/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx b/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx index fd74a1412..78404632f 100644 --- a/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx +++ b/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx @@ -1,6 +1,4 @@ -import { useTheme } from 'styled-components'; import { useCallback, useMemo, useState } from 'react'; -import { useModal } from '@ebay/nice-modal-react'; import { useAtom } from 'jotai'; import { AssetChainInput } from '@/components/AssetChainInput'; import { Column } from '@/components/Layout'; @@ -14,7 +12,7 @@ import { SwapPageSettings } from './SwapPageSettings'; import { SwapPageFooter } from './SwapPageFooter'; import { SwapPageBridge } from './SwapPageBridge'; import { SwapPageHeader } from './SwapPageHeader'; -import { useThemedModal } from '@/components/Modal'; +import { useModal } from '@/components/Modal'; const sourceAssetBalance = 125; @@ -25,8 +23,8 @@ export const SwapPage = () => { const [{ data: assets }] = useAtom(skipAssets); const [destinationAsset, setDestinationAsset] = useAtom(destinationAssetAtom); - const swapFlowSettings = useThemedModal(SwapPageSettings); - const tokenAndChainSelectorFlow = useThemedModal(TokenAndChainSelectorModal); + const swapFlowSettings = useModal(SwapPageSettings); + const tokenAndChainSelectorFlow = useModal(TokenAndChainSelectorModal); const chainsContainingSourceAsset = useMemo(() => { if (!assets || !sourceAsset?.symbol) return; diff --git a/packages/widget-v2/src/state/modal.ts b/packages/widget-v2/src/state/modal.ts new file mode 100644 index 000000000..7aa3d87ff --- /dev/null +++ b/packages/widget-v2/src/state/modal.ts @@ -0,0 +1,3 @@ +import { atom } from 'jotai'; + +export const numberOfModalsOpenAtom = atom(0); diff --git a/packages/widget-v2/src/widget/Widget.tsx b/packages/widget-v2/src/widget/Widget.tsx index db7b8fc5b..753fc5280 100644 --- a/packages/widget-v2/src/widget/Widget.tsx +++ b/packages/widget-v2/src/widget/Widget.tsx @@ -1,7 +1,7 @@ import { ShadowDomAndProviders } from './ShadowDomAndProviders'; -import NiceModal, { useModal } from '@ebay/nice-modal-react'; +import NiceModal from '@ebay/nice-modal-react'; import { styled } from 'styled-components'; -import { Modal } from '@/components/Modal'; +import { Modal, useModal } from '@/components/Modal'; import { cloneElement, ReactElement } from 'react'; import { PartialTheme } from './theme'; import { Router } from './Router'; From 1faf901b3655ca8d707e147a80d2f15f2e4ddafd Mon Sep 17 00:00:00 2001 From: Todd Kao Date: Wed, 21 Aug 2024 15:54:48 -0400 Subject: [PATCH 7/8] Update useModal types --- packages/widget-v2/src/components/Modal.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/widget-v2/src/components/Modal.tsx b/packages/widget-v2/src/components/Modal.tsx index a7190aef3..a2be6e8c7 100644 --- a/packages/widget-v2/src/components/Modal.tsx +++ b/packages/widget-v2/src/components/Modal.tsx @@ -76,9 +76,9 @@ export const createModal = ( return NiceModal.create(WrappedComponent); }; -export const useModal = >( - modal?: T, - initialArgs?: Partial> +export const useModal = ( + modal?: FC, + initialArgs?: Partial ) => { const theme = useTheme(); const [numberOfModalsOpen, setNumberOfModalsOpen] = useAtom( @@ -90,15 +90,15 @@ export const useModal = >( : useNiceModal(); const show = useCallback( - (showArgs?: any) => { + (showArgs?: Partial) => { setNumberOfModalsOpen((prev) => prev + 1); modalInstance.show({ theme, stackedModal: numberOfModalsOpen > 0, ...showArgs, - }); + } as Partial); }, - [modalInstance, setNumberOfModalsOpen] + [modalInstance, setNumberOfModalsOpen, theme, numberOfModalsOpen] ); const remove = useCallback(() => { From 1173e74092b2e8d15ae755aeaef4cf7488a984d7 Mon Sep 17 00:00:00 2001 From: Todd Kao Date: Wed, 21 Aug 2024 16:12:38 -0400 Subject: [PATCH 8/8] Update Widget.tsx to use createModal and useModal from Modal.tsx --- packages/widget-v2/src/components/Modal.tsx | 9 +-------- .../widget-v2/src/pages/ErrorPage/ErrorPage.tsx | 1 - packages/widget-v2/src/state/modal.ts | 4 ++-- packages/widget-v2/src/widget/Widget.tsx | 14 +++++++++----- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/widget-v2/src/components/Modal.tsx b/packages/widget-v2/src/components/Modal.tsx index a2be6e8c7..a478209f0 100644 --- a/packages/widget-v2/src/components/Modal.tsx +++ b/packages/widget-v2/src/components/Modal.tsx @@ -2,14 +2,7 @@ import { css, styled, useTheme } from 'styled-components'; import * as Dialog from '@radix-ui/react-dialog'; import { ShadowDomAndProviders } from '@/widget/ShadowDomAndProviders'; import NiceModal, { useModal as useNiceModal } from '@ebay/nice-modal-react'; -import { - ComponentProps, - ComponentType, - FC, - useCallback, - useEffect, - useMemo, -} from 'react'; +import { ComponentType, FC, useCallback, useEffect, useMemo } from 'react'; import { PartialTheme } from '@/widget/theme'; import { ErrorBoundary } from 'react-error-boundary'; diff --git a/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx b/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx index 1edd6e58f..264f7d2b8 100644 --- a/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx +++ b/packages/widget-v2/src/pages/ErrorPage/ErrorPage.tsx @@ -1,5 +1,4 @@ import { errorAtom } from '@/state/errorPage'; -import NiceModal from '@ebay/nice-modal-react'; import { useResetAtom } from 'jotai/utils'; export const ErrorPage = ({ diff --git a/packages/widget-v2/src/state/modal.ts b/packages/widget-v2/src/state/modal.ts index 7aa3d87ff..89476e04e 100644 --- a/packages/widget-v2/src/state/modal.ts +++ b/packages/widget-v2/src/state/modal.ts @@ -1,3 +1,3 @@ -import { atom } from 'jotai'; +import { atomWithReset } from 'jotai/utils'; -export const numberOfModalsOpenAtom = atom(0); +export const numberOfModalsOpenAtom = atomWithReset(0); diff --git a/packages/widget-v2/src/widget/Widget.tsx b/packages/widget-v2/src/widget/Widget.tsx index 753fc5280..225f82a65 100644 --- a/packages/widget-v2/src/widget/Widget.tsx +++ b/packages/widget-v2/src/widget/Widget.tsx @@ -1,10 +1,12 @@ import { ShadowDomAndProviders } from './ShadowDomAndProviders'; import NiceModal from '@ebay/nice-modal-react'; import { styled } from 'styled-components'; -import { Modal, useModal } from '@/components/Modal'; +import { createModal, useModal } from '@/components/Modal'; import { cloneElement, ReactElement } from 'react'; import { PartialTheme } from './theme'; import { Router } from './Router'; +import { useResetAtom } from 'jotai/utils'; +import { numberOfModalsOpenAtom } from '@/state/modal'; export type SwapWidgetProps = { theme?: PartialTheme; @@ -40,12 +42,14 @@ export const ShowSwapWidget = ({ button = , ...props }: ShowSwapWidget) => { - const modal = useModal(NiceModal.create(Modal)); + const modal = useModal( + createModal(() => ) + ); + const resetNumberOfModalsOpen = useResetAtom(numberOfModalsOpenAtom); const handleClick = () => { - modal.show({ - children: , - }); + resetNumberOfModalsOpen(); + modal.show(); }; const Element = cloneElement(button, { onClick: handleClick });