#386: Addressbook transaction details (#407)

* Development (#378)

* Adds cookie permissions to localStorage/redux state

* Adds action

* Adds files to git

* (fix) linting issues

* (update) flow-typed

* (update) .eslint and .flowconfig

* (add) cookie banner

* Finish cookie banner implementation

* (Add) checkbox's disabled style.

* Removes redux for cookiesStorage

* Fix cookieStore deletion

* Fixs cookies acceptance

* Fixs cookies banner verbiage
Fix "x" in wrong place for snackbar messages

* (remove) unused library

* Adds cookies utils
Replaces localStorage with cookies
Adds js-cookie

* (fix) added correct polished library and import, updated flow-typed

* (update) removed polish flow type, added js-cookie flow type

* Add link to cookie policy, use generic links for legal docs

* Remove link to cookie policy from sidebar, link cookie policy in the banner

* Let the user re-open the cookie banner

* remove withMutations from cookies reducer, move utils/cookies to logic/cookies

* Now the sidebar closes when the cookie banner is toggled

* Feature #169: Intercom (#301)

* Implements intercom
Adds REACT_APP_INTERCOM_ID_MAINNET and REACT_APP_INTERCOM_ID_RINKEBY env vars

* Adds .env.example

* Adds intercom env vars

* Updates env vars
Replaces "rinkeby" and "mainnet" with "non-production" and "production"

* Now loads intercom after the user accepted the analytics

* Add env variable for production intercom id

* Update .env.example

* Removes react-intercom
Fixs getIntercomId with default dev appID
Now loads intercom as script

* Renegerate flow-types

* Remove 'Hide zero balances' (#310)

* Use medium font size for 'select an asset' label (#312)

* Feature #272: Google Analytics (#299)

* Adds google analytics tracking for every route

* Adds cookies acceptance check before tracking

* Fix react-ga dependency

* Fix cookieStore deletion

* Merge with #189-cookie-banner

* Fixs react ga version
Refactored HOC with hooks

* Fix TYPO

* Fix path for cookies utils

* Fix imports

* remove flow type definition for polish

* Add GA ID log

* Fix load GA After cookies acceptance

* Feature #224: Activate tokens automatically (#300)

* Replace 'Manage Tokens' with 'Manage List'

* prevent 301 redirects

* Add `BLACKLISTED_TOKENS` key to persist through immortal

* Add store/action to extract _activate tokens by its balance_

- keeps already activated tokens
- discards blacklisted tokens
- adds tokens whose vales are bigger than zero and are not blacklisted

* Add `blacklistedTokens` list to safe's store

* Display activeTokensByBalance in 'Balances' screen

* Enable token's blacklisting functionality in Tokens List

* Retrieve balance from API

* Rename action to `activateTokensByBalance`

* Fix linting errors

- line too long
- required return

* Do not persist a separate list into `BLACKLISTED_TOKENS`

* Typo fix (#326)

* Fix security vulnerability: Remove uglifyjs, use terser plugin (#327)

* Remove uglifyjs, use terser plugin

* fix css-loader config

* Feature #256: Sticky header (#308)

* Add sticky header

* Remove react-headroom, set position to fixed for header

* Regenerate yarn lock

* Remove unused headroom style from root.scss

* Pull from dev, conflict fixes

* Update welcome text (#323)

* Feature #137: Tx list improvements (#222)

* Fix swapOwners threshold displayed as hex in tx list

* Refactor spinner in empty table

* Fix number of rows per page in table pagination

* Add use of EtherscanLink component

* Set short version of strings in tx list

* Adjust styles in tx list

* Add more styles to table

* WIP

* An attempt to fix #204 by showing UNKNOWN instead of failed to fetch token symbol

* Table pagination style fixes

* Show confirm transaction button in owner list

* Update dependencies

* Add confirmation icons to owner list in tx list

* exclude unneeded stuff from travis.yml

* Adds cookie permissions to localStorage/redux state

* Update dependencies

* Adds action

* Adds files to git

* (fix) linting issues

* (update) flow-typed

* (update) .eslint and .flowconfig

* (add) cookie banner

* Finish cookie banner implementation

* (Add) checkbox's disabled style.

* Removes redux for cookiesStorage

* Fix cookieStore deletion

* Increase TO_EXP for bignumber.js

* Fixs cookies acceptance

* Fixs cookies banner verbiage
Fix "x" in wrong place for snackbar messages

* (fix) added correct polished library and import, updated flow-typed

* (update) removed polish flow type, added js-cookie flow type

* Add link to cookie policy, use generic links for legal docs

* Remove link to cookie policy from sidebar, link cookie policy in the banner

* Mock Safe creation transaction

* Format code

* Fix break statement

* Remove deployment of storybook

* Let the user re-open the cookie banner

* Update tx status messages and visual confirmation progress

* Fix svg in tx confirmation progress

* Add styles to tx type in tx list

* Replace nonce in tx list with tx id

* Update opacity of cancelled tx

* Fix short version of address

* remove withMutations from cookies reducer, move utils/cookies to logic/cookies

* Now the sidebar closes when the cookie banner is toggled

* Fix styles in tx list

* Add Pending status in tx description

* (remove) unused library

* Adds cookies utils
Replaces localStorage with cookies
Adds js-cookie

* Set 25 rows per page in tx list by default

* Align tx table

* Adjust tx table and tx details borders

* Fix fetching transactions to show Safe creation tx alone

* Fix failed Safe creation transaction

* Add styles to tx data

* Refactor and fix owner list in transaction

* Refactor use of theme variables

* Remove storybook files

* Update dependencies

* Fix warnings

* Fix dependencies

* Update file-loader config

* Fix owner colors in the tx confirmation progress

* Fix transaction type icon height

* Tx list adjustments

* Update readme

* (Feature) Etherscan button icon (#331)

* (add) new open on etherscan button icon

* (remove) unused asset

* (fix) icon background

* Feature #239: Replace early access label with network label (#311)

* Remove early access label

* Revert "Remove early access label"

This reverts commit 34682f0f6d9c1974a6e45c2a31358864931d9c1e.

* Replace early access label with network label

* Capitalzie first letter of the network name

* Adds threshold update on checkAndUpdateSafe (#320)

* Feature #159: Pending transaction that requires user confirmation (#330)

* Creates a new notification: waitingConfirmation
Adds key as optional parameter for notification
Implemented getAwaitingTransactions to get the transactions that needs to be confirmed by the current user
Not fetchTransactions action also dispatch a notification for awaiting transactions
Improved performance of routes/safe/container/index to avoid re-rendering

* Removes notification logic on fetchTransactions
Adds notificationsMiddleware

* Moves fetchTransaction to container

* Removes unused param on fetchTransactions

* Fixs null safe check

* Fixs middleware declaration

* Removes lodash

* Changes cancelled transaction detection logic

* Feature #122: Multisig migration (#315)

* Adds query-string package.json
Parses query string on open layout

* Implements load all the values on openSafe view from param querys

* Adds query params validation

* Moves query parse logic to open.jsx

* Changes default no metamask component on open page

* Replaces global isNaN

* Fix threshold parsing validation

* Updates the welcome component with new verbiage for open

* Renames isOpenSafe to isOldMultisigMigration

* Merge branch 'development' of https://github.com/gnosis/safe-react into 122-multisig-migration

# Conflicts:
#	src/routes/open/components/Layout.jsx

* Merge branch 'development' of https://github.com/gnosis/safe-react into 159-pending-transactions

# Conflicts:
#	src/routes/safe/components/Transactions/index.jsx
#	yarn.lock

* set anonymizeIp to true (#335)

* Feature #180: Predict transaction nonce (#293)

* Dep bump

* Fetch transactions when safe view is mounted

* eslint fix

* Calculate new tx nonce from latest tx in service

* Fix tx cancellation, allow passing nonce to createTransaction

* dep bump

* Refactor createTransaction/processTransaction to use object as argument

* Adopting transactions table to new send tx flow with predicted nonces

* dep bump, disable esModule in file-loader options after new v5 release

* Don't show older tx annotation for already executed txs

* sort tx by nonce

* get new safe nonce after tx execution

* Bugfixes

* remove whitespace for showOlderTxAnnotation

* Feature #329: Rename to Multisig (#334)

* Rename to Multisig

* migration text fix

* replace safe for teams with multisig

* Fixs race condition (#341)

Fixs typo

* (Feature) Incoming transactions (#333)

* Add `blockNumber` to transactions model

* Create `incomingTransaction` node in store and load it along with `transactions`

* Add incoming transfers to the Transactions table

* Rename `transactionHash` to `executionTxHash` for better incoming/outgoing txs unification in Transactions table

* Add incoming transactions details

* Add transaction type icon in table row

* Add snackbar notification for incoming txs

* Make incoming transaction snackbar to show on any tab

* Use makeStyles hooks

* Fix incoming amounts conversion from wei

* Make concurrent promise calls

* Use date to calculate transactions ids

* Prevent repeating messages

- also move logic to display snack bar into the notifications middleware

* Merge transactions and incomingTxs to the transactions selector

* Show 'Multiple incoming transfers' if they are more than 3

* Prevent incoming transactions snack bar for first-timer users

* Set ID as the default order

* Use constant for _incoming_ type

* Feature #154: Fiat Balances (#290)

* Adds DropdownCurrency
Adds redux store for currencyValues
Adds Value column on the assets table
Adds mocked currency values

* (add) base currency dropdown

* (add) dropdown styles

* Refactors data fetching of the balances list
Now uses the endpoint

* Fix column value styling

* Adds support for ECB currency values

* Fixs list overflow

* Changes endpoint url
Adds decimals for balance values

* (fix) remove inline style

* (add) currencies dropdown search field

* (fix) list items' hover color

* Implements filter search

* Fix warning on dropdown template

* Saves selected currency in localStorage

* Remove spaces on curly braces
Add alt
Renames rowItem to cellItem
Improves fetchCurrenciesRates handling

* Removes withMutations

* Removes middleware
Export style to another file for dropdownCurrency

* Adds classNames

* Fix incomming transactions fetching (#346)

* Feature: Activate fortmatic (#339)

* Add fortmatic integration to web3connect

* add fortmatic

* Safe open form improvements: limit calling initContracts to 1 time

* update .env.example

* Feature #336: Confirmation required notification for non-owners fix (#338)

* Refactors grantedSelector with isUserOwner function
Checks if the user is owner of the safe before sending notification

* Adds safeParamAddressFromStateSelector
Refactors notificationsMiddleware with new selector

* Remove old size check

* safe notifications middleware fixes

* add apt-get update to travis yml

* (Fix) Incoming transactions inline-styles (#344)

* Remove inline styles

* Replace ternary with logical && operator

* use cn as shortcut for classnames

* Makes minMaxLength 2 to AddCustomToken (#363)

* Fixs ETH display on balances list (#360)

* Bug #348: Safelist entries get removed (#358)

* Fix balances saved to localStorage not in format [tokenAdd, balance] but [balance]

* Updates localStorage version value

* Use submission instead of execution date to sort outgoing txs (#364)

* Feature #190: Sidebar improvements (#347)

* Change icons
Adds checked icon

* Adds safeParamAddressFromStateSelector for get current safe selected
Implements check icon on sidebar

* Remove overflow on sidebar
Start alignments

* Removes headerPlaceholder

* Improves header

* Improves header

* Fix header style

* use sameAddress function to check address eqaulity when fetching transactions (#365)

* Bug #352: Owner shown multiple times (#367)

* Ensure lowercased string comparison for owners' addresses

* Use `sameAddress` for addresses comparison

* Use transaction value as a string (#369)

* Update isTokenTransfer to use value as a string

* Rename error message

* Update dependencies

* Refactor

* Fix alternative token abi and token address for incoming transactions (#373)

* Bug #313: Payload breaks ui (#371)

* Makes minMaxLength 2 to AddCustomToken

* Fix styling

* Fix typo

* Feature #200: Show version number (#370)

* Add `dotenv-expand` as a dependency

* Add app version to sidebar

* Add hardcoded latest safe version to env variables

* Add `semver` to compare current vs latest version

* Add Safe version to Safe Details

* Adjustments in version number

* Fix transaction description value (#377)

* Fix transaction description value

* Remove duplicated symbols

* fix checkAndUpdateSafe logic (#379)

* Update .env.example

* update package json version

* update package json version

* Fix app version in side bar

* add REACT_APP_APP_VERSION global env var

* add react_app_version to build script

* remove react_app_app_version from build-mainnet

* Adds basic addressBook table

* Implements redux and localStorage for addressBook

* Disables loading page on empty address book

* Fix address display

* Adds logic for add entry

* Implements update localStorage and redux state on new entry created

* Updates default row per page

* Renames createEntry modal to createEditEntryModal
Implements edit entry logic

* Fix save/edit entry notification verbiage

* Implements delete entry

* Finish delete entry implementation
Moves update/remove/add entry logic to redux

* Updates defaultRowsPerPage to 25

* Implements sendFunds modal within addressBook
Refactors safeSelector with safeParamAddressFromStateSelector

* Removes unused addressBook container

* Moves loadAddressBook to safeContainer
Adds <OwnerAddressTableCell/> in transaction details
Adds userName (if available) on OwnerAddressTableCell

* Removes unused pops
Renames AddressBookEntry with AddressBookEntry

* Replaces updateAddressBook with addAddressBook

* Fixs transaction details styling with OwnerAddressTableCell
Show menu off Edit/Add entry

* Implements logic to add/edit addressBook entry from transaction details

* Fix duplicated entry validation

* Fix edit entry

* Adds OwnerAddressTableCell in SettingsDescription and CustomDescription
Shows owners name in addressboko from owner lists

* Refactor redux addressBook, now saves the data for each safe

* Fix addressbook url

* Fix display addressbook names on transaction details

* Fix entry exists validation

* Refactors create/edit/delete entry, now the addressbook is global for all the safes

* Refactor, uses immutable

* Adds variable for hideBorderBottom

* Adds disabled bin icon
Disable the delete button for owner entries

* Adds getAddressBookListSelector

* Simplifies validator logic

* Makes AddressBookEntry an immutable js list

* Feedback fixes

Co-authored-by: Germán Martínez <germartinez@users.noreply.github.com>
Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com>
This commit is contained in:
Agustin Pane 2020-01-15 09:12:17 -03:00 committed by Mikhail Mikheev
parent f37c3f9e61
commit 08e00a65ab
14 changed files with 294 additions and 109 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ build_webpack/
build/
yarn-error.log
.env*
.idea/

View File

@ -1,29 +1,36 @@
// @flow
import React from 'react'
import { withStyles } from '@material-ui/core/styles'
import cn from 'classnames'
import Block from '~/components/layout/Block'
import Span from '~/components/layout/Span'
import CopyBtn from '~/components/CopyBtn'
import EtherscanBtn from '~/components/EtherscanBtn'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import { styles } from './style.js'
import EllipsisTransactionDetails from '~/routes/safe/components/AddressBook/EllipsisTransactionDetails'
import Span from '~/components/layout/Span'
type EtherscanLinkProps = {
type: 'tx' | 'address',
value: string,
cut?: number,
knownAddress?: boolean,
classes: Object,
}
const EtherscanLink = ({
type, value, cut, classes,
type, value, cut, classes, knownAddress,
}: EtherscanLinkProps) => (
<Block className={classes.etherscanLink}>
<Span size="md">
<Span
size="md"
className={cn(knownAddress && classes.addressParagraph)}
>
{cut ? shortVersionOf(value, cut) : value}
</Span>
<CopyBtn content={value} />
<EtherscanBtn type={type} value={value} />
{knownAddress !== undefined ? <EllipsisTransactionDetails knownAddress={knownAddress} address={value} /> : null}
</Block>
)

View File

@ -5,4 +5,7 @@ export const styles = () => ({
display: 'flex',
alignItems: 'center',
},
addressParagraph: {
fontSize: '13px',
},
})

View File

@ -1,6 +1,7 @@
// @flow
import { List, Map } from 'immutable'
import { createSelector, Selector } from 'reselect'
import { useSelector } from 'react-redux'
import { ADDRESS_BOOK_REDUCER_ID } from '~/logic/addressBook/store/reducer/addressBook'
import type { GlobalState } from '~/store'
import type { AddressBook } from '~/logic/addressBook/model/addressBook'
@ -32,3 +33,15 @@ export const getAddressBookListSelector: Selector<GlobalState, {}, List<AddressB
return result
},
)
export const getNameFromAddressBook = (userAddress: string): string | null => {
if (!userAddress) {
return null
}
const addressBook = useSelector(getAddressBook)
const result = addressBook.filter((addressBookItem) => addressBookItem.address === userAddress)
if (result.size > 0) {
return result.get(0).name
}
return null
}

View File

@ -19,3 +19,5 @@ export const saveAddressBook = async (addressBook: AddressBook) => {
}
export const getAddressesListFromAdbk = (addressBook: AddressBook) => Array.from(addressBook).map((entry) => entry.address)

View File

@ -35,6 +35,7 @@ type Props = {
newEntryModalHandler: Function,
editEntryModalHandler: Function,
entryToEdit?: AddressBookEntry,
newEntryDefaultAddress: string | null,
}
const CreateEditEntryModalComponent = ({
@ -43,6 +44,7 @@ const CreateEditEntryModalComponent = ({
classes,
newEntryModalHandler,
entryToEdit,
newEntryDefaultAddress,
editEntryModalHandler,
}: Props) => {
const onFormSubmitted = (values) => {
@ -98,7 +100,7 @@ const CreateEditEntryModalComponent = ({
text="Owner address*"
className={classes.addressInput}
testId={CREATE_ENTRY_INPUT_ADDRESS_ID}
defaultValue={entryToEdit ? entryToEdit.entry.address : undefined}
defaultValue={entryToEdit ? entryToEdit.entry.address : newEntryDefaultAddress}
/>
</Row>
</Block>

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fill-rule="evenodd">
<path fill="#B2B5B2" fill-rule="nonzero" d="M14 13h2V6h-5v2h2a1 1 0 0 1 1 1v4zM9 8V5a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1h-3v3a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1h3zm-2 2v7h5v-7H7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 351 B

View File

@ -0,0 +1,77 @@
// @flow
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { makeStyles } from '@material-ui/core/styles'
import MoreHorizIcon from '@material-ui/icons/MoreHoriz'
import Menu from '@material-ui/core/Menu'
import MenuItem from '@material-ui/core/MenuItem'
import ClickAwayListener from '@material-ui/core/ClickAwayListener'
import { Divider } from '@material-ui/core'
import { push } from 'connected-react-router'
import { xs } from '~/theme/variables'
import { safeParamAddressFromStateSelector } from '~/routes/safe/store/selectors'
import { SAFELIST_ADDRESS } from '~/routes/routes'
const useStyles = makeStyles({
container: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
cursor: 'pointer',
margin: `0 ${xs}`,
borderRadius: '50%',
transition: 'background-color .2s ease-in-out',
'&:hover': {
backgroundColor: '#F0EFEE',
},
},
increasedPopperZindex: {
zIndex: 2001,
},
})
type EllipsisTransactionDetailsProps = {
knownAddress: boolean,
address: string,
}
const EllipsisTransactionDetails = ({ knownAddress, address }: EllipsisTransactionDetailsProps) => {
const classes = useStyles()
const [anchorEl, setAnchorEl] = React.useState(null)
const dispatch = useDispatch()
const currentSafeAddress = useSelector(safeParamAddressFromStateSelector)
const handleClick = (event) => {
setAnchorEl(event.currentTarget)
}
const closeMenuHandler = () => setAnchorEl(null)
const addOrEditEntryHandler = () => {
dispatch(push(`${SAFELIST_ADDRESS}/${currentSafeAddress}/address-book?entryAddress=${address}`))
closeMenuHandler()
}
return (
<ClickAwayListener onClickAway={closeMenuHandler}>
<div className={classes.container} onClick={handleClick}>
<MoreHorizIcon />
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={closeMenuHandler}
>
<MenuItem onClick={closeMenuHandler} disabled>Send Again</MenuItem>
<Divider />
{ knownAddress ? <MenuItem onClick={addOrEditEntryHandler}>Edit Address book Entry</MenuItem> : <MenuItem onClick={addOrEditEntryHandler}>Add to address book</MenuItem>}
</Menu>
</div>
</ClickAwayListener>
)
}
export default EllipsisTransactionDetails

View File

@ -1,5 +1,5 @@
// @flow
import React, { useState } from 'react'
import React, { useState, useEffect } from 'react'
import cn from 'classnames'
import { List } from 'immutable'
@ -40,7 +40,7 @@ import { updateAddressBookEntry } from '~/logic/addressBook/store/actions/update
import { removeAddressBookEntry } from '~/logic/addressBook/store/actions/removeAddressBookEntry'
import { addAddressBookEntry } from '~/logic/addressBook/store/actions/addAddressBookEntry'
import SendModal from '~/routes/safe/components/Balances/SendModal'
import { safeSelector, safesListSelector } from '~/routes/safe/store/selectors'
import { safeSelector, safesListSelector, addressBookQueryParamsSelector } from '~/routes/safe/store/selectors'
import { extendedSafeTokensSelector } from '~/routes/safe/container/selector'
import { isUserOwnerOnAnySafe } from '~/logic/wallets/ethAddresses'
@ -59,6 +59,31 @@ const AddressBookTable = ({ classes }: Props) => {
)
const [deleteEntryModalOpen, setDeleteEntryModalOpen] = useState(false)
const [sendFundsModalOpen, setSendFundsModalOpen] = useState(false)
const [defaultNewEntryAddress, setDefaultNewEntryAddress] = useState(null)
const entryAddressToEditOrCreateNew = useSelector(addressBookQueryParamsSelector)
useEffect(() => {
if (entryAddressToEditOrCreateNew) {
setEditCreateEntryModalOpen(true)
}
}, [])
useEffect(() => {
if (entryAddressToEditOrCreateNew) {
const key = addressBook.findKey((entry) => entry.address === entryAddressToEditOrCreateNew)
if (key >= 0) {
// Edit old entry
const value = addressBook.get(key)
setSelectedEntry({ entry: value, index: key })
} else {
// Create new entry
setDefaultNewEntryAddress(entryAddressToEditOrCreateNew)
setSelectedEntry(null)
}
}
},
[addressBook])
const safe = useSelector(safeSelector)
const safesList = useSelector(safesListSelector)
@ -68,6 +93,7 @@ const AddressBookTable = ({ classes }: Props) => {
const newEntryModalHandler = (entry: AddressBookEntry) => {
setEditCreateEntryModalOpen(false)
dispatch(addAddressBookEntry(entry))
setDefaultNewEntryAddress(null)
}
const editEntryModalHandler = (entry: AddressBookEntry) => {
@ -198,6 +224,7 @@ const AddressBookTable = ({ classes }: Props) => {
newEntryModalHandler={newEntryModalHandler}
editEntryModalHandler={editEntryModalHandler}
entryToEdit={selectedEntry}
newEntryDefaultAddress={defaultNewEntryAddress}
/>
<DeleteEntryModal
onClose={() => setDeleteEntryModalOpen(false)}

View File

@ -8,16 +8,21 @@ import EtherScanLink from '~/components/EtherscanLink'
type Props = {
address: string,
showLinks?: boolean,
knownAddress?: boolean,
userName?: boolean,
}
const OwnerAddressTableCell = (props: Props) => {
const { address, showLinks } = props
const {
address, userName, showLinks, knownAddress,
} = props
return (
<Block justify="left">
<Identicon address={address} diameter={32} />
{ showLinks ? (
<div style={{ marginLeft: 10 }}>
<EtherScanLink type="address" value={address} />
{ userName }
<EtherScanLink type="address" value={address} knownAddress={knownAddress} />
</div>
) : <Paragraph style={{ marginLeft: 10 }}>{address}</Paragraph> }
</Block>

View File

@ -7,12 +7,17 @@ import EtherscanLink from '~/components/EtherscanLink'
import Block from '~/components/layout/Block'
import { md, lg } from '~/theme/variables'
import { getIncomingTxAmount } from '~/routes/safe/components/Transactions/TxsTable/columns'
import OwnerAddressTableCell from '~/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell'
import { getNameFromAddressBook } from '~/logic/addressBook/store/selectors'
export const TRANSACTIONS_DESC_INCOMING_TEST_ID = 'tx-description-incoming'
const useStyles = makeStyles({
txDataContainer: {
padding: `${lg} ${md}`,
paddingTop: lg,
paddingLeft: md,
paddingBottom: md,
borderRight: '2px solid rgb(232, 231, 230)',
},
})
@ -24,9 +29,10 @@ type Props = {
type TransferDescProps = {
value: string,
from: string,
txFromName?: string,
}
const TransferDescription = ({ value = '', from }: TransferDescProps) => (
const TransferDescription = ({ value = '', from, txFromName }: TransferDescProps) => (
<Block data-testid={TRANSACTIONS_DESC_INCOMING_TEST_ID}>
<Bold>
Received
@ -36,16 +42,18 @@ const TransferDescription = ({ value = '', from }: TransferDescProps) => (
from:
</Bold>
<br />
<EtherscanLink type="address" value={from} />
{txFromName ? <OwnerAddressTableCell address={from} showLinks userName={txFromName} knownAddress />
: <EtherscanLink type="address" value={from} knownAddress={false} />}
</Block>
)
const IncomingTxDescription = ({ tx }: Props) => {
const classes = useStyles()
const txFromName = getNameFromAddressBook(tx.from)
return (
<Block className={classes.txDataContainer}>
<TransferDescription value={getIncomingTxAmount(tx)} from={tx.from} />
<TransferDescription value={getIncomingTxAmount(tx)} from={tx.from} txFromName={txFromName} />
</Block>
)
}

View File

@ -12,6 +12,8 @@ import { styles } from './style'
import ConfirmSmallGreyIcon from './assets/confirm-small-grey.svg'
import ConfirmSmallGreenIcon from './assets/confirm-small-green.svg'
import ConfirmSmallFilledIcon from './assets/confirm-small-filled.svg'
import { getNameFromAddressBook } from '~/logic/addressBook/store/selectors'
export const CONFIRM_TX_BTN_TEST_ID = 'confirm-btn'
export const EXECUTE_TX_BTN_TEST_ID = 'execute-btn'
@ -40,65 +42,69 @@ const OwnerComponent = ({
executor,
confirmed,
thresholdReached,
}: OwnerProps) => (
<Block className={classes.container}>
<div
className={
confirmed || thresholdReached || executor
? classes.verticalLineProgressDone
: classes.verticalLineProgressPending
}
/>
<div className={classes.iconState}>
{confirmed ? (
<Img src={ConfirmSmallFilledIcon} />
) : thresholdReached || executor ? (
<Img src={ConfirmSmallGreenIcon} />
) : (
<Img src={ConfirmSmallGreyIcon} />
)}
</div>
<Identicon address={owner.address} diameter={32} className={classes.icon} />
<Block>
<Paragraph className={classes.name} noMargin>
{owner.name}
</Paragraph>
<EtherscanLink
className={classes.address}
type="address"
value={owner.address}
cut={4}
}: OwnerProps) => {
const nameInAdbk = getNameFromAddressBook(owner.address)
const ownerName = owner.name === 'UNKNOWN' && nameInAdbk ? nameInAdbk : owner.name
return (
<Block className={classes.container}>
<div
className={
confirmed || thresholdReached || executor
? classes.verticalLineProgressDone
: classes.verticalLineProgressPending
}
/>
<div className={classes.iconState}>
{confirmed ? (
<Img src={ConfirmSmallFilledIcon} />
) : thresholdReached || executor ? (
<Img src={ConfirmSmallGreenIcon} />
) : (
<Img src={ConfirmSmallGreyIcon} />
)}
</div>
<Identicon address={owner.address} diameter={32} className={classes.icon} />
<Block>
<Paragraph className={classes.name} noMargin>
{ownerName}
</Paragraph>
<EtherscanLink
className={classes.address}
type="address"
value={owner.address}
cut={4}
/>
</Block>
<Block className={classes.spacer} />
{showConfirmBtn && owner.address === userAddress && (
<Button
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
onClick={onTxConfirm}
testId={CONFIRM_TX_BTN_TEST_ID}
>
Confirm tx
</Button>
)}
{showExecuteBtn && owner.address === userAddress && (
<Button
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
onClick={onTxExecute}
testId={EXECUTE_TX_BTN_TEST_ID}
>
Execute tx
</Button>
)}
{owner.address === executor && (
<Block className={classes.executor}>Executor</Block>
)}
</Block>
<Block className={classes.spacer} />
{showConfirmBtn && owner.address === userAddress && (
<Button
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
onClick={onTxConfirm}
testId={CONFIRM_TX_BTN_TEST_ID}
>
Confirm tx
</Button>
)}
{showExecuteBtn && owner.address === userAddress && (
<Button
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
onClick={onTxExecute}
testId={EXECUTE_TX_BTN_TEST_ID}
>
Execute tx
</Button>
)}
{owner.address === executor && (
<Block className={classes.executor}>Executor</Block>
)}
</Block>
)
)
}
export default withStyles(styles)(OwnerComponent)

View File

@ -11,6 +11,9 @@ import { md, lg } from '~/theme/variables'
import { getTxData } from './utils'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import LinkWithRef from '~/components/layout/Link'
import OwnerAddressTableCell from '~/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell'
import { getNameFromAddressBook } from '~/logic/addressBook/store/selectors'
export const TRANSACTIONS_DESC_ADD_OWNER_TEST_ID = 'tx-description-add-owner'
export const TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID = 'tx-description-remove-owner'
@ -21,7 +24,9 @@ export const TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID = 'tx-description-custom-data
export const styles = () => ({
txDataContainer: {
padding: `${lg} ${md}`,
paddingTop: lg,
paddingLeft: md,
paddingBottom: md,
},
txData: {
wordBreak: 'break-all',
@ -58,48 +63,62 @@ type CustomDescProps = {
classes: Object,
}
const TransferDescription = ({ amount = '', recipient }: TransferDescProps) => (
<Block data-testid={TRANSACTIONS_DESC_SEND_TEST_ID}>
<Bold>
Send
{' '}
{amount}
{' '}
to:
</Bold>
<EtherscanLink type="address" value={recipient} />
</Block>
)
const TransferDescription = ({ amount = '', recipient }: TransferDescProps) => {
const recipientName = getNameFromAddressBook(recipient)
return (
<Block data-testid={TRANSACTIONS_DESC_SEND_TEST_ID}>
<Bold>
Send
{' '}
{amount}
{' '}
to:
</Bold>
{recipientName ? <OwnerAddressTableCell address={recipient} showLinks knownAddress userName={recipientName} />
: <EtherscanLink type="address" value={recipient} knownAddress={false} />}
</Block>
)
}
const SettingsDescription = ({ removedOwner, addedOwner, newThreshold }: DescriptionDescProps) => (
<>
{removedOwner && (
<Block data-testid={TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID}>
<Bold>Remove owner:</Bold>
<EtherscanLink type="address" value={removedOwner} />
</Block>
)}
{addedOwner && (
<Block data-testid={TRANSACTIONS_DESC_ADD_OWNER_TEST_ID}>
<Bold>Add owner:</Bold>
<EtherscanLink type="address" value={addedOwner} />
</Block>
)}
{newThreshold && (
<Block data-testid={TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID}>
<Bold>Change required confirmations:</Bold>
<Paragraph size="md" noMargin>
{newThreshold}
</Paragraph>
</Block>
)}
</>
)
const SettingsDescription = ({
removedOwner, addedOwner, newThreshold,
}: DescriptionDescProps) => {
const ownerChangedName = removedOwner ? getNameFromAddressBook(removedOwner) : getNameFromAddressBook(addedOwner)
return (
<>
{removedOwner && (
<Block data-testid={TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID}>
<Bold>Remove owner:</Bold>
{ownerChangedName
? <OwnerAddressTableCell address={removedOwner} showLinks knownAddress userName={ownerChangedName} />
: <EtherscanLink type="address" value={removedOwner} knownAddress={false} />}
</Block>
)}
{addedOwner && (
<Block data-testid={TRANSACTIONS_DESC_ADD_OWNER_TEST_ID}>
<Bold>Add owner:</Bold>
{ownerChangedName
? <OwnerAddressTableCell address={addedOwner} showLinks knownAddress userName={ownerChangedName} />
: <EtherscanLink type="address" value={addedOwner} knownAddress={false} />}
</Block>
)}
{newThreshold && (
<Block data-testid={TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID}>
<Bold>Change required confirmations:</Bold>
<Paragraph size="md" noMargin>
{newThreshold}
</Paragraph>
</Block>
)}
</>
)
}
const CustomDescription = ({
data, amount = 0, recipient, classes,
}: CustomDescProps) => {
const [showTxData, setShowTxData] = useState(false)
const recipientName = getNameFromAddressBook(recipient)
return (
<>
<Block data-testid={TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID}>
@ -110,7 +129,7 @@ const CustomDescription = ({
{' '}
to:
</Bold>
<EtherscanLink type="address" value={recipient} />
{ recipientName ? <OwnerAddressTableCell address={recipient} showLinks knownAddress userName={recipientName} /> : <EtherscanLink type="address" value={recipient} knownAddress={false} />}
</Block>
<Block className={classes.txData} data-testid={TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID}>
<Bold>Data (hex encoded):</Bold>

View File

@ -70,6 +70,16 @@ export const safeTransactionsSelector: Selector<GlobalState, RouterProps, List<T
},
)
export const addressBookQueryParamsSelector = (state: GlobalState): string => {
const { location } = state.router
let entryAddressToEditOrCreateNew = null
if (location && location.query) {
const { entryAddress } = location.query
entryAddressToEditOrCreateNew = entryAddress
}
return entryAddressToEditOrCreateNew
}
export const safeParamAddressFromStateSelector = (state: GlobalState): string => {
const match = matchPath(
state.router.location.pathname,