From c0f5fab922db51a60cca1623b2547ecfe2dd1749 Mon Sep 17 00:00:00 2001 From: katspaugh <381895+katspaugh@users.noreply.github.com> Date: Thu, 22 Jun 2023 17:54:54 +0200 Subject: [PATCH 1/7] Fix: address book entry dialog (#2156) --- .../address-book/EntryDialog/index.tsx | 17 ++++++------ .../common/AddressBookInput/index.tsx | 27 ++++++++++++++++--- .../common/AddressBookInput/styles.module.css | 6 +++++ src/components/common/AddressInput/index.tsx | 13 +++++---- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/components/address-book/EntryDialog/index.tsx b/src/components/address-book/EntryDialog/index.tsx index af9571d0e9..fe63ae7b08 100644 --- a/src/components/address-book/EntryDialog/index.tsx +++ b/src/components/address-book/EntryDialog/index.tsx @@ -1,8 +1,5 @@ -import Box from '@mui/material/Box' -import Button from '@mui/material/Button' -import DialogActions from '@mui/material/DialogActions' -import DialogContent from '@mui/material/DialogContent' -import type { ReactElement } from 'react' +import type { ReactElement, BaseSyntheticEvent } from 'react' +import { Box, Button, DialogActions, DialogContent } from '@mui/material' import { FormProvider, useForm } from 'react-hook-form' import AddressInput from '@/components/common/AddressInput' @@ -41,16 +38,20 @@ const EntryDialog = ({ const { handleSubmit, formState } = methods - const onSubmit = (data: AddressEntry) => { + const submitCallback = handleSubmit((data: AddressEntry) => { dispatch(upsertAddressBookEntry({ ...data, chainId: chainId || currentChainId })) - handleClose() + }) + + const onSubmit = (e: BaseSyntheticEvent) => { + e.stopPropagation() + submitCallback(e) } return ( -
+ diff --git a/src/components/common/AddressBookInput/index.tsx b/src/components/common/AddressBookInput/index.tsx index 8a04fad4f4..6d7a78e393 100644 --- a/src/components/common/AddressBookInput/index.tsx +++ b/src/components/common/AddressBookInput/index.tsx @@ -6,6 +6,7 @@ import useAddressBook from '@/hooks/useAddressBook' import AddressInput, { type AddressInputProps } from '../AddressInput' import EthHashInfo from '../EthHashInfo' import InfoIcon from '@/public/images/notifications/info.svg' +import EntryDialog from '@/components/address-book/EntryDialog' import css from './styles.module.css' const abFilterOptions = createFilterOptions({ @@ -15,11 +16,12 @@ const abFilterOptions = createFilterOptions({ /** * Temporary component until revamped safe components are done */ -const AddressBookInput = ({ name, canAdd, ...props }: AddressInputProps): ReactElement => { +const AddressBookInput = ({ name, canAdd, ...props }: AddressInputProps & { canAdd?: boolean }): ReactElement => { const addressBook = useAddressBook() const { setValue, control } = useFormContext() const addressValue = useWatch({ name, control }) const [open, setOpen] = useState(false) + const [openAddressBook, setOpenAddressBook] = useState(false) const addressBookEntries = Object.entries(addressBook).map(([address, name]) => ({ label: address, @@ -35,6 +37,12 @@ const AddressBookInput = ({ name, canAdd, ...props }: AddressInputProps): ReactE setOpen((value) => !value) } + const onAddressBookClick = canAdd + ? () => { + setOpenAddressBook(true) + } + : undefined + return ( <> )} /> {canAdd ? ( - This is an unknown address. Consider adding it to your address book. + + This is an unknown address. You can{' '} + + add it to your address book + + . + ) : null} + + {openAddressBook && ( + setOpenAddressBook(false)} + defaultValues={{ name: '', address: addressValue }} + /> + )} ) } diff --git a/src/components/common/AddressBookInput/styles.module.css b/src/components/common/AddressBookInput/styles.module.css index f9e328c609..c1366746d2 100644 --- a/src/components/common/AddressBookInput/styles.module.css +++ b/src/components/common/AddressBookInput/styles.module.css @@ -12,3 +12,9 @@ .unknownAddress svg { height: auto; } + +.unknownAddress a { + color: inherit; + text-decoration: underline; + cursor: pointer; +} diff --git a/src/components/common/AddressInput/index.tsx b/src/components/common/AddressInput/index.tsx index c0ae50d9f5..fae4fc7997 100644 --- a/src/components/common/AddressInput/index.tsx +++ b/src/components/common/AddressInput/index.tsx @@ -19,18 +19,17 @@ import { cleanInputValue, parsePrefixedAddress } from '@/utils/addresses' import useDebounce from '@/hooks/useDebounce' import CaretDownIcon from '@/public/images/common/caret-down.svg' import SaveAddressIcon from '@/public/images/common/save-address.svg' -import EntryDialog from '@/components/address-book/EntryDialog' import classnames from 'classnames' import css from './styles.module.css' export type AddressInputProps = TextFieldProps & { name: string address?: string - canAdd?: boolean onOpenListClick?: () => void isAutocompleteOpen?: boolean validate?: Validate deps?: string | string[] + onAddressBookClick?: () => void } const AddressInput = ({ @@ -39,7 +38,7 @@ const AddressInput = ({ required = true, onOpenListClick, isAutocompleteOpen, - canAdd, + onAddressBookClick, deps, ...props }: AddressInputProps): ReactElement => { @@ -55,7 +54,6 @@ const AddressInput = ({ const watchedValue = useWatch({ name, control }) const currentShortName = currentChain?.shortName || '' const [isValidating, setIsValidating] = useState(false) - const [open, setOpen] = useState(false) // Fetch an ENS resolution for the current address const isDomainLookupEnabled = !!currentChain && hasFeature(currentChain, FEATURES.DOMAIN_LOOKUP) @@ -91,12 +89,14 @@ const AddressInput = ({ ) : !props.disabled ? ( <> - {canAdd && ( - setOpen(true)}> + {onAddressBookClick && ( + )} + + {onOpenListClick && ( - {open && setOpen(false)} defaultValues={{ name: '', address: watchedValue }} />} ) } From a80992c287e90c864bcc5867b5c395ae81ab8a62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Jun 2023 07:17:57 +0200 Subject: [PATCH 2/7] chore(deps): bump semver from 7.3.8 to 7.5.2 (#2158) Bumps [semver](https://github.com/npm/node-semver) from 7.3.8 to 7.5.2. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v7.3.8...v7.5.2) --- updated-dependencies: - dependency-name: semver dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index caa21a82b1..def28b9540 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "react-papaparse": "^4.0.2", "react-qr-reader": "2.2.1", "react-redux": "^8.0.5", - "semver": "^7.3.7" + "semver": "^7.5.2" }, "devDependencies": { "@next/bundle-analyzer": "^13.1.1", diff --git a/yarn.lock b/yarn.lock index e06b21a6bd..93dd1f8dee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12495,10 +12495,10 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== +semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2: + version "7.5.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb" + integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ== dependencies: lru-cache "^6.0.0" From 714fc358702c275aad92a1f400212e552b550e03 Mon Sep 17 00:00:00 2001 From: Usame Algan <5880855+usame-algan@users.noreply.github.com> Date: Fri, 23 Jun 2023 09:36:43 +0200 Subject: [PATCH 3/7] [TX flow] Mobile optimisation (#2154) * Add folder structure for tx flow * feat: create new-tx route and NewTxMenu component * feat: Add StepperFactory and new tx layout (#2040) * feat: Add StepperFactory, new tx pages * wip: context instead of routes * Add tx flows to new modal context * fix: Close modal when user navigates * Export all flows from one file * refactor: Remove unused code from StepperFactory * fix: Duplicate ModalDialog to fix failing tests * Refactor: reactive recommended nonce (#2050) * Refactor: reactive recommended nonce Reduce re-renders Nonce -1 * Use "nonceReadyOnly" instead of -1 * Split sign and execute into two components * feat: Transaction status widget (#2062) * feat: add tx status widget UI * add logic to paint the stepper * port the ConfirmProposedTx to the new layout * pass tx data to the TxStatusWidget to get the tx confirmations * style: add new lines between adjacent tags * Refactor: SafeTxProvider (#2064) * Refactor: SafeTxProvider * Avoid oscillating nonce * fix reject tx for new provider --------- Co-authored-by: Usame Algan * Move progress to TxLayout * Refactor: useRecommendedNonce + useSafeTxGas (#2066) * Refactor: useRecommendedNonce + useSafeTxGas * Fix lint * Get recommended nonce by "estimating" an empty tx * Adjust ConfirmTx and ExecuteTxButton * Refactor: a less verbose ModalProvider (#2068) * Refactor: a less verbose ModalProvider * Fix Cannot redefine property: dispatchTxProposal * Refactor the tx flow system (#2071) * Refactor the tx flow system * Array * Fix: pass nonce correctly (#2072) * Fix linting errors, add TODOs for failing tx flows (#2070) * Editable nonce (#2077) * Editable nonce * Fix tests * refactor: save entire data structure on submission (#2083) * fix: Close modal on sign, only render current step * fix: Close modal on sign, only render current step * fix: set all data + move back button --------- Co-authored-by: Usame Algan * feat: Add SuccessScreen to tx flow (#2080) * Refactor: single type for tx flows (#2084) * Refactor: single type for tx flows * Omit txNonce * FormData type * feat: add owner flow (#2086) * feat: Change threshold flow (#2085) * feat: Port change threshold flow * fix: Only estimate gas when executing * fix: Remove old component * feat: remove owner flow * feat: replace owner flow (#2087) * feat: add owner flow * feat: replace owner flow * feat: replace owner flow * feat: update flow (#2089) * fix: Remove Module tx flow (#2090) * Add flow for remove guard (#2091) * Safe Apps tx flow (#2081) * SafeAppsTx flow * On close * Handle txFlow close * feat: new spending limit flow (#2093) * feat: new spending limit flow * fix: preserve token address + reset time values * Onclose callback (#2094) * Send button in Assets (#2097) * Send button in Assets * Supress contentEditable warning * Fix: align Next and Back buttons (#2103) * feat: remove spending limit flow (#2098) * Refactor: move AdvancedParams to ExecuteForm (#2104) * fix: Move sign msg modal to new flow (#2102) * fix: Move sign msg modal to new flow * Adjust flex property if subtitle exists * fix: Add flag to hide nonce field in TxLayout * TxCard layout (#2105) * Modal title and icon (#2107) * Modal title and icon * NFTs * feat: spending limit selector (#2106) * feat: batch execute flow (#2108) * Move on-chain sign to new flow (#2109) * feat: amount selector (#2111) * feat: amount selector * fix: use CSS variables * fix: cleanup styles * feat: execute/sign `RadioGroup` (#2117) * [Tx flow] feat: address input redesign (#2112) * feat: AddressInputReadOnly component * improve AddressInput * make component readonly * enable create AB entry from input component * show SaveAddressicon if address not in AB * open the list when clicking the caret * fix component height * show caret when there are available options * rm leftover code * do not highlight the readonly input on hover/click * focus the AddressInput on clicking to edit * change add to AB info text * do not truncate the address in the readonly component * show SaveAddressIcon when address is valid * amount input grows until token name * [TX flow] feat: confirm/execute title component (#2119) * feat: confirm/execute titles * place the component as per design * remove redundant code * use willExecute flag to display execution title * adjust the gap between SignOrExecuteForm elements * fix: remove error casting (#2127) * fix: remove error casting * refactor: don't call `asError` twice * fix: execution method style (#2125) * fix: execution method style * fix: change component * fix: change component * fix: update amount field style (#2124) * [TX flow] Send tokens overview (#2136) * fix: Adjust TxLayout header design * fix: Implement Token Transfer overview design * Remove loading state * [TX flow] style: offchain messages info boxes styles (#2134) * style: adjust success and info box styles * adjust msgSigners style * style margins in the info elements * clean up redundant variable * test: update tx builder URL * Feat: editable safeTxGas in Advanced details (#2132) * Feat: editable safeTxGas in Advanced details * Prettier * Make the form a popover * PR comments * fix: Nonce form (#2120) * fix: Update nonce input to show queued txs and reset button * fix: Extract hook, show input error outline, hide reset button if readonly * Add isEmpty flag to nonce input * Fix test * [TX flow] style: send token flow (#2126) * placeholder for AddressInput identicon * rm Send From * add the dividers to the layout * style CardActions * fix tests * [TX flow] styles: fix send token styles (#2138) * style: remove unnecessary CSS * style: consider the input label font-size in spacing * Small UI tweaks * fix: move default value to placeholder (#2139) * Fix DecodedTx tests * [TX flow] feat: add owner modal (#2143) * feat: create add owner * adjust ReviewOwner design * component to wrap owner address and include subtitle in modal * prefer RHF for form fields. use sx instead of classes * use MUI component * fix: remove owner flow styling (#2150) * fix: remove owner flow styling * fix: add titles * fix: Optimize new tx flow for mobile screens * refactor: Adjust all max media queries --------- Co-authored-by: Diogo Soares Co-authored-by: katspaugh <381895+katspaugh@users.noreply.github.com> Co-authored-by: katspaugh Co-authored-by: Diogo Soares <32431609+DiogoSoaress@users.noreply.github.com> Co-authored-by: Aaron Cook --- .../AddressBookTable/styles.module.css | 2 +- .../balances/AssetsTable/styles.module.css | 2 +- .../HiddenTokenButton/styles.module.css | 2 +- .../common/ConnectWallet/styles.module.css | 2 +- .../common/CookieBanner/styles.module.css | 2 +- .../common/EnhancedTable/styles.module.css | 2 +- .../common/EthHashInfo/styles.module.css | 2 +- .../common/Footer/styles.module.css | 2 +- .../common/Header/styles.module.css | 4 +- .../common/NewModalDialog/index.tsx | 103 ------------------ .../common/NewModalDialog/styles.module.css | 25 ----- .../common/PageHeader/styles.module.css | 2 +- .../common/PageLayout/styles.module.css | 4 +- .../common/ProgressBar/styles.module.css | 2 +- src/components/common/TxModalDialog/index.tsx | 50 +++++++++ .../common/TxModalDialog/styles.module.css | 70 ++++++++++++ .../common/WalletInfo/styles.module.css | 2 +- .../dashboard/PendingTxs/styles.module.css | 2 +- .../new-safe/CardStepper/styles.module.css | 2 +- .../new-safe/OwnerRow/styles.module.css | 2 +- .../new-safe/create/styles.module.css | 2 +- .../SafeAppsHeader/styles.module.css | 2 +- .../sidebar/SafeList/styles.module.css | 2 +- .../sidebar/Sidebar/styles.module.css | 2 +- .../GroupedTxListItems/styles.module.css | 2 +- .../Summary/TxDataRow/styles.module.css | 2 +- .../transactions/TxDetails/styles.module.css | 2 +- .../TxFilterForm/styles.module.css | 2 +- .../transactions/TxSummary/styles.module.css | 2 +- .../tx-flow/common/TxLayout/index.tsx | 55 ++++++++-- .../tx-flow/common/TxLayout/styles.module.css | 53 +++++++++ .../tx-flow/common/TxStatusWidget/index.tsx | 20 +++- .../common/TxStatusWidget/styles.module.css | 35 ++++++ src/components/tx-flow/flows/NewTx/index.tsx | 3 +- .../tx-flow/flows/NewTx/styles.module.css | 15 +++ .../tx-flow/flows/ReplaceTx/styles.module.css | 2 +- .../flows/SuccessScreen/styles.module.css | 2 +- src/components/tx-flow/index.tsx | 6 +- src/components/welcome/styles.module.css | 4 +- src/styles/globals.css | 2 +- 40 files changed, 322 insertions(+), 177 deletions(-) delete mode 100644 src/components/common/NewModalDialog/index.tsx delete mode 100644 src/components/common/NewModalDialog/styles.module.css create mode 100644 src/components/common/TxModalDialog/index.tsx create mode 100644 src/components/common/TxModalDialog/styles.module.css create mode 100644 src/components/tx-flow/flows/NewTx/styles.module.css diff --git a/src/components/address-book/AddressBookTable/styles.module.css b/src/components/address-book/AddressBookTable/styles.module.css index f1b90b0d0d..fb6af6268a 100644 --- a/src/components/address-book/AddressBookTable/styles.module.css +++ b/src/components/address-book/AddressBookTable/styles.module.css @@ -23,7 +23,7 @@ margin-bottom: 8px; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .container td:last-of-type button { opacity: 1; } diff --git a/src/components/balances/AssetsTable/styles.module.css b/src/components/balances/AssetsTable/styles.module.css index b9b5882cd5..55c14fbbe9 100644 --- a/src/components/balances/AssetsTable/styles.module.css +++ b/src/components/balances/AssetsTable/styles.module.css @@ -14,7 +14,7 @@ gap: var(--space-1); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .container td:last-of-type, .container th:last-of-type { display: none; diff --git a/src/components/balances/HiddenTokenButton/styles.module.css b/src/components/balances/HiddenTokenButton/styles.module.css index fddd67f640..ce335e2648 100644 --- a/src/components/balances/HiddenTokenButton/styles.module.css +++ b/src/components/balances/HiddenTokenButton/styles.module.css @@ -1,4 +1,4 @@ -@media (max-width: 600px) { +@media (max-width: 599.95px) { .hiddenTokenButton { display: none; } diff --git a/src/components/common/ConnectWallet/styles.module.css b/src/components/common/ConnectWallet/styles.module.css index 592eb7841f..d988b29eec 100644 --- a/src/components/common/ConnectWallet/styles.module.css +++ b/src/components/common/ConnectWallet/styles.module.css @@ -54,7 +54,7 @@ gap: var(--space-2); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .buttonContainer button { font-size: 12px; } diff --git a/src/components/common/CookieBanner/styles.module.css b/src/components/common/CookieBanner/styles.module.css index 50e113c97f..a49f9f4436 100644 --- a/src/components/common/CookieBanner/styles.module.css +++ b/src/components/common/CookieBanner/styles.module.css @@ -16,7 +16,7 @@ user-select: none; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .container { right: 0; bottom: 0; diff --git a/src/components/common/EnhancedTable/styles.module.css b/src/components/common/EnhancedTable/styles.module.css index f1f7861458..a2bd170f72 100644 --- a/src/components/common/EnhancedTable/styles.module.css +++ b/src/components/common/EnhancedTable/styles.module.css @@ -18,7 +18,7 @@ gap: var(--space-1); } -@media (max-width: 900px) { +@media (max-width: 899.95px) { .mobileColumn thead th { display: none; } diff --git a/src/components/common/EthHashInfo/styles.module.css b/src/components/common/EthHashInfo/styles.module.css index 021866118c..a64151a6eb 100644 --- a/src/components/common/EthHashInfo/styles.module.css +++ b/src/components/common/EthHashInfo/styles.module.css @@ -30,7 +30,7 @@ display: none; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .mobileAddress { display: inline-block; } diff --git a/src/components/common/Footer/styles.module.css b/src/components/common/Footer/styles.module.css index 2631f4f2b3..54fbe3a3ee 100644 --- a/src/components/common/Footer/styles.module.css +++ b/src/components/common/Footer/styles.module.css @@ -30,7 +30,7 @@ pointer-events: none; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .container li:not(:last-of-type):after { visibility: hidden; } diff --git a/src/components/common/Header/styles.module.css b/src/components/common/Header/styles.module.css index 20c62faed2..7a439a57df 100644 --- a/src/components/common/Header/styles.module.css +++ b/src/components/common/Header/styles.module.css @@ -51,7 +51,7 @@ flex-shrink: 0; } -@media (max-width: 900px) { +@media (max-width: 899.95px) { .logo { display: none; } @@ -61,7 +61,7 @@ } } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .element { padding: 0 var(--space-1); } diff --git a/src/components/common/NewModalDialog/index.tsx b/src/components/common/NewModalDialog/index.tsx deleted file mode 100644 index e559b293d2..0000000000 --- a/src/components/common/NewModalDialog/index.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { type ReactElement, type ReactNode } from 'react' -import { IconButton, type ModalProps } from '@mui/material' -import { Dialog, DialogTitle, type DialogProps, useMediaQuery } from '@mui/material' -import { useTheme } from '@mui/material/styles' -import ChainIndicator from '@/components/common/ChainIndicator' -import CloseIcon from '@mui/icons-material/Close' -import css from './styles.module.css' - -interface ModalDialogProps extends DialogProps { - dialogTitle?: React.ReactNode - hideChainIndicator?: boolean -} - -interface DialogTitleProps { - children: ReactNode - onClose?: ModalProps['onClose'] - hideChainIndicator?: boolean -} - -export const ModalDialogTitle = ({ children, onClose, hideChainIndicator = false, ...other }: DialogTitleProps) => { - return ( - - {children} - - {!hideChainIndicator && } - {onClose ? ( - { - onClose(e, 'backdropClick') - }} - size="small" - sx={{ - ml: 2, - color: 'border.main', - }} - > - - - ) : null} - - ) -} - -const NewModalDialog = ({ - dialogTitle, - hideChainIndicator, - children, - onClose, - fullScreen = false, - ...restProps -}: ModalDialogProps): ReactElement => { - const theme = useTheme() - const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')) - - return ( - e.stopPropagation()} - sx={{ - top: 52, - left: isSmallScreen ? 0 : 230, - zIndex: 1200, - }} - slots={{ backdrop: 'div' }} - PaperProps={{ - sx: { - pb: 8, - backgroundColor: (theme) => theme.palette.border.background, - }, - }} - > - theme.palette.background.paper, - }} - > - - onClose?.(e, 'backdropClick')} - size="small" - sx={{ - ml: 2, - color: 'border.main', - }} - > - - - - - {children} - - ) -} - -export default NewModalDialog diff --git a/src/components/common/NewModalDialog/styles.module.css b/src/components/common/NewModalDialog/styles.module.css deleted file mode 100644 index 526648940f..0000000000 --- a/src/components/common/NewModalDialog/styles.module.css +++ /dev/null @@ -1,25 +0,0 @@ -.dialog :global .MuiDialogActions-root { - border-top: 2px solid var(--color-border-light); - padding: var(--space-3); -} - -.dialog :global .MuiDialogActions-root > :last-of-type:not(:first-of-type) { - order: 2; -} - -.dialog :global .MuiDialogActions-root:after { - content: ''; - order: 1; - flex: 1; -} - -.dialog :global .MuiDialogTitle-root { - border-bottom: 2px solid var(--color-border-light); -} - -@media (min-width: 600px) { - .dialog :global .MuiDialog-paper { - min-width: 600px; - margin: 0; - } -} diff --git a/src/components/common/PageHeader/styles.module.css b/src/components/common/PageHeader/styles.module.css index 73bc9914c6..e4f79953a2 100644 --- a/src/components/common/PageHeader/styles.module.css +++ b/src/components/common/PageHeader/styles.module.css @@ -30,7 +30,7 @@ gap: var(--space-1); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .container { padding: var(--space-3) var(--space-2) 0; } diff --git a/src/components/common/PageLayout/styles.module.css b/src/components/common/PageLayout/styles.module.css index 2f8f578ea0..e7b2ea8ad7 100644 --- a/src/components/common/PageLayout/styles.module.css +++ b/src/components/common/PageLayout/styles.module.css @@ -72,7 +72,7 @@ background-color: var(--color-background-light); } -@media (max-width: 900px) { +@media (max-width: 899.95px) { .main { padding-left: 0; } @@ -82,7 +82,7 @@ } } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .main main { padding: var(--space-2); } diff --git a/src/components/common/ProgressBar/styles.module.css b/src/components/common/ProgressBar/styles.module.css index f3463cbc42..bdc2c6a2eb 100644 --- a/src/components/common/ProgressBar/styles.module.css +++ b/src/components/common/ProgressBar/styles.module.css @@ -9,7 +9,7 @@ border-radius: 6px; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .progressBar { border-radius: 0; } diff --git a/src/components/common/TxModalDialog/index.tsx b/src/components/common/TxModalDialog/index.tsx new file mode 100644 index 0000000000..5191961e6d --- /dev/null +++ b/src/components/common/TxModalDialog/index.tsx @@ -0,0 +1,50 @@ +import { type ReactElement } from 'react' +import { IconButton } from '@mui/material' +import { Dialog, DialogTitle, type DialogProps } from '@mui/material' +import CloseIcon from '@mui/icons-material/Close' +import css from './styles.module.css' + +interface ModalDialogProps extends DialogProps { + dialogTitle?: React.ReactNode + hideChainIndicator?: boolean +} + +const TxModalDialog = ({ + dialogTitle, + hideChainIndicator, + children, + onClose, + fullScreen = false, + ...restProps +}: ModalDialogProps): ReactElement => { + return ( + e.stopPropagation()} + slots={{ backdrop: 'div' }} + PaperProps={{ + className: css.paper, + }} + > + +
+ onClose?.(e, 'backdropClick')} + size="small" + > + + +
+
+ + {children} +
+ ) +} + +export default TxModalDialog diff --git a/src/components/common/TxModalDialog/styles.module.css b/src/components/common/TxModalDialog/styles.module.css new file mode 100644 index 0000000000..210b644a0e --- /dev/null +++ b/src/components/common/TxModalDialog/styles.module.css @@ -0,0 +1,70 @@ +.dialog { + top: 52px; + left: 230px; + z-index: 1300; +} + +.dialog :global .MuiDialogActions-root { + border-top: 2px solid var(--color-border-light); + padding: var(--space-3); +} + +.dialog :global .MuiDialogActions-root > :last-of-type:not(:first-of-type) { + order: 2; +} + +.dialog :global .MuiDialogActions-root:after { + content: ''; + order: 1; + flex: 1; +} + +.dialog :global .MuiDialogTitle-root { + border-bottom: 2px solid var(--color-border-light); +} + +.title { + display: flex; + align-items: center; + background-color: var(--color-background-paper); + padding: 0; + margin-bottom: var(--space-8); +} + +.buttons { + margin-left: auto; +} + +.close { + color: var(--color-border-main); + padding: var(--space-2); + border-left: 1px solid var(--color-border-light); + border-radius: 0; +} + +.paper { + padding-bottom: var(--space-8); + background-color: var(--color-border-background); +} + +@media (min-width: 600px) { + .dialog :global .MuiDialog-paper { + min-width: 600px; + margin: 0; + } +} + +@media (max-width: 899.95px) { + .dialog { + left: 0; + top: 0; + } + + .dialog :global .MuiDialogActions-root { + padding: 0; + } + + .title { + margin-bottom: var(--space-3); + } +} diff --git a/src/components/common/WalletInfo/styles.module.css b/src/components/common/WalletInfo/styles.module.css index 4b22ce8f66..6bc2e53d07 100644 --- a/src/components/common/WalletInfo/styles.module.css +++ b/src/components/common/WalletInfo/styles.module.css @@ -15,7 +15,7 @@ filter: invert(100%); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .buttonContainer button { font-size: 12px; } diff --git a/src/components/dashboard/PendingTxs/styles.module.css b/src/components/dashboard/PendingTxs/styles.module.css index 42326042e4..f5dc2103d5 100644 --- a/src/components/dashboard/PendingTxs/styles.module.css +++ b/src/components/dashboard/PendingTxs/styles.module.css @@ -37,7 +37,7 @@ word-break: break-word; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .confirmationsCount { padding: 4px var(--space-1); } diff --git a/src/components/new-safe/CardStepper/styles.module.css b/src/components/new-safe/CardStepper/styles.module.css index c7cdb6ec38..53cef51b2a 100644 --- a/src/components/new-safe/CardStepper/styles.module.css +++ b/src/components/new-safe/CardStepper/styles.module.css @@ -33,7 +33,7 @@ display: none; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .header { padding: var(--space-2); flex-direction: column; diff --git a/src/components/new-safe/OwnerRow/styles.module.css b/src/components/new-safe/OwnerRow/styles.module.css index 3369f41056..d30004fee4 100644 --- a/src/components/new-safe/OwnerRow/styles.module.css +++ b/src/components/new-safe/OwnerRow/styles.module.css @@ -3,7 +3,7 @@ bottom: -20px; } -@media (max-width: 900px) { +@media (max-width: 899.95px) { .name :global .MuiFormHelperText-root { position: relative; bottom: 0; diff --git a/src/components/new-safe/create/styles.module.css b/src/components/new-safe/create/styles.module.css index 2cae562226..38feb0b251 100644 --- a/src/components/new-safe/create/styles.module.css +++ b/src/components/new-safe/create/styles.module.css @@ -3,7 +3,7 @@ padding: var(--space-4) var(--space-7); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .row { padding: var(--space-2); } diff --git a/src/components/safe-apps/SafeAppsHeader/styles.module.css b/src/components/safe-apps/SafeAppsHeader/styles.module.css index 95f75eb8c3..b400ca92f4 100644 --- a/src/components/safe-apps/SafeAppsHeader/styles.module.css +++ b/src/components/safe-apps/SafeAppsHeader/styles.module.css @@ -27,7 +27,7 @@ border-bottom: 1px solid var(--color-border-light); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .tabs { padding: 0 24px; } diff --git a/src/components/sidebar/SafeList/styles.module.css b/src/components/sidebar/SafeList/styles.module.css index 2074c89fee..275ee9c000 100644 --- a/src/components/sidebar/SafeList/styles.module.css +++ b/src/components/sidebar/SafeList/styles.module.css @@ -37,7 +37,7 @@ padding: 0 0; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .list { overflow-x: auto; } diff --git a/src/components/sidebar/Sidebar/styles.module.css b/src/components/sidebar/Sidebar/styles.module.css index f6d1be7b18..08b9dff4c3 100644 --- a/src/components/sidebar/Sidebar/styles.module.css +++ b/src/components/sidebar/Sidebar/styles.module.css @@ -64,7 +64,7 @@ transform: translateX(-25%); } -@media (max-width: 900px) { +@media (max-width: 899.95px) { .container { padding-top: var(--header-height); } diff --git a/src/components/transactions/GroupedTxListItems/styles.module.css b/src/components/transactions/GroupedTxListItems/styles.module.css index 6fc69fbf51..e9581dfbb2 100644 --- a/src/components/transactions/GroupedTxListItems/styles.module.css +++ b/src/components/transactions/GroupedTxListItems/styles.module.css @@ -31,7 +31,7 @@ text-decoration: line-through; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .disclaimerContainer { gap: var(--space-1); align-items: flex-start; diff --git a/src/components/transactions/TxDetails/Summary/TxDataRow/styles.module.css b/src/components/transactions/TxDetails/Summary/TxDataRow/styles.module.css index b27dff0d8c..91bad958c2 100644 --- a/src/components/transactions/TxDetails/Summary/TxDataRow/styles.module.css +++ b/src/components/transactions/TxDetails/Summary/TxDataRow/styles.module.css @@ -26,7 +26,7 @@ align-items: center; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .gridRow { grid-template-columns: 1fr; gap: 0; diff --git a/src/components/transactions/TxDetails/styles.module.css b/src/components/transactions/TxDetails/styles.module.css index d6d1c295eb..3837760f96 100644 --- a/src/components/transactions/TxDetails/styles.module.css +++ b/src/components/transactions/TxDetails/styles.module.css @@ -57,7 +57,7 @@ border-top: 1px solid var(--color-border-light); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .container { flex-direction: column; } diff --git a/src/components/transactions/TxFilterForm/styles.module.css b/src/components/transactions/TxFilterForm/styles.module.css index 96a6ffe762..d865142627 100644 --- a/src/components/transactions/TxFilterForm/styles.module.css +++ b/src/components/transactions/TxFilterForm/styles.module.css @@ -5,7 +5,7 @@ border-width: 1px; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .filterWrapper { position: relative; z-index: 0; diff --git a/src/components/transactions/TxSummary/styles.module.css b/src/components/transactions/TxSummary/styles.module.css index 124d150606..044a9ea0e5 100644 --- a/src/components/transactions/TxSummary/styles.module.css +++ b/src/components/transactions/TxSummary/styles.module.css @@ -34,7 +34,7 @@ white-space: normal; } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .columnWrap { word-break: break-word; } diff --git a/src/components/tx-flow/common/TxLayout/index.tsx b/src/components/tx-flow/common/TxLayout/index.tsx index d392cb744c..a9e032df28 100644 --- a/src/components/tx-flow/common/TxLayout/index.tsx +++ b/src/components/tx-flow/common/TxLayout/index.tsx @@ -1,11 +1,23 @@ -import type { ComponentType, ReactElement, ReactNode } from 'react' -import { Box, Container, Grid, Typography, Button, Paper, SvgIcon } from '@mui/material' +import { type ComponentType, type ReactElement, type ReactNode, useEffect, useState } from 'react' +import { + Box, + Container, + Grid, + Typography, + Button, + Paper, + SvgIcon, + IconButton, + useMediaQuery, + useTheme, +} from '@mui/material' import type { TransactionSummary } from '@safe-global/safe-gateway-typescript-sdk' import { ProgressBar } from '@/components/common/ProgressBar' import SafeTxProvider from '../../SafeTxProvider' import TxNonce from '../TxNonce' import TxStatusWidget from '../TxStatusWidget' import css from './styles.module.css' +import SafeLogo from '@/public/images/logo-no-text.svg' type TxLayoutProps = { title: ReactNode @@ -28,23 +40,46 @@ const TxLayout = ({ onBack, hideNonce = false, }: TxLayoutProps): ReactElement => { + const [statusVisible, setStatusVisible] = useState(true) + + const theme = useTheme() + const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')) + const steps = Array.isArray(children) ? children : [children] const progress = Math.round(((step + 1) / steps.length) * 100) + useEffect(() => { + setStatusVisible(!isSmallScreen) + }, [isSmallScreen]) + + const toggleStatus = () => { + setStatusVisible((prev) => !prev) + } + return ( - + - + {title} + + + - + - + + + @@ -74,9 +109,11 @@ const TxLayout = ({ - - - + {statusVisible && ( + + setStatusVisible(false)} /> + + )} diff --git a/src/components/tx-flow/common/TxLayout/styles.module.css b/src/components/tx-flow/common/TxLayout/styles.module.css index 8fd7a997d0..664989b9b2 100644 --- a/src/components/tx-flow/common/TxLayout/styles.module.css +++ b/src/components/tx-flow/common/TxLayout/styles.module.css @@ -63,3 +63,56 @@ font-weight: bold; font-size: 14px; } + +.statusButton { + position: absolute; + top: 0; + right: 57px; + color: var(--color-text-primary); + padding: var(--space-2); + border-left: 1px solid var(--color-border-light); + border-radius: 0; + width: 24px; + height: 24px; + box-sizing: content-box; + display: none; +} + +@media (max-width: 899.95px) { + .widget { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1; + } + + .widget :global .MuiPaper-root { + height: 100%; + } + + .title { + font-size: 16px; + position: absolute; + top: 12px; + left: var(--space-3); + } + + .container { + padding: 0; + } + + .progressBar { + display: none; + } + + .step :global(.MuiCard-root), + .header { + border-radius: 0; + } + + .statusButton { + display: inline-flex; + } +} diff --git a/src/components/tx-flow/common/TxStatusWidget/index.tsx b/src/components/tx-flow/common/TxStatusWidget/index.tsx index 69b1565c86..8e8950b69c 100644 --- a/src/components/tx-flow/common/TxStatusWidget/index.tsx +++ b/src/components/tx-flow/common/TxStatusWidget/index.tsx @@ -1,4 +1,4 @@ -import { Divider, List, ListItem, ListItemIcon, ListItemText, Paper, Typography } from '@mui/material' +import { Divider, IconButton, List, ListItem, ListItemIcon, ListItemText, Paper, Typography } from '@mui/material' import CreatedIcon from '@/public/images/messages/created.svg' import SignedIcon from '@/public/images/messages/signed.svg' import { type TransactionSummary } from '@safe-global/safe-gateway-typescript-sdk' @@ -6,6 +6,7 @@ import useSafeInfo from '@/hooks/useSafeInfo' import { isMultisigExecutionInfo } from '@/utils/transaction-guards' import classnames from 'classnames' import css from './styles.module.css' +import CloseIcon from '@mui/icons-material/Close' const confirmedMessage = (threshold: number, confirmations: number) => { return ( @@ -15,7 +16,15 @@ const confirmedMessage = (threshold: number, confirmations: number) => { ) } -const TxStatusWidget = ({ step, txSummary }: { step: number; txSummary?: TransactionSummary }) => { +const TxStatusWidget = ({ + step, + txSummary, + handleClose, +}: { + step: number + txSummary?: TransactionSummary + handleClose: () => void +}) => { const { safe } = useSafeInfo() const { threshold } = safe @@ -27,10 +36,13 @@ const TxStatusWidget = ({ step, txSummary }: { step: number; txSummary?: Transac return (
- Safe logo - + Safe logo + Transaction status + + +
diff --git a/src/components/tx-flow/common/TxStatusWidget/styles.module.css b/src/components/tx-flow/common/TxStatusWidget/styles.module.css index d3eeb1628d..7daa843422 100644 --- a/src/components/tx-flow/common/TxStatusWidget/styles.module.css +++ b/src/components/tx-flow/common/TxStatusWidget/styles.module.css @@ -43,3 +43,38 @@ .incomplete > * { color: var(--color-text-secondary) !important; } + +.close { + color: var(--color-border-main); + padding: var(--space-2); + border-left: 1px solid var(--color-border-light); + border-radius: 0; + margin-left: auto; + display: none; +} + +.logo { + width: 32px; + height: 32px; +} + +@media (max-width: 899.95px) { + .header { + padding: 0; + flex-direction: row; + } + + .logo { + width: 16px; + height: 16px; + margin-left: 16px; + } + + .title { + font-size: 16px; + } + + .close { + display: flex; + } +} diff --git a/src/components/tx-flow/flows/NewTx/index.tsx b/src/components/tx-flow/flows/NewTx/index.tsx index c10b7334f3..ceaba3b1dd 100644 --- a/src/components/tx-flow/flows/NewTx/index.tsx +++ b/src/components/tx-flow/flows/NewTx/index.tsx @@ -6,6 +6,7 @@ import { Box, Typography } from '@mui/material' import { TxModalContext } from '../../' import TokenTransferFlow from '../TokenTransfer' import { AppRoutes } from '@/config/routes' +import css from './styles.module.css' const BUTTONS_HEIGHT = '91px' @@ -23,7 +24,7 @@ const NewTxMenu = () => { }, [setTxFlow]) return ( - + New transaction diff --git a/src/components/tx-flow/flows/NewTx/styles.module.css b/src/components/tx-flow/flows/NewTx/styles.module.css new file mode 100644 index 0000000000..a7bcddbdd2 --- /dev/null +++ b/src/components/tx-flow/flows/NewTx/styles.module.css @@ -0,0 +1,15 @@ +.wrapper { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--space-2); + width: 100%; + margin: auto; + padding: 0 var(--space-2); +} + +@media (min-width: 600px) { + .wrapper { + width: 452px; + } +} diff --git a/src/components/tx-flow/flows/ReplaceTx/styles.module.css b/src/components/tx-flow/flows/ReplaceTx/styles.module.css index 27968e698d..91cc85e213 100644 --- a/src/components/tx-flow/flows/ReplaceTx/styles.module.css +++ b/src/components/tx-flow/flows/ReplaceTx/styles.module.css @@ -48,7 +48,7 @@ padding: var(--space-2) var(--space-3); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .container { padding: var(--space-3) !important; } diff --git a/src/components/tx-flow/flows/SuccessScreen/styles.module.css b/src/components/tx-flow/flows/SuccessScreen/styles.module.css index ef72f03f0e..aa72e2cf90 100644 --- a/src/components/tx-flow/flows/SuccessScreen/styles.module.css +++ b/src/components/tx-flow/flows/SuccessScreen/styles.module.css @@ -3,7 +3,7 @@ padding: var(--space-4) var(--space-7); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .row { padding: var(--space-2); } diff --git a/src/components/tx-flow/index.tsx b/src/components/tx-flow/index.tsx index 03bb39ae77..875286e0b1 100644 --- a/src/components/tx-flow/index.tsx +++ b/src/components/tx-flow/index.tsx @@ -1,5 +1,5 @@ import { createContext, type ReactElement, type ReactNode, useState, useEffect, useCallback } from 'react' -import NewModalDialog from '@/components/common/NewModalDialog' +import TxModalDialog from '@/components/common/TxModalDialog' import { useRouter } from 'next/router' const noop = () => {} @@ -47,9 +47,9 @@ export const TxModalProvider = ({ children }: { children: ReactNode }): ReactEle {children} - + {txFlow} - + ) } diff --git a/src/components/welcome/styles.module.css b/src/components/welcome/styles.module.css index 5a9ca361c5..109c8246e2 100644 --- a/src/components/welcome/styles.module.css +++ b/src/components/welcome/styles.module.css @@ -63,7 +63,7 @@ padding: 0; } -@media (max-width: 900px) { +@media (max-width: 899.95px) { .sidebar :global .MuiPaper-root { height: 100%; } @@ -85,7 +85,7 @@ } } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .content { padding: var(--space-4); } diff --git a/src/styles/globals.css b/src/styles/globals.css index f828e0bf22..1734b5b58e 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -74,7 +74,7 @@ input[type='number'] { stroke: var(--color-logo-background); } -@media (max-width: 600px) { +@media (max-width: 599.95px) { .sticky { position: sticky; right: 0; From 9936a6ae85361067bdf54d7c72d31dcce5e81d3c Mon Sep 17 00:00:00 2001 From: katspaugh <381895+katspaugh@users.noreply.github.com> Date: Fri, 23 Jun 2023 10:46:31 +0200 Subject: [PATCH 4/7] Docs: fix readme formatting (#2159) * Docs: fix readme formatting The env vars table was broken * Move Redefine API URL to env vars * REDEFINE_REQUEST_URL -> REDEFINE_API --- .env.example | 3 ++ README.md | 45 ++++++++++--------- .../tx/security/redefine/useRedefine.test.ts | 6 +++ src/config/constants.ts | 2 +- .../security/modules/RedefineModule/index.ts | 8 +++- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/.env.example b/.env.example index 712dd0c709..b2804bb7d4 100644 --- a/.env.example +++ b/.env.example @@ -31,3 +31,6 @@ NEXT_PUBLIC_CYPRESS_MNEMONIC= # Safe Gelato relay service NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION= NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING= + +# Redefine +NEXT_PUBLIC_REDEFINE_API= \ No newline at end of file diff --git a/README.md b/README.md index dbead0c151..89d7f458bc 100644 --- a/README.md +++ b/README.md @@ -19,28 +19,29 @@ Create a `.env` file with environment variables. You can use the `.env.example` Here's the list of all the required and optional variables: -| Env variable | | Description | -| ------------------------------------------------------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | -| `NEXT_PUBLIC_INFURA_TOKEN` | **required** | [Infura](https://docs.infura.io/infura/networks/ethereum/how-to/secure-a-project/project-id) RPC API token | -| `NEXT_PUBLIC_SAFE_APPS_INFURA_TOKEN` | optional | Infura token for Safe Apps, falls back to `NEXT_PUBLIC_INFURA_TOKEN` | -| `NEXT_PUBLIC_IS_PRODUCTION` | optional | Set to `true` to build a minified production app | -| `NEXT_PUBLIC_GATEWAY_URL_PRODUCTION` | optional | The base URL for the [Safe Client Gateway](https://github.com/safe-global/safe-client-gateway) | -| `NEXT_PUBLIC_GATEWAY_URL_STAGING` | optional | The base CGW URL on staging | -| `NEXT_PUBLIC_SAFE_VERSION` | optional | The latest version of the Safe contract, defaults to 1.3.0 | | -| `NEXT_PUBLIC_WC_BRIDGE` | optional | [WalletConnect v1](https://docs.walletconnect.com/1.0/bridge-server) bridge URL, falls back to the public WC bridge | -| `NEXT_PUBLIC_WC_PROJECT_ID` | optional | [WalletConnect v2](https://docs.walletconnect.com/2.0/cloud/relay) project ID | -| `NEXT_PUBLIC_TENDERLY_ORG_NAME` | optional | [Tenderly](https://tenderly.co) org name for Transaction Simulation | -| `NEXT_PUBLIC_TENDERLY_PROJECT_NAME` | optional | Tenderly project name | -| `NEXT_PUBLIC_TENDERLY_SIMULATE_ENDPOINT_URL` | optional | Tenderly simulation URL | -| `NEXT_PUBLIC_BEAMER_ID` | optional | [Beamer](https://www.getbeamer.com) is a news feed for in-app announcements | -| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID` | optional | [GTM](https://tagmanager.google.com) project id | -| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_DEVELOPMENT_AUTH` | optional | Dev GTM key | -| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_LATEST_AUTH` | optional | Preview GTM key | -| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_LIVE_AUTH` | optional | Production GTM key | -| `NEXT_PUBLIC_SENTRY_DSN` | optional | [Sentry](https://sentry.io) id for tracking runtime errors | -| `NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION` | optional | [Safe Gelato Relay Service](https://github.com/safe-global/safe-gelato-relay-service) URL to allow relaying transactions via Gelato | -| `NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING` | optional | Relay URL on staging | -| `NEXT_PUBLIC_IS_OFFICIAL_HOST` | optional | Whether it's the official distribution of the app, or a fork; has legal implications. Set to true only if you also update the legal pages like Imprint and Terms of use | +| Env variable | | Description +| ------------------------------------------------------ | ------------ | ----------- +| `NEXT_PUBLIC_INFURA_TOKEN` | **required** | [Infura](https://docs.infura.io/infura/networks/ethereum/how-to/secure-a-project/project-id) RPC API token +| `NEXT_PUBLIC_SAFE_APPS_INFURA_TOKEN` | optional | Infura token for Safe Apps, falls back to `NEXT_PUBLIC_INFURA_TOKEN` +| `NEXT_PUBLIC_IS_PRODUCTION` | optional | Set to `true` to build a minified production app +| `NEXT_PUBLIC_GATEWAY_URL_PRODUCTION` | optional | The base URL for the [Safe Client Gateway](https://github.com/safe-global/safe-client-gateway) +| `NEXT_PUBLIC_GATEWAY_URL_STAGING` | optional | The base CGW URL on staging +| `NEXT_PUBLIC_SAFE_VERSION` | optional | The latest version of the Safe contract, defaults to 1.3.0 +| `NEXT_PUBLIC_WC_BRIDGE` | optional | [WalletConnect v1](https://docs.walletconnect.com/1.0/bridge-server) bridge URL, falls back to the public WC bridge +| `NEXT_PUBLIC_WC_PROJECT_ID` | optional | [WalletConnect v2](https://docs.walletconnect.com/2.0/cloud/relay) project ID +| `NEXT_PUBLIC_TENDERLY_ORG_NAME` | optional | [Tenderly](https://tenderly.co) org name for Transaction Simulation +| `NEXT_PUBLIC_TENDERLY_PROJECT_NAME` | optional | Tenderly project name +| `NEXT_PUBLIC_TENDERLY_SIMULATE_ENDPOINT_URL` | optional | Tenderly simulation URL +| `NEXT_PUBLIC_BEAMER_ID` | optional | [Beamer](https://www.getbeamer.com) is a news feed for in-app announcements +| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID` | optional | [GTM](https://tagmanager.google.com) project id +| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_DEVELOPMENT_AUTH` | optional | Dev GTM key +| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_LATEST_AUTH` | optional | Preview GTM key +| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_LIVE_AUTH` | optional | Production GTM key +| `NEXT_PUBLIC_SENTRY_DSN` | optional | [Sentry](https://sentry.io) id for tracking runtime errors +| `NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION` | optional | [Safe Gelato Relay Service](https://github.com/safe-global/safe-gelato-relay-service) URL to allow relaying transactions via Gelato +| `NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING` | optional | Relay URL on staging +| `NEXT_PUBLIC_IS_OFFICIAL_HOST` | optional | Whether it's the official distribution of the app, or a fork; has legal implications. Set to true only if you also update the legal pages like Imprint and Terms of use +| `NEXT_PUBLIC_REDEFINE_API` | optional | Redefine API base URL If you don't provide some of the optional vars, the corresponding features will be disabled in the UI. diff --git a/src/components/tx/security/redefine/useRedefine.test.ts b/src/components/tx/security/redefine/useRedefine.test.ts index 10a16cb91d..a8ae921495 100644 --- a/src/components/tx/security/redefine/useRedefine.test.ts +++ b/src/components/tx/security/redefine/useRedefine.test.ts @@ -17,6 +17,12 @@ const setupFetchStub = (data: any) => (_url: string) => { }) } +// Mock REDEFINE_API +jest.mock('@/config/constants', () => ({ + ...jest.requireActual('@/config/constants'), + REDEFINE_API: 'https://redefine-api.test', +})) + describe('useRedefine', () => { let mockUseWallet: jest.SpyInstance diff --git a/src/config/constants.ts b/src/config/constants.ts index db19d1f9d3..771e8ed57e 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -92,4 +92,4 @@ export const IS_OFFICIAL_HOST = process.env.NEXT_PUBLIC_IS_OFFICIAL_HOST || fals // Risk mitigation (Redefine) export const REDEFINE_SIMULATION_URL = 'https://dashboard.redefine.net/reports/' -export const REDEFINE_REQUEST_URL = 'https://risk-analysis.safe.global/messages' +export const REDEFINE_API = process.env.NEXT_PUBLIC_REDEFINE_API diff --git a/src/services/security/modules/RedefineModule/index.ts b/src/services/security/modules/RedefineModule/index.ts index e3dd54a5bf..1a1373164c 100644 --- a/src/services/security/modules/RedefineModule/index.ts +++ b/src/services/security/modules/RedefineModule/index.ts @@ -1,4 +1,4 @@ -import { REDEFINE_REQUEST_URL } from '@/config/constants' +import { REDEFINE_API } from '@/config/constants' import { type SafeTransaction } from '@safe-global/safe-core-sdk-types' import { generateTypedData } from '@safe-global/safe-core-sdk-utils' import { type SecurityResponse, type SecurityModule, SecuritySeverity } from '../types' @@ -107,6 +107,10 @@ export type RedefineResponse = { export class RedefineModule implements SecurityModule { async scanTransaction(request: RedefineModuleRequest): Promise> { + if (!REDEFINE_API) { + throw new Error('Redefine API URL is not set') + } + const { chainId, safeAddress } = request const txTypedData = generateTypedData({ @@ -124,7 +128,7 @@ export class RedefineModule implements SecurityModule Date: Fri, 23 Jun 2023 11:08:37 +0200 Subject: [PATCH 5/7] Chore: update MUI --- package.json | 2 +- src/components/common/QRCode/index.tsx | 2 +- .../tx-flow/common/TxLayout/index.tsx | 14 +- yarn.lock | 198 ++++++++++++------ 4 files changed, 134 insertions(+), 82 deletions(-) diff --git a/package.json b/package.json index def28b9540..d9f5ddcb37 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@emotion/server": "^11.10.0", "@emotion/styled": "^11.10.0", "@mui/icons-material": "^5.8.4", - "@mui/material": "^5.11.10", + "@mui/material": "^5.13.5", "@mui/x-date-pickers": "^5.0.12", "@reduxjs/toolkit": "^1.9.5", "@safe-global/safe-apps-sdk": "7.11.0", diff --git a/src/components/common/QRCode/index.tsx b/src/components/common/QRCode/index.tsx index db4058252a..533ecdcf02 100644 --- a/src/components/common/QRCode/index.tsx +++ b/src/components/common/QRCode/index.tsx @@ -1,6 +1,6 @@ import QRCodeReact from 'qrcode.react' import { Skeleton } from '@mui/material' -import { useTheme } from '@mui/system' +import { useTheme } from '@mui/material/styles' import type { ReactElement } from 'react' const QR_LOGO_SIZE = 20 diff --git a/src/components/tx-flow/common/TxLayout/index.tsx b/src/components/tx-flow/common/TxLayout/index.tsx index a9e032df28..fcbc234add 100644 --- a/src/components/tx-flow/common/TxLayout/index.tsx +++ b/src/components/tx-flow/common/TxLayout/index.tsx @@ -1,16 +1,6 @@ import { type ComponentType, type ReactElement, type ReactNode, useEffect, useState } from 'react' -import { - Box, - Container, - Grid, - Typography, - Button, - Paper, - SvgIcon, - IconButton, - useMediaQuery, - useTheme, -} from '@mui/material' +import { Box, Container, Grid, Typography, Button, Paper, SvgIcon, IconButton, useMediaQuery } from '@mui/material' +import { useTheme } from '@mui/material/styles' import type { TransactionSummary } from '@safe-global/safe-gateway-typescript-sdk' import { ProgressBar } from '@/components/common/ProgressBar' import SafeTxProvider from '../../SafeTxProvider' diff --git a/yarn.lock b/yarn.lock index 93dd1f8dee..2f6e14c55b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1003,10 +1003,10 @@ dependencies: regenerator-runtime "^0.13.11" -"@babel/runtime@^7.20.13": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" - integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== +"@babel/runtime@^7.21.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" + integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA== dependencies: regenerator-runtime "^0.13.11" @@ -1178,6 +1178,17 @@ "@emotion/weak-memoize" "^0.3.0" stylis "4.1.3" +"@emotion/cache@^11.11.0": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" + integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== + dependencies: + "@emotion/memoize" "^0.8.1" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" + stylis "4.2.0" + "@emotion/hash@^0.9.0": version "0.9.0" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" @@ -1190,11 +1201,23 @@ dependencies: "@emotion/memoize" "^0.8.0" +"@emotion/is-prop-valid@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc" + integrity sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw== + dependencies: + "@emotion/memoize" "^0.8.1" + "@emotion/memoize@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== +"@emotion/memoize@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" + integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== + "@emotion/react@^11.10.0": version "11.10.5" resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.5.tgz#95fff612a5de1efa9c0d535384d3cfa115fe175d" @@ -1235,6 +1258,11 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c" integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA== +"@emotion/sheet@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" + integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== + "@emotion/styled@^11.10.0": version "11.10.5" resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.5.tgz#1fe7bf941b0909802cb826457e362444e7e96a79" @@ -1262,11 +1290,21 @@ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== +"@emotion/utils@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" + integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== + "@emotion/weak-memoize@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== +"@emotion/weak-memoize@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" + integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== + "@eslint/eslintrc@^1.4.1": version "1.4.1" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" @@ -2625,24 +2663,24 @@ "@motionone/dom" "^10.16.2" tslib "^2.3.1" -"@mui/base@5.0.0-alpha.118": - version "5.0.0-alpha.118" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.118.tgz#335e7496ea605c9b7bda4164efb2da3f09f36dfc" - integrity sha512-GAEpqhnuHjRaAZLdxFNuOf2GDTp9sUawM46oHZV4VnYPFjXJDkIYFWfIQLONb0nga92OiqS5DD/scGzVKCL0Mw== +"@mui/base@5.0.0-beta.4": + version "5.0.0-beta.4" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.4.tgz#e3f4f4a056b88ab357194a245e223177ce35e0b0" + integrity sha512-ejhtqYJpjDgHGEljjMBQWZ22yEK0OzIXNa7toJmmXsP4TT3W7xVy8bTJ0TniPDf+JNjrsgfgiFTDGdlEhV1E+g== dependencies: - "@babel/runtime" "^7.20.13" - "@emotion/is-prop-valid" "^1.2.0" - "@mui/types" "^7.2.3" - "@mui/utils" "^5.11.9" - "@popperjs/core" "^2.11.6" + "@babel/runtime" "^7.21.0" + "@emotion/is-prop-valid" "^1.2.1" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.1" + "@popperjs/core" "^2.11.8" clsx "^1.2.1" prop-types "^15.8.1" react-is "^18.2.0" -"@mui/core-downloads-tracker@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.9.tgz#0d3b20c2ef7704537c38597f9ecfc1894fe7c367" - integrity sha512-YGEtucQ/Nl91VZkzYaLad47Cdui51n/hW+OQm4210g4N3/nZzBxmGeKfubEalf+ShKH4aYDS86XTO6q/TpZnjQ== +"@mui/core-downloads-tracker@^5.13.4": + version "5.13.4" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.4.tgz#7e4b491d8081b6d45ae51556d82cb16b31315a19" + integrity sha512-yFrMWcrlI0TqRN5jpb6Ma9iI7sGTHpytdzzL33oskFHNQ8UgrtPas33Y1K7sWAMwCrr1qbWDrOHLAQG4tAzuSw== "@mui/icons-material@^5.8.4": version "5.11.0" @@ -2651,61 +2689,61 @@ dependencies: "@babel/runtime" "^7.20.6" -"@mui/material@^5.11.10": - version "5.11.10" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.11.10.tgz#d1a7e1691b36eb6aab0f41a82e9c5c564699f599" - integrity sha512-hs1WErbiedqlJIZsljgoil908x4NMp8Lfk8di+5c7o809roqKcFTg2+k3z5ucKvs29AXcsdXrDB/kn2K6dGYIw== - dependencies: - "@babel/runtime" "^7.20.13" - "@mui/base" "5.0.0-alpha.118" - "@mui/core-downloads-tracker" "^5.11.9" - "@mui/system" "^5.11.9" - "@mui/types" "^7.2.3" - "@mui/utils" "^5.11.9" - "@types/react-transition-group" "^4.4.5" +"@mui/material@^5.13.5": + version "5.13.5" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.13.5.tgz#c14f14824f3a37ae0c5ebddbc0034956bc6fec30" + integrity sha512-eMay+Ue1OYXOFMQA5Aau7qbAa/kWHLAyi0McsbPTWssCbGehqkF6CIdPsfVGw6tlO+xPee1hUitphHJNL3xpOQ== + dependencies: + "@babel/runtime" "^7.21.0" + "@mui/base" "5.0.0-beta.4" + "@mui/core-downloads-tracker" "^5.13.4" + "@mui/system" "^5.13.5" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.1" + "@types/react-transition-group" "^4.4.6" clsx "^1.2.1" - csstype "^3.1.1" + csstype "^3.1.2" prop-types "^15.8.1" react-is "^18.2.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.11.9.tgz#ce3f7b7fa7de3e8d6b2a3132a22bffd6bfaabe9b" - integrity sha512-XMyVIFGomVCmCm92EvYlgq3zrC9K+J6r7IKl/rBJT2/xVYoRY6uM7jeB+Wxh7kXxnW9Dbqsr2yL3cx6wSD1sAg== +"@mui/private-theming@^5.13.1": + version "5.13.1" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.13.1.tgz#c3e9a0b44f9c5a51b92cfcfb660536060cb61ed7" + integrity sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ== dependencies: - "@babel/runtime" "^7.20.13" - "@mui/utils" "^5.11.9" + "@babel/runtime" "^7.21.0" + "@mui/utils" "^5.13.1" prop-types "^15.8.1" -"@mui/styled-engine@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.11.9.tgz#105da848163b993522de0deaada82e10ad357194" - integrity sha512-bkh2CjHKOMy98HyOc8wQXEZvhOmDa/bhxMUekFX5IG0/w4f5HJ8R6+K6nakUUYNEgjOWPYzNPrvGB8EcGbhahQ== +"@mui/styled-engine@^5.13.2": + version "5.13.2" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.13.2.tgz#c87bd61c0ab8086d34828b6defe97c02bcd642ef" + integrity sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw== dependencies: - "@babel/runtime" "^7.20.13" - "@emotion/cache" "^11.10.5" - csstype "^3.1.1" + "@babel/runtime" "^7.21.0" + "@emotion/cache" "^11.11.0" + csstype "^3.1.2" prop-types "^15.8.1" -"@mui/system@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.11.9.tgz#61f83c538cb4bb9383bcfb39734d9d22ae11c3e7" - integrity sha512-h6uarf+l3FO6l75Nf7yO+qDGrIoa1DM9nAMCUFZQsNCDKOInRzcptnm8M1w/Z3gVetfeeGoIGAYuYKbft6KZZA== +"@mui/system@^5.13.5": + version "5.13.5" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.13.5.tgz#9f67ea0c4f6974713f90b7b94c999fd3f40f8de3" + integrity sha512-n0gzUxoZ2ZHZgnExkh2Htvo9uW2oakofgPRQrDoa/GQOWyRD0NH9MDszBwOb6AAoXZb+OV5TE7I4LeZ/dzgHYA== dependencies: - "@babel/runtime" "^7.20.13" - "@mui/private-theming" "^5.11.9" - "@mui/styled-engine" "^5.11.9" - "@mui/types" "^7.2.3" - "@mui/utils" "^5.11.9" + "@babel/runtime" "^7.21.0" + "@mui/private-theming" "^5.13.1" + "@mui/styled-engine" "^5.13.2" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.1" clsx "^1.2.1" - csstype "^3.1.1" + csstype "^3.1.2" prop-types "^15.8.1" -"@mui/types@^7.2.3": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.3.tgz#06faae1c0e2f3a31c86af6f28b3a4a42143670b9" - integrity sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw== +"@mui/types@^7.2.4": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328" + integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA== "@mui/utils@^5.10.3": version "5.11.1" @@ -2718,14 +2756,14 @@ prop-types "^15.8.1" react-is "^18.2.0" -"@mui/utils@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.11.9.tgz#8fab9cf773c63ad916597921860d2344b5d4b706" - integrity sha512-eOJaqzcEs4qEwolcvFAmXGpln+uvouvOS9FUX6Wkrte+4I8rZbjODOBDVNlK+V6/ziTfD4iNKC0G+KfOTApbqg== +"@mui/utils@^5.13.1": + version "5.13.1" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.13.1.tgz#86199e46014215f95da046a5ec803f4a39c96eee" + integrity sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A== dependencies: - "@babel/runtime" "^7.20.13" + "@babel/runtime" "^7.21.0" "@types/prop-types" "^15.7.5" - "@types/react-is" "^16.7.1 || ^17.0.0" + "@types/react-is" "^18.2.0" prop-types "^15.8.1" react-is "^18.2.0" @@ -2922,10 +2960,10 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== -"@popperjs/core@^2.11.6": - version "2.11.6" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" - integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== +"@popperjs/core@^2.11.8": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" @@ -4094,6 +4132,13 @@ dependencies: "@types/react" "*" +"@types/react-is@^18.2.0": + version "18.2.1" + resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-18.2.1.tgz#61d01c2a6fc089a53520c0b66996d458fdc46863" + integrity sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw== + dependencies: + "@types/react" "*" + "@types/react-qr-reader@^2.1.4": version "2.1.4" resolved "https://registry.yarnpkg.com/@types/react-qr-reader/-/react-qr-reader-2.1.4.tgz#a36f0b83b4402e26c4217d0e8af6b5e2887fc749" @@ -4108,6 +4153,13 @@ dependencies: "@types/react" "*" +"@types/react-transition-group@^4.4.6": + version "4.4.6" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.6.tgz#18187bcda5281f8e10dfc48f0943e2fdf4f75e2e" + integrity sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@18.0.26": version "18.0.26" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.26.tgz#8ad59fc01fef8eaf5c74f4ea392621749f0b7917" @@ -6475,11 +6527,16 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csstype@^3.0.2, csstype@^3.1.1: +csstype@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== +csstype@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== + cypress-file-upload@^5.0.8: version "5.0.8" resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz#d8824cbeaab798e44be8009769f9a6c9daa1b4a1" @@ -13009,6 +13066,11 @@ stylis@4.1.3: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== +stylis@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== + stylus@^0.59.0: version "0.59.0" resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.59.0.tgz#a344d5932787142a141946536d6e24e6a6be7aa6" From 83d0c359a3f63ec3af8d2433e3bcaf5322d5a963 Mon Sep 17 00:00:00 2001 From: Usame Algan <5880855+usame-algan@users.noreply.github.com> Date: Fri, 23 Jun 2023 12:37:17 +0200 Subject: [PATCH 6/7] fix: Enable spending limit txs in new flow (#2160) * fix: Enable spending limit txs in new flow * fix: Style review spending limit component --- .../address-book/AddressBookTable/index.tsx | 19 +- .../TxData/Transfer/TransferActions.tsx | 22 +- .../NewSpendingLimit/CreateSpendingLimit.tsx | 2 +- .../NewSpendingLimit/ReviewSpendingLimit.tsx | 12 +- .../RemoveSpendingLimit.tsx | 7 +- .../TokenTransfer/CreateTokenTransfer.tsx | 31 ++- .../TokenTransfer}/ReviewSpendingLimitTx.tsx | 42 +-- .../flows/TokenTransfer/ReviewTokenTx.tsx | 25 ++ .../flows/TokenTransfer/SendAmountBlock.tsx | 38 ++- .../flows/TokenTransfer/SendToBlock.tsx | 3 +- .../tx-flow/flows/TokenTransfer/index.tsx | 4 +- src/components/tx/SpendingLimitRow/index.tsx | 12 +- .../TokenTransferModal/ReviewMultisigTx.tsx | 39 --- .../TokenTransferModal/ReviewTokenTx.tsx | 47 ---- .../TokenTransferModal/SendAssetsForm.tsx | 261 ------------------ .../tx/modals/TokenTransferModal/index.tsx | 38 --- .../TokenTransferModal/styles.module.css | 16 -- .../useIsSafeTokenPaused.ts | 0 src/hooks/useSpendingLimitGas.ts | 2 +- src/services/tx/tx-sender/dispatch.ts | 2 +- 20 files changed, 136 insertions(+), 486 deletions(-) rename src/components/{tx/modals/TokenTransferModal => tx-flow/flows/TokenTransfer}/ReviewSpendingLimitTx.tsx (81%) create mode 100644 src/components/tx-flow/flows/TokenTransfer/ReviewTokenTx.tsx delete mode 100644 src/components/tx/modals/TokenTransferModal/ReviewMultisigTx.tsx delete mode 100644 src/components/tx/modals/TokenTransferModal/ReviewTokenTx.tsx delete mode 100644 src/components/tx/modals/TokenTransferModal/SendAssetsForm.tsx delete mode 100644 src/components/tx/modals/TokenTransferModal/index.tsx delete mode 100644 src/components/tx/modals/TokenTransferModal/styles.module.css rename src/{components/tx/modals/TokenTransferModal => hooks}/useIsSafeTokenPaused.ts (100%) diff --git a/src/components/address-book/AddressBookTable/index.tsx b/src/components/address-book/AddressBookTable/index.tsx index ad38e2f5c5..743f74c806 100644 --- a/src/components/address-book/AddressBookTable/index.tsx +++ b/src/components/address-book/AddressBookTable/index.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState } from 'react' +import { useContext, useMemo, useState } from 'react' import { Box } from '@mui/material' import EnhancedTable from '@/components/common/EnhancedTable' import type { AddressEntry } from '@/components/address-book/EntryDialog' @@ -21,8 +21,8 @@ import PagePlaceholder from '@/components/common/PagePlaceholder' import NoEntriesIcon from '@/public/images/address-book/no-entries.svg' import { useCurrentChain } from '@/hooks/useChains' import tableCss from '@/components/common/EnhancedTable/styles.module.css' -import TokenTransferModal from '@/components/tx/modals/TokenTransferModal' -import { SendAssetsField } from '@/components/tx/modals/TokenTransferModal/SendAssetsForm' +import { TxModalContext } from '@/components/tx-flow' +import TokenTransferFlow from '@/components/tx-flow/flows/TokenTransfer' import CheckWallet from '@/components/common/CheckWallet' const headCells = [ @@ -47,10 +47,11 @@ const defaultOpen = { const AddressBookTable = () => { const chain = useCurrentChain() + const { setTxFlow } = useContext(TxModalContext) + const [open, setOpen] = useState(defaultOpen) const [searchQuery, setSearchQuery] = useState('') const [defaultValues, setDefaultValues] = useState(undefined) - const [selectedAddress, setSelectedAddress] = useState() const handleOpenModal = (type: keyof typeof open) => () => { setOpen((prev) => ({ ...prev, [type]: true })) @@ -117,7 +118,7 @@ const AddressBookTable = () => { variant="contained" color="primary" size="small" - onClick={() => setSelectedAddress(address)} + onClick={() => setTxFlow()} disabled={!isOk} > Send @@ -165,14 +166,6 @@ const AddressBookTable = () => { )} {open[ModalType.REMOVE] && } - - {/* Send funds modal */} - {selectedAddress && ( - setSelectedAddress(undefined)} - initialData={[{ [SendAssetsField.recipient]: selectedAddress }]} - /> - )} ) } diff --git a/src/components/transactions/TxDetails/TxData/Transfer/TransferActions.tsx b/src/components/transactions/TxDetails/TxData/Transfer/TransferActions.tsx index 75d64a53e8..b31894ee7d 100644 --- a/src/components/transactions/TxDetails/TxData/Transfer/TransferActions.tsx +++ b/src/components/transactions/TxDetails/TxData/Transfer/TransferActions.tsx @@ -1,5 +1,5 @@ import type { MouseEvent } from 'react' -import { type ReactElement, useState } from 'react' +import { type ReactElement, useContext, useState } from 'react' import IconButton from '@mui/material/IconButton' import MoreHorizIcon from '@mui/icons-material/MoreHoriz' import MenuItem from '@mui/material/MenuItem' @@ -8,7 +8,7 @@ import ListItemText from '@mui/material/ListItemText' import useAddressBook from '@/hooks/useAddressBook' import EntryDialog from '@/components/address-book/EntryDialog' import ContextMenu from '@/components/common/ContextMenu' -import TokenTransferModal from '@/components/tx/modals/TokenTransferModal' +import TokenTransferFlow from '@/components/tx-flow/flows/TokenTransfer' import type { Transfer } from '@safe-global/safe-gateway-typescript-sdk' import { TransferDirection } from '@safe-global/safe-gateway-typescript-sdk' import { ZERO_ADDRESS } from '@safe-global/safe-core-sdk/dist/src/utils/constants' @@ -16,21 +16,23 @@ import { isERC20Transfer, isNativeTokenTransfer } from '@/utils/transaction-guar import { trackEvent, TX_LIST_EVENTS } from '@/services/analytics' import { safeFormatUnits } from '@/utils/formatters' import CheckWallet from '@/components/common/CheckWallet' +import { TxModalContext } from '@/components/tx-flow' +// TODO: No need for an enum anymore enum ModalType { - SEND_AGAIN = 'SEND_AGAIN', ADD_TO_AB = 'ADD_TO_AB', } const ETHER = 'ether' -const defaultOpen = { [ModalType.SEND_AGAIN]: false, [ModalType.ADD_TO_AB]: false } +const defaultOpen = { [ModalType.ADD_TO_AB]: false } const TransferActions = ({ address, txInfo }: { address: string; txInfo: Transfer }): ReactElement => { const [anchorEl, setAnchorEl] = useState() const [open, setOpen] = useState(defaultOpen) const addressBook = useAddressBook() const name = addressBook?.[address] + const { setTxFlow } = useContext(TxModalContext) const handleOpenContextMenu = (e: MouseEvent) => { setAnchorEl(e.currentTarget) @@ -75,7 +77,13 @@ const TransferActions = ({ address, txInfo }: { address: string; txInfo: Transfe {canSendAgain && ( {(isOk) => ( - + { + handleCloseContextMenu() + setTxFlow() + }} + disabled={!isOk} + > Send again )} @@ -87,10 +95,6 @@ const TransferActions = ({ address, txInfo }: { address: string; txInfo: Transfe - {open[ModalType.SEND_AGAIN] && ( - - )} - {open[ModalType.ADD_TO_AB] && ( )} diff --git a/src/components/tx-flow/flows/NewSpendingLimit/CreateSpendingLimit.tsx b/src/components/tx-flow/flows/NewSpendingLimit/CreateSpendingLimit.tsx index d943819886..d27549f3f8 100644 --- a/src/components/tx-flow/flows/NewSpendingLimit/CreateSpendingLimit.tsx +++ b/src/components/tx-flow/flows/NewSpendingLimit/CreateSpendingLimit.tsx @@ -18,7 +18,7 @@ import { parseUnits, defaultAbiCoder } from 'ethers/lib/utils' import AddressBookInput from '@/components/common/AddressBookInput' import { validateAmount, validateDecimalLength } from '@/utils/validation' -import { AutocompleteItem } from '@/components/tx/modals/TokenTransferModal/SendAssetsForm' +import { AutocompleteItem } from '@/components/tx-flow/flows/TokenTransfer/CreateTokenTransfer' import useChainId from '@/hooks/useChainId' import { getResetTimeOptions } from '@/components/transactions/TxDetails/TxData/SpendingLimits' import NumberField from '@/components/common/NumberField' diff --git a/src/components/tx-flow/flows/NewSpendingLimit/ReviewSpendingLimit.tsx b/src/components/tx-flow/flows/NewSpendingLimit/ReviewSpendingLimit.tsx index e2795b57e9..d3a13a1ad7 100644 --- a/src/components/tx-flow/flows/NewSpendingLimit/ReviewSpendingLimit.tsx +++ b/src/components/tx-flow/flows/NewSpendingLimit/ReviewSpendingLimit.tsx @@ -5,7 +5,7 @@ import { Typography, Box } from '@mui/material' import SpendingLimitLabel from '@/components/common/SpendingLimitLabel' import { getResetTimeOptions } from '@/components/transactions/TxDetails/TxData/SpendingLimits' -import { TokenTransferReview } from '@/components/tx/modals/TokenTransferModal/ReviewTokenTx' +import { AmountBlock } from '@/components/tx-flow/flows/TokenTransfer/SendAmountBlock' import SignOrExecuteForm from '@/components/tx/SignOrExecuteForm' import useBalances from '@/hooks/useBalances' import useChainId from '@/hooks/useChainId' @@ -59,16 +59,16 @@ export const ReviewSpendingLimit = ({ params }: { params: NewSpendingLimitFlowPr return ( {token && ( - + {!!existingSpendingLimit && ( <> - - {formatVisualAmount(BigNumber.from(existingSpendingLimit.amount), decimals)} {symbol} + + {formatVisualAmount(BigNumber.from(existingSpendingLimit.amount), decimals)} - {' → '} + {'→'} )} - + )} palette.text.secondary} pb={1}> Beneficiary diff --git a/src/components/tx-flow/flows/RemoveSpendingLimit/RemoveSpendingLimit.tsx b/src/components/tx-flow/flows/RemoveSpendingLimit/RemoveSpendingLimit.tsx index 0efc16481b..dc4e8eabb6 100644 --- a/src/components/tx-flow/flows/RemoveSpendingLimit/RemoveSpendingLimit.tsx +++ b/src/components/tx-flow/flows/RemoveSpendingLimit/RemoveSpendingLimit.tsx @@ -9,7 +9,7 @@ import type { SpendingLimitState } from '@/store/spendingLimitsSlice' import { relativeTime } from '@/utils/date' import { trackEvent, SETTINGS_EVENTS } from '@/services/analytics' import useBalances from '@/hooks/useBalances' -import { TokenTransferReview } from '@/components/tx/modals/TokenTransferModal/ReviewTokenTx' +import { AmountBlock } from '@/components/tx-flow/flows/TokenTransfer/SendAmountBlock' import { safeFormatUnits } from '@/utils/formatters' import SpendingLimitLabel from '@/components/common/SpendingLimitLabel' import { createTx } from '@/services/tx/tx-sender' @@ -49,10 +49,7 @@ export const RemoveSpendingLimit = ({ params }: { params: SpendingLimitState }) return ( {token && ( - + )} ({ color: palette.primary.light })}>Beneficiary diff --git a/src/components/tx-flow/flows/TokenTransfer/CreateTokenTransfer.tsx b/src/components/tx-flow/flows/TokenTransfer/CreateTokenTransfer.tsx index 32eaa5ac03..97cd3d37d8 100644 --- a/src/components/tx-flow/flows/TokenTransfer/CreateTokenTransfer.tsx +++ b/src/components/tx-flow/flows/TokenTransfer/CreateTokenTransfer.tsx @@ -1,9 +1,10 @@ import { type ReactElement, useMemo, useState, useCallback } from 'react' +import { type TokenInfo } from '@safe-global/safe-gateway-typescript-sdk' import { useVisibleBalances } from '@/hooks/useVisibleBalances' import useAddressBook from '@/hooks/useAddressBook' import useChainId from '@/hooks/useChainId' import { getSafeTokenAddress } from '@/components/common/SafeTokenWidget' -import useIsSafeTokenPaused from '@/components/tx/modals/TokenTransferModal/useIsSafeTokenPaused' +import useIsSafeTokenPaused from '@/hooks/useIsSafeTokenPaused' import useIsOnlySpendingLimitBeneficiary from '@/hooks/useIsOnlySpendingLimitBeneficiary' import { useAppSelector } from '@/store' import { selectSpendingLimits } from '@/store/spendingLimitsSlice' @@ -39,6 +40,20 @@ import { formatVisualAmount, safeFormatUnits } from '@/utils/formatters' import commonCss from '@/components/tx-flow/common/styles.module.css' import css from './styles.module.css' +export const AutocompleteItem = (item: { tokenInfo: TokenInfo; balance: string }): ReactElement => ( + + + + + {item.tokenInfo.name} + + + {formatVisualAmount(item.balance, item.tokenInfo.decimals)} {item.tokenInfo.symbol} + + + +) + const CreateTokenTransfer = ({ params, onSubmit, @@ -201,19 +216,7 @@ const CreateTokenTransfer = ({ > {balancesItems.map((item) => ( - - - - - - {item.tokenInfo.name} - - - - {formatVisualAmount(item.balance, item.tokenInfo.decimals)} {item.tokenInfo.symbol} - - - + ))} diff --git a/src/components/tx/modals/TokenTransferModal/ReviewSpendingLimitTx.tsx b/src/components/tx-flow/flows/TokenTransfer/ReviewSpendingLimitTx.tsx similarity index 81% rename from src/components/tx/modals/TokenTransferModal/ReviewSpendingLimitTx.tsx rename to src/components/tx-flow/flows/TokenTransfer/ReviewSpendingLimitTx.tsx index 4f8806bd38..4ea209735f 100644 --- a/src/components/tx/modals/TokenTransferModal/ReviewSpendingLimitTx.tsx +++ b/src/components/tx-flow/flows/TokenTransfer/ReviewSpendingLimitTx.tsx @@ -1,11 +1,10 @@ import type { ReactElement, SyntheticEvent } from 'react' import { useMemo, useState } from 'react' import type { BigNumberish, BytesLike } from 'ethers' -import { Button, DialogContent, Typography } from '@mui/material' -import SendFromBlock from '@/components/tx/SendFromBlock' -import SendToBlock from '@/components/tx/SendToBlock' -import type { TokenTransferModalProps } from '.' -import { TokenTransferReview } from '@/components/tx/modals/TokenTransferModal/ReviewTokenTx' +import { Button, CardActions, Typography } from '@mui/material' +import SendToBlock from '@/components/tx-flow/flows/TokenTransfer/SendToBlock' +import { type TokenTransferParams } from '@/components/tx-flow/flows/TokenTransfer/index' +import SendAmountBlock from '@/components/tx-flow/flows/TokenTransfer/SendAmountBlock' import useBalances from '@/hooks/useBalances' import useSpendingLimit from '@/hooks/useSpendingLimit' import useSpendingLimitGas from '@/hooks/useSpendingLimitGas' @@ -22,6 +21,7 @@ import { MODALS_EVENTS, trackEvent } from '@/services/analytics' import useOnboard from '@/hooks/wallets/useOnboard' import { WrongChainWarning } from '@/components/tx/WrongChainWarning' import { asError } from '@/services/exceptions/utils' +import TxCard from '@/components/tx-flow/common/TxCard' export type SpendingLimitTxParams = { safeAddress: string @@ -34,7 +34,13 @@ export type SpendingLimitTxParams = { signature: BytesLike } -const ReviewSpendingLimitTx = ({ params, onSubmit }: TokenTransferModalProps): ReactElement => { +const ReviewSpendingLimitTx = ({ + params, + onSubmit, +}: { + params: TokenTransferParams + onSubmit: () => void +}): ReactElement => { const [isSubmittable, setIsSubmittable] = useState(true) const [submitError, setSubmitError] = useState() const currentChain = useCurrentChain() @@ -67,10 +73,7 @@ const ReviewSpendingLimitTx = ({ params, onSubmit }: TokenTransferModalProps): R const { gasLimit, gasLimitLoading } = useSpendingLimitGas(txParams) - const [advancedParams, setManualParams] = useAdvancedParams({ - gasLimit, - nonce: params.txNonce, - }) + const [advancedParams, setManualParams] = useAdvancedParams(gasLimit) const handleSubmit = async (e: SyntheticEvent) => { e.preventDefault() @@ -99,15 +102,14 @@ const ReviewSpendingLimitTx = ({ params, onSubmit }: TokenTransferModalProps): R return ( - - + + Spending limit transactions only appear in the interface once they are successfully processed and indexed. Pending transactions can only be viewed in your signer wallet application or under your wallet address on a Blockchain Explorer. - {token && } - + {token && } @@ -119,14 +121,16 @@ const ReviewSpendingLimitTx = ({ params, onSubmit }: TokenTransferModalProps): R Error submitting the transaction. Please try again. )} - + You're about to create a transaction and will need to confirm it with your currently connected wallet. - - + + + + ) } diff --git a/src/components/tx-flow/flows/TokenTransfer/ReviewTokenTx.tsx b/src/components/tx-flow/flows/TokenTransfer/ReviewTokenTx.tsx new file mode 100644 index 0000000000..98e2535f31 --- /dev/null +++ b/src/components/tx-flow/flows/TokenTransfer/ReviewTokenTx.tsx @@ -0,0 +1,25 @@ +import { type ReactElement } from 'react' +import { type TokenTransferParams, TokenTransferType } from '@/components/tx-flow/flows/TokenTransfer/index' +import ReviewTokenTransfer from '@/components/tx-flow/flows/TokenTransfer/ReviewTokenTransfer' +import ReviewSpendingLimitTx from '@/components/tx-flow/flows/TokenTransfer/ReviewSpendingLimitTx' + +// TODO: Split this into separate flows +const ReviewTokenTx = ({ + params, + onSubmit, + txNonce, +}: { + params: TokenTransferParams + onSubmit: () => void + txNonce?: number +}): ReactElement => { + const isSpendingLimitTx = params.type === TokenTransferType.spendingLimit + + return isSpendingLimitTx ? ( + + ) : ( + + ) +} + +export default ReviewTokenTx diff --git a/src/components/tx-flow/flows/TokenTransfer/SendAmountBlock.tsx b/src/components/tx-flow/flows/TokenTransfer/SendAmountBlock.tsx index ef51527810..8ce4362a64 100644 --- a/src/components/tx-flow/flows/TokenTransfer/SendAmountBlock.tsx +++ b/src/components/tx-flow/flows/TokenTransfer/SendAmountBlock.tsx @@ -1,20 +1,46 @@ +import { type ReactNode } from 'react' import { type TokenInfo } from '@safe-global/safe-gateway-typescript-sdk' import { Grid, Typography } from '@mui/material' import css from './styles.module.css' import TokenIcon from '@/components/common/TokenIcon' import { formatAmountPrecise } from '@/utils/formatNumber' -const SendAmountBlock = ({ amount, tokenInfo }: { amount: number | string; tokenInfo: TokenInfo }) => { +export const AmountBlock = ({ + amount, + tokenInfo, + children, +}: { + amount: number | string + tokenInfo: TokenInfo + children?: ReactNode +}) => { + return ( + + + {tokenInfo.symbol} + {children} + {formatAmountPrecise(amount, tokenInfo.decimals)} + + ) +} + +const SendAmountBlock = ({ + amount, + tokenInfo, + children, +}: { + amount: number | string + tokenInfo: TokenInfo + children?: ReactNode +}) => { return ( Send - - - {tokenInfo.symbol} - {formatAmountPrecise(amount, tokenInfo.decimals)} - + + {children} + ) } diff --git a/src/components/tx-flow/flows/TokenTransfer/SendToBlock.tsx b/src/components/tx-flow/flows/TokenTransfer/SendToBlock.tsx index dbdfde34d3..3367f0cb17 100644 --- a/src/components/tx-flow/flows/TokenTransfer/SendToBlock.tsx +++ b/src/components/tx-flow/flows/TokenTransfer/SendToBlock.tsx @@ -1,6 +1,5 @@ import { Grid, Typography } from '@mui/material' import EthHashInfo from '@/components/common/EthHashInfo' -import css from '@/components/tx/modals/TokenTransferModal/styles.module.css' const SendToBlock = ({ address }: { address: string; title?: string }) => { return ( @@ -8,7 +7,7 @@ const SendToBlock = ({ address }: { address: string; title?: string }) => { To - + diff --git a/src/components/tx-flow/flows/TokenTransfer/index.tsx b/src/components/tx-flow/flows/TokenTransfer/index.tsx index bbfa36b406..eca9b4f47e 100644 --- a/src/components/tx-flow/flows/TokenTransfer/index.tsx +++ b/src/components/tx-flow/flows/TokenTransfer/index.tsx @@ -1,7 +1,7 @@ import TxLayout from '@/components/tx-flow/common/TxLayout' import useTxStepper from '../../useTxStepper' import CreateTokenTransfer from './CreateTokenTransfer' -import ReviewTokenTransfer from './ReviewTokenTransfer' +import ReviewTokenTx from '@/components/tx-flow/flows/TokenTransfer/ReviewTokenTx' import AssetsIcon from '@/public/images/sidebar/assets.svg' import { ZERO_ADDRESS } from '@safe-global/safe-core-sdk/dist/src/utils/constants' @@ -49,7 +49,7 @@ const TokenTransferFlow = ({ txNonce, ...params }: TokenTransferFlowProps) => { onSubmit={(formData) => nextStep({ ...data, ...formData })} />, - null} />, + null} />, ] return ( diff --git a/src/components/tx/SpendingLimitRow/index.tsx b/src/components/tx/SpendingLimitRow/index.tsx index 5e116cdbb2..f9c4b2a8ec 100644 --- a/src/components/tx/SpendingLimitRow/index.tsx +++ b/src/components/tx/SpendingLimitRow/index.tsx @@ -4,7 +4,7 @@ import type { BigNumber } from '@ethersproject/bignumber' import classNames from 'classnames' import { safeFormatUnits } from '@/utils/formatters' import type { TokenInfo } from '@safe-global/safe-gateway-typescript-sdk' -import { SendAssetsField, SendTxType } from '@/components/tx/modals/TokenTransferModal/SendAssetsForm' +import { TokenTransferFields, TokenTransferType } from '@/components/tx-flow/flows/TokenTransfer' import useIsOnlySpendingLimitBeneficiary from '@/hooks/useIsOnlySpendingLimitBeneficiary' import css from './styles.module.css' @@ -29,7 +29,7 @@ const SpendingLimitRow = ({ ( { - trigger(SendAssetsField.amount) + trigger(TokenTransferFields.amount) }, 10) }} {...field} - defaultValue={SendTxType.multiSig} + defaultValue={TokenTransferType.multiSig} className={css.group} > {!isOnlySpendLimitBeneficiary && ( } @@ -56,7 +56,7 @@ const SpendingLimitRow = ({ /> )} diff --git a/src/components/tx/modals/TokenTransferModal/ReviewMultisigTx.tsx b/src/components/tx/modals/TokenTransferModal/ReviewMultisigTx.tsx deleted file mode 100644 index 66ba684b6c..0000000000 --- a/src/components/tx/modals/TokenTransferModal/ReviewMultisigTx.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { type ReactElement } from 'react' -import type { SafeTransaction } from '@safe-global/safe-core-sdk-types' - -import SignOrExecuteForm from '@/components/tx/SignOrExecuteForm' -import { createTokenTransferParams } from '@/services/tx/tokenTransferParams' -import useBalances from '@/hooks/useBalances' -import useAsync from '@/hooks/useAsync' -import SendToBlock from '@/components/tx/SendToBlock' -import SendFromBlock from '../../SendFromBlock' -import type { TokenTransferModalProps } from '.' -import { TokenTransferReview } from '@/components/tx/modals/TokenTransferModal/ReviewTokenTx' -import { createTx } from '@/services/tx/tx-sender' - -const ReviewMultisigTx = ({ params, onSubmit }: TokenTransferModalProps): ReactElement => { - const { balances } = useBalances() - - const token = balances.items.find((item) => item.tokenInfo.address === params.tokenAddress) - const { decimals, address } = token?.tokenInfo || {} - - // Create a safeTx - const [safeTx, safeTxError] = useAsync(() => { - if (!address || typeof decimals === 'undefined') return - const txParams = createTokenTransferParams(params.recipient, params.amount, decimals, address) - return createTx(txParams, params.txNonce) - }, [params, decimals, address]) - - // TODO: Need to use the SafeTxProvider here - return ( - - {token && } - - - - - - ) -} - -export default ReviewMultisigTx diff --git a/src/components/tx/modals/TokenTransferModal/ReviewTokenTx.tsx b/src/components/tx/modals/TokenTransferModal/ReviewTokenTx.tsx deleted file mode 100644 index 0a05065e4b..0000000000 --- a/src/components/tx/modals/TokenTransferModal/ReviewTokenTx.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { type ReactNode, type ReactElement } from 'react' -import { Box } from '@mui/material' -import type { TokenInfo } from '@safe-global/safe-gateway-typescript-sdk' - -import css from './styles.module.css' -import type { TokenTransferModalProps } from '.' -import { SendTxType } from '@/components/tx/modals/TokenTransferModal/SendAssetsForm' -import TokenIcon from '@/components/common/TokenIcon' -import ReviewSpendingLimitTx from '@/components/tx/modals/TokenTransferModal/ReviewSpendingLimitTx' -import ReviewMultisigTx from '@/components/tx/modals/TokenTransferModal/ReviewMultisigTx' -import { formatAmountPrecise } from '@/utils/formatNumber' - -export const TokenTransferReview = ({ - amount, - tokenInfo, - children, -}: { - amount: number | string - tokenInfo: TokenInfo - children?: ReactNode -}) => { - return ( - - - - - - - {children} - {formatAmountPrecise(amount, tokenInfo.decimals)} {tokenInfo.symbol} - - - ) -} - -// OLD -const ReviewTokenTx = ({ params, onSubmit }: TokenTransferModalProps): ReactElement => { - const isSpendingLimitTx = params.type === SendTxType.spendingLimit - - return isSpendingLimitTx ? ( - - ) : ( - - ) -} - -export default ReviewTokenTx diff --git a/src/components/tx/modals/TokenTransferModal/SendAssetsForm.tsx b/src/components/tx/modals/TokenTransferModal/SendAssetsForm.tsx deleted file mode 100644 index d7dd4ede00..0000000000 --- a/src/components/tx/modals/TokenTransferModal/SendAssetsForm.tsx +++ /dev/null @@ -1,261 +0,0 @@ -import type { ReactElement } from 'react' -import { useCallback, useMemo } from 'react' -import { useForm, FormProvider, Controller } from 'react-hook-form' -import { - Button, - FormControl, - Grid, - InputLabel, - MenuItem, - Select, - Typography, - DialogContent, - Box, - SvgIcon, -} from '@mui/material' -import { type TokenInfo } from '@safe-global/safe-gateway-typescript-sdk' -import { BigNumber } from '@ethersproject/bignumber' - -import TokenIcon from '@/components/common/TokenIcon' -import { formatVisualAmount, safeFormatUnits } from '@/utils/formatters' -import { validateDecimalLength, validateLimitedAmount } from '@/utils/validation' -import AddressBookInput from '@/components/common/AddressBookInput' -import InputValueHelper from '@/components/common/InputValueHelper' -import SendFromBlock from '../../SendFromBlock' -import SpendingLimitRow from '@/components/tx/SpendingLimitRow' -import useSpendingLimit from '@/hooks/useSpendingLimit' -import SendToBlock from '@/components/tx/SendToBlock' -import useAddressBook from '@/hooks/useAddressBook' -import { getSafeTokenAddress } from '@/components/common/SafeTokenWidget' -import useChainId from '@/hooks/useChainId' -import { sameAddress } from '@/utils/addresses' -import InfoIcon from '@/public/images/notifications/info.svg' -import useIsSafeTokenPaused from '@/components/tx/modals/TokenTransferModal/useIsSafeTokenPaused' -import NumberField from '@/components/common/NumberField' -import { useVisibleBalances } from '@/hooks/useVisibleBalances' -import useIsOnlySpendingLimitBeneficiary from '@/hooks/useIsOnlySpendingLimitBeneficiary' -import { useAppSelector } from '@/store' -import { selectSpendingLimits } from '@/store/spendingLimitsSlice' -import useWallet from '@/hooks/wallets/useWallet' - -export const AutocompleteItem = (item: { tokenInfo: TokenInfo; balance: string }): ReactElement => ( - - - - - {item.tokenInfo.name} - - - {formatVisualAmount(item.balance, item.tokenInfo.decimals)} {item.tokenInfo.symbol} - - - -) - -export enum SendTxType { - multiSig = 'multiSig', - spendingLimit = 'spendingLimit', -} - -export enum SendAssetsField { - recipient = 'recipient', - tokenAddress = 'tokenAddress', - amount = 'amount', - type = 'type', -} - -export type SendAssetsFormData = { - [SendAssetsField.recipient]: string - [SendAssetsField.tokenAddress]: string - [SendAssetsField.amount]: string - [SendAssetsField.type]: SendTxType -} - -type SendAssetsFormProps = { - formData?: SendAssetsFormData - disableSpendingLimit?: boolean - onSubmit: (formData: SendAssetsFormData) => void -} - -const SendAssetsForm = ({ - onSubmit, - formData, - // Spending limits only disabled upon replacement, which pure spending limit beneficiaries can't do - disableSpendingLimit = false, -}: SendAssetsFormProps): ReactElement => { - const { balances } = useVisibleBalances() - const addressBook = useAddressBook() - const chainId = useChainId() - const safeTokenAddress = getSafeTokenAddress(chainId) - const isSafeTokenPaused = useIsSafeTokenPaused() - const isOnlySpendingLimitBeneficiary = useIsOnlySpendingLimitBeneficiary() - const spendingLimits = useAppSelector(selectSpendingLimits) - const wallet = useWallet() - - const formMethods = useForm({ - defaultValues: { - [SendAssetsField.recipient]: formData?.[SendAssetsField.recipient] || '', - [SendAssetsField.tokenAddress]: formData?.[SendAssetsField.tokenAddress] || '', - [SendAssetsField.amount]: formData?.[SendAssetsField.amount] || '', - [SendAssetsField.type]: disableSpendingLimit - ? SendTxType.multiSig - : isOnlySpendingLimitBeneficiary - ? SendTxType.spendingLimit - : formData?.[SendAssetsField.type] || SendTxType.multiSig, - }, - mode: 'onChange', - delayError: 500, - }) - const { - register, - handleSubmit, - setValue, - resetField, - watch, - formState: { errors }, - control, - } = formMethods - - const recipient = watch(SendAssetsField.recipient) - - // Selected token - const tokenAddress = watch(SendAssetsField.tokenAddress) - const selectedToken = tokenAddress - ? balances.items.find((item) => item.tokenInfo.address === tokenAddress) - : undefined - - const type = watch(SendAssetsField.type) - const spendingLimit = useSpendingLimit(selectedToken?.tokenInfo) - const isSpendingLimitType = type === SendTxType.spendingLimit - const spendingLimitAmount = spendingLimit ? BigNumber.from(spendingLimit.amount).sub(spendingLimit.spent) : undefined - const totalAmount = BigNumber.from(selectedToken?.balance || 0) - const maxAmount = isSpendingLimitType - ? spendingLimitAmount && totalAmount.gt(spendingLimitAmount) - ? spendingLimitAmount - : totalAmount - : totalAmount - - const balancesItems = useMemo(() => { - return isOnlySpendingLimitBeneficiary - ? balances.items.filter(({ tokenInfo }) => { - return spendingLimits?.some(({ beneficiary, token }) => { - return sameAddress(beneficiary, wallet?.address || '') && sameAddress(tokenInfo.address, token.address) - }) - }) - : balances.items - }, [balances.items, isOnlySpendingLimitBeneficiary, spendingLimits, wallet?.address]) - - const onMaxAmountClick = useCallback(() => { - if (!selectedToken) return - - const amount = - isSpendingLimitType && spendingLimitAmount && spendingLimitAmount.lte(selectedToken.balance) - ? spendingLimitAmount.toString() - : selectedToken.balance - - setValue(SendAssetsField.amount, safeFormatUnits(amount, selectedToken.tokenInfo.decimals), { - shouldValidate: true, - }) - }, [isSpendingLimitType, selectedToken, setValue, spendingLimitAmount]) - - const isSafeTokenSelected = sameAddress(safeTokenAddress, tokenAddress) - const isDisabled = isSafeTokenSelected && isSafeTokenPaused - - return ( - -
- - - - - {addressBook[recipient] ? ( - setValue(SendAssetsField.recipient, '')}> - - - ) : ( - - )} - - - ( - - - Select an asset - - - - )} - /> - - {isDisabled && ( - - - - $SAFE is currently non-transferable. - - - )} - - {!disableSpendingLimit && !!spendingLimitAmount && ( - - - - )} - - - - Max - - ), - }} - // @see https://github.com/react-hook-form/react-hook-form/issues/220 - InputLabelProps={{ - shrink: !!watch(SendAssetsField.amount), - }} - required - {...register(SendAssetsField.amount, { - required: true, - validate: (val) => { - const decimals = selectedToken?.tokenInfo.decimals - return ( - validateLimitedAmount(val, decimals, maxAmount.toString()) || validateDecimalLength(val, decimals) - ) - }, - })} - /> - - - - -
-
- ) -} - -export default SendAssetsForm diff --git a/src/components/tx/modals/TokenTransferModal/index.tsx b/src/components/tx/modals/TokenTransferModal/index.tsx deleted file mode 100644 index b5feadcb5f..0000000000 --- a/src/components/tx/modals/TokenTransferModal/index.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react' - -import type { TxStepperProps } from '@/components/tx/TxStepper/useTxStepper' -import type { SendAssetsFormData } from '@/components/tx/modals/TokenTransferModal/SendAssetsForm' -import SendAssetsForm from '@/components/tx/modals/TokenTransferModal/SendAssetsForm' -import ReviewTokenTx from '@/components/tx/modals/TokenTransferModal/ReviewTokenTx' -import type { TxModalProps } from '@/components/tx/TxModal' -import TxModal from '@/components/tx/TxModal' - -export type TokenTransferModalProps = { - params: SendAssetsFormData & { txNonce?: number; disableSpendingLimit?: boolean } - onSubmit: () => void -} - -export const TokenTransferSteps: TxStepperProps['steps'] = [ - { - label: 'Send tokens', - render: (data, onSubmit) => { - const { disableSpendingLimit, ...formData } = data as SendAssetsFormData & { disableSpendingLimit?: boolean } - return - }, - }, - { - label: 'Review transaction', - render: (data, onSubmit) => ( - } - /> - ), - }, -] - -const TokenTransferModal = (props: Omit) => { - return -} - -export default TokenTransferModal diff --git a/src/components/tx/modals/TokenTransferModal/styles.module.css b/src/components/tx/modals/TokenTransferModal/styles.module.css deleted file mode 100644 index dc1718b7b6..0000000000 --- a/src/components/tx/modals/TokenTransferModal/styles.module.css +++ /dev/null @@ -1,16 +0,0 @@ -.container { - display: flex; - flex-direction: column; - flex-wrap: wrap; - gap: var(--space-3); - padding: var(--space-3); -} - -.tokenPreview { - text-align: center; -} - -.tokenIcon { - display: flex; - justify-content: center; -} diff --git a/src/components/tx/modals/TokenTransferModal/useIsSafeTokenPaused.ts b/src/hooks/useIsSafeTokenPaused.ts similarity index 100% rename from src/components/tx/modals/TokenTransferModal/useIsSafeTokenPaused.ts rename to src/hooks/useIsSafeTokenPaused.ts diff --git a/src/hooks/useSpendingLimitGas.ts b/src/hooks/useSpendingLimitGas.ts index d43906a33b..e21be1c74f 100644 --- a/src/hooks/useSpendingLimitGas.ts +++ b/src/hooks/useSpendingLimitGas.ts @@ -2,7 +2,7 @@ import type { BigNumber } from 'ethers' import { useWeb3 } from '@/hooks/wallets/web3' import { getSpendingLimitContract } from '@/services/contracts/spendingLimitContracts' import useAsync from '@/hooks/useAsync' -import type { SpendingLimitTxParams } from '@/components/tx/modals/TokenTransferModal/ReviewSpendingLimitTx' +import { type SpendingLimitTxParams } from '@/components/tx-flow/flows/TokenTransfer/ReviewSpendingLimitTx' import useChainId from '@/hooks/useChainId' const useSpendingLimitGas = (params: SpendingLimitTxParams) => { diff --git a/src/services/tx/tx-sender/dispatch.ts b/src/services/tx/tx-sender/dispatch.ts index faf102738f..c2baac3b02 100644 --- a/src/services/tx/tx-sender/dispatch.ts +++ b/src/services/tx/tx-sender/dispatch.ts @@ -3,7 +3,7 @@ import type { SafeTransaction, TransactionOptions, TransactionResult } from '@sa import type { EthersError } from '@/utils/ethers-utils' import { didReprice, didRevert } from '@/utils/ethers-utils' import type MultiSendCallOnlyEthersContract from '@safe-global/safe-ethers-lib/dist/src/contracts/MultiSendCallOnly/MultiSendCallOnlyEthersContract' -import type { SpendingLimitTxParams } from '@/components/tx/modals/TokenTransferModal/ReviewSpendingLimitTx' +import { type SpendingLimitTxParams } from '@/components/tx-flow/flows/TokenTransfer/ReviewSpendingLimitTx' import { getSpendingLimitContract } from '@/services/contracts/spendingLimitContracts' import type { ContractTransaction } from 'ethers' import type { RequestId } from '@safe-global/safe-apps-sdk' From d259685439cfd951aa5e3e69ead06e624053441d Mon Sep 17 00:00:00 2001 From: Usame Algan <5880855+usame-algan@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:30:50 +0200 Subject: [PATCH 7/7] Adjust review screen design, fix nft link (#2162) --- .../tx-flow/common/TxLayout/styles.module.css | 4 +++ .../tx-flow/common/TxNonce/index.tsx | 2 +- .../tx-flow/common/styles.module.css | 2 +- src/components/tx-flow/flows/NewTx/index.tsx | 26 ++++++++++++------- .../flows/TokenTransfer/SendAmountBlock.tsx | 2 +- .../flows/TokenTransfer/SendToBlock.tsx | 2 +- src/components/tx/DecodedTx/index.tsx | 3 ++- .../tx/ExecuteCheckbox/styles.module.css | 4 +-- .../tx/SignOrExecuteForm/ExecuteForm.tsx | 5 +++- .../tx/SignOrExecuteForm/SignForm.tsx | 5 +++- .../tx/SignOrExecuteForm/TxChecks.tsx | 3 +++ src/components/tx/SignOrExecuteForm/index.tsx | 19 ++++---------- .../tx/SignOrExecuteForm/styles.module.css | 2 +- src/components/tx/TxSimulation/index.tsx | 2 +- .../tx/TxSimulation/styles.module.css | 1 - .../shared/SecurityWarnings/styles.module.css | 1 - 16 files changed, 47 insertions(+), 36 deletions(-) diff --git a/src/components/tx-flow/common/TxLayout/styles.module.css b/src/components/tx-flow/common/TxLayout/styles.module.css index 664989b9b2..04ba4783b6 100644 --- a/src/components/tx-flow/common/TxLayout/styles.module.css +++ b/src/components/tx-flow/common/TxLayout/styles.module.css @@ -64,6 +64,10 @@ font-size: 14px; } +.step :global(.MuiAccordionSummary-expandIconWrapper) { + margin-left: var(--space-2); +} + .statusButton { position: absolute; top: 0; diff --git a/src/components/tx-flow/common/TxNonce/index.tsx b/src/components/tx-flow/common/TxNonce/index.tsx index 058dbd351e..bdbcc7edcc 100644 --- a/src/components/tx-flow/common/TxNonce/index.tsx +++ b/src/components/tx-flow/common/TxNonce/index.tsx @@ -83,7 +83,7 @@ const TxNonce = () => { setNonce(recommendedNonce) }, [recommendedNonce, setNonce]) - if (nonce === undefined) return + if (nonce === undefined) return return ( diff --git a/src/components/tx-flow/common/styles.module.css b/src/components/tx-flow/common/styles.module.css index ed96768f02..be6c33ebc4 100644 --- a/src/components/tx-flow/common/styles.module.css +++ b/src/components/tx-flow/common/styles.module.css @@ -1,7 +1,7 @@ .cardContent { display: flex; flex-direction: column; - gap: var(--space-3); + gap: var(--space-2); padding: var(--space-3); } diff --git a/src/components/tx-flow/flows/NewTx/index.tsx b/src/components/tx-flow/flows/NewTx/index.tsx index ceaba3b1dd..9b089bd017 100644 --- a/src/components/tx-flow/flows/NewTx/index.tsx +++ b/src/components/tx-flow/flows/NewTx/index.tsx @@ -7,6 +7,7 @@ import { TxModalContext } from '../../' import TokenTransferFlow from '../TokenTransfer' import { AppRoutes } from '@/config/routes' import css from './styles.module.css' +import Link from 'next/link' const BUTTONS_HEIGHT = '91px' @@ -16,7 +17,10 @@ const NewTxMenu = () => { const txBuilder = useTxBuilderApp() const onNftsClick = useCallback(() => { - router.push(AppRoutes.balances.nfts, { query: { safe: router.query.safe } }) + router.push({ + pathname: AppRoutes.balances.nfts, + query: { safe: router.query.safe }, + }) }, [router]) const onTokensClick = useCallback(() => { @@ -34,14 +38,18 @@ const NewTxMenu = () => { {txBuilder && txBuilder.app && ( - } - variant="outlined" - onClick={() => console.log('open contract interaction flow')} - sx={{ height: BUTTONS_HEIGHT }} - > - Contract interaction - + + + } + variant="outlined" + onClick={() => console.log('open contract interaction flow')} + sx={{ height: BUTTONS_HEIGHT }} + > + Contract interaction + + + )} ) diff --git a/src/components/tx-flow/flows/TokenTransfer/SendAmountBlock.tsx b/src/components/tx-flow/flows/TokenTransfer/SendAmountBlock.tsx index 8ce4362a64..9a1a3dd6e4 100644 --- a/src/components/tx-flow/flows/TokenTransfer/SendAmountBlock.tsx +++ b/src/components/tx-flow/flows/TokenTransfer/SendAmountBlock.tsx @@ -34,7 +34,7 @@ const SendAmountBlock = ({ children?: ReactNode }) => { return ( - + Send diff --git a/src/components/tx-flow/flows/TokenTransfer/SendToBlock.tsx b/src/components/tx-flow/flows/TokenTransfer/SendToBlock.tsx index 3367f0cb17..727775b9fa 100644 --- a/src/components/tx-flow/flows/TokenTransfer/SendToBlock.tsx +++ b/src/components/tx-flow/flows/TokenTransfer/SendToBlock.tsx @@ -3,7 +3,7 @@ import EthHashInfo from '@/components/common/EthHashInfo' const SendToBlock = ({ address }: { address: string; title?: string }) => { return ( - + To diff --git a/src/components/tx/DecodedTx/index.tsx b/src/components/tx/DecodedTx/index.tsx index 2709ef17b9..c0cb6c6aab 100644 --- a/src/components/tx/DecodedTx/index.tsx +++ b/src/components/tx/DecodedTx/index.tsx @@ -31,6 +31,7 @@ import Multisend from '@/components/transactions/TxDetails/TxData/DecodedData/Mu import InfoIcon from '@/public/images/notifications/info.svg' import ExternalLink from '@/components/common/ExternalLink' import { HelpCenterArticle } from '@/config/constants' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' type DecodedTxProps = { tx?: SafeTransaction @@ -93,7 +94,7 @@ const DecodedTx = ({ tx, txId }: DecodedTxProps): ReactElement | null => { )} - + }> Transaction details {decodedData ? decodedData.method : tx?.data.operation === OperationType.DelegateCall ? 'Delegate call' : ''} diff --git a/src/components/tx/ExecuteCheckbox/styles.module.css b/src/components/tx/ExecuteCheckbox/styles.module.css index 68726726f3..f5e8a99061 100644 --- a/src/components/tx/ExecuteCheckbox/styles.module.css +++ b/src/components/tx/ExecuteCheckbox/styles.module.css @@ -6,7 +6,7 @@ .radio { margin: 0; - border: 1px solid var(--color-border-main); - border-radius: 4px; + border: 1px solid var(--color-border-light); + border-radius: 6px; padding: 9px 3px; } diff --git a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx index afbd079bcf..857d275004 100644 --- a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx +++ b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx @@ -1,5 +1,5 @@ import { type ReactElement, type SyntheticEvent, useContext, useState } from 'react' -import { Button, CardActions } from '@mui/material' +import { Button, CardActions, Divider } from '@mui/material' import classNames from 'classnames' import ErrorMessage from '@/components/tx/ErrorMessage' @@ -23,6 +23,7 @@ import AdvancedParams, { useAdvancedParams } from '../AdvancedParams' import { asError } from '@/services/exceptions/utils' import css from './styles.module.css' +import commonCss from '@/components/tx-flow/common/styles.module.css' const ExecuteForm = ({ safeTx, @@ -131,6 +132,8 @@ const ExecuteForm = ({ )} + + {/* Submit button */} diff --git a/src/components/tx/SignOrExecuteForm/SignForm.tsx b/src/components/tx/SignOrExecuteForm/SignForm.tsx index 7f0b5490bd..4bca8280c5 100644 --- a/src/components/tx/SignOrExecuteForm/SignForm.tsx +++ b/src/components/tx/SignOrExecuteForm/SignForm.tsx @@ -1,5 +1,5 @@ import { type ReactElement, type SyntheticEvent, useContext, useState } from 'react' -import { Button, CardActions } from '@mui/material' +import { Button, CardActions, Divider } from '@mui/material' import ErrorMessage from '@/components/tx/ErrorMessage' import { logError, Errors } from '@/services/exceptions' @@ -10,6 +10,7 @@ import type { SignOrExecuteProps } from '.' import type { SafeTransaction } from '@safe-global/safe-core-sdk-types' import { TxModalContext } from '@/components/tx-flow' import { asError } from '@/services/exceptions/utils' +import commonCss from '@/components/tx-flow/common/styles.module.css' const SignForm = ({ safeTx, @@ -65,6 +66,8 @@ const SignForm = ({ ) )} + + {/* Submit button */} diff --git a/src/components/tx/SignOrExecuteForm/TxChecks.tsx b/src/components/tx/SignOrExecuteForm/TxChecks.tsx index 02dc1a201c..81e75a7383 100644 --- a/src/components/tx/SignOrExecuteForm/TxChecks.tsx +++ b/src/components/tx/SignOrExecuteForm/TxChecks.tsx @@ -2,6 +2,7 @@ import { type ReactElement, useContext } from 'react' import { TxSimulation } from '../TxSimulation' import { SafeTxContext } from '@/components/tx-flow/SafeTxProvider' import { Typography } from '@mui/material' +import { RedefineScanResult } from '@/components/tx/security/redefine/RedefineScanResult/RedefineScanResult' const TxChecks = (): ReactElement => { const { safeTx } = useContext(SafeTxContext) @@ -11,6 +12,8 @@ const TxChecks = (): ReactElement => { Transaction checks + + ) } diff --git a/src/components/tx/SignOrExecuteForm/index.tsx b/src/components/tx/SignOrExecuteForm/index.tsx index b05f2c03d2..c84f9d0a9f 100644 --- a/src/components/tx/SignOrExecuteForm/index.tsx +++ b/src/components/tx/SignOrExecuteForm/index.tsx @@ -12,10 +12,7 @@ import TxCard from '@/components/tx-flow/common/TxCard' import ConfirmationTitle, { ConfirmationTitleTypes } from '@/components/tx/SignOrExecuteForm/ConfirmationTitle' import { useAppSelector } from '@/store' import { selectSettings } from '@/store/settingsSlice' -import { Divider } from '@mui/material' -import commonCss from '@/components/tx-flow/common/styles.module.css' import { TransactionSecurityProvider } from '../security/TransactionSecurityContext' -import { RedefineScanResult } from '@/components/tx/security/redefine/RedefineScanResult/RedefineScanResult' export type SignOrExecuteProps = { txId?: string @@ -59,23 +56,17 @@ const SignOrExecuteForm = (props: SignOrExecuteProps): ReactElement => { isCreation={isCreation} /> - {canExecute && !props.onlyExecute && } - - - - {/* Warning message and switch button */} - - {safeTxError && ( This transaction will most likely fail. To save gas costs, avoid confirming the transaction. )} -
- - {willExecute ? : } -
+ {canExecute && !props.onlyExecute && } + + + + {willExecute ? : } diff --git a/src/components/tx/SignOrExecuteForm/styles.module.css b/src/components/tx/SignOrExecuteForm/styles.module.css index aadc28aae9..e469867c00 100644 --- a/src/components/tx/SignOrExecuteForm/styles.module.css +++ b/src/components/tx/SignOrExecuteForm/styles.module.css @@ -1,8 +1,8 @@ .wrapper { - padding: 8px 0px 8px; display: flex; align-items: center; gap: var(--space-2); + margin-bottom: var(--space-1); } .icon { diff --git a/src/components/tx/TxSimulation/index.tsx b/src/components/tx/TxSimulation/index.tsx index de4c78f3cf..5622c6e6f5 100644 --- a/src/components/tx/TxSimulation/index.tsx +++ b/src/components/tx/TxSimulation/index.tsx @@ -54,7 +54,7 @@ const TxSimulationBlock = ({ transactions, canExecute, disabled, gasLimit }: TxS const isSimulationLoading = simulationRequestStatus === FETCH_STATUS.LOADING return ( - + {!isSimulationFinished ? ( Transaction validity diff --git a/src/components/tx/TxSimulation/styles.module.css b/src/components/tx/TxSimulation/styles.module.css index 6842dfa30f..54ea615951 100644 --- a/src/components/tx/TxSimulation/styles.module.css +++ b/src/components/tx/TxSimulation/styles.module.css @@ -14,5 +14,4 @@ .skeletonWrapper { border-radius: 8px; overflow: hidden; - margin-top: var(--space-2); } diff --git a/src/components/tx/security/shared/SecurityWarnings/styles.module.css b/src/components/tx/security/shared/SecurityWarnings/styles.module.css index 697205454c..d8a40f647a 100644 --- a/src/components/tx/security/shared/SecurityWarnings/styles.module.css +++ b/src/components/tx/security/shared/SecurityWarnings/styles.module.css @@ -55,6 +55,5 @@ border-radius: 6px; border: 1px solid var(--color-border-light); padding: 0; - margin-top: var(--space-2); background-color: var(--color-background-main); }