From 3e4c9cf7d365ce64f9ff3c66522e74142228c9cc Mon Sep 17 00:00:00 2001 From: Mati Dastugue Date: Tue, 25 May 2021 05:41:13 -0300 Subject: [PATCH] Bugfix - Safes added via URL not stored when changing name (#2310) * Fix Types * Fix adding a safe to the list after it was accessed via URL Co-authored-by: Daniel Sanchez --- .../safe/store/middleware/safeStorage.ts | 21 ++++++++++++++----- src/logic/safe/store/reducer/safe.ts | 19 ++++++++++------- .../components/ReviewInformation/index.tsx | 2 +- src/routes/load/container/Load.tsx | 5 ++++- .../components/Settings/SafeDetails/index.tsx | 10 ++++++--- src/routes/safe/components/Settings/index.tsx | 13 +++++++----- 6 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/logic/safe/store/middleware/safeStorage.ts b/src/logic/safe/store/middleware/safeStorage.ts index 8ce1a5b9..53eeaccf 100644 --- a/src/logic/safe/store/middleware/safeStorage.ts +++ b/src/logic/safe/store/middleware/safeStorage.ts @@ -1,3 +1,4 @@ +import { Store } from 'redux' import { saveDefaultSafe, saveSafes } from 'src/logic/safe/utils' import { ADD_SAFE_OWNER } from 'src/logic/safe/store/actions/addSafeOwner' import { EDIT_SAFE_OWNER } from 'src/logic/safe/store/actions/editSafeOwner' @@ -12,6 +13,7 @@ import { makeAddressBookEntry } from 'src/logic/addressBook/model/addressBook' import { checksumAddress } from 'src/utils/checksumAddress' import { isValidAddressBookName } from 'src/logic/addressBook/utils' import { addOrUpdateAddressBookEntry } from 'src/logic/addressBook/store/actions/addOrUpdateAddressBookEntry' +import { SafeRecord } from '../models/safe' const watchedActions = [ UPDATE_SAFE, @@ -24,7 +26,16 @@ const watchedActions = [ SET_DEFAULT_SAFE, ] -export const safeStorageMiddleware = (store) => (next) => async (action) => { +type SafeProps = { + safe: SafeRecord +} + +export const safeStorageMiddleware = (store: Store) => ( + next: (arg0: { type: string; payload: string | SafeProps | { address: string; name: string } }) => any, +) => async (action: { + type: string + payload: string | SafeProps | { name: string; address: string } +}): Promise => { const handledAction = next(action) if (watchedActions.includes(action.type)) { @@ -35,8 +46,8 @@ export const safeStorageMiddleware = (store) => (next) => async (action) => { switch (action.type) { case ADD_OR_UPDATE_SAFE: { - const { safe } = action.payload - safe.owners.forEach((owner) => { + const { safe } = action.payload as SafeProps + safe.owners.forEach((owner: { address: string; name: any }) => { const checksumEntry = makeAddressBookEntry({ address: checksumAddress(owner.address), name: owner.name }) if (isValidAddressBookName(checksumEntry.name)) { dispatch(addOrUpdateAddressBookEntry(checksumEntry)) @@ -51,7 +62,7 @@ export const safeStorageMiddleware = (store) => (next) => async (action) => { break } case UPDATE_SAFE: { - const { name, address } = action.payload + const { name, address } = action.payload as { name: string; address: string } if (name) { dispatch(addOrUpdateAddressBookEntry(makeAddressBookEntry({ name, address }))) } @@ -59,7 +70,7 @@ export const safeStorageMiddleware = (store) => (next) => async (action) => { } case SET_DEFAULT_SAFE: { if (action.payload) { - saveDefaultSafe(action.payload) + saveDefaultSafe(action.payload as string) } break } diff --git a/src/logic/safe/store/reducer/safe.ts b/src/logic/safe/store/reducer/safe.ts index 8602db8f..7af28956 100644 --- a/src/logic/safe/store/reducer/safe.ts +++ b/src/logic/safe/store/reducer/safe.ts @@ -80,16 +80,16 @@ export default handleActions( const safeAddress = safe.address const shouldUpdate = shouldSafeStoreBeUpdated(safe, state.getIn(['safes', safeAddress])) - let loadedViaUrl = safe.loadedViaUrl - - if (!state.hasIn(['safes', safeAddress])) { - loadedViaUrl = !safe?.name || safe?.name === LOADED_SAFE_KEY - } return shouldUpdate ? state.updateIn( ['safes', safeAddress], - makeSafe({ name: safe?.name || LOADED_SAFE_KEY, address: safeAddress, loadedViaUrl }), + // This intermediate value is used as prevSafe if no previous state. Else is not used + makeSafe({ + name: safe?.name || LOADED_SAFE_KEY, + address: safeAddress, + loadedViaUrl: !safe?.name || safe?.name === LOADED_SAFE_KEY, + }), (prevSafe) => updateSafeProps(prevSafe, safe), ) : state @@ -106,7 +106,12 @@ export default handleActions( return shouldUpdate ? state.updateIn( ['safes', safeAddress], - makeSafe({ name: safe?.name || LOADED_SAFE_KEY, address: safeAddress, loadedViaUrl: !!safe?.name }), + // This intermediate value is used as prevSafe if no previous state. Else is not used + makeSafe({ + name: safe?.name || LOADED_SAFE_KEY, + address: safeAddress, + loadedViaUrl: !safe?.name || safe?.name === LOADED_SAFE_KEY, + }), (prevSafe) => updateSafeProps(prevSafe, safe), ) : state diff --git a/src/routes/load/components/ReviewInformation/index.tsx b/src/routes/load/components/ReviewInformation/index.tsx index 96178867..9156f1d0 100644 --- a/src/routes/load/components/ReviewInformation/index.tsx +++ b/src/routes/load/components/ReviewInformation/index.tsx @@ -106,7 +106,7 @@ const ReviewComponent = ({ userAddress, values }: Props): React.ReactElement => {owners.map((address, index) => ( <> - + => { const safeProps = await buildSafe(safeAddress, safeName) safeProps.owners = owners + // We are manually adding the safe. We enforce this state in case the safe was previously + // accessed by URL + safeProps.loadedViaUrl = false const storedSafes = (await loadStoredSafes()) || {} diff --git a/src/routes/safe/components/Settings/SafeDetails/index.tsx b/src/routes/safe/components/Settings/SafeDetails/index.tsx index 1a5ccbd2..1e3aeafe 100644 --- a/src/routes/safe/components/Settings/SafeDetails/index.tsx +++ b/src/routes/safe/components/Settings/SafeDetails/index.tsx @@ -1,6 +1,8 @@ +import { Icon, Link, Text } from '@gnosis.pm/safe-react-components' import { makeStyles } from '@material-ui/core/styles' import React, { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' +import styled from 'styled-components' import { styles } from './style' @@ -22,8 +24,6 @@ import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { UpdateSafeModal } from 'src/routes/safe/components/Settings/UpdateSafeModal' import { grantedSelector } from 'src/routes/safe/container/selector' import { updateSafe } from 'src/logic/safe/store/actions/updateSafe' -import { Icon, Link, Text } from '@gnosis.pm/safe-react-components' -import styled from 'styled-components' import { latestMasterContractVersionSelector, @@ -35,6 +35,7 @@ import { import { useAnalytics, SAFE_NAVIGATION_EVENT } from 'src/utils/googleAnalytics' import { fetchMasterCopies, MasterCopy, MasterCopyDeployer } from 'src/logic/contracts/api/masterCopies' import { getMasterCopyAddressFromProxyAddress } from 'src/logic/contracts/safeContracts' +import { LOADED_SAFE_KEY } from 'src/utils/constants' export const SAFE_NAME_INPUT_TEST_ID = 'safe-name-input' export const SAFE_NAME_SUBMIT_BTN_TEST_ID = 'change-safe-name-btn' @@ -70,7 +71,10 @@ const SafeDetails = (): React.ReactElement => { } const handleSubmit = (values) => { - dispatch(updateSafe({ address: safeAddress, name: values.safeName })) + // In case they set a name we assume the safe want to be stored even if it was opened via URL + dispatch( + updateSafe({ address: safeAddress, name: values.safeName, loadedViaUrl: values.safeName === LOADED_SAFE_KEY }), + ) const notification = getNotificationsFromTxType(TX_NOTIFICATION_TYPES.SAFE_NAME_CHANGE_TX) dispatch(enqueueSnackbar(enhanceSnackbarForAction(notification.afterExecution.noMoreConfirmationsNeeded))) diff --git a/src/routes/safe/components/Settings/index.tsx b/src/routes/safe/components/Settings/index.tsx index 9a3dc27e..8b72b285 100644 --- a/src/routes/safe/components/Settings/index.tsx +++ b/src/routes/safe/components/Settings/index.tsx @@ -26,7 +26,7 @@ import Row from 'src/components/layout/Row' import Span from 'src/components/layout/Span' import { addressBookSelector } from 'src/logic/addressBook/store/selectors' import { grantedSelector } from 'src/routes/safe/container/selector' -import { safeNeedsUpdateSelector, safeOwnersSelector } from 'src/logic/safe/store/selectors' +import { safeLoadedViaUrlSelector, safeNeedsUpdateSelector, safeOwnersSelector } from 'src/logic/safe/store/selectors' export const OWNERS_SETTINGS_TAB_TEST_ID = 'owner-settings-tab' @@ -41,6 +41,7 @@ const Settings: React.FC = () => { const classes = useStyles() const [state, setState] = useState(INITIAL_STATE) const owners = useSelector(safeOwnersSelector) + const isSafeLoadedViaUrl = useSelector(safeLoadedViaUrlSelector) const needsUpdate = useSelector(safeNeedsUpdateSelector) const granted = useSelector(grantedSelector) const addressBook = useSelector(addressBookSelector) @@ -66,10 +67,12 @@ const Settings: React.FC = () => { ) : ( <> - - Remove Safe - Trash Icon - + {!isSafeLoadedViaUrl && ( + + Remove Safe + Trash Icon + + )}