mirror of
https://github.com/status-im/safe-react.git
synced 2025-01-11 18:44:07 +00:00
Development (#368)
* 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)
This commit is contained in:
parent
fff057d8e6
commit
c593c8edaa
20
package.json
20
package.json
@ -31,18 +31,18 @@
|
||||
"dependencies": {
|
||||
"@gnosis.pm/safe-contracts": "1.0.0",
|
||||
"@gnosis.pm/util-contracts": "2.0.4",
|
||||
"@material-ui/core": "4.7.2",
|
||||
"@material-ui/core": "4.8.0",
|
||||
"@material-ui/icons": "4.5.1",
|
||||
"@portis/web3": "^2.0.0-beta.45",
|
||||
"@testing-library/jest-dom": "4.2.4",
|
||||
"@toruslabs/torus-embed": "0.2.9",
|
||||
"@toruslabs/torus-embed": "0.2.10",
|
||||
"@walletconnect/web3-provider": "^1.0.0-beta.37",
|
||||
"@welldone-software/why-did-you-render": "3.3.9",
|
||||
"@welldone-software/why-did-you-render": "3.4.1",
|
||||
"axios": "0.19.0",
|
||||
"bignumber.js": "9.0.0",
|
||||
"connected-react-router": "6.6.1",
|
||||
"date-fns": "2.8.1",
|
||||
"currency-flags": "^2.1.1",
|
||||
"date-fns": "2.8.1",
|
||||
"dotenv": "^8.2.0",
|
||||
"ethereum-ens": "0.7.8",
|
||||
"final-form": "4.18.6",
|
||||
@ -102,7 +102,7 @@
|
||||
"@babel/preset-env": "7.7.6",
|
||||
"@babel/preset-flow": "7.7.4",
|
||||
"@babel/preset-react": "7.7.4",
|
||||
"@testing-library/react": "9.3.3",
|
||||
"@testing-library/react": "9.4.0",
|
||||
"autoprefixer": "9.7.3",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"babel-eslint": "10.0.3",
|
||||
@ -113,7 +113,7 @@
|
||||
"babel-plugin-transform-es3-property-literals": "^6.22.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"classnames": "^2.2.6",
|
||||
"css-loader": "3.3.0",
|
||||
"css-loader": "3.3.2",
|
||||
"detect-port": "^1.3.0",
|
||||
"eslint": "6.7.2",
|
||||
"eslint-config-airbnb": "18.0.1",
|
||||
@ -125,7 +125,7 @@
|
||||
"ethereumjs-abi": "0.6.8",
|
||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||
"file-loader": "5.0.2",
|
||||
"flow-bin": "0.113.0",
|
||||
"flow-bin": "0.114.0",
|
||||
"fs-extra": "8.1.0",
|
||||
"html-loader": "^0.5.5",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
@ -140,12 +140,12 @@
|
||||
"prettier-eslint-cli": "5.0.0",
|
||||
"run-with-testrpc": "0.3.1",
|
||||
"style-loader": "1.0.1",
|
||||
"terser-webpack-plugin": "2.2.3",
|
||||
"truffle": "5.1.3",
|
||||
"terser-webpack-plugin": "2.3.0",
|
||||
"truffle": "5.1.4",
|
||||
"truffle-contract": "4.0.31",
|
||||
"truffle-solidity-loader": "0.1.32",
|
||||
"url-loader": "3.0.0",
|
||||
"webpack": "4.41.2",
|
||||
"webpack": "4.41.3",
|
||||
"webpack-bundle-analyzer": "3.6.0",
|
||||
"webpack-cli": "3.3.10",
|
||||
"webpack-dev-server": "3.9.0",
|
||||
|
3
src/assets/icons/check.svg
Normal file
3
src/assets/icons/check.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="14" viewBox="0 0 18 14">
|
||||
<path fill="#008C73" fill-rule="evenodd" d="M5.6 10.6L1.4 6.4 0 7.8l5.6 5.6 12-12L16.2 0z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 188 B |
3
src/assets/icons/shape.svg
Normal file
3
src/assets/icons/shape.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="15" viewBox="0 0 20 15">
|
||||
<path fill="#B2B5B2" fill-rule="evenodd" d="M3 8l-1.562.01a.5.5 0 0 1-.315-.89L9.969.036 10 0l.007.006.008-.006.03.037 8.845 7.091a.5.5 0 0 1-.313.89H17V15h-6v-5H9v5H3V8zm2-1.624V13h2V8h6v5h2V6.61L9.975 2.55 5 6.377z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 315 B |
@ -45,7 +45,6 @@ const SafeListHeader = ({ safesCount }: Props) => {
|
||||
return (
|
||||
<Col start="xs" middle="xs" className={classes.container}>
|
||||
Safes
|
||||
{' '}
|
||||
<Paragraph size="xs" className={classes.counter}>
|
||||
{safesCount}
|
||||
</Paragraph>
|
||||
|
@ -4,20 +4,23 @@ import { makeStyles } from '@material-ui/core/styles'
|
||||
import Img from '~/components/layout/Img'
|
||||
import Block from '~/components/layout/Block'
|
||||
import Paragraph from '~/components/layout/Paragraph'
|
||||
import { primary, sm } from '~/theme/variables'
|
||||
import StarIcon from './assets/star.svg'
|
||||
import { primary, secondaryBackground, md } from '~/theme/variables'
|
||||
import HomeIcon from '~/assets/icons/shape.svg'
|
||||
|
||||
const useStyles = makeStyles({
|
||||
container: {
|
||||
background: primary,
|
||||
background: secondaryBackground,
|
||||
padding: '5px',
|
||||
boxSizing: 'border-box',
|
||||
width: '73px',
|
||||
width: '76px',
|
||||
justifyContent: 'space-around',
|
||||
marginLeft: sm,
|
||||
marginLeft: md,
|
||||
color: '#fff',
|
||||
borderRadius: '3px',
|
||||
},
|
||||
defaultText: {
|
||||
color: primary,
|
||||
},
|
||||
})
|
||||
|
||||
const DefaultBadge = () => {
|
||||
@ -25,9 +28,9 @@ const DefaultBadge = () => {
|
||||
|
||||
return (
|
||||
<Block justify="left" className={classes.container}>
|
||||
<Img src={StarIcon} alt="Star Icon" />
|
||||
<Paragraph noMargin size="xs">
|
||||
default
|
||||
<Img src={HomeIcon} alt="Home Icon" />
|
||||
<Paragraph noMargin size="xs" className={classes.defaultText}>
|
||||
Default
|
||||
</Paragraph>
|
||||
</Block>
|
||||
)
|
||||
|
@ -12,18 +12,21 @@ import Paragraph from '~/components/layout/Paragraph'
|
||||
import ButtonLink from '~/components/layout/ButtonLink'
|
||||
import Identicon from '~/components/Identicon'
|
||||
import {
|
||||
mediumFontSize, sm, secondary, primary,
|
||||
mediumFontSize, sm, primary, disabled, md,
|
||||
} from '~/theme/variables'
|
||||
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
||||
import { shortVersionOf, sameAddress } from '~/logic/wallets/ethAddresses'
|
||||
import { type Safe } from '~/routes/safe/store/models/safe'
|
||||
import { SAFELIST_ADDRESS } from '~/routes/routes'
|
||||
import DefaultBadge from './DefaultBadge'
|
||||
import Img from '~/components/layout/Img'
|
||||
import check from '~/assets/icons/check.svg'
|
||||
|
||||
export const SIDEBAR_SAFELIST_ROW_TESTID = 'SIDEBAR_SAFELIST_ROW_TESTID'
|
||||
|
||||
type SafeListProps = {
|
||||
safes: List<Safe>,
|
||||
currentSafe: string,
|
||||
onSafeClick: Function,
|
||||
setDefaultSafe: Function,
|
||||
defaultSafe: string,
|
||||
@ -33,9 +36,12 @@ const useStyles = makeStyles({
|
||||
icon: {
|
||||
marginRight: sm,
|
||||
},
|
||||
checkIcon: {
|
||||
marginRight: '10px',
|
||||
},
|
||||
list: {
|
||||
overflow: 'hidden',
|
||||
overflowY: 'scroll',
|
||||
overflowY: 'hidden',
|
||||
padding: 0,
|
||||
height: '100%',
|
||||
},
|
||||
@ -50,21 +56,25 @@ const useStyles = makeStyles({
|
||||
},
|
||||
},
|
||||
safeName: {
|
||||
color: secondary,
|
||||
color: primary,
|
||||
},
|
||||
safeAddress: {
|
||||
color: primary,
|
||||
color: disabled,
|
||||
fontSize: mediumFontSize,
|
||||
},
|
||||
makeDefaultBtn: {
|
||||
padding: 0,
|
||||
marginLeft: sm,
|
||||
marginLeft: md,
|
||||
visibility: 'hidden',
|
||||
},
|
||||
noIcon: {
|
||||
visibility: 'hidden',
|
||||
width: '28px',
|
||||
},
|
||||
})
|
||||
|
||||
const SafeList = ({
|
||||
safes, onSafeClick, setDefaultSafe, defaultSafe,
|
||||
safes, onSafeClick, setDefaultSafe, defaultSafe, currentSafe,
|
||||
}: SafeListProps) => {
|
||||
const classes = useStyles()
|
||||
|
||||
@ -78,6 +88,11 @@ const SafeList = ({
|
||||
data-testid={SIDEBAR_SAFELIST_ROW_TESTID}
|
||||
>
|
||||
<ListItem classes={{ root: classes.listItemRoot }}>
|
||||
{ sameAddress(currentSafe, safe.address) ? (
|
||||
<ListItemIcon>
|
||||
<Img src={check} alt="check" className={classes.checkIcon} />
|
||||
</ListItemIcon>
|
||||
) : <div className={classes.noIcon}>placeholder</div> }
|
||||
<ListItemIcon>
|
||||
<Identicon address={safe.address} diameter={32} className={classes.icon} />
|
||||
</ListItemIcon>
|
||||
|
@ -14,19 +14,21 @@ import Hairline from '~/components/layout/Hairline'
|
||||
import Row from '~/components/layout/Row'
|
||||
import { WELCOME_ADDRESS } from '~/routes/routes'
|
||||
import { type Safe } from '~/routes/safe/store/models/safe'
|
||||
import { defaultSafeSelector } from '~/routes/safe/store/selectors'
|
||||
import {
|
||||
defaultSafeSelector,
|
||||
safeParamAddressFromStateSelector,
|
||||
} from '~/routes/safe/store/selectors'
|
||||
import setDefaultSafe from '~/routes/safe/store/actions/setDefaultSafe'
|
||||
import { sortedSafeListSelector } from './selectors'
|
||||
import SafeList from './SafeList'
|
||||
import LegalLinks from './LegalLinks'
|
||||
import useSidebarStyles from './style'
|
||||
|
||||
|
||||
const { useState, useEffect, useMemo } = React
|
||||
|
||||
type TSidebarContext = {
|
||||
isOpen: boolean,
|
||||
toggleSidebar: Function,
|
||||
toggleSidebar: Function
|
||||
}
|
||||
|
||||
export const SidebarContext = React.createContext<TSidebarContext>({
|
||||
@ -39,6 +41,7 @@ type SidebarProps = {
|
||||
safes: List<Safe>,
|
||||
setDefaultSafeAction: Function,
|
||||
defaultSafe: string,
|
||||
currentSafe: string
|
||||
}
|
||||
|
||||
const filterBy = (filter: string, safes: List<Safe>): List<Safe> => safes.filter(
|
||||
@ -48,7 +51,11 @@ const filterBy = (filter: string, safes: List<Safe>): List<Safe> => safes.filter
|
||||
)
|
||||
|
||||
const Sidebar = ({
|
||||
children, safes, setDefaultSafeAction, defaultSafe,
|
||||
children,
|
||||
safes,
|
||||
setDefaultSafeAction,
|
||||
defaultSafe,
|
||||
currentSafe,
|
||||
}: SidebarProps) => {
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false)
|
||||
const [filter, setFilter] = useState<string>('')
|
||||
@ -97,7 +104,6 @@ const Sidebar = ({
|
||||
classes={{ paper: classes.sidebarPaper }}
|
||||
ModalProps={{ onBackdropClick: toggleSidebar }}
|
||||
>
|
||||
<div className={classes.headerPlaceholder} />
|
||||
<Row align="center">
|
||||
<SearchIcon className={classes.searchIcon} />
|
||||
<SearchBar
|
||||
@ -108,7 +114,6 @@ const Sidebar = ({
|
||||
onCancelSearch={handleFilterCancel}
|
||||
value={filter}
|
||||
/>
|
||||
<Spacer />
|
||||
<Divider />
|
||||
<Spacer />
|
||||
<Button
|
||||
@ -130,6 +135,7 @@ const Sidebar = ({
|
||||
onSafeClick={toggleSidebar}
|
||||
setDefaultSafe={setDefaultSafeAction}
|
||||
defaultSafe={defaultSafe}
|
||||
currentSafe={currentSafe}
|
||||
/>
|
||||
<LegalLinks toggleSidebar={toggleSidebar} />
|
||||
</Drawer>
|
||||
@ -141,6 +147,10 @@ const Sidebar = ({
|
||||
|
||||
export default connect<Object, Object, ?Function, ?Object>(
|
||||
// $FlowFixMe
|
||||
(state) => ({ safes: sortedSafeListSelector(state), defaultSafe: defaultSafeSelector(state) }),
|
||||
(state) => ({
|
||||
safes: sortedSafeListSelector(state),
|
||||
defaultSafe: defaultSafeSelector(state),
|
||||
currentSafe: safeParamAddressFromStateSelector(state),
|
||||
}),
|
||||
{ setDefaultSafeAction: setDefaultSafe },
|
||||
)(Sidebar)
|
||||
|
@ -5,13 +5,24 @@ import {
|
||||
} from '~/theme/variables'
|
||||
|
||||
const sidebarWidth = '400px'
|
||||
const sidebarMarginLeft = '12px'
|
||||
const sidebarMarginTop = '12px'
|
||||
const sidebarMarginBottom = '12px'
|
||||
const sidebarBorderRadius = '8px'
|
||||
|
||||
const useSidebarStyles = makeStyles({
|
||||
sidebar: {
|
||||
width: sidebarWidth,
|
||||
marginLeft: sidebarMarginLeft,
|
||||
borderRadius: sidebarBorderRadius,
|
||||
top: sidebarMarginTop,
|
||||
},
|
||||
sidebarPaper: {
|
||||
width: sidebarWidth,
|
||||
marginLeft: sidebarMarginLeft,
|
||||
top: `calc(${headerHeight} + ${sidebarMarginTop})`,
|
||||
maxHeight: `calc(100vh - ${headerHeight} - ${sidebarMarginTop} - ${sidebarMarginBottom})`,
|
||||
borderRadius: sidebarBorderRadius,
|
||||
},
|
||||
headerPlaceholder: {
|
||||
minHeight: headerHeight,
|
||||
@ -37,7 +48,7 @@ const useSidebarStyles = makeStyles({
|
||||
},
|
||||
},
|
||||
searchContainer: {
|
||||
width: '180px',
|
||||
width: '190px',
|
||||
marginLeft: xs,
|
||||
marginRight: xs,
|
||||
},
|
||||
|
@ -25,22 +25,29 @@ const activateTokensByBalance = (safeAddress: string) => async (
|
||||
// balances: tokens' balance returned by the backend
|
||||
const { addresses, balances } = result.data.reduce((acc, { tokenAddress, balance }) => ({
|
||||
addresses: [...acc.addresses, tokenAddress],
|
||||
balances: [...acc.balances, balance],
|
||||
}), { addresses: [], balances: [] })
|
||||
balances: [[tokenAddress, balance]],
|
||||
}), {
|
||||
addresses: [],
|
||||
balances: [],
|
||||
})
|
||||
|
||||
// update balance list for the safe
|
||||
dispatch(updateSafe({ address: safeAddress, balances: Set(balances) }))
|
||||
dispatch(updateSafe({
|
||||
address: safeAddress,
|
||||
balances: Set(balances),
|
||||
}))
|
||||
|
||||
// active tokens by balance, excluding those already blacklisted and the `null` address
|
||||
const activeByBalance = addresses.filter((address) => address !== null && !blacklistedTokens.includes(address))
|
||||
|
||||
// need to persist those already active tokens, despite its balances
|
||||
const activeTokens = alreadyActiveTokens.toSet().union(activeByBalance)
|
||||
const activeTokens = alreadyActiveTokens.toSet()
|
||||
.union(activeByBalance)
|
||||
|
||||
// update list of active tokens
|
||||
dispatch(updateActiveTokens(safeAddress, activeTokens))
|
||||
} catch (err) {
|
||||
console.error('Error fetching token list', err)
|
||||
console.error('Error fetching active token list', err)
|
||||
}
|
||||
|
||||
return null
|
||||
|
@ -158,7 +158,7 @@ const AddCustomToken = (props: Props) => {
|
||||
name="symbol"
|
||||
component={TextField}
|
||||
type="text"
|
||||
validate={composeValidators(required, minMaxLength(3, 12))}
|
||||
validate={composeValidators(required, minMaxLength(2, 12))}
|
||||
placeholder="Token symbol*"
|
||||
text="Token symbol"
|
||||
className={classes.addressInput}
|
||||
|
@ -1,11 +1,16 @@
|
||||
// @flow
|
||||
import { List } from 'immutable'
|
||||
import { type Token } from '~/logic/tokens/store/model/token'
|
||||
import { buildOrderFieldFrom, FIXED, type SortRow } from '~/components/Table/sorting'
|
||||
import {
|
||||
buildOrderFieldFrom,
|
||||
FIXED,
|
||||
type SortRow,
|
||||
} from '~/components/Table/sorting'
|
||||
import { type Column } from '~/components/Table/TableHead'
|
||||
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
||||
import type { BalanceCurrencyType } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import { ETH_ADDRESS } from '~/logic/tokens/utils/tokenHelpers'
|
||||
|
||||
export const BALANCE_TABLE_ASSET_ID = 'asset'
|
||||
export const BALANCE_TABLE_BALANCE_ID = 'balance'
|
||||
@ -13,19 +18,35 @@ export const BALANCE_TABLE_VALUE_ID = 'value'
|
||||
|
||||
type BalanceData = {
|
||||
asset: Object,
|
||||
balance: string,
|
||||
balance: string
|
||||
}
|
||||
|
||||
export type BalanceRow = SortRow<BalanceData>
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
const getTokenPriceInCurrency = (token: Token, currencySelected: AVAILABLE_CURRENCIES, currencyValues: List<BalanceCurrencyType>): string => {
|
||||
const getTokenPriceInCurrency = (
|
||||
token: Token,
|
||||
currencySelected: typeof AVAILABLE_CURRENCIES,
|
||||
currencyValues: List<BalanceCurrencyType>,
|
||||
): string => {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
|
||||
for (const tokenPriceIterator of currencyValues) {
|
||||
const { tokenAddress, balanceInSelectedCurrency, currencyName } = tokenPriceIterator
|
||||
const {
|
||||
tokenAddress,
|
||||
balanceInSelectedCurrency,
|
||||
currencyName,
|
||||
} = tokenPriceIterator
|
||||
if (token.address === tokenAddress && currencySelected === currencyName) {
|
||||
const balance = balanceInSelectedCurrency ? parseFloat(balanceInSelectedCurrency, 10).toFixed(2) : balanceInSelectedCurrency
|
||||
const balance = balanceInSelectedCurrency
|
||||
? parseFloat(balanceInSelectedCurrency, 10).toFixed(2)
|
||||
: balanceInSelectedCurrency
|
||||
return `${balance} ${currencySelected}`
|
||||
}
|
||||
// ETH token
|
||||
if (token.address === ETH_ADDRESS && !tokenAddress) {
|
||||
const balance = balanceInSelectedCurrency
|
||||
? parseFloat(balanceInSelectedCurrency, 10).toFixed(2)
|
||||
: balanceInSelectedCurrency
|
||||
return `${balance} ${currencySelected}`
|
||||
}
|
||||
}
|
||||
@ -33,14 +54,28 @@ const getTokenPriceInCurrency = (token: Token, currencySelected: AVAILABLE_CURRE
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export const getBalanceData = (activeTokens: List<Token>, currencySelected: string, currencyValues: List<BalanceCurrencyType>): List<BalanceRow> => {
|
||||
export const getBalanceData = (
|
||||
activeTokens: List<Token>,
|
||||
currencySelected: string,
|
||||
currencyValues: List<BalanceCurrencyType>,
|
||||
): List<BalanceRow> => {
|
||||
const rows = activeTokens.map((token: Token) => ({
|
||||
[BALANCE_TABLE_ASSET_ID]: { name: token.name, logoUri: token.logoUri, address: token.address },
|
||||
[BALANCE_TABLE_ASSET_ID]: {
|
||||
name: token.name,
|
||||
logoUri: token.logoUri,
|
||||
address: token.address,
|
||||
},
|
||||
[buildOrderFieldFrom(BALANCE_TABLE_ASSET_ID)]: token.name,
|
||||
[BALANCE_TABLE_BALANCE_ID]: `${formatAmount(token.balance)} ${token.symbol}`,
|
||||
[BALANCE_TABLE_BALANCE_ID]: `${formatAmount(token.balance)} ${
|
||||
token.symbol
|
||||
}`,
|
||||
[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)]: Number(token.balance),
|
||||
[FIXED]: token.get('symbol') === 'ETH',
|
||||
[BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(token, currencySelected, currencyValues),
|
||||
[BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(
|
||||
token,
|
||||
currencySelected,
|
||||
currencyValues,
|
||||
),
|
||||
}))
|
||||
|
||||
return rows
|
||||
@ -96,4 +131,7 @@ export const generateColumns = () => {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export const filterByZero = (data: List<BalanceRow>, hideZero: boolean): List<BalanceRow> => data.filter((row: BalanceRow) => (hideZero ? row[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)] !== 0 : true))
|
||||
export const filterByZero = (
|
||||
data: List<BalanceRow>,
|
||||
hideZero: boolean,
|
||||
): List<BalanceRow> => data.filter((row: BalanceRow) => (hideZero ? row[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)] !== 0 : true))
|
||||
|
@ -24,7 +24,7 @@ type TxData = {
|
||||
date: string,
|
||||
dateOrder?: number,
|
||||
amount: number | string,
|
||||
tx: Transaction,
|
||||
tx: Transaction | IncomingTransaction,
|
||||
status?: string,
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ const getIncomingTxTableData = (tx: IncomingTransaction): TransactionRow => ({
|
||||
})
|
||||
|
||||
const getTransactionTableData = (tx: Transaction): TransactionRow => {
|
||||
const txDate = tx.isExecuted ? tx.executionDate : tx.submissionDate
|
||||
const txDate = tx.submissionDate
|
||||
|
||||
let txType = 'outgoing'
|
||||
if (tx.modifySettingsTx) {
|
||||
@ -80,9 +80,7 @@ const getTransactionTableData = (tx: Transaction): TransactionRow => {
|
||||
return {
|
||||
[TX_TABLE_ID]: tx.blockNumber,
|
||||
[TX_TABLE_TYPE_ID]: <TxType txType={txType} />,
|
||||
[TX_TABLE_DATE_ID]: tx.isExecuted
|
||||
? tx.executionDate && formatDate(tx.executionDate)
|
||||
: tx.submissionDate && formatDate(tx.submissionDate),
|
||||
[TX_TABLE_DATE_ID]: txDate ? formatDate(txDate) : '',
|
||||
[buildOrderFieldFrom(TX_TABLE_DATE_ID)]: txDate ? getTime(parseISO(txDate)) : null,
|
||||
[TX_TABLE_AMOUNT_ID]: getTxAmount(tx),
|
||||
[TX_TABLE_STATUS_ID]: tx.status,
|
||||
|
@ -19,7 +19,7 @@ import { getHumanFriendlyToken } from '~/logic/tokens/store/actions/fetchTokens'
|
||||
import { isTokenTransfer } from '~/logic/tokens/utils/tokenHelpers'
|
||||
import { decodeParamsFromSafeMethod } from '~/logic/contracts/methodIds'
|
||||
import { ALTERNATIVE_TOKEN_ABI } from '~/logic/tokens/utils/alternativeAbi'
|
||||
import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
|
||||
import { ZERO_ADDRESS, sameAddress } from '~/logic/wallets/ethAddresses'
|
||||
|
||||
let web3
|
||||
|
||||
@ -77,10 +77,10 @@ export const buildTransactionFrom = async (
|
||||
})
|
||||
}),
|
||||
)
|
||||
const modifySettingsTx = tx.to === safeAddress && Number(tx.value) === 0 && !!tx.data
|
||||
const cancellationTx = tx.to === safeAddress && Number(tx.value) === 0 && !tx.data
|
||||
const modifySettingsTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !!tx.data
|
||||
const cancellationTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !tx.data
|
||||
const isSendTokenTx = await isTokenTransfer(tx.data, tx.value)
|
||||
const customTx = tx.to !== safeAddress && !!tx.data && !isSendTokenTx
|
||||
const customTx = !sameAddress(tx.to, safeAddress) && !!tx.data && !isSendTokenTx
|
||||
|
||||
let refundParams = null
|
||||
if (tx.gasPrice > 0) {
|
||||
|
@ -70,6 +70,15 @@ export const safeTransactionsSelector: Selector<GlobalState, RouterProps, List<T
|
||||
},
|
||||
)
|
||||
|
||||
export const safeParamAddressFromStateSelector = (state: GlobalState): string => {
|
||||
const match = matchPath(
|
||||
state.router.location.pathname,
|
||||
{ path: `${SAFELIST_ADDRESS}/:safeAddress` },
|
||||
)
|
||||
|
||||
return match ? match.params.safeAddress : null
|
||||
}
|
||||
|
||||
export const safeIncomingTransactionsSelector: Selector<GlobalState, RouterProps, List<IncomingTransaction>> = createSelector(
|
||||
incomingTransactionsSelector,
|
||||
safeParamAddressSelector,
|
||||
|
@ -13,6 +13,7 @@ const md = '16px'
|
||||
const primary = '#001428'
|
||||
const secondary = '#008C73'
|
||||
const secondaryTextOrSvg = '#B2B5B2'
|
||||
const secondaryBackground = '#f0efee'
|
||||
const sm = '8px'
|
||||
const warningColor = '#ffc05f'
|
||||
const xl = '32px'
|
||||
@ -57,6 +58,7 @@ module.exports = {
|
||||
secondary,
|
||||
secondaryFontFamily: 'Averta, monospace',
|
||||
secondaryText: secondaryTextOrSvg,
|
||||
secondaryBackground,
|
||||
sm,
|
||||
smallFontSize: '12px',
|
||||
warning: warningColor,
|
||||
|
@ -8,7 +8,7 @@ import { getNetwork } from '~/config'
|
||||
const stores = [IndexedDbStore, LocalStorageStore]
|
||||
export const storage = new ImmortalStorage(stores)
|
||||
|
||||
const PREFIX = `v1_${getNetwork()}`
|
||||
const PREFIX = `v2_${getNetwork()}`
|
||||
|
||||
export const loadFromStorage = async (key: string): Promise<*> => {
|
||||
try {
|
||||
|
Loading…
x
Reference in New Issue
Block a user