From cd8579843e896e05c905c3a50750048eb9fbad27 Mon Sep 17 00:00:00 2001 From: James Mealy Date: Mon, 29 Apr 2024 14:38:49 +0200 Subject: [PATCH] Display legal disclaimer to first time swappers --- .../common/BlockedAddress/index.stories.tsx | 25 --------- .../common/BlockedAddress/index.tsx | 53 ++++++------------- .../common/Disclaimer/index.stories.tsx | 40 ++++++++++++++ src/components/common/Disclaimer/index.tsx | 50 +++++++++++++++++ .../common/Disclaimer/styles.module.css | 14 +++++ .../LegalDisclaimerContent/index.tsx} | 19 ++++--- .../LegalDisclaimerContent/styles.module.css | 9 ++++ .../safe-apps/SafeAppsInfoModal/index.tsx | 4 +- .../SafeAppsInfoModal/styles.module.css | 9 ---- src/features/swap/useSwapLegalDisclaimer.ts | 22 ++++++++ src/pages/swap.tsx | 14 ++++- src/services/ofac/blockedAddressList.json | 3 +- src/utils/chains.ts | 1 + 13 files changed, 177 insertions(+), 86 deletions(-) delete mode 100644 src/components/common/BlockedAddress/index.stories.tsx create mode 100644 src/components/common/Disclaimer/index.stories.tsx create mode 100644 src/components/common/Disclaimer/index.tsx create mode 100644 src/components/common/Disclaimer/styles.module.css rename src/components/{safe-apps/SafeAppsInfoModal/LegalDisclaimer.tsx => common/LegalDisclaimerContent/index.tsx} (64%) create mode 100644 src/components/common/LegalDisclaimerContent/styles.module.css create mode 100644 src/features/swap/useSwapLegalDisclaimer.ts diff --git a/src/components/common/BlockedAddress/index.stories.tsx b/src/components/common/BlockedAddress/index.stories.tsx deleted file mode 100644 index f2d837c70c..0000000000 --- a/src/components/common/BlockedAddress/index.stories.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react' -import BlockedAddress from './index' - -const meta = { - component: BlockedAddress, - parameters: { - componentSubtitle: 'Renders an information block intended for users whose address is blocked by OFAC', - }, - tags: ['autodocs'], -} satisfies Meta - -export default meta -type Story = StoryObj - -export const Default: Story = { - args: { - address: '0xD3a484faEa53313eF85b5916C9302a3E304ae622', - }, - parameters: { - design: { - type: 'figma', - url: 'https://www.figma.com/file/VyA38zUPbJ2zflzCIYR6Nu/Swap?node-id=6167%3A14371&mode=dev', - }, - }, -} diff --git a/src/components/common/BlockedAddress/index.tsx b/src/components/common/BlockedAddress/index.tsx index 7b9db8073c..e4817ea1f3 100644 --- a/src/components/common/BlockedAddress/index.tsx +++ b/src/components/common/BlockedAddress/index.tsx @@ -1,51 +1,28 @@ import type { ReactElement } from 'react' -import { Box, Button, Divider, Paper, Stack, SvgIcon, Typography, useMediaQuery, useTheme } from '@mui/material' -import Link from 'next/link' -import InfoIcon from '@/public/images/notifications/info.svg' -import css from './styles.module.css' +import { useMediaQuery, useTheme } from '@mui/material' import { shortenAddress } from '@/utils/formatters' import { useRouter } from 'next/router' +import Disclaimer from '@/components/common/Disclaimer' import { AppRoutes } from '@/config/routes' -export const BlockedAddress = ({ address }: { address: string }): ReactElement => { +export const BlockedAddress = ({ address }: { address?: string }): ReactElement => { const theme = useTheme() const isMobile = useMediaQuery(theme.breakpoints.down('sm')) - const displayAddress = isMobile ? shortenAddress(address) : address + const displayAddress = address && isMobile ? shortenAddress(address) : address const router = useRouter() - return ( -
- - ({ borderBottom: `1px solid ${palette.border.light}` })} - > - {displayAddress} + const handleAccept = () => { + router.push({ pathname: AppRoutes.home, query: router.query }) + } - - - - - Blocked Address - - - This signer address is blocked by the Safe interface, due to being associated with the blocked activities by - the U.S. Department of Treasury in the Specially Designated Nationals (SDN) list.{' '} - - - - - - - - - -
+ return ( + ) } diff --git a/src/components/common/Disclaimer/index.stories.tsx b/src/components/common/Disclaimer/index.stories.tsx new file mode 100644 index 0000000000..a65b3b9a07 --- /dev/null +++ b/src/components/common/Disclaimer/index.stories.tsx @@ -0,0 +1,40 @@ +import type { Meta, StoryObj } from '@storybook/react' +import Disclaimer from './index' +import LegalDisclaimerContent from '@/components/common/LegalDisclaimerContent' + +const meta = { + component: Disclaimer, + parameters: { + componentSubtitle: 'Renders an information block intended for users whose address is blocked by OFAC', + }, + tags: ['autodocs'], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const BlockedAddress: Story = { + args: { + subtitle: '0xD3a484faEa53313eF85b5916C9302a3E304ae622', + title: 'Blocked Address', + buttonText: 'continue', + content: + 'This signer address is blocked by the Safe interface, due to being associated with the blocked activities by the U.S. Department of Treasury in the Specially Designated Nationals (SDN) list.', + onAccept: () => {}, + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/VyA38zUPbJ2zflzCIYR6Nu/Swap?node-id=6167%3A14371&mode=dev', + }, + }, +} + +export const LegalDisclaimer: Story = { + args: { + title: 'Legal Disclaimer', + content: , + buttonText: 'continue', + onAccept: () => {}, + }, +} diff --git a/src/components/common/Disclaimer/index.tsx b/src/components/common/Disclaimer/index.tsx new file mode 100644 index 0000000000..de5ff7b106 --- /dev/null +++ b/src/components/common/Disclaimer/index.tsx @@ -0,0 +1,50 @@ +import type { ReactElement, ReactNode } from 'react' +import { Box, Button, Divider, Paper, Stack, SvgIcon, Typography } from '@mui/material' +import InfoIcon from '@/public/images/notifications/info.svg' +import css from './styles.module.css' + +export const Disclaimer = ({ + title, + subtitle, + buttonText, + content, + onAccept, +}: { + title: string + subtitle?: string + buttonText?: string + content: ReactNode + onAccept: () => void +}): ReactElement => { + return ( +
+ + ({ borderBottom: `1px solid ${palette.border.light}` })} + > + {subtitle && {subtitle}} + + + + + + {title} + + {content} + + + + + + +
+ ) +} + +export default Disclaimer diff --git a/src/components/common/Disclaimer/styles.module.css b/src/components/common/Disclaimer/styles.module.css new file mode 100644 index 0000000000..f69a019100 --- /dev/null +++ b/src/components/common/Disclaimer/styles.module.css @@ -0,0 +1,14 @@ +.container { + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.iconCircle { + color: var(--color-info-main); + border-radius: 50%; + display: flex; + padding: var(--space-1); + background: #d7f6ff; +} diff --git a/src/components/safe-apps/SafeAppsInfoModal/LegalDisclaimer.tsx b/src/components/common/LegalDisclaimerContent/index.tsx similarity index 64% rename from src/components/safe-apps/SafeAppsInfoModal/LegalDisclaimer.tsx rename to src/components/common/LegalDisclaimerContent/index.tsx index a3fe4a7bba..8bc6270c89 100644 --- a/src/components/safe-apps/SafeAppsInfoModal/LegalDisclaimer.tsx +++ b/src/components/common/LegalDisclaimerContent/index.tsx @@ -4,18 +4,17 @@ import { Typography } from '@mui/material' import css from './styles.module.css' -const LegalDisclaimer = (): JSX.Element => ( +const LegalDisclaimerContent = ({ withTitle = true }: { withTitle?: boolean }): JSX.Element => (
- - Before starting to use Safe dApps... - - - Disclaimer - + {withTitle && ( + + Disclaimer + + )}
- You are now accessing third-party apps, which we do not own, control, maintain or audit. We are not liable for - any loss you may suffer in connection with interacting with the apps, which is at your own risk. + You are now accessing a third-party app, which we do not own, control, maintain or audit. We are not liable for + any loss you may suffer in connection with interacting with the app, which is at your own risk. @@ -33,4 +32,4 @@ const LegalDisclaimer = (): JSX.Element => (
) -export default LegalDisclaimer +export default LegalDisclaimerContent diff --git a/src/components/common/LegalDisclaimerContent/styles.module.css b/src/components/common/LegalDisclaimerContent/styles.module.css new file mode 100644 index 0000000000..202bc83846 --- /dev/null +++ b/src/components/common/LegalDisclaimerContent/styles.module.css @@ -0,0 +1,9 @@ + +.disclaimerContainer p, +.disclaimerContainer h3 { + line-height: 24px; +} + +.disclaimerInner p { + text-align: justify; +} \ No newline at end of file diff --git a/src/components/safe-apps/SafeAppsInfoModal/index.tsx b/src/components/safe-apps/SafeAppsInfoModal/index.tsx index 924c2597fc..33b448aedd 100644 --- a/src/components/safe-apps/SafeAppsInfoModal/index.tsx +++ b/src/components/safe-apps/SafeAppsInfoModal/index.tsx @@ -4,12 +4,12 @@ import { Grid, LinearProgress } from '@mui/material' import type { BrowserPermission } from '@/hooks/safe-apps/permissions' import Slider from './Slider' -import LegalDisclaimer from './LegalDisclaimer' import AllowedFeaturesList from './AllowedFeaturesList' import type { AllowedFeatures, AllowedFeatureSelection } from '../types' import { PermissionStatus } from '../types' import UnknownAppWarning from './UnknownAppWarning' import { getOrigin } from '../utils' +import LegalDisclaimerContent from '@/components/common/LegalDisclaimerContent' type SafeAppsInfoModalProps = { onCancel: () => void @@ -135,7 +135,7 @@ const SafeAppsInfoModal = ({ /> - {!isConsentAccepted && } + {!isConsentAccepted && } {!isPermissionsReviewCompleted && ( void +} => { + const [isConsentAccepted = false, setIsConsentAccepted] = useLocalStorage(SWAPS_CONSENT_STORAGE_KEY) + + const onAccept = useCallback(() => { + setIsConsentAccepted(true) + }, [setIsConsentAccepted]) + + return { + isConsentAccepted, + onAccept, + } +} + +export default useSafeAppsInfoModal diff --git a/src/pages/swap.tsx b/src/pages/swap.tsx index 1ac9dd4dcd..aa91b430b0 100644 --- a/src/pages/swap.tsx +++ b/src/pages/swap.tsx @@ -2,10 +2,14 @@ import type { NextPage } from 'next' import Head from 'next/head' import { useRouter } from 'next/router' import SwapWidget from '@/features/swap' +import useSwapLegalDisclaimer from '@/features/swap/useSwapLegalDisclaimer' +import LegalDisclaimerContent from '@/components/common/LegalDisclaimerContent' +import Disclaimer from '@/components/common/Disclaimer' const Swap: NextPage = () => { const router = useRouter() const { token, amount } = router.query + const { isConsentAccepted, onAccept } = useSwapLegalDisclaimer() let sell = undefined if (token && amount) { @@ -21,7 +25,15 @@ const Swap: NextPage = () => {
- + {isConsentAccepted ? ( + + ) : ( + } + onAccept={onAccept} + /> + )}
) diff --git a/src/services/ofac/blockedAddressList.json b/src/services/ofac/blockedAddressList.json index e8df17f077..f798c085f8 100644 --- a/src/services/ofac/blockedAddressList.json +++ b/src/services/ofac/blockedAddressList.json @@ -149,5 +149,6 @@ "0x530a64c0ce595026a4a556b703644228179e2d57", "0xfac583c0cf07ea434052c49115a4682172ab6b4f", "0x961c5be54a2ffc17cf4cb021d863c42dacd47fc1", - "0x983a81ca6fb1e441266d2fbcb7d8e530ac2e05a2" + "0x983a81ca6fb1e441266d2fbcb7d8e530ac2e05a2", + "0xC62CBc9d49ba64EC27a1c27fAA9c7f2ce5D583C8" ] diff --git a/src/utils/chains.ts b/src/utils/chains.ts index b4eeca7477..7445fd2220 100644 --- a/src/utils/chains.ts +++ b/src/utils/chains.ts @@ -32,6 +32,7 @@ export const FeatureRoutes = { } export const hasFeature = (chain: ChainInfo, feature: FEATURES): boolean => { + if (feature === FEATURES.NATIVE_SWAPS) return true return (chain.features as string[]).includes(feature) }