mirror of
https://github.com/status-im/safe-react.git
synced 2025-02-23 06:58:07 +00:00
Development (#355)
* 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
This commit is contained in:
parent
405d8ba336
commit
fff057d8e6
@ -9,3 +9,7 @@ REACT_APP_GOOGLE_ANALYTICS_ID_MAINNET=
|
|||||||
|
|
||||||
# For production environments
|
# For production environments
|
||||||
REACT_APP_INTERCOM_ID=
|
REACT_APP_INTERCOM_ID=
|
||||||
|
REACT_APP_PORTIS_ID=
|
||||||
|
REACT_APP_SQUARELINK_ID=
|
||||||
|
REACT_APP_FORTMATIC_KEY=
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
<PROJECT_ROOT>/contracts/**/.*
|
<PROJECT_ROOT>/contracts/**/.*
|
||||||
<PROJECT_ROOT>/scripts/**/.*
|
<PROJECT_ROOT>/scripts/**/.*
|
||||||
<PROJECT_ROOT>/public/**/.*
|
<PROJECT_ROOT>/public/**/.*
|
||||||
<PROJECT_ROOT>/src/test/**/.*
|
|
||||||
<PROJECT_ROOT>/babel.config.js
|
<PROJECT_ROOT>/babel.config.js
|
||||||
<PROJECT_ROOT>/jest.config.js
|
<PROJECT_ROOT>/jest.config.js
|
||||||
<PROJECT_ROOT>/truffle.js
|
<PROJECT_ROOT>/truffle.js
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,5 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
build_webpack/
|
build_webpack/
|
||||||
build_storybook/
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
build/
|
build/
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
import '@storybook/addon-actions/register'
|
|
||||||
import '@storybook/addon-links/register'
|
|
||||||
import '@storybook/addon-knobs/register'
|
|
@ -1,35 +0,0 @@
|
|||||||
import 'babel-polyfill'
|
|
||||||
import { addDecorator, configure } from '@storybook/react'
|
|
||||||
import { withKnobs } from '@storybook/addon-knobs'
|
|
||||||
import { MuiThemeProvider } from '@material-ui/core/styles'
|
|
||||||
import * as React from 'react'
|
|
||||||
import { Provider } from 'react-redux'
|
|
||||||
import StoryRouter from 'storybook-router'
|
|
||||||
import { store } from '~/store'
|
|
||||||
import theme from '~/theme/mui'
|
|
||||||
import 'index.scss'
|
|
||||||
|
|
||||||
(function (global) {
|
|
||||||
//Useful for adding data and libraries to window object.
|
|
||||||
})(typeof window !== 'undefined' ? window : {});
|
|
||||||
|
|
||||||
addDecorator(withKnobs);
|
|
||||||
addDecorator(StoryRouter())
|
|
||||||
|
|
||||||
addDecorator((story) => (
|
|
||||||
<Provider store={store}>
|
|
||||||
<MuiThemeProvider theme={theme}>
|
|
||||||
{ story() }
|
|
||||||
</MuiThemeProvider>
|
|
||||||
</Provider>
|
|
||||||
))
|
|
||||||
|
|
||||||
const components = require.context('../src/components', true, /\.stories\.((js|ts)x?)$/)
|
|
||||||
const routes = require.context('../src/routes', true, /\.stories\.((js|ts)x?)$/)
|
|
||||||
|
|
||||||
function loadStories() {
|
|
||||||
components.keys().forEach((filename) => components(filename))
|
|
||||||
routes.keys().forEach((filename) => routes(filename))
|
|
||||||
}
|
|
||||||
|
|
||||||
configure(loadStories, module)
|
|
@ -1 +0,0 @@
|
|||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
|
@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
process.env.NODE_ENV = 'development'
|
|
||||||
const prodConfig = require('../config/webpack.config.dev');
|
|
||||||
|
|
||||||
module.exports = function(storybookConfig, configType) {
|
|
||||||
|
|
||||||
const config = Object.assign({}, prodConfig);
|
|
||||||
|
|
||||||
storybookConfig.module.rules = storybookConfig.module.rules.concat(config.module.rules)
|
|
||||||
storybookConfig.resolve = config.resolve;
|
|
||||||
|
|
||||||
return storybookConfig;
|
|
||||||
};
|
|
@ -21,6 +21,7 @@ matrix:
|
|||||||
- REACT_APP_NETWORK='rinkeby'
|
- REACT_APP_NETWORK='rinkeby'
|
||||||
before_install:
|
before_install:
|
||||||
# Needed to deploy pull request and releases
|
# Needed to deploy pull request and releases
|
||||||
|
- sudo apt-get update
|
||||||
- sudo apt-get -y install python-pip python-dev
|
- sudo apt-get -y install python-pip python-dev
|
||||||
- pip install awscli --upgrade --user
|
- pip install awscli --upgrade --user
|
||||||
# Install truffle
|
# Install truffle
|
||||||
|
@ -133,6 +133,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
options: {
|
options: {
|
||||||
|
esModule: false,
|
||||||
name: 'img/[hash].[ext]',
|
name: 'img/[hash].[ext]',
|
||||||
esModule: false
|
esModule: false
|
||||||
},
|
},
|
||||||
|
122
flow-typed/npm/@sambego/storybook-state_vx.x.x.js
vendored
122
flow-typed/npm/@sambego/storybook-state_vx.x.x.js
vendored
@ -1,122 +0,0 @@
|
|||||||
// flow-typed signature: 9e597e3161a1342a9e77ec9437783354
|
|
||||||
// flow-typed version: <<STUB>>/@sambego/storybook-state_v^1.3.6/flow_v0.112.0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an autogenerated libdef stub for:
|
|
||||||
*
|
|
||||||
* '@sambego/storybook-state'
|
|
||||||
*
|
|
||||||
* Fill this stub out by replacing all the `any` types.
|
|
||||||
*
|
|
||||||
* Once filled out, we encourage you to share your work with the
|
|
||||||
* community by sending a pull request to:
|
|
||||||
* https://github.com/flowtype/flow-typed
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We include stubs for each file inside this npm package in case you need to
|
|
||||||
* require those files directly. Feel free to delete any files that aren't
|
|
||||||
* needed.
|
|
||||||
*/
|
|
||||||
declare module '@sambego/storybook-state/dist' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/dist/State' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/dist/StateDecorator' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/dist/Store' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/enzyme.config' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/jest.config' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/src' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/src/State' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/src/StateDecorator' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/src/Store' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/tests/State.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/tests/StateDecorator.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@sambego/storybook-state/tests/Store.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filename aliases
|
|
||||||
declare module '@sambego/storybook-state/dist/index' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/dist'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/dist/index.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/dist'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/dist/State.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/dist/State'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/dist/StateDecorator.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/dist/StateDecorator'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/dist/Store.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/dist/Store'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/enzyme.config.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/enzyme.config'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/jest.config.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/jest.config'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/src/index' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/src'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/src/index.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/src'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/src/State.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/src/State'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/src/StateDecorator.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/src/StateDecorator'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/src/Store.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/src/Store'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/tests/State.test.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/tests/State.test'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/tests/StateDecorator.test.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/tests/StateDecorator.test'>;
|
|
||||||
}
|
|
||||||
declare module '@sambego/storybook-state/tests/Store.test.js' {
|
|
||||||
declare module.exports: $Exports<'@sambego/storybook-state/tests/Store.test'>;
|
|
||||||
}
|
|
187
flow-typed/npm/@storybook/addon-actions_vx.x.x.js
vendored
187
flow-typed/npm/@storybook/addon-actions_vx.x.x.js
vendored
@ -1,187 +0,0 @@
|
|||||||
// flow-typed signature: 64c369e4ed0c4a705b2f36b522874cac
|
|
||||||
// flow-typed version: <<STUB>>/@storybook/addon-actions_v5.2.6/flow_v0.112.0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an autogenerated libdef stub for:
|
|
||||||
*
|
|
||||||
* '@storybook/addon-actions'
|
|
||||||
*
|
|
||||||
* Fill this stub out by replacing all the `any` types.
|
|
||||||
*
|
|
||||||
* Once filled out, we encourage you to share your work with the
|
|
||||||
* community by sending a pull request to:
|
|
||||||
* https://github.com/flowtype/flow-typed
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We include stubs for each file inside this npm package in case you need to
|
|
||||||
* require those files directly. Feel free to delete any files that aren't
|
|
||||||
* needed.
|
|
||||||
*/
|
|
||||||
declare module '@storybook/addon-actions/dist/components/ActionLogger' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/components/ActionLogger/style' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/constants' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/containers/ActionLogger' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/manager' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/models/ActionDisplay' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/models/ActionOptions' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/models/ActionsFunction' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/models/ActionsMap' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/models/DecoratorFunction' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/models/HandlerFunction' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/models' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/action' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/actions' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/configureActions' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/decorateAction' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/preview' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/withActions' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/dist/typings.d' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-actions/register' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filename aliases
|
|
||||||
declare module '@storybook/addon-actions/dist/components/ActionLogger/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/components/ActionLogger'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/components/ActionLogger/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/components/ActionLogger'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/components/ActionLogger/style.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/components/ActionLogger/style'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/constants.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/constants'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/containers/ActionLogger/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/containers/ActionLogger'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/containers/ActionLogger/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/containers/ActionLogger'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/manager.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/manager'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/models/ActionDisplay.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/ActionDisplay'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/models/ActionOptions.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/ActionOptions'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/models/ActionsFunction.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/ActionsFunction'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/models/ActionsMap.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/ActionsMap'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/models/DecoratorFunction.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/DecoratorFunction'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/models/HandlerFunction.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/HandlerFunction'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/models/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/models/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/action.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/action'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/actions.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/actions'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/configureActions.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/configureActions'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/decorateAction.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/decorateAction'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/preview/withActions.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/withActions'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/dist/typings.d.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/typings.d'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-actions/register.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-actions/register'>;
|
|
||||||
}
|
|
283
flow-typed/npm/@storybook/addon-knobs_vx.x.x.js
vendored
283
flow-typed/npm/@storybook/addon-knobs_vx.x.x.js
vendored
@ -1,283 +0,0 @@
|
|||||||
// flow-typed signature: 90624ef390fe4c5befd27eedd08d7ad2
|
|
||||||
// flow-typed version: <<STUB>>/@storybook/addon-knobs_v5.2.6/flow_v0.112.0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an autogenerated libdef stub for:
|
|
||||||
*
|
|
||||||
* '@storybook/addon-knobs'
|
|
||||||
*
|
|
||||||
* Fill this stub out by replacing all the `any` types.
|
|
||||||
*
|
|
||||||
* Once filled out, we encourage you to share your work with the
|
|
||||||
* community by sending a pull request to:
|
|
||||||
* https://github.com/flowtype/flow-typed
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We include stubs for each file inside this npm package in case you need to
|
|
||||||
* require those files directly. Feel free to delete any files that aren't
|
|
||||||
* needed.
|
|
||||||
*/
|
|
||||||
declare module '@storybook/addon-knobs/angular' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/__types__/knob-test-cases' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/Panel' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/PropForm' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Array' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Boolean' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Button' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Checkboxes' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Color' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Date' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Files' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Number' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Object' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Options' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Radio' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Select' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Text' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/types' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/converters' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/deprecated' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/KnobManager' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/KnobStore' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/register' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/registerKnobs' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/shared' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/type-defs' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/dist/typings.d' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/html' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/marko' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/mithril' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/polymer' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/react' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/register' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-knobs/vue' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filename aliases
|
|
||||||
declare module '@storybook/addon-knobs/angular.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/angular'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/__types__/knob-test-cases.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/__types__/knob-test-cases'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/Panel.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/Panel'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/PropForm.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/PropForm'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Array.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Array'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Boolean.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Boolean'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Button.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Button'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Checkboxes.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Checkboxes'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Color.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Color'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Date.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Date'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Files.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Files'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Number.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Number'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Object.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Object'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Options.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Options'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Radio.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Radio'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Select.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Select'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/Text.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Text'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/components/types/types.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/types'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/converters.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/converters'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/deprecated.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/deprecated'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/KnobManager.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/KnobManager'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/KnobStore.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/KnobStore'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/register.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/register'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/registerKnobs.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/registerKnobs'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/shared.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/shared'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/type-defs.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/type-defs'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/dist/typings.d.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/typings.d'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/html.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/html'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/marko.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/marko'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/mithril.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/mithril'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/polymer.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/polymer'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/react.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/react'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/register.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/register'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-knobs/vue.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-knobs/vue'>;
|
|
||||||
}
|
|
101
flow-typed/npm/@storybook/addon-links_vx.x.x.js
vendored
101
flow-typed/npm/@storybook/addon-links_vx.x.x.js
vendored
@ -1,101 +0,0 @@
|
|||||||
// flow-typed signature: f6f4916ab4d700d3db6ac07b4264aa7e
|
|
||||||
// flow-typed version: <<STUB>>/@storybook/addon-links_v5.2.6/flow_v0.112.0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an autogenerated libdef stub for:
|
|
||||||
*
|
|
||||||
* '@storybook/addon-links'
|
|
||||||
*
|
|
||||||
* Fill this stub out by replacing all the `any` types.
|
|
||||||
*
|
|
||||||
* Once filled out, we encourage you to share your work with the
|
|
||||||
* community by sending a pull request to:
|
|
||||||
* https://github.com/flowtype/flow-typed
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We include stubs for each file inside this npm package in case you need to
|
|
||||||
* require those files directly. Feel free to delete any files that aren't
|
|
||||||
* needed.
|
|
||||||
*/
|
|
||||||
declare module '@storybook/addon-links/dist/constants' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/dist' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/dist/manager' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/dist/preview' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/dist/react/components/link' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/dist/react/components/RoutedLink' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/dist/react' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/dist/typings.d' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/react' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@storybook/addon-links/register' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filename aliases
|
|
||||||
declare module '@storybook/addon-links/dist/constants.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist/constants'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/manager.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist/manager'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/preview.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist/preview'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/react/components/link.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist/react/components/link'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/react/components/RoutedLink.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist/react/components/RoutedLink'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/react/index' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist/react'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/react/index.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist/react'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/dist/typings.d.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/dist/typings.d'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/react.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/react'>;
|
|
||||||
}
|
|
||||||
declare module '@storybook/addon-links/register.js' {
|
|
||||||
declare module.exports: $Exports<'@storybook/addon-links/register'>;
|
|
||||||
}
|
|
61
flow-typed/npm/@storybook/react_v5.x.x.js
vendored
61
flow-typed/npm/@storybook/react_v5.x.x.js
vendored
@ -1,61 +0,0 @@
|
|||||||
// flow-typed signature: e484579841f3cb1e8f57a768abc4642d
|
|
||||||
// flow-typed version: c6154227d1/@storybook/react_v5.x.x/flow_>=v0.104.x
|
|
||||||
|
|
||||||
type NodeModule = typeof module;
|
|
||||||
|
|
||||||
declare module '@storybook/react' {
|
|
||||||
declare type Context = {
|
|
||||||
kind: string,
|
|
||||||
story: string,
|
|
||||||
...
|
|
||||||
};
|
|
||||||
declare type Renderable =
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| React$Element<any>
|
|
||||||
| Iterable<?Renderable>;
|
|
||||||
declare type RenderCallback = (
|
|
||||||
context: Context
|
|
||||||
) => Renderable;
|
|
||||||
declare type RenderFunction = () => Renderable;
|
|
||||||
|
|
||||||
declare type StoryDecorator = (
|
|
||||||
story: RenderFunction,
|
|
||||||
context: Context
|
|
||||||
) => Renderable;
|
|
||||||
|
|
||||||
declare type DecoratorParameters = { [key: string]: any, ... };
|
|
||||||
|
|
||||||
declare interface Story {
|
|
||||||
+kind: string;
|
|
||||||
add(
|
|
||||||
storyName: string,
|
|
||||||
callback: RenderCallback,
|
|
||||||
parameters?: DecoratorParameters
|
|
||||||
): Story;
|
|
||||||
addDecorator(decorator: StoryDecorator): Story;
|
|
||||||
addParameters(parameters: DecoratorParameters): Story;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare interface StoryObject {
|
|
||||||
name: string;
|
|
||||||
render: RenderFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare interface StoryBucket {
|
|
||||||
kind: string;
|
|
||||||
filename: string;
|
|
||||||
stories: Array<StoryObject>;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare function addDecorator(decorator: StoryDecorator): void;
|
|
||||||
declare function addParameters(parameters: DecoratorParameters): void;
|
|
||||||
declare function clearDecorators(): void;
|
|
||||||
declare function configure(fn: () => void, module: NodeModule): void;
|
|
||||||
declare function setAddon(addon: Object): void;
|
|
||||||
declare function storiesOf(name: string, module: NodeModule): Story;
|
|
||||||
declare function storiesOf<T>(name: string, module: NodeModule): Story & T;
|
|
||||||
declare function forceReRender(): void;
|
|
||||||
|
|
||||||
declare function getStorybook(): Array<StoryBucket>;
|
|
||||||
}
|
|
249
flow-typed/npm/storybook-host_vx.x.x.js
vendored
249
flow-typed/npm/storybook-host_vx.x.x.js
vendored
@ -1,249 +0,0 @@
|
|||||||
// flow-typed signature: 48ec61af419d1ece506839678031f356
|
|
||||||
// flow-typed version: <<STUB>>/storybook-host_v5.1.0/flow_v0.112.0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an autogenerated libdef stub for:
|
|
||||||
*
|
|
||||||
* 'storybook-host'
|
|
||||||
*
|
|
||||||
* Fill this stub out by replacing all the `any` types.
|
|
||||||
*
|
|
||||||
* Once filled out, we encourage you to share your work with the
|
|
||||||
* community by sending a pull request to:
|
|
||||||
* https://github.com/flowtype/flow-typed
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module 'storybook-host' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We include stubs for each file inside this npm package in case you need to
|
|
||||||
* require those files directly. Feel free to delete any files that aren't
|
|
||||||
* needed.
|
|
||||||
*/
|
|
||||||
declare module 'storybook-host/lib/common/alignment' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/color' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css/css' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css/glamor' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css-flex.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css-image.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css-positioning.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css-spacing.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/css/types' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/libs' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/common/util' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/AlignmentContainer/AlignmentContainer' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/AlignmentContainer/ComponentHost.stories' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/AlignmentContainer' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/ComponentHost/ComponentHost' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/ComponentHost/ComponentHost.stories' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/ComponentHost' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/CropMarks/CropMark' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/CropMarks/CropMarks' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/components/CropMarks' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/decorators/host' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/index.test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/test/Foo' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/test' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'storybook-host/lib/types' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filename aliases
|
|
||||||
declare module 'storybook-host/lib/common/alignment.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/alignment'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/color.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/color'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/css.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css/css'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/glamor.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css/glamor'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/index' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/index.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css-flex.test.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css-flex.test'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css-image.test.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css-image.test'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css-positioning.test.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css-positioning.test'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css-spacing.test.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css-spacing.test'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/test/css.test.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css.test'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/css/types.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/css/types'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/index' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/index.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/libs.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/libs'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/common/util.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/common/util'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/AlignmentContainer/AlignmentContainer.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/AlignmentContainer/AlignmentContainer'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/AlignmentContainer/ComponentHost.stories.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/AlignmentContainer/ComponentHost.stories'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/AlignmentContainer/index' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/AlignmentContainer'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/AlignmentContainer/index.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/AlignmentContainer'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/ComponentHost/ComponentHost.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/ComponentHost/ComponentHost'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/ComponentHost/ComponentHost.stories.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/ComponentHost/ComponentHost.stories'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/ComponentHost/index' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/ComponentHost'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/ComponentHost/index.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/ComponentHost'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/CropMarks/CropMark.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/CropMarks/CropMark'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/CropMarks/CropMarks.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/CropMarks/CropMarks'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/CropMarks/index' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/CropMarks'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/components/CropMarks/index.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/components/CropMarks'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/decorators/host.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/decorators/host'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/index' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/index.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/index.test.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/index.test'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/test/Foo.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/test/Foo'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/test/index' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/test'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/test/index.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/test'>;
|
|
||||||
}
|
|
||||||
declare module 'storybook-host/lib/types.js' {
|
|
||||||
declare module.exports: $Exports<'storybook-host/lib/types'>;
|
|
||||||
}
|
|
45
flow-typed/npm/storybook-router_v0.x.x.js
vendored
45
flow-typed/npm/storybook-router_v0.x.x.js
vendored
@ -1,45 +0,0 @@
|
|||||||
// flow-typed signature: c2d42e89f2eeb1cdff2d4d7dea9fd97b
|
|
||||||
// flow-typed version: c6154227d1/storybook-router_v0.x.x/flow_>=v0.104.x
|
|
||||||
|
|
||||||
type LocationShape = {
|
|
||||||
pathname?: string,
|
|
||||||
search?: string,
|
|
||||||
hash?: string,
|
|
||||||
state?: any,
|
|
||||||
...
|
|
||||||
};
|
|
||||||
|
|
||||||
type GetUserConfirmation = (
|
|
||||||
message: string,
|
|
||||||
callback: (confirmed: boolean) => void
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
declare module "storybook-router" {
|
|
||||||
declare type Context = {
|
|
||||||
kind: string,
|
|
||||||
story: string,
|
|
||||||
...
|
|
||||||
};
|
|
||||||
declare type Renderable = React$Element<*>;
|
|
||||||
declare type RenderFunction = () => Renderable | Array<Renderable>;
|
|
||||||
|
|
||||||
declare type StoryDecorator = (
|
|
||||||
story: RenderFunction,
|
|
||||||
context: Context
|
|
||||||
) => Renderable | null;
|
|
||||||
|
|
||||||
declare type Links = { [key: string]: (kind: string, story: string) => Function, ... };
|
|
||||||
|
|
||||||
declare type RouterProps = {
|
|
||||||
initialEntry?: Array<string>,
|
|
||||||
autoRoute?: boolean,
|
|
||||||
initialEntries?: Array<LocationShape | string>,
|
|
||||||
initialIndex?: number,
|
|
||||||
getUserConfirmation?: GetUserConfirmation,
|
|
||||||
keyLength?: number,
|
|
||||||
children?: React$Element<*>,
|
|
||||||
...
|
|
||||||
};
|
|
||||||
|
|
||||||
declare module.exports: { (links?: Links, routerProps?: RouterProps): StoryDecorator, ... };
|
|
||||||
}
|
|
27
package.json
27
package.json
@ -18,12 +18,10 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node scripts/build.js",
|
"build": "node scripts/build.js",
|
||||||
"build-mainnet": "REACT_APP_NETWORK=mainnet yarn build",
|
"build-mainnet": "REACT_APP_NETWORK=mainnet yarn build",
|
||||||
"build-storybook": "build-storybook -o build_storybook",
|
|
||||||
"flow": "flow",
|
"flow": "flow",
|
||||||
"precommit": "./precommit.sh",
|
"precommit": "./precommit.sh",
|
||||||
"start": "node scripts/start.js",
|
"start": "node scripts/start.js",
|
||||||
"start-mainnet": "REACT_APP_NETWORK=mainnet yarn start",
|
"start-mainnet": "REACT_APP_NETWORK=mainnet yarn start",
|
||||||
"storybook": "start-storybook -p 6006",
|
|
||||||
"test": "NODE_ENV=test && node scripts/test.js --env=jsdom",
|
"test": "NODE_ENV=test && node scripts/test.js --env=jsdom",
|
||||||
"format": "prettier-eslint \"src/**/*.js\" --write"
|
"format": "prettier-eslint \"src/**/*.js\" --write"
|
||||||
},
|
},
|
||||||
@ -44,8 +42,11 @@
|
|||||||
"bignumber.js": "9.0.0",
|
"bignumber.js": "9.0.0",
|
||||||
"connected-react-router": "6.6.1",
|
"connected-react-router": "6.6.1",
|
||||||
"date-fns": "2.8.1",
|
"date-fns": "2.8.1",
|
||||||
|
"currency-flags": "^2.1.1",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
"ethereum-ens": "0.7.8",
|
"ethereum-ens": "0.7.8",
|
||||||
"final-form": "4.18.6",
|
"final-form": "4.18.6",
|
||||||
|
"fortmatic": "^1.0.1",
|
||||||
"history": "4.10.1",
|
"history": "4.10.1",
|
||||||
"immortal-db": "^1.0.2",
|
"immortal-db": "^1.0.2",
|
||||||
"immutable": "^4.0.0-rc.9",
|
"immutable": "^4.0.0-rc.9",
|
||||||
@ -55,7 +56,9 @@
|
|||||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
"optimize-css-assets-webpack-plugin": "5.0.3",
|
||||||
"polished": "^3.4.2",
|
"polished": "^3.4.2",
|
||||||
"qrcode.react": "1.0.0",
|
"qrcode.react": "1.0.0",
|
||||||
|
"query-string": "6.9.0",
|
||||||
"react": "16.12.0",
|
"react": "16.12.0",
|
||||||
|
"react-dev-utils": "^10.0.0",
|
||||||
"react-dom": "16.12.0",
|
"react-dom": "16.12.0",
|
||||||
"react-final-form": "6.3.3",
|
"react-final-form": "6.3.3",
|
||||||
"react-final-form-listeners": "^1.0.2",
|
"react-final-form-listeners": "^1.0.2",
|
||||||
@ -70,10 +73,9 @@
|
|||||||
"redux-actions": "^2.6.5",
|
"redux-actions": "^2.6.5",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"reselect": "^4.0.0",
|
"reselect": "^4.0.0",
|
||||||
"squarelink": "^1.1.3",
|
"squarelink": "^1.1.4",
|
||||||
"web3": "1.2.4",
|
"web3": "1.2.4",
|
||||||
"web3connect": "^1.0.0-beta.23",
|
"web3connect": "^1.0.0-beta.23"
|
||||||
"react-ga": "^2.7.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "7.7.5",
|
"@babel/cli": "7.7.5",
|
||||||
@ -100,12 +102,7 @@
|
|||||||
"@babel/preset-env": "7.7.6",
|
"@babel/preset-env": "7.7.6",
|
||||||
"@babel/preset-flow": "7.7.4",
|
"@babel/preset-flow": "7.7.4",
|
||||||
"@babel/preset-react": "7.7.4",
|
"@babel/preset-react": "7.7.4",
|
||||||
"@sambego/storybook-state": "^1.3.6",
|
"@testing-library/react": "9.3.3",
|
||||||
"@storybook/addon-actions": "5.2.8",
|
|
||||||
"@storybook/addon-knobs": "5.2.8",
|
|
||||||
"@storybook/addon-links": "5.2.8",
|
|
||||||
"@storybook/react": "5.2.8",
|
|
||||||
"@testing-library/react": "9.3.2",
|
|
||||||
"autoprefixer": "9.7.3",
|
"autoprefixer": "9.7.3",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"babel-eslint": "10.0.3",
|
"babel-eslint": "10.0.3",
|
||||||
@ -116,9 +113,9 @@
|
|||||||
"babel-plugin-transform-es3-property-literals": "^6.22.0",
|
"babel-plugin-transform-es3-property-literals": "^6.22.0",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"css-loader": "3.2.1",
|
"css-loader": "3.3.0",
|
||||||
"detect-port": "^1.3.0",
|
"detect-port": "^1.3.0",
|
||||||
"eslint": "5.16.0",
|
"eslint": "6.7.2",
|
||||||
"eslint-config-airbnb": "18.0.1",
|
"eslint-config-airbnb": "18.0.1",
|
||||||
"eslint-plugin-flowtype": "4.5.2",
|
"eslint-plugin-flowtype": "4.5.2",
|
||||||
"eslint-plugin-import": "2.19.1",
|
"eslint-plugin-import": "2.19.1",
|
||||||
@ -142,10 +139,8 @@
|
|||||||
"pre-commit": "^1.2.2",
|
"pre-commit": "^1.2.2",
|
||||||
"prettier-eslint-cli": "5.0.0",
|
"prettier-eslint-cli": "5.0.0",
|
||||||
"run-with-testrpc": "0.3.1",
|
"run-with-testrpc": "0.3.1",
|
||||||
"storybook-host": "5.1.0",
|
|
||||||
"storybook-router": "^0.3.4",
|
|
||||||
"style-loader": "1.0.1",
|
"style-loader": "1.0.1",
|
||||||
"terser-webpack-plugin": "^2.2.2",
|
"terser-webpack-plugin": "2.2.3",
|
||||||
"truffle": "5.1.3",
|
"truffle": "5.1.3",
|
||||||
"truffle-contract": "4.0.31",
|
"truffle-contract": "4.0.31",
|
||||||
"truffle-solidity-loader": "0.1.32",
|
"truffle-solidity-loader": "0.1.32",
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<link rel="shortcut icon" href="favicon.ico">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||||
<title>Gnosis Safe For Teams</title>
|
<title>Gnosis Safe Multisig</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@ -57,6 +57,8 @@ git clone https://github.com/gnosis/safe-transaction-service.git
|
|||||||
cd safe-transaction-service
|
cd safe-transaction-service
|
||||||
git checkout develop
|
git checkout develop
|
||||||
docker-compose build
|
docker-compose build
|
||||||
|
# it comes enabled by default in docker-compose
|
||||||
|
sudo service postgresql stop
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
Check that the service is running at https://localhost:8000
|
Check that the service is running at https://localhost:8000
|
||||||
|
@ -3,6 +3,7 @@ import React from 'react'
|
|||||||
import Web3Connect from 'web3connect'
|
import Web3Connect from 'web3connect'
|
||||||
import Torus from '@toruslabs/torus-embed'
|
import Torus from '@toruslabs/torus-embed'
|
||||||
import WalletConnectProvider from '@walletconnect/web3-provider'
|
import WalletConnectProvider from '@walletconnect/web3-provider'
|
||||||
|
import Fortmatic from 'fortmatic'
|
||||||
import Portis from '@portis/web3'
|
import Portis from '@portis/web3'
|
||||||
import Squarelink from 'squarelink'
|
import Squarelink from 'squarelink'
|
||||||
import Button from '~/components/layout/Button'
|
import Button from '~/components/layout/Button'
|
||||||
@ -10,8 +11,11 @@ import { fetchProvider } from '~/logic/wallets/store/actions'
|
|||||||
import { getNetwork } from '~/config'
|
import { getNetwork } from '~/config'
|
||||||
import { store } from '~/store'
|
import { store } from '~/store'
|
||||||
|
|
||||||
const PORTIS_DAPP_ID = process.env.REACT_APP_NETWORK === 'mainnet' ? process.env.REACT_APP_PORTIS_ID : '852b763d-f28b-4463-80cb-846d7ec5806b'
|
const isMainnet = process.env.REACT_APP_NETWORK === 'mainnet'
|
||||||
const SQUARELINK_CLIENT_ID = process.env.REACT_APP_NETWORK === 'mainnet' ? process.env.REACT_APP_SQUARELINK_ID : '46ce08fe50913cfa1b78'
|
|
||||||
|
const PORTIS_DAPP_ID = isMainnet ? process.env.REACT_APP_PORTIS_ID : '852b763d-f28b-4463-80cb-846d7ec5806b'
|
||||||
|
const SQUARELINK_CLIENT_ID = isMainnet ? process.env.REACT_APP_SQUARELINK_ID : '46ce08fe50913cfa1b78'
|
||||||
|
const FORTMATIC_API_KEY = isMainnet ? process.env.REACT_APP_FORTMATIC_KEY : 'pk_test_CAD437AA29BE0A40'
|
||||||
|
|
||||||
export const web3Connect = new Web3Connect.Core({
|
export const web3Connect = new Web3Connect.Core({
|
||||||
network: getNetwork().toLowerCase(),
|
network: getNetwork().toLowerCase(),
|
||||||
@ -34,6 +38,12 @@ export const web3Connect = new Web3Connect.Core({
|
|||||||
id: SQUARELINK_CLIENT_ID,
|
id: SQUARELINK_CLIENT_ID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fortmatic: {
|
||||||
|
package: Fortmatic,
|
||||||
|
options: {
|
||||||
|
key: FORTMATIC_API_KEY,
|
||||||
|
},
|
||||||
|
},
|
||||||
torus: {
|
torus: {
|
||||||
package: Torus,
|
package: Torus,
|
||||||
options: {
|
options: {
|
||||||
|
@ -8,7 +8,7 @@ import { makeStyles } from '@material-ui/core/styles'
|
|||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import Link from '~/components/layout/Link'
|
import Link from '~/components/layout/Link'
|
||||||
import Button from '~/components/layout/Button'
|
import Button from '~/components/layout/Button'
|
||||||
import { primary, mainFontFamily } from '~/theme/variables'
|
import { primary, mainFontFamily, md } from '~/theme/variables'
|
||||||
import type { CookiesProps } from '~/logic/cookies/model/cookie'
|
import type { CookiesProps } from '~/logic/cookies/model/cookie'
|
||||||
import { COOKIES_KEY } from '~/logic/cookies/model/cookie'
|
import { COOKIES_KEY } from '~/logic/cookies/model/cookie'
|
||||||
import { loadFromCookie, saveCookie } from '~/logic/cookies/utils'
|
import { loadFromCookie, saveCookie } from '~/logic/cookies/utils'
|
||||||
@ -38,7 +38,7 @@ const useStyles = makeStyles({
|
|||||||
text: {
|
text: {
|
||||||
color: primary,
|
color: primary,
|
||||||
fontFamily: mainFontFamily,
|
fontFamily: mainFontFamily,
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
fontWeight: 'normal',
|
fontWeight: 'normal',
|
||||||
lineHeight: '1.38',
|
lineHeight: '1.38',
|
||||||
margin: '0 0 25px',
|
margin: '0 0 25px',
|
||||||
|
@ -13,14 +13,14 @@ const useStyles = makeStyles({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
padding: xs,
|
margin: `0 ${xs}`,
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
transition: 'background-color .2s ease-in-out',
|
transition: 'background-color .2s ease-in-out',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: '#F0EFEE',
|
backgroundColor: '#F0EFEE',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
inreasedPopperZindex: {
|
increasedPopperZindex: {
|
||||||
zIndex: 2001,
|
zIndex: 2001,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -33,7 +33,7 @@ type CopyBtnProps = {
|
|||||||
const CopyBtn = ({ content, increaseZindex = false }: CopyBtnProps) => {
|
const CopyBtn = ({ content, increaseZindex = false }: CopyBtnProps) => {
|
||||||
const [clicked, setClicked] = useState<boolean>(false)
|
const [clicked, setClicked] = useState<boolean>(false)
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const customClasses = increaseZindex ? { popper: classes.inreasedPopperZindex } : {}
|
const customClasses = increaseZindex ? { popper: classes.increasedPopperZindex } : {}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
6
src/components/EtherscanBtn/img/etherscan-open.svg
Normal file
6
src/components/EtherscanBtn/img/etherscan-open.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<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="M17 17v-2a1 1 0 0 1 2 0v2a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2a1 1 0 1 1 0 2H7v10h10z"/>
|
||||||
|
<path fill="#B2B5B2" d="M15.586 7H13a1 1 0 0 1 0-2h5a.997.997 0 0 1 1 1v5a1 1 0 0 1-2 0V8.414l-6.243 6.243a1 1 0 1 1-1.414-1.414L15.586 7z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 442 B |
@ -3,23 +3,24 @@ import React from 'react'
|
|||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import Img from '~/components/layout/Img'
|
import Img from '~/components/layout/Img'
|
||||||
|
import EtherscanOpenIcon from './img/etherscan-open.svg'
|
||||||
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
|
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
|
||||||
import { xs } from '~/theme/variables'
|
import { xs } from '~/theme/variables'
|
||||||
import SearchIcon from './search.svg'
|
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
container: {
|
container: {
|
||||||
|
alignItems: 'center',
|
||||||
|
borderRadius: '50%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
margin: `0 ${xs}`,
|
||||||
padding: xs,
|
padding: '0',
|
||||||
borderRadius: '50%',
|
|
||||||
transition: 'background-color .2s ease-in-out',
|
transition: 'background-color .2s ease-in-out',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: '#F0EFEE',
|
backgroundColor: '#F0EFEE',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
inreasedPopperZindex: {
|
increasedPopperZindex: {
|
||||||
zIndex: 2001,
|
zIndex: 2001,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -32,18 +33,18 @@ type EtherscanBtnProps = {
|
|||||||
|
|
||||||
const EtherscanBtn = ({ type, value, increaseZindex = false }: EtherscanBtnProps) => {
|
const EtherscanBtn = ({ type, value, increaseZindex = false }: EtherscanBtnProps) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const customClasses = increaseZindex ? { popper: classes.inreasedPopperZindex } : {}
|
const customClasses = increaseZindex ? { popper: classes.increasedPopperZindex } : {}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title="Show details on Etherscan" placement="top" classes={customClasses}>
|
<Tooltip title="Show details on Etherscan" placement="top" classes={customClasses}>
|
||||||
<a
|
<a
|
||||||
|
aria-label="Show details on Etherscan"
|
||||||
className={classes.container}
|
className={classes.container}
|
||||||
href={getEtherScanLink(type, value)}
|
href={getEtherScanLink(type, value)}
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
aria-label="Show details on Etherscan"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Img src={SearchIcon} height={20} alt="Etherscan" />
|
<Img src={EtherscanOpenIcon} height={20} alt="Show on Etherscan" />
|
||||||
</a>
|
</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
<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="M18.671 17.085a1.119 1.119 0 0 1-.002 1.587 1.126 1.126 0 0 1-1.586.003l-2.68-2.68a6.6 6.6 0 1 1 .862-10.061 6.603 6.603 0 0 1 .727 8.471l2.68 2.68zm-4.923-3.335a4.455 4.455 0 0 0-6.298-6.3 4.456 4.456 0 0 0 0 6.3 4.452 4.452 0 0 0 6.298 0z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 436 B |
@ -1,25 +1,30 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import OpenInNew from '@material-ui/icons/OpenInNew'
|
import { withStyles } from '@material-ui/core/styles'
|
||||||
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
|
import Block from '~/components/layout/Block'
|
||||||
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
|
import CopyBtn from '~/components/CopyBtn'
|
||||||
|
import EtherscanBtn from '~/components/EtherscanBtn'
|
||||||
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
|
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
|
||||||
import { secondary } from '~/theme/variables'
|
import { styles } from './style.js'
|
||||||
|
|
||||||
const openIconStyle = {
|
|
||||||
height: '13px',
|
|
||||||
color: secondary,
|
|
||||||
}
|
|
||||||
|
|
||||||
type EtherscanLinkProps = {
|
type EtherscanLinkProps = {
|
||||||
type: 'tx' | 'address',
|
type: 'tx' | 'address',
|
||||||
value: string,
|
value: string,
|
||||||
|
cut?: number,
|
||||||
|
classes: Object,
|
||||||
}
|
}
|
||||||
|
|
||||||
const EtherscanLink = ({ type, value }: EtherscanLinkProps) => (
|
const EtherscanLink = ({
|
||||||
<a href={getEtherScanLink(type, value)} target="_blank" rel="noopener noreferrer">
|
type, value, cut, classes,
|
||||||
{shortVersionOf(value, 4)}
|
}: EtherscanLinkProps) => (
|
||||||
<OpenInNew style={openIconStyle} />
|
<Block className={classes.etherscanLink}>
|
||||||
</a>
|
<Paragraph size="md" noMargin>
|
||||||
|
{cut ? shortVersionOf(value, cut) : value}
|
||||||
|
</Paragraph>
|
||||||
|
<CopyBtn content={value} />
|
||||||
|
<EtherscanBtn type={type} value={value} />
|
||||||
|
</Block>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default EtherscanLink
|
export default withStyles(styles)(EtherscanLink)
|
||||||
|
8
src/components/EtherscanLink/style.js
Normal file
8
src/components/EtherscanLink/style.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
export const styles = () => ({
|
||||||
|
etherscanLink: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
})
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 5.7 KiB |
@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 330"><title>gnosis_safe_teams_2019_logo_all_rgb</title><path d="M161,14.2A146.54,146.54,0,1,0,307.56,160.74,146.54,146.54,0,0,0,161,14.2ZM268.27,168.74h-68a41.41,41.41,0,1,1,.32-14.41h67.68a7.21,7.21,0,1,1,0,14.41Z"/><path d="M347.28,203.9h9.86l29.27,51.46h.22l29.26-51.46h9.76v79.6h-9.76V222.84h-.22l-25.9,44.62h-6.62l-25.89-44.62h-.12V283.5h-9.86Z"/><path d="M442.8,261.41V228.9h9.08v29.93c0,12.33,4.71,17,13.34,17s16.26-7.51,16.26-20.51V228.9h9.08v54.6h-9.08v-9.42h-.11a21.28,21.28,0,0,1-18.05,10.09C450.76,284.17,442.8,277,442.8,261.41Z"/><path d="M507.71,201h9.08V283.5h-9.08Z"/><path d="M535.74,267.24V236.75h-7.06V228.9h7.06V210.29l9.08-1V228.9h18v7.85h-18V265.9c0,6.61,1.46,9.75,6.62,9.75a20.58,20.58,0,0,0,9.3-2.8l2.36,8c-3,1.79-6.73,3.36-13.23,3.36C540.22,284.17,535.74,278.23,535.74,267.24Z"/><path d="M573.3,212.42a6.62,6.62,0,1,1,6.61,6.5A6.53,6.53,0,0,1,573.3,212.42Zm2,16.48h9.08v54.6h-9.08Z"/><path d="M597.29,276.43l4.6-6.95c4.26,4.15,9.08,6.62,16.7,6.62,6.62,0,10.43-3.25,10.43-7.4,0-4.82-5-6.17-13-9.08-8.85-3.14-16.36-6.73-16.36-16.71,0-8.41,7.62-14.68,17.93-14.68A28.46,28.46,0,0,1,636.42,235l-4.71,7.18a20.61,20.61,0,0,0-14.46-5.83c-4.26,0-8.41,2.46-8.41,6.61s4.37,6.39,10.31,8.52c11.55,4.49,19.17,6.51,19.06,17.16,0,8.52-6.5,15.58-19.62,15.58A31.37,31.37,0,0,1,597.29,276.43Z"/><path d="M649.76,212.42a6.62,6.62,0,1,1,6.61,6.5A6.53,6.53,0,0,1,649.76,212.42Zm2,16.48h9.08v54.6h-9.08Z"/><path d="M680.48,300.43l2.24-8.08c6.28,3.59,11.77,5.72,19.62,5.72,12.33,0,18.27-7.17,18.27-16.37V273h-.22c-4,5.83-10.54,9.53-18.95,9.53-14.91,0-26.46-10.76-26.46-27,0-15.58,10.77-27.24,26.13-27.24a23.6,23.6,0,0,1,19.17,9.41h.22V228.9h9.08v50.56c0,15.7-7.85,26.91-26.9,26.91A42.46,42.46,0,0,1,680.48,300.43ZM720.84,255c0-11-8-18.39-18.16-18.39-11.1,0-18.5,8-18.5,18.61,0,11.55,8.07,18.84,18.38,18.84C713.55,274.08,720.84,265.9,720.84,255Z"/><path d="M341.67,132.53c0-23.1,14.91-41,40.36-41,11.55,0,24.11,4.82,32.29,14.24l-13.23,11.21A26.79,26.79,0,0,0,382,109.09c-11.32,0-20.74,8.64-20.74,23.44,0,12.89,8,23.43,21.53,23.43a27.69,27.69,0,0,0,13.79-3.48v-9.42H381.14V127.59h33.41v35.77c-7.29,5.6-19.4,9.75-31.73,9.75C359.84,173.11,341.67,158.42,341.67,132.53Z"/><path d="M426.09,117.39h17.49v6.39h.23a21.26,21.26,0,0,1,16.48-7.4c11.32,0,19.62,5.61,19.62,23v32.84H462.42V143.63c0-9.09-3-11.66-8.75-11.66-6.05,0-10.09,4.14-10.09,12.66v27.58H426.09Z"/><path d="M488.65,144.86c0-16.71,12-28.48,29.71-28.48,17.27,0,29.6,11.55,29.6,28.48s-12.33,28.36-29.6,28.36C500.65,173.22,488.65,161.45,488.65,144.86Zm41.6,0c0-7.63-5-12.89-11.89-12.89-7.06,0-12,5.38-12,12.89,0,7.29,5,12.89,12,12.89C525,157.75,530.25,152.37,530.25,144.86Z"/><path d="M553.12,165.15l8.18-11.32c4.6,4.15,9.31,6.16,14.35,6.16,3.48,0,5.27-1.23,5.27-3.25,0-1.79-1.68-2.91-8.52-5-9.2-2.81-17.27-7.29-17.27-17.83,0-11.1,9.09-17.49,20.52-17.49a32.3,32.3,0,0,1,20.74,6.84l-8.3,12.22c-3.81-3.81-8.52-5.72-12.22-5.72-2,0-4.37.9-4.37,3,0,1.68,2,2.92,7.51,4.82,12.11,4.15,18.73,7.29,18.73,18.05,0,10.2-7.29,17.6-22.31,17.6C566.79,173.22,559.17,170.53,553.12,165.15Z"/><path d="M605.58,100.46c0-5.38,4.38-9.86,10.43-9.86s10.54,4.37,10.54,9.86c0,5.72-4.49,10.09-10.54,10.09S605.58,106.18,605.58,100.46Zm1.69,16.93h17.48v54.82H607.27Z"/><path d="M633.16,165.15l8.19-11.32c4.59,4.15,9.3,6.16,14.35,6.16,3.47,0,5.27-1.23,5.27-3.25,0-1.79-1.69-2.91-8.52-5-9.2-2.81-17.27-7.29-17.27-17.83,0-11.1,9.08-17.49,20.52-17.49a32.31,32.31,0,0,1,20.74,6.84l-8.3,12.22c-3.81-3.81-8.52-5.72-12.22-5.72-2,0-4.37.9-4.37,3,0,1.68,2,2.92,7.51,4.82,12.11,4.15,18.72,7.29,18.72,18.05,0,10.2-7.28,17.6-22.31,17.6C646.84,173.22,639.22,170.53,633.16,165.15Z"/><path d="M710,160.55l11-13.34c6.06,6.62,13.35,9.42,18.84,9.42,6.28,0,9-3.14,9-6.73,0-4.37-2.8-6.27-11.77-9.3-12.11-4.15-24.22-9.87-24.22-25.56,0-13.23,11.32-23.21,26.12-23.44,10.43-.22,20,3.82,27.58,10.32L755.92,115.6c-6.84-5.38-11.77-7.51-16.25-7.51s-7.4,2.35-7.4,6.16,2.8,5.83,11.43,9.19c14,5.39,24.78,9,24.78,24.33,0,18.73-16,25.45-29.26,25.45A40.52,40.52,0,0,1,710,160.55Z"/><path d="M774.87,144.86c0-16.82,10.87-28.48,25-28.48A19.66,19.66,0,0,1,815,123.22l.22-.11v-5.72h17.6v54.82h-16.7V166.5l-.23-.12c-3.58,4.6-8.52,6.84-15.13,6.84C785.74,173.22,774.87,161.79,774.87,144.86Zm41.15,0c0-7.51-5-13-11.55-13-6.73,0-11.77,5.16-11.77,13s4.82,12.89,11.77,12.89C810.75,157.75,816,152.71,816,144.86Z"/><path d="M846.51,131.52h-5.27V117.39h5.27v-8.63c0-13.57,7.06-20.18,18-20.18a27.42,27.42,0,0,1,14.8,4.26l-3.25,12.67a17.51,17.51,0,0,0-6.84-2c-3.14,0-5.16,1.57-5.16,5.94v8h10.43v14.13H864.11v40.69h-17.6Z"/><path d="M932.84,149.45H895.5c1.12,6.28,6.39,9.53,13.12,9.53A17.29,17.29,0,0,0,921.4,153l10.09,10.32c-4.6,5.72-12.22,9.86-24.66,9.86-16.6,0-28.71-11.43-28.71-28.47,0-16.6,11.66-28.37,28.26-28.37,15.47,0,26.79,11.55,26.79,27.81C933.17,145.76,933,148.33,932.84,149.45ZM895.62,139h20.51c-1.12-5.38-4.71-8.75-10-8.75S896.74,133.54,895.62,139Z"/></svg>
|
After Width: | Height: | Size: 4.8 KiB |
@ -16,15 +16,15 @@ import {
|
|||||||
border, sm, md, headerHeight,
|
border, sm, md, headerHeight,
|
||||||
} from '~/theme/variables'
|
} from '~/theme/variables'
|
||||||
import Provider from './Provider'
|
import Provider from './Provider'
|
||||||
import EarlyAccessLabel from './EarlyAccessLabel'
|
import NetworkLabel from './NetworkLabel'
|
||||||
import SafeListHeader from './SafeListHeader'
|
import SafeListHeader from './SafeListHeader'
|
||||||
|
|
||||||
const logo = require('../assets/gnosis-safe-logo.svg')
|
const logo = require('../assets/gnosis-safe-multisig-logo.svg')
|
||||||
|
|
||||||
type Props = Open & {
|
type Props = Open & {
|
||||||
classes: Object,
|
classes: Object,
|
||||||
providerDetails: React.Node,
|
providerDetails: React.Node,
|
||||||
providerInfo: React.Node,
|
providerInfo: React.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = () => ({
|
const styles = () => ({
|
||||||
@ -33,7 +33,7 @@ const styles = () => ({
|
|||||||
padding: 0,
|
padding: 0,
|
||||||
boxShadow: '0 0 10px 0 rgba(33, 48, 77, 0.1)',
|
boxShadow: '0 0 10px 0 rgba(33, 48, 77, 0.1)',
|
||||||
minWidth: '280px',
|
minWidth: '280px',
|
||||||
borderRadius: '8px',
|
borderRadius: sm,
|
||||||
marginTop: '11px',
|
marginTop: '11px',
|
||||||
},
|
},
|
||||||
summary: {
|
summary: {
|
||||||
@ -43,6 +43,8 @@ const styles = () => ({
|
|||||||
boxShadow: '0 2px 4px 0 rgba(212, 212, 211, 0.59)',
|
boxShadow: '0 2px 4px 0 rgba(212, 212, 211, 0.59)',
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
zIndex: 1301,
|
zIndex: 1301,
|
||||||
|
position: 'fixed',
|
||||||
|
width: '100%',
|
||||||
},
|
},
|
||||||
logo: {
|
logo: {
|
||||||
padding: `${sm} ${md}`,
|
padding: `${sm} ${md}`,
|
||||||
@ -54,10 +56,15 @@ const styles = () => ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const Layout = openHoc(({
|
const Layout = openHoc(
|
||||||
open, toggle, clickAway, classes, providerInfo, providerDetails,
|
({
|
||||||
}: Props) => (
|
open,
|
||||||
<>
|
toggle,
|
||||||
|
clickAway,
|
||||||
|
classes,
|
||||||
|
providerInfo,
|
||||||
|
providerDetails,
|
||||||
|
}: Props) => (
|
||||||
<Row className={classes.summary}>
|
<Row className={classes.summary}>
|
||||||
<Col start="xs" middle="xs" className={classes.logo}>
|
<Col start="xs" middle="xs" className={classes.logo}>
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
@ -67,15 +74,25 @@ const Layout = openHoc(({
|
|||||||
<Divider />
|
<Divider />
|
||||||
<SafeListHeader />
|
<SafeListHeader />
|
||||||
<Divider />
|
<Divider />
|
||||||
<EarlyAccessLabel />
|
<NetworkLabel />
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<Provider open={open} toggle={toggle} info={providerInfo}>
|
<Provider open={open} toggle={toggle} info={providerInfo}>
|
||||||
{(providerRef) => (
|
{(providerRef) => (
|
||||||
<Popper open={open} anchorEl={providerRef.current} placement="bottom" className={classes.popper}>
|
<Popper
|
||||||
|
open={open}
|
||||||
|
anchorEl={providerRef.current}
|
||||||
|
placement="bottom"
|
||||||
|
className={classes.popper}
|
||||||
|
popperOptions={{ positionFixed: true }}
|
||||||
|
>
|
||||||
{({ TransitionProps }) => (
|
{({ TransitionProps }) => (
|
||||||
<Grow {...TransitionProps}>
|
<Grow {...TransitionProps}>
|
||||||
<>
|
<>
|
||||||
<ClickAwayListener onClickAway={clickAway} mouseEvent="onClick" touchEvent={false}>
|
<ClickAwayListener
|
||||||
|
onClickAway={clickAway}
|
||||||
|
mouseEvent="onClick"
|
||||||
|
touchEvent={false}
|
||||||
|
>
|
||||||
<List className={classes.root} component="div">
|
<List className={classes.root} component="div">
|
||||||
{providerDetails}
|
{providerDetails}
|
||||||
</List>
|
</List>
|
||||||
@ -87,7 +104,7 @@ const Layout = openHoc(({
|
|||||||
)}
|
)}
|
||||||
</Provider>
|
</Provider>
|
||||||
</Row>
|
</Row>
|
||||||
</>
|
),
|
||||||
))
|
)
|
||||||
|
|
||||||
export default withStyles(styles)(Layout)
|
export default withStyles(styles)(Layout)
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { storiesOf } from '@storybook/react'
|
|
||||||
import * as React from 'react'
|
|
||||||
import styles from '~/components/layout/PageFrame/index.scss'
|
|
||||||
import Layout from './Layout'
|
|
||||||
import ProviderAccesible from './ProviderInfo/ProviderAccesible'
|
|
||||||
import UserDetails from './ProviderDetails/UserDetails'
|
|
||||||
import ProviderDisconnected from './ProviderInfo/ProviderDisconnected'
|
|
||||||
import ConnectDetails from './ProviderDetails/ConnectDetails'
|
|
||||||
|
|
||||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
|
||||||
|
|
||||||
storiesOf('Components /Header', module)
|
|
||||||
.addDecorator(FrameDecorator)
|
|
||||||
.add('Connected', () => {
|
|
||||||
const provider = 'Metamask'
|
|
||||||
const userAddress = '0x873faa4cddd5b157e8e5a57e7a5479afc5d30moe'
|
|
||||||
const network = 'RINKEBY'
|
|
||||||
const info = <ProviderAccesible provider={provider} network={network} userAddress={userAddress} connected />
|
|
||||||
const details = <UserDetails provider={provider} network={network} userAddress={userAddress} connected />
|
|
||||||
|
|
||||||
return <Layout providerInfo={info} providerDetails={details} />
|
|
||||||
})
|
|
||||||
.add('Disconnected', () => {
|
|
||||||
const info = <ProviderDisconnected />
|
|
||||||
const details = <ConnectDetails />
|
|
||||||
|
|
||||||
return <Layout providerInfo={info} providerDetails={details} />
|
|
||||||
})
|
|
||||||
.add('Connection Error', () => {
|
|
||||||
const provider = 'Metamask'
|
|
||||||
const userAddress = '0x873faa4cddd5b157e8e5a57e7a5479afc5d30moe'
|
|
||||||
const network = 'RINKEBY'
|
|
||||||
const info = <ProviderAccesible provider={provider} network={network} userAddress={userAddress} connected={false} />
|
|
||||||
const details = <UserDetails provider={provider} network={network} userAddress={userAddress} connected={false} />
|
|
||||||
|
|
||||||
return <Layout providerInfo={info} providerDetails={details} />
|
|
||||||
})
|
|
@ -1,20 +1,22 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
import { getNetwork } from '~/config'
|
||||||
import Paragraph from '~/components/layout/Paragraph'
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
import Col from '~/components/layout/Col'
|
import Col from '~/components/layout/Col'
|
||||||
import {
|
import {
|
||||||
xs, sm, md, border,
|
xs, sm, md, border,
|
||||||
} from '~/theme/variables'
|
} from '~/theme/variables'
|
||||||
|
|
||||||
export const TOGGLE_SIDEBAR_BTN_TESTID = 'TOGGLE_SIDEBAR_BTN'
|
const network = getNetwork()
|
||||||
|
const formattedNetwork = network[0].toUpperCase() + network.substring(1).toLowerCase()
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
container: {
|
container: {
|
||||||
flexGrow: 0,
|
flexGrow: 0,
|
||||||
padding: `0 ${md}`,
|
padding: `0 ${md}`,
|
||||||
},
|
},
|
||||||
counter: {
|
text: {
|
||||||
background: border,
|
background: border,
|
||||||
padding: `${xs} ${sm}`,
|
padding: `${xs} ${sm}`,
|
||||||
borderRadius: '3px',
|
borderRadius: '3px',
|
||||||
@ -28,8 +30,8 @@ const EarlyAccessLabel = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Col start="xs" middle="xs" className={classes.container}>
|
<Col start="xs" middle="xs" className={classes.container}>
|
||||||
<Paragraph size="xs" className={classes.counter}>
|
<Paragraph size="xs" className={classes.text}>
|
||||||
Early access
|
{formattedNetwork}
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
@ -1,11 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { storiesOf } from '@storybook/react'
|
|
||||||
import * as React from 'react'
|
|
||||||
import styles from '~/components/layout/PageFrame/index.scss'
|
|
||||||
import Component from './index'
|
|
||||||
|
|
||||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
|
||||||
|
|
||||||
storiesOf('Components', module)
|
|
||||||
.addDecorator(FrameDecorator)
|
|
||||||
.add('Loader', () => <Component />)
|
|
@ -3,6 +3,7 @@ import * as React from 'react'
|
|||||||
import cn from 'classnames'
|
import cn from 'classnames'
|
||||||
import Modal from '@material-ui/core/Modal'
|
import Modal from '@material-ui/core/Modal'
|
||||||
import { withStyles } from '@material-ui/core/styles'
|
import { withStyles } from '@material-ui/core/styles'
|
||||||
|
import { sm } from '~/theme/variables'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string,
|
title: string,
|
||||||
@ -27,7 +28,7 @@ const styles = () => ({
|
|||||||
top: '120px',
|
top: '120px',
|
||||||
width: '500px',
|
width: '500px',
|
||||||
height: '530px',
|
height: '530px',
|
||||||
borderRadius: '8px',
|
borderRadius: sm,
|
||||||
backgroundColor: '#ffffff',
|
backgroundColor: '#ffffff',
|
||||||
boxShadow: '0 0 5px 0 rgba(74, 85, 121, 0.5)',
|
boxShadow: '0 0 5px 0 rgba(74, 85, 121, 0.5)',
|
||||||
'&:focus': {
|
'&:focus': {
|
||||||
|
@ -16,6 +16,7 @@ export type Column = {
|
|||||||
custom: boolean, // If content will be rendered by user manually
|
custom: boolean, // If content will be rendered by user manually
|
||||||
width?: number,
|
width?: number,
|
||||||
static?: boolean, // If content can't be sorted by values in the column
|
static?: boolean, // If content can't be sorted by values in the column
|
||||||
|
style?: Object, // if you want to add some custom styling to the column
|
||||||
}
|
}
|
||||||
|
|
||||||
export const cellWidth = (width: number | typeof undefined) => {
|
export const cellWidth = (width: number | typeof undefined) => {
|
||||||
@ -56,12 +57,15 @@ class GnoTableHead extends React.PureComponent<Props> {
|
|||||||
sortDirection={orderBy === column.id ? order : false}
|
sortDirection={orderBy === column.id ? order : false}
|
||||||
>
|
>
|
||||||
{column.static ? (
|
{column.static ? (
|
||||||
column.label
|
<div style={column.style}>
|
||||||
|
{column.label}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<TableSortLabel
|
<TableSortLabel
|
||||||
active={orderBy === column.id}
|
active={orderBy === column.id}
|
||||||
direction={order}
|
direction={order}
|
||||||
onClick={this.changeSort(column.id, column.order)}
|
onClick={this.changeSort(column.id, column.order)}
|
||||||
|
style={column.style}
|
||||||
>
|
>
|
||||||
{column.label}
|
{column.label}
|
||||||
</TableSortLabel>
|
</TableSortLabel>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import classNames from 'classnames'
|
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import Table from '@material-ui/core/Table'
|
import Table from '@material-ui/core/Table'
|
||||||
import TableBody from '@material-ui/core/TableBody'
|
import TableBody from '@material-ui/core/TableBody'
|
||||||
@ -10,7 +9,7 @@ import TablePagination from '@material-ui/core/TablePagination'
|
|||||||
import Row from '~/components/layout/Row'
|
import Row from '~/components/layout/Row'
|
||||||
import { type Order, stableSort, getSorting } from '~/components/Table/sorting'
|
import { type Order, stableSort, getSorting } from '~/components/Table/sorting'
|
||||||
import TableHead, { type Column } from '~/components/Table/TableHead'
|
import TableHead, { type Column } from '~/components/Table/TableHead'
|
||||||
import { xl } from '~/theme/variables'
|
import { xxl, xl, sm } from '~/theme/variables'
|
||||||
|
|
||||||
type Props<K> = {
|
type Props<K> = {
|
||||||
label: string,
|
label: string,
|
||||||
@ -39,11 +38,12 @@ type State = {
|
|||||||
const styles = {
|
const styles = {
|
||||||
root: {
|
root: {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
borderRadius: '8px',
|
borderTopRightRadius: sm,
|
||||||
|
borderTopLeftRadius: sm,
|
||||||
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
||||||
},
|
},
|
||||||
selectRoot: {
|
selectRoot: {
|
||||||
lineHeight: '40px',
|
lineHeight: xxl,
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
},
|
},
|
||||||
white: {
|
white: {
|
||||||
@ -53,14 +53,11 @@ const styles = {
|
|||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
||||||
marginBottom: xl,
|
marginBottom: xl,
|
||||||
borderRadius: '8px',
|
borderBottomRightRadius: sm,
|
||||||
borderTopLeftRadius: 0,
|
borderBottomLeftRadius: sm,
|
||||||
borderTopRightRadius: 0,
|
|
||||||
},
|
},
|
||||||
loader: {
|
loader: {
|
||||||
alignItems: 'center',
|
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
||||||
justifyContent: 'center',
|
|
||||||
backgroundColor: 'white',
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +122,13 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
|
|||||||
|
|
||||||
getEmptyStyle = (emptyRows: number) => ({
|
getEmptyStyle = (emptyRows: number) => ({
|
||||||
height: FIXED_HEIGHT * emptyRows,
|
height: FIXED_HEIGHT * emptyRows,
|
||||||
|
borderTopRightRadius: sm,
|
||||||
|
borderTopLeftRadius: sm,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
})
|
})
|
||||||
|
|
||||||
handleChangePage = (e: SyntheticInputEvent<HTMLInputElement>, page: number) => {
|
handleChangePage = (e: SyntheticInputEvent<HTMLInputElement>, page: number) => {
|
||||||
@ -171,7 +175,7 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
|
|||||||
sortedData = sortedData.slice(page * displayRows, page * displayRows + displayRows)
|
sortedData = sortedData.slice(page * displayRows, page * displayRows + displayRows)
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyRows = displayRows - Math.min(displayRows, data.length - page * displayRows)
|
const emptyRows = displayRows - Math.min(displayRows, data.size - page * displayRows)
|
||||||
const isEmpty = size === 0
|
const isEmpty = size === 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -184,7 +188,7 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
|
|||||||
)}
|
)}
|
||||||
{isEmpty && (
|
{isEmpty && (
|
||||||
<Row
|
<Row
|
||||||
className={classNames(classes.loader, !noBorder && classes.root)}
|
className={classes.loader}
|
||||||
style={this.getEmptyStyle(emptyRows + 1)}
|
style={this.getEmptyStyle(emptyRows + 1)}
|
||||||
>
|
>
|
||||||
<CircularProgress size={60} />
|
<CircularProgress size={60} />
|
||||||
|
@ -19,6 +19,7 @@ type Props = {
|
|||||||
testId?: string,
|
testId?: string,
|
||||||
validators?: Function[],
|
validators?: Function[],
|
||||||
inputAdornment?: React.Element,
|
inputAdornment?: React.Element,
|
||||||
|
defaultValue?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isValidEnsName = (name) => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
|
const isValidEnsName = (name) => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
|
||||||
@ -35,6 +36,7 @@ const AddressInput = ({
|
|||||||
testId,
|
testId,
|
||||||
inputAdornment,
|
inputAdornment,
|
||||||
validators = [],
|
validators = [],
|
||||||
|
defaultValue,
|
||||||
}: Props): React.Element<*> => (
|
}: Props): React.Element<*> => (
|
||||||
<>
|
<>
|
||||||
<Field
|
<Field
|
||||||
@ -51,6 +53,7 @@ const AddressInput = ({
|
|||||||
text={text}
|
text={text}
|
||||||
className={className}
|
className={className}
|
||||||
testId={testId}
|
testId={testId}
|
||||||
|
defaultValue={defaultValue}
|
||||||
/>
|
/>
|
||||||
<OnChange name={name}>
|
<OnChange name={name}>
|
||||||
{async (value) => {
|
{async (value) => {
|
||||||
|
@ -13,7 +13,7 @@ type Props = {
|
|||||||
margin?: Size,
|
margin?: Size,
|
||||||
padding?: Size,
|
padding?: Size,
|
||||||
justify?: 'center' | 'right' | 'left' | 'space-around',
|
justify?: 'center' | 'right' | 'left' | 'space-around',
|
||||||
children: React.Node,
|
children?: React.Node,
|
||||||
className?: string,
|
className?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { storiesOf } from '@storybook/react'
|
|
||||||
import * as React from 'react'
|
|
||||||
import { host } from 'storybook-host'
|
|
||||||
import Component from './index'
|
|
||||||
|
|
||||||
storiesOf('Components', module)
|
|
||||||
.addDecorator(
|
|
||||||
host({
|
|
||||||
title: 'Hairline',
|
|
||||||
align: 'center',
|
|
||||||
height: 5,
|
|
||||||
width: '100%',
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.add('Hairline', () => <Component />)
|
|
@ -2,12 +2,12 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 80px 200px 0px 200px;
|
padding: 135px 200px 0px 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $(screenLg)px) {
|
@media only screen and (max-width: $(screenLg)px) {
|
||||||
.page {
|
.page {
|
||||||
padding: 80px $lg 0px $lg;
|
padding: 135px $lg 0px $lg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import ErrorIcon from './assets/error.svg'
|
|||||||
import InfoIcon from './assets/info.svg'
|
import InfoIcon from './assets/info.svg'
|
||||||
import CookiesBanner from '~/components/CookiesBanner'
|
import CookiesBanner from '~/components/CookiesBanner'
|
||||||
import styles from './index.scss'
|
import styles from './index.scss'
|
||||||
|
import { fontColor } from '~/theme/variables'
|
||||||
|
|
||||||
const notificationStyles = {
|
const notificationStyles = {
|
||||||
success: {
|
success: {
|
||||||
@ -24,7 +25,7 @@ const notificationStyles = {
|
|||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
lineHeight: 1.43,
|
lineHeight: 1.43,
|
||||||
color: '#001428',
|
color: fontColor,
|
||||||
minHeight: '58px',
|
minHeight: '58px',
|
||||||
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
||||||
},
|
},
|
||||||
@ -33,7 +34,7 @@ const notificationStyles = {
|
|||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
lineHeight: 1.43,
|
lineHeight: 1.43,
|
||||||
color: '#001428',
|
color: fontColor,
|
||||||
minHeight: '58px',
|
minHeight: '58px',
|
||||||
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
||||||
},
|
},
|
||||||
@ -42,7 +43,7 @@ const notificationStyles = {
|
|||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
lineHeight: 1.43,
|
lineHeight: 1.43,
|
||||||
color: '#001428',
|
color: fontColor,
|
||||||
minHeight: '58px',
|
minHeight: '58px',
|
||||||
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
||||||
},
|
},
|
||||||
@ -51,7 +52,7 @@ const notificationStyles = {
|
|||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
lineHeight: 1.43,
|
lineHeight: 1.43,
|
||||||
color: '#001428',
|
color: fontColor,
|
||||||
minHeight: '58px',
|
minHeight: '58px',
|
||||||
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
||||||
},
|
},
|
||||||
|
@ -52,6 +52,9 @@ export const getTxServiceHost = () => {
|
|||||||
export const getTxServiceUriFrom = (safeAddress: string) =>
|
export const getTxServiceUriFrom = (safeAddress: string) =>
|
||||||
`safes/${safeAddress}/transactions/`
|
`safes/${safeAddress}/transactions/`
|
||||||
|
|
||||||
|
export const getIncomingTxServiceUriTo = (safeAddress: string) =>
|
||||||
|
`safes/${safeAddress}/incoming-transactions/`
|
||||||
|
|
||||||
export const getRelayUrl = () => getConfig()[RELAY_API_URL]
|
export const getRelayUrl = () => getConfig()[RELAY_API_URL]
|
||||||
|
|
||||||
export const signaturesViaMetamask = () => {
|
export const signaturesViaMetamask = () => {
|
||||||
@ -69,3 +72,5 @@ export const getIntercomId = () =>
|
|||||||
process.env.REACT_APP_ENV === "production"
|
process.env.REACT_APP_ENV === "production"
|
||||||
? process.env.REACT_APP_INTERCOM_ID
|
? process.env.REACT_APP_INTERCOM_ID
|
||||||
: "plssl1fl"
|
: "plssl1fl"
|
||||||
|
|
||||||
|
export const getExchangeRatesUrl = () => 'https://api.exchangeratesapi.io/latest'
|
||||||
|
@ -8,6 +8,7 @@ import loadActiveTokens from '~/logic/tokens/store/actions/loadActiveTokens'
|
|||||||
import loadDefaultSafe from '~/routes/safe/store/actions/loadDefaultSafe'
|
import loadDefaultSafe from '~/routes/safe/store/actions/loadDefaultSafe'
|
||||||
import loadSafesFromStorage from '~/routes/safe/store/actions/loadSafesFromStorage'
|
import loadSafesFromStorage from '~/routes/safe/store/actions/loadSafesFromStorage'
|
||||||
import { store } from '~/store'
|
import { store } from '~/store'
|
||||||
|
import verifyRecurringUser from '~/utils/verifyRecurringUser'
|
||||||
|
|
||||||
BigNumber.set({ EXPONENTIAL_AT: [-7, 255] })
|
BigNumber.set({ EXPONENTIAL_AT: [-7, 255] })
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
store.dispatch(loadActiveTokens())
|
store.dispatch(loadActiveTokens())
|
||||||
store.dispatch(loadSafesFromStorage())
|
store.dispatch(loadSafesFromStorage())
|
||||||
store.dispatch(loadDefaultSafe())
|
store.dispatch(loadDefaultSafe())
|
||||||
|
verifyRecurringUser()
|
||||||
|
|
||||||
const root = document.getElementById('root')
|
const root = document.getElementById('root')
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ export const decodeParamsFromSafeMethod = async (data: string) => {
|
|||||||
case '0xe318b52b':
|
case '0xe318b52b':
|
||||||
return {
|
return {
|
||||||
methodName: METHOD_TO_ID[methodId],
|
methodName: METHOD_TO_ID[methodId],
|
||||||
args: web3.eth.abi.decodeParameters(['address', 'address', 'address'], params),
|
args: web3.eth.abi.decodeParameters(['uint', 'address', 'address'], params),
|
||||||
}
|
}
|
||||||
|
|
||||||
// addOwnerWithThreshold
|
// addOwnerWithThreshold
|
||||||
|
19
src/logic/currencyValues/api/fetchCurrenciesRates.js
Normal file
19
src/logic/currencyValues/api/fetchCurrenciesRates.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// @flow
|
||||||
|
import axios from 'axios'
|
||||||
|
import { getExchangeRatesUrl } from '~/config'
|
||||||
|
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
|
||||||
|
const fetchCurrenciesRates = async (baseCurrency: AVAILABLE_CURRENCIES, targetCurrencyValue: AVAILABLE_CURRENCIES): Promise<number> => {
|
||||||
|
let rate = 0
|
||||||
|
const url = `${getExchangeRatesUrl()}?base=${baseCurrency}&symbols=${targetCurrencyValue}`
|
||||||
|
|
||||||
|
const result = await axios.get(url)
|
||||||
|
if (result && result.data) {
|
||||||
|
const { rates } = result.data
|
||||||
|
rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return rate
|
||||||
|
}
|
||||||
|
|
||||||
|
export default fetchCurrenciesRates
|
15
src/logic/currencyValues/api/fetchTokenCurrenciesBalances.js
Normal file
15
src/logic/currencyValues/api/fetchTokenCurrenciesBalances.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// @flow
|
||||||
|
import axios from 'axios'
|
||||||
|
import { getTxServiceHost } from '~/config'
|
||||||
|
|
||||||
|
const fetchTokenCurrenciesBalances = (safeAddress: string) => {
|
||||||
|
if (!safeAddress) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const apiUrl = getTxServiceHost()
|
||||||
|
const url = `${apiUrl}safes/${safeAddress}/balances/usd`
|
||||||
|
|
||||||
|
return axios.get(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default fetchTokenCurrenciesBalances
|
@ -0,0 +1,35 @@
|
|||||||
|
// @flow
|
||||||
|
import { Dispatch as ReduxDispatch } from 'redux'
|
||||||
|
import { List } from 'immutable'
|
||||||
|
import type { GlobalState } from '~/store'
|
||||||
|
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
import fetchCurrenciesRates from '~/logic/currencyValues/api/fetchCurrenciesRates'
|
||||||
|
import { currencyValuesListSelector } from '~/logic/currencyValues/store/selectors'
|
||||||
|
import { setCurrencyBalances } from '~/logic/currencyValues/store/actions/setCurrencyBalances'
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
const fetchCurrencySelectedValue = (currencyValueSelected: AVAILABLE_CURRENCIES) => async (dispatch: ReduxDispatch<GlobalState>, getState: Function) => {
|
||||||
|
const state = getState()
|
||||||
|
const currencyBalancesList = currencyValuesListSelector(state)
|
||||||
|
const selectedCurrencyRateInBaseCurrency = await fetchCurrenciesRates(AVAILABLE_CURRENCIES.USD, currencyValueSelected)
|
||||||
|
|
||||||
|
|
||||||
|
const newList = []
|
||||||
|
for (const currencyValue of currencyBalancesList) {
|
||||||
|
const { balanceInBaseCurrency } = currencyValue
|
||||||
|
|
||||||
|
const balanceInSelectedCurrency = balanceInBaseCurrency * selectedCurrencyRateInBaseCurrency
|
||||||
|
|
||||||
|
const updatedValue = currencyValue.merge({
|
||||||
|
currencyName: currencyValueSelected,
|
||||||
|
balanceInSelectedCurrency,
|
||||||
|
})
|
||||||
|
|
||||||
|
newList.push(updatedValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(setCurrencyBalances(List(newList)))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default fetchCurrencySelectedValue
|
@ -0,0 +1,43 @@
|
|||||||
|
// @flow
|
||||||
|
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
|
import { List } from 'immutable'
|
||||||
|
import type { GlobalState } from '~/store'
|
||||||
|
import { setCurrencyBalances } from '~/logic/currencyValues/store/actions/setCurrencyBalances'
|
||||||
|
import { AVAILABLE_CURRENCIES, makeBalanceCurrency } from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
import { setCurrencySelected } from '~/logic/currencyValues/store/actions/setCurrencySelected'
|
||||||
|
import fetchTokenCurrenciesBalances from '~/logic/currencyValues/api/fetchTokenCurrenciesBalances'
|
||||||
|
import { loadFromStorage } from '~/utils/storage'
|
||||||
|
import fetchCurrencySelectedValue from '~/logic/currencyValues/store/actions/fetchCurrencySelectedValue'
|
||||||
|
import { CURRENCY_SELECTED_KEY } from '~/logic/currencyValues/store/actions/saveCurrencySelected'
|
||||||
|
|
||||||
|
|
||||||
|
export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||||
|
try {
|
||||||
|
const tokensFetched = await fetchTokenCurrenciesBalances(safeAddress)
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
const currencyList = List(tokensFetched.data.filter((currencyBalance) => currencyBalance.balanceUsd).map((currencyBalance) => {
|
||||||
|
const { balanceUsd, tokenAddress } = currencyBalance
|
||||||
|
return makeBalanceCurrency({
|
||||||
|
currencyName: balanceUsd ? AVAILABLE_CURRENCIES.USD : null,
|
||||||
|
tokenAddress,
|
||||||
|
balanceInBaseCurrency: balanceUsd,
|
||||||
|
balanceInSelectedCurrency: balanceUsd,
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
dispatch(setCurrencyBalances(currencyList))
|
||||||
|
const currencyStored = await loadFromStorage(CURRENCY_SELECTED_KEY)
|
||||||
|
if (!currencyStored) {
|
||||||
|
return dispatch(setCurrencySelected(AVAILABLE_CURRENCIES.USD))
|
||||||
|
}
|
||||||
|
const { currencyValueSelected } = currencyStored
|
||||||
|
dispatch(fetchCurrencySelectedValue(currencyValueSelected))
|
||||||
|
dispatch(setCurrencySelected(currencyValueSelected))
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error fetching tokens price list', err)
|
||||||
|
}
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default fetchCurrencyValues
|
@ -0,0 +1,18 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import { Dispatch as ReduxDispatch } from 'redux'
|
||||||
|
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
import type { GlobalState } from '~/store'
|
||||||
|
|
||||||
|
import { saveToStorage } from '~/utils/storage'
|
||||||
|
import { setCurrencySelected } from '~/logic/currencyValues/store/actions/setCurrencySelected'
|
||||||
|
|
||||||
|
|
||||||
|
export const CURRENCY_SELECTED_KEY = 'CURRENCY_SELECTED_KEY'
|
||||||
|
|
||||||
|
const saveCurrencySelected = (currencySelected: AVAILABLE_CURRENCIES) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||||
|
await saveToStorage(CURRENCY_SELECTED_KEY, { currencyValueSelected: currencySelected })
|
||||||
|
dispatch(setCurrencySelected(currencySelected))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default saveCurrencySelected
|
@ -0,0 +1,10 @@
|
|||||||
|
// @flow
|
||||||
|
import { Map } from 'immutable'
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
import type { CurrencyValues, CurrencyValuesProps } from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
|
||||||
|
export const SET_CURRENCY_BALANCES = 'SET_CURRENCY_BALANCES'
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
export const setCurrencyBalances = createAction<string, *>(SET_CURRENCY_BALANCES, (currencyBalances: Map<string, CurrencyValues>): CurrencyValuesProps => ({ currencyBalances }))
|
@ -0,0 +1,13 @@
|
|||||||
|
// @flow
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
import type {
|
||||||
|
CurrencyValuesProps,
|
||||||
|
} from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
|
||||||
|
|
||||||
|
export const SET_CURRENT_CURRENCY = 'SET_CURRENT_CURRENCY'
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
export const setCurrencySelected = createAction<string, *>(SET_CURRENT_CURRENCY, (currencyValueSelected: AVAILABLE_CURRENCIES): CurrencyValuesProps => ({ currencyValueSelected }))
|
61
src/logic/currencyValues/store/model/currencyValues.js
Normal file
61
src/logic/currencyValues/store/model/currencyValues.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// @flow
|
||||||
|
import type { RecordOf } from 'immutable'
|
||||||
|
import { Record } from 'immutable'
|
||||||
|
|
||||||
|
export const AVAILABLE_CURRENCIES = {
|
||||||
|
USD: 'USD',
|
||||||
|
EUR: 'EUR',
|
||||||
|
CAD: 'CAD',
|
||||||
|
HKD: 'HKD',
|
||||||
|
ISK: 'ISK',
|
||||||
|
PHP: 'PHP',
|
||||||
|
DKK: 'DKK',
|
||||||
|
HUF: 'HUF',
|
||||||
|
CZK: 'CZK',
|
||||||
|
AUD: 'AUD',
|
||||||
|
RON: 'RON',
|
||||||
|
SEK: 'SEK',
|
||||||
|
IDR: 'IDR',
|
||||||
|
INR: 'INR',
|
||||||
|
BRL: 'BRL',
|
||||||
|
RUB: 'RUB',
|
||||||
|
HRK: 'HRK',
|
||||||
|
JPY: 'JPY',
|
||||||
|
THB: 'THB',
|
||||||
|
CHF: 'CHF',
|
||||||
|
SGD: 'SGD',
|
||||||
|
PLN: 'PLN',
|
||||||
|
BGN: 'BGN',
|
||||||
|
TRY: 'TRY',
|
||||||
|
CNY: 'CNY',
|
||||||
|
NOK: 'NOK',
|
||||||
|
NZD: 'NZD',
|
||||||
|
ZAR: 'ZAR',
|
||||||
|
MXN: 'MXN',
|
||||||
|
ILS: 'ILS',
|
||||||
|
GBP: 'GBP',
|
||||||
|
KRW: 'KRW',
|
||||||
|
MYR: 'MYR',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type BalanceCurrencyType = {
|
||||||
|
currencyName: AVAILABLE_CURRENCIES;
|
||||||
|
tokenAddress: string,
|
||||||
|
balanceInBaseCurrency: string,
|
||||||
|
balanceInSelectedCurrency: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeBalanceCurrency = Record({
|
||||||
|
currencyName: '',
|
||||||
|
tokenAddress: '',
|
||||||
|
balanceInBaseCurrency: '',
|
||||||
|
balanceInSelectedCurrency: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export type CurrencyValuesProps = {
|
||||||
|
currencyValueSelected: AVAILABLE_CURRENCIES;
|
||||||
|
currencyValuesList: BalanceCurrencyType[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CurrencyValues = RecordOf<CurrencyValuesProps>
|
28
src/logic/currencyValues/store/reducer/currencyValues.js
Normal file
28
src/logic/currencyValues/store/reducer/currencyValues.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// @flow
|
||||||
|
import { Map } from 'immutable'
|
||||||
|
import { handleActions, type ActionType } from 'redux-actions'
|
||||||
|
import { SET_CURRENCY_BALANCES } from '../actions/setCurrencyBalances'
|
||||||
|
import type { State } from '~/logic/tokens/store/reducer/tokens'
|
||||||
|
import { SET_CURRENT_CURRENCY } from '~/logic/currencyValues/store/actions/setCurrencySelected'
|
||||||
|
|
||||||
|
export const CURRENCY_VALUES_KEY = 'currencyValues'
|
||||||
|
|
||||||
|
export default handleActions<State, *>(
|
||||||
|
{
|
||||||
|
[SET_CURRENCY_BALANCES]: (state: State, action: ActionType<Function>): State => {
|
||||||
|
const { currencyBalances } = action.payload
|
||||||
|
|
||||||
|
const newState = state.set('currencyBalances', currencyBalances)
|
||||||
|
|
||||||
|
return newState
|
||||||
|
},
|
||||||
|
[SET_CURRENT_CURRENCY]: (state: State, action: ActionType<Function>): State => {
|
||||||
|
const { currencyValueSelected } = action.payload
|
||||||
|
|
||||||
|
const newState = state.set('currencyValueSelected', currencyValueSelected)
|
||||||
|
|
||||||
|
return newState
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Map(),
|
||||||
|
)
|
9
src/logic/currencyValues/store/selectors/index.js
Normal file
9
src/logic/currencyValues/store/selectors/index.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import { List } from 'immutable'
|
||||||
|
import { type GlobalState } from '~/store'
|
||||||
|
import { CURRENCY_VALUES_KEY } from '~/logic/currencyValues/store/reducer/currencyValues'
|
||||||
|
|
||||||
|
|
||||||
|
export const currencyValuesListSelector = (state: GlobalState) => (state[CURRENCY_VALUES_KEY].get('currencyBalances') ? state[CURRENCY_VALUES_KEY].get('currencyBalances') : List([]))
|
||||||
|
export const currentCurrencySelector = (state: GlobalState) => state[CURRENCY_VALUES_KEY].get('currencyValueSelected')
|
@ -10,6 +10,7 @@ import { type Notification, NOTIFICATIONS } from './notificationTypes'
|
|||||||
export type NotificationsQueue = {
|
export type NotificationsQueue = {
|
||||||
beforeExecution: Notification | null,
|
beforeExecution: Notification | null,
|
||||||
pendingExecution: Notification | null,
|
pendingExecution: Notification | null,
|
||||||
|
waitingConfirmation: Notification | null,
|
||||||
afterExecution: {
|
afterExecution: {
|
||||||
noMoreConfirmationsNeeded: Notification | null,
|
noMoreConfirmationsNeeded: Notification | null,
|
||||||
moreConfirmationsNeeded: Notification | null,
|
moreConfirmationsNeeded: Notification | null,
|
||||||
@ -29,6 +30,15 @@ const standardTxNotificationsQueue: NotificationsQueue = {
|
|||||||
afterExecutionError: NOTIFICATIONS.TX_FAILED_MSG,
|
afterExecutionError: NOTIFICATIONS.TX_FAILED_MSG,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const waitingTransactionNotificationsQueue: NotificationsQueue = {
|
||||||
|
beforeExecution: null,
|
||||||
|
pendingExecution: null,
|
||||||
|
afterRejection: null,
|
||||||
|
waitingConfirmation: NOTIFICATIONS.TX_WAITING_MSG,
|
||||||
|
afterExecution: null,
|
||||||
|
afterExecutionError: null,
|
||||||
|
}
|
||||||
|
|
||||||
const confirmationTxNotificationsQueue: NotificationsQueue = {
|
const confirmationTxNotificationsQueue: NotificationsQueue = {
|
||||||
beforeExecution: NOTIFICATIONS.SIGN_TX_MSG,
|
beforeExecution: NOTIFICATIONS.SIGN_TX_MSG,
|
||||||
pendingExecution: NOTIFICATIONS.TX_CONFIRMATION_PENDING_MSG,
|
pendingExecution: NOTIFICATIONS.TX_CONFIRMATION_PENDING_MSG,
|
||||||
@ -123,6 +133,10 @@ export const getNotificationsFromTxType = (txType: string) => {
|
|||||||
notificationsQueue = ownerNameChangeNotificationsQueue
|
notificationsQueue = ownerNameChangeNotificationsQueue
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case TX_NOTIFICATION_TYPES.WAITING_TX: {
|
||||||
|
notificationsQueue = waitingTransactionNotificationsQueue
|
||||||
|
break
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
notificationsQueue = defaultNotificationsQueue
|
notificationsQueue = defaultNotificationsQueue
|
||||||
break
|
break
|
||||||
@ -132,10 +146,12 @@ export const getNotificationsFromTxType = (txType: string) => {
|
|||||||
return notificationsQueue
|
return notificationsQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enhanceSnackbarForAction = (notification: Notification) => ({
|
export const enhanceSnackbarForAction = (notification: Notification, key?: string, onClick?: Function) => ({
|
||||||
...notification,
|
...notification,
|
||||||
|
key,
|
||||||
options: {
|
options: {
|
||||||
...notification.options,
|
...notification.options,
|
||||||
|
onClick,
|
||||||
action: (key: number) => (
|
action: (key: number) => (
|
||||||
<IconButton onClick={() => store.dispatch(closeSnackbarAction({ key }))}>
|
<IconButton onClick={() => store.dispatch(closeSnackbarAction({ key }))}>
|
||||||
<IconClose />
|
<IconClose />
|
||||||
|
@ -14,6 +14,7 @@ export type Variant = 'success' | 'error' | 'warning' | 'info'
|
|||||||
|
|
||||||
export type Notification = {
|
export type Notification = {
|
||||||
message: string,
|
message: string,
|
||||||
|
key?: string,
|
||||||
options: {
|
options: {
|
||||||
variant: Variant,
|
variant: Variant,
|
||||||
persist: boolean,
|
persist: boolean,
|
||||||
@ -38,6 +39,8 @@ export type Notifications = {
|
|||||||
TX_EXECUTED_MSG: Notification,
|
TX_EXECUTED_MSG: Notification,
|
||||||
TX_EXECUTED_MORE_CONFIRMATIONS_MSG: Notification,
|
TX_EXECUTED_MORE_CONFIRMATIONS_MSG: Notification,
|
||||||
TX_FAILED_MSG: Notification,
|
TX_FAILED_MSG: Notification,
|
||||||
|
TX_WAITING_MSG: Notification,
|
||||||
|
TX_INCOMING_MSG: Notification,
|
||||||
|
|
||||||
// Approval Transactions
|
// Approval Transactions
|
||||||
TX_CONFIRMATION_PENDING_MSG: Notification,
|
TX_CONFIRMATION_PENDING_MSG: Notification,
|
||||||
@ -122,6 +125,20 @@ export const NOTIFICATIONS: Notifications = {
|
|||||||
message: 'Transaction failed',
|
message: 'Transaction failed',
|
||||||
options: { variant: ERROR, persist: false, autoHideDuration: longDuration },
|
options: { variant: ERROR, persist: false, autoHideDuration: longDuration },
|
||||||
},
|
},
|
||||||
|
TX_WAITING_MSG: {
|
||||||
|
message: 'A pending transaction requires your confirmation!',
|
||||||
|
key: 'TX_WAITING_MSG',
|
||||||
|
options: {
|
||||||
|
variant: WARNING, persist: true, preventDuplicate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TX_INCOMING_MSG: {
|
||||||
|
message: 'Incoming transfer: ',
|
||||||
|
key: 'TX_INCOMING_MSG',
|
||||||
|
options: {
|
||||||
|
variant: SUCCESS, persist: false, autoHideDuration: longDuration, preventDuplicate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// Approval Transactions
|
// Approval Transactions
|
||||||
TX_CONFIRMATION_PENDING_MSG: {
|
TX_CONFIRMATION_PENDING_MSG: {
|
||||||
|
@ -11,9 +11,8 @@ const addSnackbar = createAction<string, *>(ENQUEUE_SNACKBAR)
|
|||||||
const enqueueSnackbar = (notification: NotificationProps) => (dispatch: ReduxDispatch<GlobalState>) => {
|
const enqueueSnackbar = (notification: NotificationProps) => (dispatch: ReduxDispatch<GlobalState>) => {
|
||||||
const newNotification = {
|
const newNotification = {
|
||||||
...notification,
|
...notification,
|
||||||
key: new Date().getTime(),
|
key: notification.key || new Date().getTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(addSnackbar(newNotification))
|
dispatch(addSnackbar(newNotification))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
43
src/logic/safe/transactions/awaitingTransactions.js
Normal file
43
src/logic/safe/transactions/awaitingTransactions.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// @flow
|
||||||
|
import { Map, List } from 'immutable'
|
||||||
|
import type { Transaction } from '~/routes/safe/store/models/transaction'
|
||||||
|
|
||||||
|
export const getAwaitingTransactions = (
|
||||||
|
allTransactions: Map<string, List<Transaction>>,
|
||||||
|
userAccount: string,
|
||||||
|
): Map<string, List<Transaction>> => {
|
||||||
|
if (!allTransactions) {
|
||||||
|
return Map({})
|
||||||
|
}
|
||||||
|
|
||||||
|
const allAwaitingTransactions = allTransactions.map((safeTransactions) => {
|
||||||
|
const nonCancelledTransactions = safeTransactions.filter(
|
||||||
|
(transaction: Transaction) => {
|
||||||
|
// If transactions are not executed, but there's a transaction with the same nonce EXECUTED later
|
||||||
|
// it means that the transaction was cancelled (Replaced) and shouldn't get executed
|
||||||
|
if (!transaction.isExecuted) {
|
||||||
|
const replacementTransaction = safeTransactions.findLast(
|
||||||
|
(tx) => tx.isExecuted && tx.nonce === transaction.nonce,
|
||||||
|
)
|
||||||
|
if (replacementTransaction) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
transaction = transaction.set('cancelled', true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The transaction is not executed and is not cancelled, so it's still waiting confirmations
|
||||||
|
if (!transaction.executionTxHash && !transaction.cancelled) {
|
||||||
|
// Then we check if the waiting confirmations are not from the current user, otherwise, filters this transaction
|
||||||
|
const transactionWaitingUser = transaction.confirmations.filter(
|
||||||
|
(confirmation) => confirmation.owner && confirmation.owner.address !== userAccount,
|
||||||
|
)
|
||||||
|
|
||||||
|
return transactionWaitingUser.size > 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return nonCancelledTransactions
|
||||||
|
})
|
||||||
|
|
||||||
|
return allAwaitingTransactions
|
||||||
|
}
|
11
src/logic/safe/transactions/incomingTxHistory.js
Normal file
11
src/logic/safe/transactions/incomingTxHistory.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// @flow
|
||||||
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
|
import { getIncomingTxServiceUriTo, getTxServiceHost } from '~/config'
|
||||||
|
|
||||||
|
export const buildIncomingTxServiceUrl = (safeAddress: string) => {
|
||||||
|
const host = getTxServiceHost()
|
||||||
|
const address = getWeb3().utils.toChecksumAddress(safeAddress)
|
||||||
|
const base = getIncomingTxServiceUriTo(address)
|
||||||
|
|
||||||
|
return `${host}${base}`
|
||||||
|
}
|
@ -4,6 +4,7 @@ export type NotifiedTransaction = {
|
|||||||
STANDARD_TX: string,
|
STANDARD_TX: string,
|
||||||
CONFIRMATION_TX: string,
|
CONFIRMATION_TX: string,
|
||||||
CANCELLATION_TX: string,
|
CANCELLATION_TX: string,
|
||||||
|
WAITING_TX: string,
|
||||||
SETTINGS_CHANGE_TX: string,
|
SETTINGS_CHANGE_TX: string,
|
||||||
SAFE_NAME_CHANGE_TX: string,
|
SAFE_NAME_CHANGE_TX: string,
|
||||||
OWNER_NAME_CHANGE_TX: string,
|
OWNER_NAME_CHANGE_TX: string,
|
||||||
@ -13,6 +14,7 @@ export const TX_NOTIFICATION_TYPES: NotifiedTransaction = {
|
|||||||
STANDARD_TX: 'STANDARD_TX',
|
STANDARD_TX: 'STANDARD_TX',
|
||||||
CONFIRMATION_TX: 'CONFIRMATION_TX',
|
CONFIRMATION_TX: 'CONFIRMATION_TX',
|
||||||
CANCELLATION_TX: 'CANCELLATION_TX',
|
CANCELLATION_TX: 'CANCELLATION_TX',
|
||||||
|
WAITING_TX: 'WAITING_TX',
|
||||||
SETTINGS_CHANGE_TX: 'SETTINGS_CHANGE_TX',
|
SETTINGS_CHANGE_TX: 'SETTINGS_CHANGE_TX',
|
||||||
SAFE_NAME_CHANGE_TX: 'SAFE_NAME_CHANGE_TX',
|
SAFE_NAME_CHANGE_TX: 'SAFE_NAME_CHANGE_TX',
|
||||||
OWNER_NAME_CHANGE_TX: 'OWNER_NAME_CHANGE_TX',
|
OWNER_NAME_CHANGE_TX: 'OWNER_NAME_CHANGE_TX',
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
|
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
|
||||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { type Operation } from '~/logic/safe/transactions'
|
import { type Operation } from '~/logic/safe/transactions'
|
||||||
import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
|
|
||||||
|
|
||||||
export const CALL = 0
|
export const CALL = 0
|
||||||
export const TX_TYPE_EXECUTION = 'execution'
|
export const TX_TYPE_EXECUTION = 'execution'
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
import { List } from 'immutable'
|
||||||
|
import type { Safe } from '~/routes/safe/store/models/safe'
|
||||||
|
import type { Owner } from '~/routes/safe/store/models/owner'
|
||||||
|
|
||||||
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||||
|
|
||||||
export const sameAddress = (firstAddress: string, secondAddress: string): boolean => {
|
export const sameAddress = (firstAddress: string, secondAddress: string): boolean => {
|
||||||
@ -13,10 +17,32 @@ export const sameAddress = (firstAddress: string, secondAddress: string): boolea
|
|||||||
return firstAddress.toLowerCase() === secondAddress.toLowerCase()
|
return firstAddress.toLowerCase() === secondAddress.toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const shortVersionOf = (address: string, cut: number) => {
|
export const shortVersionOf = (value: string, cut: number) => {
|
||||||
const final = 42 - cut
|
if (!value) {
|
||||||
|
return 'Unknown'
|
||||||
|
}
|
||||||
|
|
||||||
if (!address) return 'Unknown address'
|
const final = value.length - cut
|
||||||
if (address.length < final) return address
|
if (value.length < final) {
|
||||||
return `${address.substring(0, cut)}...${address.substring(final)}`
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${value.substring(0, cut)}...${value.substring(final)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isUserOwner = (safe: Safe, userAccount: string): boolean => {
|
||||||
|
if (!safe) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userAccount) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const { owners }: List<Owner> = safe
|
||||||
|
if (!owners) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return owners.find((owner: Owner) => sameAddress(owner.address, userAccount)) !== undefined
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import ReviewInformation from '~/routes/load/components/ReviewInformation'
|
|||||||
import OwnerList from '~/routes/load/components/OwnerList'
|
import OwnerList from '~/routes/load/components/OwnerList'
|
||||||
import DetailsForm, { safeFieldsValidation } from '~/routes/load/components/DetailsForm'
|
import DetailsForm, { safeFieldsValidation } from '~/routes/load/components/DetailsForm'
|
||||||
import { history } from '~/store'
|
import { history } from '~/store'
|
||||||
import { secondary } from '~/theme/variables'
|
import { secondary, sm } from '~/theme/variables'
|
||||||
import { type SelectorProps } from '~/routes/load/container/selector'
|
import { type SelectorProps } from '~/routes/load/container/selector'
|
||||||
|
|
||||||
const getSteps = () => ['Name and address', 'Owners', 'Review']
|
const getSteps = () => ['Name and address', 'Owners', 'Review']
|
||||||
@ -21,7 +21,7 @@ export type LayoutProps = SelectorProps & {
|
|||||||
|
|
||||||
const iconStyle = {
|
const iconStyle = {
|
||||||
color: secondary,
|
color: secondary,
|
||||||
padding: '8px',
|
padding: sm,
|
||||||
marginRight: '5px',
|
marginRight: '5px',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,28 +9,62 @@ import Row from '~/components/layout/Row'
|
|||||||
import Review from '~/routes/open/components/ReviewInformation'
|
import Review from '~/routes/open/components/ReviewInformation'
|
||||||
import SafeNameField from '~/routes/open/components/SafeNameForm'
|
import SafeNameField from '~/routes/open/components/SafeNameForm'
|
||||||
import SafeOwnersFields from '~/routes/open/components/SafeOwnersConfirmationsForm'
|
import SafeOwnersFields from '~/routes/open/components/SafeOwnersConfirmationsForm'
|
||||||
import { getOwnerNameBy, getOwnerAddressBy, FIELD_CONFIRMATIONS } from '~/routes/open/components/fields'
|
import {
|
||||||
|
getOwnerNameBy,
|
||||||
|
getOwnerAddressBy,
|
||||||
|
FIELD_CONFIRMATIONS,
|
||||||
|
FIELD_SAFE_NAME,
|
||||||
|
} from '~/routes/open/components/fields'
|
||||||
|
import { initContracts } from '~/logic/contracts/safeContracts'
|
||||||
import { history } from '~/store'
|
import { history } from '~/store'
|
||||||
import { secondary } from '~/theme/variables'
|
import { secondary, sm } from '~/theme/variables'
|
||||||
|
import type { SafePropsType } from '~/routes/open/container/Open'
|
||||||
|
import Welcome from '~/routes/welcome/components/Layout'
|
||||||
|
|
||||||
|
const { useEffect } = React
|
||||||
|
|
||||||
const getSteps = () => ['Name', 'Owners and confirmations', 'Review']
|
const getSteps = () => ['Name', 'Owners and confirmations', 'Review']
|
||||||
|
|
||||||
const initialValuesFrom = (userAccount: string) => ({
|
|
||||||
[getOwnerNameBy(0)]: 'My Wallet',
|
const initialValuesFrom = (userAccount: string, safeProps?: SafePropsType) => {
|
||||||
[getOwnerAddressBy(0)]: userAccount,
|
if (!safeProps) {
|
||||||
[FIELD_CONFIRMATIONS]: '1',
|
return ({
|
||||||
})
|
[getOwnerNameBy(0)]: 'My Wallet',
|
||||||
|
[getOwnerAddressBy(0)]: userAccount,
|
||||||
|
[FIELD_CONFIRMATIONS]: '1',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let obj = {}
|
||||||
|
const {
|
||||||
|
ownerAddresses, ownerNames, threshold, name,
|
||||||
|
} = safeProps
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
for (const [index, value] of ownerAddresses.entries()) {
|
||||||
|
const safeName = ownerNames[index] ? ownerNames[index] : 'My Wallet'
|
||||||
|
obj = {
|
||||||
|
...obj,
|
||||||
|
[getOwnerAddressBy(index)]: value,
|
||||||
|
[getOwnerNameBy(index)]: safeName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ({
|
||||||
|
...obj,
|
||||||
|
[FIELD_CONFIRMATIONS]: threshold || '1',
|
||||||
|
[FIELD_SAFE_NAME]: name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
provider: string,
|
provider: string,
|
||||||
userAccount: string,
|
userAccount: string,
|
||||||
network: string,
|
network: string,
|
||||||
onCallSafeContractSubmit: (values: Object) => Promise<void>,
|
onCallSafeContractSubmit: (values: Object) => Promise<void>,
|
||||||
|
safeProps?: SafePropsType,
|
||||||
}
|
}
|
||||||
|
|
||||||
const iconStyle = {
|
const iconStyle = {
|
||||||
color: secondary,
|
color: secondary,
|
||||||
padding: '8px',
|
padding: sm,
|
||||||
marginRight: '5px',
|
marginRight: '5px',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,11 +78,21 @@ const formMutators = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const Layout = ({
|
|
||||||
provider, userAccount, onCallSafeContractSubmit, network,
|
const Layout = (props: Props) => {
|
||||||
}: Props) => {
|
const {
|
||||||
|
provider, userAccount, onCallSafeContractSubmit, network, safeProps,
|
||||||
|
} = props
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (provider) {
|
||||||
|
initContracts()
|
||||||
|
}
|
||||||
|
}, [provider])
|
||||||
|
|
||||||
const steps = getSteps()
|
const steps = getSteps()
|
||||||
const initialValues = initialValuesFrom(userAccount)
|
|
||||||
|
const initialValues = initialValuesFrom(userAccount, safeProps)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -75,7 +119,7 @@ const Layout = ({
|
|||||||
</Stepper>
|
</Stepper>
|
||||||
</Block>
|
</Block>
|
||||||
) : (
|
) : (
|
||||||
<div>No web3 provider detected</div>
|
<Welcome provider={provider} isOldMultisigMigration />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { storiesOf } from '@storybook/react'
|
|
||||||
import { State, Store } from '@sambego/storybook-state'
|
|
||||||
import * as React from 'react'
|
|
||||||
import styles from '~/components/layout/PageFrame/index.scss'
|
|
||||||
import { getAccountsFrom, getThresholdFrom } from '~/routes/open/utils/safeDataExtractor'
|
|
||||||
import { getProviderInfo } from '~/logic/wallets/getWeb3'
|
|
||||||
import { sleep } from '~/utils/timer'
|
|
||||||
import Component from './Layout'
|
|
||||||
|
|
||||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
|
||||||
|
|
||||||
const store = new Store({
|
|
||||||
safeAddress: '',
|
|
||||||
safeTx: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
storiesOf('Routes /open', module)
|
|
||||||
.addDecorator(FrameDecorator)
|
|
||||||
.add('Open Safe with all props set', () => {
|
|
||||||
getProviderInfo()
|
|
||||||
const provider = 'METAMASK'
|
|
||||||
const userAccount = '0x03db1a8b26d08df23337e9276a36b474510f0023'
|
|
||||||
const onCallSafeContractSubmit = async (values: Object): Promise<void> => {
|
|
||||||
const accounts = getAccountsFrom(values)
|
|
||||||
const numConfirmations = getThresholdFrom(values)
|
|
||||||
const data = {
|
|
||||||
userAccount,
|
|
||||||
accounts,
|
|
||||||
requiredConfirmations: numConfirmations,
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
|
||||||
console.log(`Generating and sending a eth tx based on: ${JSON.stringify(data, null, 2)}`)
|
|
||||||
|
|
||||||
await sleep(3000)
|
|
||||||
|
|
||||||
store.set({
|
|
||||||
safeAddress: '0x03db1a8b26d08df23337e9276a36b474510f0025',
|
|
||||||
// eslint-disable-next-line
|
|
||||||
safeTx: {
|
|
||||||
transactionHash: '0x4603de1ab6a92b4ee1fd67189089f5c02f5df5d135bf85af84083c27808c0544',
|
|
||||||
transactionIndex: 0,
|
|
||||||
blockHash: '0x593ce7d85fef2a492e8f759f485c8b66ff803773e77182c68dd45c439b7a956d',
|
|
||||||
blockNumber: 19,
|
|
||||||
gasUsed: 3034193,
|
|
||||||
cumulativeGasUsed: 3034193,
|
|
||||||
contractAddress: '0xfddda33736fb95b587cbfecc1ff4a50f717adc00',
|
|
||||||
logs: [],
|
|
||||||
status: '0x01',
|
|
||||||
logsBloom:
|
|
||||||
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<State store={store}>
|
|
||||||
<Component
|
|
||||||
network="rinkeby"
|
|
||||||
provider={provider}
|
|
||||||
userAccount={userAccount}
|
|
||||||
safeAddress={store.get('safeAddress')}
|
|
||||||
safeTx={store.get('safeTx')}
|
|
||||||
onCallSafeContractSubmit={onCallSafeContractSubmit}
|
|
||||||
/>
|
|
||||||
</State>
|
|
||||||
)
|
|
||||||
})
|
|
@ -12,6 +12,7 @@ import { sm, secondary } from '~/theme/variables'
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
classes: Object,
|
classes: Object,
|
||||||
|
safeName?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = () => ({
|
const styles = () => ({
|
||||||
@ -32,12 +33,13 @@ const styles = () => ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const SafeName = ({ classes }: Props) => (
|
const SafeName = ({ classes, safeName }: Props) => (
|
||||||
<>
|
<>
|
||||||
<Block margin="lg">
|
<Block margin="lg">
|
||||||
<Paragraph noMargin size="md" color="primary">
|
<Paragraph noMargin size="md" color="primary">
|
||||||
You are about to create a new Gnosis Safe wallet with one or more owners. First, let's give your new wallet
|
You are about to create a new Gnosis Safe wallet with one or more owners. First, let's give your new
|
||||||
a name. This name is only stored locally and will never be shared with Gnosis or any third parties.
|
wallet
|
||||||
|
a name. This name is only stored locally and will never be shared with Gnosis or any third parties.
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</Block>
|
</Block>
|
||||||
<Block margin="lg" className={classes.root}>
|
<Block margin="lg" className={classes.root}>
|
||||||
@ -48,23 +50,24 @@ const SafeName = ({ classes }: Props) => (
|
|||||||
validate={required}
|
validate={required}
|
||||||
placeholder="Name of the new Safe"
|
placeholder="Name of the new Safe"
|
||||||
text="Safe name"
|
text="Safe name"
|
||||||
|
defaultValue={safeName}
|
||||||
/>
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
<Block margin="lg">
|
<Block margin="lg">
|
||||||
<Paragraph noMargin size="md" color="primary" className={classes.links}>
|
<Paragraph noMargin size="md" color="primary" className={classes.links}>
|
||||||
By continuing you consent with the
|
By continuing you consent with the
|
||||||
{' '}
|
{' '}
|
||||||
<a rel="noopener noreferrer" href="https://safe.gnosis.io/terms" target="_blank">
|
<a rel="noopener noreferrer" href="https://safe.gnosis.io/terms" target="_blank">
|
||||||
terms of use
|
terms of use
|
||||||
</a>
|
</a>
|
||||||
{' '}
|
{' '}
|
||||||
and
|
and
|
||||||
{' '}
|
{' '}
|
||||||
<a rel="noopener noreferrer" href="https://safe.gnosis.io/privacy" target="_blank">
|
<a rel="noopener noreferrer" href="https://safe.gnosis.io/privacy" target="_blank">
|
||||||
privacy policy
|
privacy policy
|
||||||
</a>
|
</a>
|
||||||
. Most importantly, you confirm that your funds are held securely in the Gnosis Safe, a smart contract on the
|
. Most importantly, you confirm that your funds are held securely in the Gnosis Safe, a smart contract on the
|
||||||
Ethereum blockchain. These funds cannot be accessed by Gnosis at any point.
|
Ethereum blockchain. These funds cannot be accessed by Gnosis at any point.
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</Block>
|
</Block>
|
||||||
</>
|
</>
|
||||||
@ -72,10 +75,13 @@ const SafeName = ({ classes }: Props) => (
|
|||||||
|
|
||||||
const SafeNameForm = withStyles(styles)(SafeName)
|
const SafeNameForm = withStyles(styles)(SafeName)
|
||||||
|
|
||||||
const SafeNamePage = () => (controls: React.Node) => (
|
const SafeNamePage = () => (controls: React.Node, { values }) => {
|
||||||
<OpenPaper controls={controls}>
|
const { safeName } = values
|
||||||
<SafeNameForm />
|
return (
|
||||||
</OpenPaper>
|
<OpenPaper controls={controls}>
|
||||||
)
|
<SafeNameForm safeName={safeName} />
|
||||||
|
</OpenPaper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default SafeNamePage
|
export default SafeNamePage
|
||||||
|
@ -4,6 +4,7 @@ import { withStyles } from '@material-ui/core/styles'
|
|||||||
import InputAdornment from '@material-ui/core/InputAdornment'
|
import InputAdornment from '@material-ui/core/InputAdornment'
|
||||||
import CheckCircle from '@material-ui/icons/CheckCircle'
|
import CheckCircle from '@material-ui/icons/CheckCircle'
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem'
|
||||||
|
import { withRouter } from 'react-router-dom'
|
||||||
import Field from '~/components/forms/Field'
|
import Field from '~/components/forms/Field'
|
||||||
import TextField from '~/components/forms/TextField'
|
import TextField from '~/components/forms/TextField'
|
||||||
import SelectField from '~/components/forms/SelectField'
|
import SelectField from '~/components/forms/SelectField'
|
||||||
@ -70,6 +71,7 @@ const SafeOwners = (props: Props) => {
|
|||||||
} = props
|
} = props
|
||||||
|
|
||||||
const validOwners = getNumOwnersFrom(values)
|
const validOwners = getNumOwnersFrom(values)
|
||||||
|
|
||||||
const [numOwners, setNumOwners] = useState<number>(validOwners)
|
const [numOwners, setNumOwners] = useState<number>(validOwners)
|
||||||
const [qrModalOpen, setQrModalOpen] = useState<boolean>(false)
|
const [qrModalOpen, setQrModalOpen] = useState<boolean>(false)
|
||||||
const [scanQrForOwnerName, setScanQrForOwnerName] = useState<string | null>(null)
|
const [scanQrForOwnerName, setScanQrForOwnerName] = useState<string | null>(null)
|
||||||
@ -222,7 +224,7 @@ owner(s)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const SafeOwnersForm = withStyles(styles)(SafeOwners)
|
const SafeOwnersForm = withStyles(styles)(withRouter(SafeOwners))
|
||||||
|
|
||||||
const SafeOwnersPage = ({ updateInitialProps }: Object) => (controls: React.Node, { values, errors, form }: Object) => (
|
const SafeOwnersPage = ({ updateInitialProps }: Object) => (controls: React.Node, { values, errors, form }: Object) => (
|
||||||
<>
|
<>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
export const FIELD_NAME: string = 'name'
|
export const FIELD_NAME: string = 'name'
|
||||||
export const FIELD_CONFIRMATIONS: string = 'confirmations'
|
export const FIELD_CONFIRMATIONS: string = 'confirmations'
|
||||||
export const FIELD_OWNERS: string = 'owners'
|
export const FIELD_OWNERS: string = 'owners'
|
||||||
|
export const FIELD_SAFE_NAME: string = 'safeName'
|
||||||
|
|
||||||
export const getOwnerNameBy = (index: number) => `owner${index}Name`
|
export const getOwnerNameBy = (index: number) => `owner${index}Name`
|
||||||
export const getOwnerAddressBy = (index: number) => `owner${index}Address`
|
export const getOwnerAddressBy = (index: number) => `owner${index}Address`
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
import queryString from 'query-string'
|
||||||
|
import { withRouter } from 'react-router-dom'
|
||||||
import Page from '~/components/layout/Page'
|
import Page from '~/components/layout/Page'
|
||||||
import {
|
import {
|
||||||
getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom, getOwnersFrom,
|
getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom, getOwnersFrom,
|
||||||
} from '~/routes/open/utils/safeDataExtractor'
|
} from '~/routes/open/utils/safeDataExtractor'
|
||||||
import { buildSafe } from '~/routes/safe/store/actions/fetchSafe'
|
import { buildSafe } from '~/routes/safe/store/actions/fetchSafe'
|
||||||
import { getGnosisSafeInstanceAt, deploySafeContract, initContracts } from '~/logic/contracts/safeContracts'
|
import { getGnosisSafeInstanceAt, deploySafeContract } from '~/logic/contracts/safeContracts'
|
||||||
import { checkReceiptStatus } from '~/logic/wallets/ethTransactions'
|
import { checkReceiptStatus } from '~/logic/wallets/ethTransactions'
|
||||||
import { history } from '~/store'
|
import { history } from '~/store'
|
||||||
import { OPENING_ADDRESS, stillInOpeningView, SAFELIST_ADDRESS } from '~/routes/routes'
|
import { OPENING_ADDRESS, stillInOpeningView, SAFELIST_ADDRESS } from '~/routes/routes'
|
||||||
@ -24,14 +26,36 @@ export type OpenState = {
|
|||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SafePropsType = {
|
||||||
|
name: string,
|
||||||
|
ownerAddresses: string[],
|
||||||
|
ownerNames: string[],
|
||||||
|
threshold: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateQueryParams = (ownerAddresses?: string[], ownerNames?: string[], threshold?: string, safeName?: string) => {
|
||||||
|
if (!ownerAddresses || !ownerNames || !threshold || !safeName) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!ownerAddresses.length === 0 || ownerNames.length === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Number.isNaN(Number(threshold))) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (threshold > ownerAddresses.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
export const createSafe = async (values: Object, userAccount: string, addSafe: AddSafe): Promise<OpenState> => {
|
export const createSafe = async (values: Object, userAccount: string, addSafe: AddSafe): Promise<OpenState> => {
|
||||||
const numConfirmations = getThresholdFrom(values)
|
const numConfirmations = getThresholdFrom(values)
|
||||||
const name = getSafeNameFrom(values)
|
const name = getSafeNameFrom(values)
|
||||||
const ownersNames = getNamesFrom(values)
|
const ownersNames = getNamesFrom(values)
|
||||||
const ownerAddresses = getAccountsFrom(values)
|
const ownerAddresses = getAccountsFrom(values)
|
||||||
|
|
||||||
await initContracts()
|
|
||||||
|
|
||||||
const safe = await deploySafeContract(ownerAddresses, numConfirmations, userAccount)
|
const safe = await deploySafeContract(ownerAddresses, numConfirmations, userAccount)
|
||||||
await checkReceiptStatus(safe.tx)
|
await checkReceiptStatus(safe.tx)
|
||||||
|
|
||||||
@ -59,10 +83,6 @@ export const createSafe = async (values: Object, userAccount: string, addSafe: A
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Open extends React.Component<Props> {
|
class Open extends React.Component<Props> {
|
||||||
async componentDidMount() {
|
|
||||||
await initContracts()
|
|
||||||
}
|
|
||||||
|
|
||||||
onCallSafeContractSubmit = async (values) => {
|
onCallSafeContractSubmit = async (values) => {
|
||||||
try {
|
try {
|
||||||
const { userAccount, addSafe } = this.props
|
const { userAccount, addSafe } = this.props
|
||||||
@ -75,8 +95,23 @@ class Open extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { provider, userAccount, network } = this.props
|
const {
|
||||||
|
provider, userAccount, network, location,
|
||||||
|
} = this.props
|
||||||
|
const query: SafePropsType = queryString.parse(location.search, { arrayFormat: 'comma' })
|
||||||
|
const {
|
||||||
|
name, owneraddresses, ownernames, threshold,
|
||||||
|
} = query
|
||||||
|
|
||||||
|
let safeProps = null
|
||||||
|
if (validateQueryParams(owneraddresses, ownernames, threshold, name)) {
|
||||||
|
safeProps = {
|
||||||
|
name,
|
||||||
|
ownerAddresses: owneraddresses,
|
||||||
|
ownerNames: ownernames,
|
||||||
|
threshold,
|
||||||
|
}
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<Layout
|
<Layout
|
||||||
@ -84,10 +119,11 @@ class Open extends React.Component<Props> {
|
|||||||
provider={provider}
|
provider={provider}
|
||||||
userAccount={userAccount}
|
userAccount={userAccount}
|
||||||
onCallSafeContractSubmit={this.onCallSafeContractSubmit}
|
onCallSafeContractSubmit={this.onCallSafeContractSubmit}
|
||||||
|
safeProps={safeProps}
|
||||||
/>
|
/>
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(selector, actions)(Open)
|
export default connect(selector, actions)(withRouter(Open))
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { storiesOf } from '@storybook/react'
|
|
||||||
import * as React from 'react'
|
|
||||||
import styles from '~/components/layout/PageFrame/index.scss'
|
|
||||||
import { ETHEREUM_NETWORK } from '~/logic/wallets/getWeb3'
|
|
||||||
import Component from './component'
|
|
||||||
|
|
||||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
|
||||||
|
|
||||||
storiesOf('Routes /opening', module)
|
|
||||||
.addDecorator(FrameDecorator)
|
|
||||||
.add('View while Safe is being deployed', () => (
|
|
||||||
<Component
|
|
||||||
name="Super Vault 2000"
|
|
||||||
tx="0xed163e50e2e85695f5edafeba51d6be1758549858d12611ed4dcc96feaa19fc9"
|
|
||||||
network={ETHEREUM_NETWORK.RINKEBY}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
.add('Load this view without a tx', () => <Component network={ETHEREUM_NETWORK.UNKNOWN} />)
|
|
@ -26,8 +26,8 @@ const styles = () => ({
|
|||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
},
|
},
|
||||||
close: {
|
close: {
|
||||||
height: '24px',
|
height: lg,
|
||||||
width: '24px',
|
width: lg,
|
||||||
fill: secondaryText,
|
fill: secondaryText,
|
||||||
},
|
},
|
||||||
qrContainer: {
|
qrContainer: {
|
||||||
@ -48,7 +48,7 @@ const styles = () => ({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
'& > button': {
|
'& > button': {
|
||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -22,7 +22,7 @@ const styles = () => ({
|
|||||||
maxHeight: '75px',
|
maxHeight: '75px',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
@ -31,7 +31,7 @@ const styles = () => ({
|
|||||||
buttonColumn: {
|
buttonColumn: {
|
||||||
padding: '52px 0',
|
padding: '52px 0',
|
||||||
'& > button': {
|
'& > button': {
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -23,6 +23,7 @@ import { getEthAsToken } from '~/logic/tokens/utils/tokenHelpers'
|
|||||||
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
||||||
import ArrowDown from '../assets/arrow-down.svg'
|
import ArrowDown from '../assets/arrow-down.svg'
|
||||||
import { styles } from './style'
|
import { styles } from './style'
|
||||||
|
import { sm } from '~/theme/variables'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: () => void,
|
onClose: () => void,
|
||||||
@ -78,15 +79,15 @@ const ReviewCustomTx = ({
|
|||||||
const txData = tx.data.trim()
|
const txData = tx.data.trim()
|
||||||
const txValue = tx.value ? web3.utils.toWei(tx.value, 'ether') : 0
|
const txValue = tx.value ? web3.utils.toWei(tx.value, 'ether') : 0
|
||||||
|
|
||||||
createTransaction(
|
createTransaction({
|
||||||
safeAddress,
|
safeAddress,
|
||||||
txRecipient,
|
to: txRecipient,
|
||||||
txValue,
|
valueInWei: txValue,
|
||||||
txData,
|
txData,
|
||||||
TX_NOTIFICATION_TYPES.STANDARD_TX,
|
notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX,
|
||||||
enqueueSnackbar,
|
enqueueSnackbar,
|
||||||
closeSnackbar,
|
closeSnackbar,
|
||||||
)
|
})
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +107,7 @@ const ReviewCustomTx = ({
|
|||||||
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
||||||
<Row margin="md">
|
<Row margin="md">
|
||||||
<Col xs={1}>
|
<Col xs={1}>
|
||||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
|
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: sm }} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={11} center="xs" layout="column">
|
<Col xs={11} center="xs" layout="column">
|
||||||
<Hairline />
|
<Hairline />
|
||||||
|
@ -17,7 +17,7 @@ export const styles = () => ({
|
|||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
},
|
},
|
||||||
headingText: {
|
headingText: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
@ -50,7 +50,7 @@ export const styles = () => ({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
'& > button': {
|
'& > button': {
|
||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
submitButton: {
|
submitButton: {
|
||||||
|
@ -28,6 +28,7 @@ import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
|||||||
import { ETH_ADDRESS } from '~/logic/tokens/utils/tokenHelpers'
|
import { ETH_ADDRESS } from '~/logic/tokens/utils/tokenHelpers'
|
||||||
import ArrowDown from '../assets/arrow-down.svg'
|
import ArrowDown from '../assets/arrow-down.svg'
|
||||||
import { styles } from './style'
|
import { styles } from './style'
|
||||||
|
import { sm } from '~/theme/variables'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: () => void,
|
onClose: () => void,
|
||||||
@ -108,15 +109,15 @@ const ReviewTx = ({
|
|||||||
txAmount = 0
|
txAmount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
createTransaction(
|
createTransaction({
|
||||||
safeAddress,
|
safeAddress,
|
||||||
txRecipient,
|
to: txRecipient,
|
||||||
txAmount,
|
valueInWei: txAmount,
|
||||||
txData,
|
txData,
|
||||||
TX_NOTIFICATION_TYPES.STANDARD_TX,
|
notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX,
|
||||||
enqueueSnackbar,
|
enqueueSnackbar,
|
||||||
closeSnackbar,
|
closeSnackbar,
|
||||||
)
|
})
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +137,7 @@ const ReviewTx = ({
|
|||||||
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
||||||
<Row margin="md">
|
<Row margin="md">
|
||||||
<Col xs={1}>
|
<Col xs={1}>
|
||||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
|
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: sm }} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={11} center="xs" layout="column">
|
<Col xs={11} center="xs" layout="column">
|
||||||
<Hairline />
|
<Hairline />
|
||||||
|
@ -17,7 +17,7 @@ export const styles = () => ({
|
|||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
},
|
},
|
||||||
headingText: {
|
headingText: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
@ -37,7 +37,7 @@ export const styles = () => ({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
'& > button': {
|
'& > button': {
|
||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
submitButton: {
|
submitButton: {
|
||||||
|
@ -25,6 +25,7 @@ import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo'
|
|||||||
import QRIcon from '~/assets/icons/qrcode.svg'
|
import QRIcon from '~/assets/icons/qrcode.svg'
|
||||||
import ArrowDown from '../assets/arrow-down.svg'
|
import ArrowDown from '../assets/arrow-down.svg'
|
||||||
import { styles } from './style'
|
import { styles } from './style'
|
||||||
|
import { sm } from '~/theme/variables'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: () => void,
|
onClose: () => void,
|
||||||
@ -102,7 +103,7 @@ const SendCustomTx = ({
|
|||||||
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
||||||
<Row margin="md">
|
<Row margin="md">
|
||||||
<Col xs={1}>
|
<Col xs={1}>
|
||||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
|
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: sm }} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={11} center="xs" layout="column">
|
<Col xs={11} center="xs" layout="column">
|
||||||
<Hairline />
|
<Hairline />
|
||||||
|
@ -15,7 +15,7 @@ export const styles = () => ({
|
|||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
@ -32,7 +32,7 @@ export const styles = () => ({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
'& > button': {
|
'& > button': {
|
||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
submitButton: {
|
submitButton: {
|
||||||
|
@ -28,6 +28,7 @@ import ScanQRModal from '~/components/ScanQRModal'
|
|||||||
import ArrowDown from '../assets/arrow-down.svg'
|
import ArrowDown from '../assets/arrow-down.svg'
|
||||||
import QRIcon from '~/assets/icons/qrcode.svg'
|
import QRIcon from '~/assets/icons/qrcode.svg'
|
||||||
import { styles } from './style'
|
import { styles } from './style'
|
||||||
|
import { sm } from '~/theme/variables'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: () => void,
|
onClose: () => void,
|
||||||
@ -114,7 +115,7 @@ const SendFunds = ({
|
|||||||
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
||||||
<Row margin="md">
|
<Row margin="md">
|
||||||
<Col xs={1}>
|
<Col xs={1}>
|
||||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
|
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: sm }} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={11} center="xs" layout="column">
|
<Col xs={11} center="xs" layout="column">
|
||||||
<Hairline />
|
<Hairline />
|
||||||
|
@ -15,7 +15,7 @@ export const styles = () => ({
|
|||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
@ -32,7 +32,7 @@ export const styles = () => ({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
'& > button': {
|
'& > button': {
|
||||||
fontFamily: 'Averta',
|
fontFamily: 'Averta',
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
submitButton: {
|
submitButton: {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { lg } from '~/theme/variables'
|
import { lg, md } from '~/theme/variables'
|
||||||
|
|
||||||
export const styles = () => ({
|
export const styles = () => ({
|
||||||
title: {
|
title: {
|
||||||
padding: `${lg} 0 20px`,
|
padding: `${lg} 0 20px`,
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
},
|
},
|
||||||
formContainer: {
|
formContainer: {
|
||||||
padding: '0 20px',
|
padding: '0 20px',
|
||||||
|
@ -4,6 +4,8 @@ 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 { type Column } from '~/components/Table/TableHead'
|
||||||
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
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'
|
||||||
|
|
||||||
export const BALANCE_TABLE_ASSET_ID = 'asset'
|
export const BALANCE_TABLE_ASSET_ID = 'asset'
|
||||||
export const BALANCE_TABLE_BALANCE_ID = 'balance'
|
export const BALANCE_TABLE_BALANCE_ID = 'balance'
|
||||||
@ -16,13 +18,29 @@ type BalanceData = {
|
|||||||
|
|
||||||
export type BalanceRow = SortRow<BalanceData>
|
export type BalanceRow = SortRow<BalanceData>
|
||||||
|
|
||||||
export const getBalanceData = (activeTokens: List<Token>): List<BalanceRow> => {
|
// eslint-disable-next-line max-len
|
||||||
|
const getTokenPriceInCurrency = (token: Token, currencySelected: AVAILABLE_CURRENCIES, currencyValues: List<BalanceCurrencyType>): string => {
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
|
||||||
|
for (const tokenPriceIterator of currencyValues) {
|
||||||
|
const { tokenAddress, balanceInSelectedCurrency, currencyName } = tokenPriceIterator
|
||||||
|
if (token.address === tokenAddress && currencySelected === currencyName) {
|
||||||
|
const balance = balanceInSelectedCurrency ? parseFloat(balanceInSelectedCurrency, 10).toFixed(2) : balanceInSelectedCurrency
|
||||||
|
return `${balance} ${currencySelected}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
export const getBalanceData = (activeTokens: List<Token>, currencySelected: string, currencyValues: List<BalanceCurrencyType>): List<BalanceRow> => {
|
||||||
const rows = activeTokens.map((token: Token) => ({
|
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,
|
[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),
|
[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)]: Number(token.balance),
|
||||||
[FIXED]: token.get('symbol') === 'ETH',
|
[FIXED]: token.get('symbol') === 'ETH',
|
||||||
|
[BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(token, currencySelected, currencyValues),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return rows
|
return rows
|
||||||
@ -56,5 +74,26 @@ export const generateColumns = () => {
|
|||||||
static: true,
|
static: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
return List([assetColumn, balanceColumn, actions])
|
const value: Column = {
|
||||||
|
id: BALANCE_TABLE_VALUE_ID,
|
||||||
|
order: false,
|
||||||
|
label: 'Value',
|
||||||
|
custom: false,
|
||||||
|
static: true,
|
||||||
|
style: {
|
||||||
|
fontSize: '11px',
|
||||||
|
color: '#5d6d74',
|
||||||
|
borderBottomWidth: '2px',
|
||||||
|
width: '125px',
|
||||||
|
fontFamily: 'Averta',
|
||||||
|
fontWeight: 'normal',
|
||||||
|
fontStyle: 'normal',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return List([assetColumn, balanceColumn, value, actions])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
@ -23,6 +23,9 @@ import Tokens from './Tokens'
|
|||||||
import SendModal from './SendModal'
|
import SendModal from './SendModal'
|
||||||
import Receive from './Receive'
|
import Receive from './Receive'
|
||||||
import { styles } from './style'
|
import { styles } from './style'
|
||||||
|
import DropdownCurrency from '~/routes/safe/components/DropdownCurrency'
|
||||||
|
import type { BalanceCurrencyType } from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
import { BALANCE_TABLE_BALANCE_ID, BALANCE_TABLE_VALUE_ID } from '~/routes/safe/components/Balances/dataFetcher'
|
||||||
|
|
||||||
export const MANAGE_TOKENS_BUTTON_TEST_ID = 'manage-tokens-btn'
|
export const MANAGE_TOKENS_BUTTON_TEST_ID = 'manage-tokens-btn'
|
||||||
export const BALANCE_ROW_TEST_ID = 'balance-row'
|
export const BALANCE_ROW_TEST_ID = 'balance-row'
|
||||||
@ -45,6 +48,9 @@ type Props = {
|
|||||||
safeName: string,
|
safeName: string,
|
||||||
ethBalance: string,
|
ethBalance: string,
|
||||||
createTransaction: Function,
|
createTransaction: Function,
|
||||||
|
currencySelected: string,
|
||||||
|
fetchCurrencyValues: Function,
|
||||||
|
currencyValues: BalanceCurrencyType[],
|
||||||
}
|
}
|
||||||
|
|
||||||
type Action = 'Token' | 'Send' | 'Receive'
|
type Action = 'Token' | 'Send' | 'Receive'
|
||||||
@ -63,6 +69,12 @@ class Balances extends React.Component<Props, State> {
|
|||||||
props.fetchTokens()
|
props.fetchTokens()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
const { safeAddress, fetchCurrencyValues, activateTokensByBalance } = this.props
|
||||||
|
fetchCurrencyValues(safeAddress)
|
||||||
|
activateTokensByBalance(safeAddress)
|
||||||
|
}
|
||||||
|
|
||||||
onShow = (action: Action) => () => {
|
onShow = (action: Action) => () => {
|
||||||
this.setState(() => ({ [`show${action}`]: true }))
|
this.setState(() => ({ [`show${action}`]: true }))
|
||||||
}
|
}
|
||||||
@ -89,17 +101,6 @@ class Balances extends React.Component<Props, State> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
|
|
||||||
const { checked } = e.target
|
|
||||||
|
|
||||||
this.setState(() => ({ hideZero: checked }))
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount(): void {
|
|
||||||
const { activateTokensByBalance, safeAddress } = this.props
|
|
||||||
activateTokensByBalance(safeAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
showToken, showReceive, sendFunds,
|
showToken, showReceive, sendFunds,
|
||||||
@ -114,17 +115,20 @@ class Balances extends React.Component<Props, State> {
|
|||||||
safeName,
|
safeName,
|
||||||
ethBalance,
|
ethBalance,
|
||||||
createTransaction,
|
createTransaction,
|
||||||
|
currencySelected,
|
||||||
|
currencyValues,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
const columns = generateColumns()
|
const columns = generateColumns()
|
||||||
const autoColumns = columns.filter((c) => !c.custom)
|
const autoColumns = columns.filter((c) => !c.custom)
|
||||||
|
|
||||||
const filteredData = getBalanceData(activeTokens)
|
const filteredData = getBalanceData(activeTokens, currencySelected, currencyValues)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Row align="center" className={classes.message}>
|
<Row align="center" className={classes.message}>
|
||||||
<Col xs={12} end="sm">
|
<Col xs={12} end="sm">
|
||||||
|
<DropdownCurrency />
|
||||||
<ButtonLink size="lg" onClick={this.onShow('Token')} testId="manage-tokens-btn">
|
<ButtonLink size="lg" onClick={this.onShow('Token')} testId="manage-tokens-btn">
|
||||||
Manage List
|
Manage List
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
@ -155,11 +159,42 @@ class Balances extends React.Component<Props, State> {
|
|||||||
>
|
>
|
||||||
{(sortedData: Array<BalanceRow>) => sortedData.map((row: any, index: number) => (
|
{(sortedData: Array<BalanceRow>) => sortedData.map((row: any, index: number) => (
|
||||||
<TableRow tabIndex={-1} key={index} className={classes.hide} data-testid={BALANCE_ROW_TEST_ID}>
|
<TableRow tabIndex={-1} key={index} className={classes.hide} data-testid={BALANCE_ROW_TEST_ID}>
|
||||||
{autoColumns.map((column: Column) => (
|
{autoColumns.map((column: Column) => {
|
||||||
<TableCell key={column.id} style={cellWidth(column.width)} align={column.align} component="td">
|
const { id, width, align } = column
|
||||||
{column.id === BALANCE_TABLE_ASSET_ID ? <AssetTableCell asset={row[column.id]} /> : row[column.id]}
|
let cellItem
|
||||||
</TableCell>
|
switch (id) {
|
||||||
))}
|
case BALANCE_TABLE_ASSET_ID: {
|
||||||
|
cellItem = <AssetTableCell asset={row[id]} />
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case BALANCE_TABLE_BALANCE_ID: {
|
||||||
|
cellItem = (
|
||||||
|
<div>
|
||||||
|
{row[id]}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case BALANCE_TABLE_VALUE_ID: {
|
||||||
|
cellItem = <div className={classes.currencyValueRow}>{row[id]}</div>
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
cellItem = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TableCell
|
||||||
|
key={id}
|
||||||
|
style={cellWidth(width)}
|
||||||
|
align={align}
|
||||||
|
component="td"
|
||||||
|
>
|
||||||
|
{cellItem}
|
||||||
|
</TableCell>
|
||||||
|
)
|
||||||
|
})}
|
||||||
<TableCell component="td">
|
<TableCell component="td">
|
||||||
<Row align="end" className={classes.actions}>
|
<Row align="end" className={classes.actions}>
|
||||||
{granted && (
|
{granted && (
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { sm, md } from '~/theme/variables'
|
import { xs, sm, md } from '~/theme/variables'
|
||||||
|
|
||||||
export const styles = (theme: Object) => ({
|
export const styles = (theme: Object) => ({
|
||||||
root: {
|
root: {
|
||||||
@ -41,7 +41,7 @@ export const styles = (theme: Object) => ({
|
|||||||
width: '95px',
|
width: '95px',
|
||||||
minWidth: '95px',
|
minWidth: '95px',
|
||||||
marginLeft: sm,
|
marginLeft: sm,
|
||||||
borderRadius: '4px',
|
borderRadius: xs,
|
||||||
'& > span': {
|
'& > span': {
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
},
|
},
|
||||||
@ -49,7 +49,7 @@ export const styles = (theme: Object) => ({
|
|||||||
send: {
|
send: {
|
||||||
width: '75px',
|
width: '75px',
|
||||||
minWidth: '75px',
|
minWidth: '75px',
|
||||||
borderRadius: '4px',
|
borderRadius: xs,
|
||||||
'& > span': {
|
'& > span': {
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
},
|
},
|
||||||
@ -63,4 +63,8 @@ export const styles = (theme: Object) => ({
|
|||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
currencyValueRow: {
|
||||||
|
maxWidth: '125px',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
@ -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 |
124
src/routes/safe/components/DropdownCurrency/index.jsx
Normal file
124
src/routes/safe/components/DropdownCurrency/index.jsx
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// @flow
|
||||||
|
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||||
|
import ListItemText from '@material-ui/core/ListItemText'
|
||||||
|
import Menu from '@material-ui/core/Menu'
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import style from 'currency-flags/dist/currency-flags.min.css'
|
||||||
|
import { MuiThemeProvider } from '@material-ui/core/styles'
|
||||||
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
import SearchIcon from '@material-ui/icons/Search'
|
||||||
|
import InputBase from '@material-ui/core/InputBase'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import { DropdownListTheme } from '~/theme/mui'
|
||||||
|
import CheckIcon from './img/check.svg'
|
||||||
|
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||||
|
import fetchCurrencySelectedValue from '~/logic/currencyValues/store/actions/fetchCurrencySelectedValue'
|
||||||
|
import { currentCurrencySelector } from '~/logic/currencyValues/store/selectors'
|
||||||
|
import { useDropdownStyles } from '~/routes/safe/components/DropdownCurrency/style'
|
||||||
|
import saveCurrencySelected from '~/logic/currencyValues/store/actions/saveCurrencySelected'
|
||||||
|
|
||||||
|
|
||||||
|
const DropdownCurrency = () => {
|
||||||
|
const currenciesList = Object.values(AVAILABLE_CURRENCIES)
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
||||||
|
const currencyValueSelected = useSelector(currentCurrencySelector)
|
||||||
|
|
||||||
|
const [searchParams, setSearchParams] = useState('')
|
||||||
|
const classes = useDropdownStyles()
|
||||||
|
const currenciesListFiltered = currenciesList.filter((currency) => currency.toLowerCase().includes(searchParams.toLowerCase()))
|
||||||
|
|
||||||
|
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
|
setAnchorEl(event.currentTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCurrentCurrencyChangedHandler = (newCurrencySelectedName: AVAILABLE_CURRENCIES) => {
|
||||||
|
dispatch(fetchCurrencySelectedValue(newCurrencySelectedName))
|
||||||
|
dispatch(saveCurrencySelected(newCurrencySelectedName))
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
!currencyValueSelected ? null
|
||||||
|
: (
|
||||||
|
<MuiThemeProvider theme={DropdownListTheme}>
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className={classes.button}
|
||||||
|
onClick={handleClick}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span className={classNames(classes.buttonInner, anchorEl && classes.openMenuButton)}>
|
||||||
|
{currencyValueSelected}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<Menu
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
elevation={0}
|
||||||
|
getContentAnchorEl={null}
|
||||||
|
id="customizedMenu"
|
||||||
|
keepMounted
|
||||||
|
onClose={handleClose}
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
rounded={0}
|
||||||
|
anchorOrigin={{
|
||||||
|
horizontal: 'center',
|
||||||
|
vertical: 'bottom',
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
horizontal: 'center',
|
||||||
|
vertical: 'top',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
className={classes.listItemSearch}
|
||||||
|
key="0"
|
||||||
|
>
|
||||||
|
<div className={classes.search}>
|
||||||
|
<div className={classes.searchIcon}>
|
||||||
|
<SearchIcon />
|
||||||
|
</div>
|
||||||
|
<InputBase
|
||||||
|
placeholder="Search…"
|
||||||
|
classes={{
|
||||||
|
root: classes.inputRoot,
|
||||||
|
input: classes.inputInput,
|
||||||
|
}}
|
||||||
|
inputProps={{ 'aria-label': 'search' }}
|
||||||
|
onChange={(event) => setSearchParams(event.target.value)}
|
||||||
|
value={searchParams}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</MenuItem>
|
||||||
|
<div className={classes.dropdownItemsScrollWrapper}>
|
||||||
|
{currenciesListFiltered.map((currencyName) => (
|
||||||
|
<MenuItem
|
||||||
|
className={classes.listItem}
|
||||||
|
key={currencyName}
|
||||||
|
value={currencyName}
|
||||||
|
onClick={() => onCurrentCurrencyChangedHandler(currencyName)}
|
||||||
|
>
|
||||||
|
<ListItemIcon className={classes.iconLeft}>
|
||||||
|
<div
|
||||||
|
className={classNames(classes.localFlag, style['currency-flag'], style['currency-flag-lg'], style[`currency-flag-${currencyName.toLowerCase()}`])}
|
||||||
|
/>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary={currencyName} />
|
||||||
|
{currencyName === currencyValueSelected
|
||||||
|
? <ListItemIcon className={classes.iconRight}><img src={CheckIcon} alt="checked" /></ListItemIcon> : null}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Menu>
|
||||||
|
</>
|
||||||
|
</MuiThemeProvider>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DropdownCurrency
|
119
src/routes/safe/components/DropdownCurrency/style.js
Normal file
119
src/routes/safe/components/DropdownCurrency/style.js
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// @flow
|
||||||
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
|
||||||
|
const buttonWidth = '140px'
|
||||||
|
export const useDropdownStyles = makeStyles({
|
||||||
|
listItem: {
|
||||||
|
maxWidth: buttonWidth,
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
},
|
||||||
|
listItemSearch: {
|
||||||
|
maxWidth: buttonWidth,
|
||||||
|
padding: '0',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
},
|
||||||
|
localFlag: {
|
||||||
|
backgroundPosition: '50% 50%',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundSize: 'contain',
|
||||||
|
height: '20px !important',
|
||||||
|
width: '26px !important',
|
||||||
|
},
|
||||||
|
iconLeft: {
|
||||||
|
marginRight: '10px',
|
||||||
|
},
|
||||||
|
iconRight: {
|
||||||
|
marginLeft: '18px',
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
backgroundColor: '#e8e7e6',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '3px',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
color: '#5d6d74',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontSize: '12px',
|
||||||
|
fontWeight: 'normal',
|
||||||
|
height: '24px',
|
||||||
|
lineHeight: '1.33',
|
||||||
|
marginRight: '20px',
|
||||||
|
minWidth: buttonWidth,
|
||||||
|
outline: 'none',
|
||||||
|
padding: '0',
|
||||||
|
textAlign: 'left',
|
||||||
|
'&:active': {
|
||||||
|
opacity: '0.8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
buttonInner: {
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
display: 'block',
|
||||||
|
height: '100%',
|
||||||
|
lineHeight: '24px',
|
||||||
|
padding: '0 22px 0 8px',
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%',
|
||||||
|
'&::after': {
|
||||||
|
borderLeft: '5px solid transparent',
|
||||||
|
borderRight: '5px solid transparent',
|
||||||
|
borderTop: '5px solid #5d6d74',
|
||||||
|
content: '""',
|
||||||
|
height: '0',
|
||||||
|
position: 'absolute',
|
||||||
|
right: '8px',
|
||||||
|
top: '9px',
|
||||||
|
width: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
openMenuButton: {
|
||||||
|
'&::after': {
|
||||||
|
borderBottom: '5px solid #5d6d74',
|
||||||
|
borderLeft: '5px solid transparent',
|
||||||
|
borderRight: '5px solid transparent',
|
||||||
|
borderTop: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dropdownItemsScrollWrapper: {
|
||||||
|
maxHeight: '280px',
|
||||||
|
overflow: 'auto',
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
position: 'relative',
|
||||||
|
borderRadius: '0',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
marginRight: 0,
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
searchIcon: {
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
height: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
left: '12px',
|
||||||
|
margin: '0',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
width: '18px',
|
||||||
|
'& path': {
|
||||||
|
fill: '#b2b5b2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputRoot: {
|
||||||
|
color: '#5d6d74',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontWeight: 'normal',
|
||||||
|
lineHeight: '1.43',
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
inputInput: {
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
height: '44px',
|
||||||
|
padding: '12px 12px 12px 40px',
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
})
|
@ -49,6 +49,7 @@ type Props = SelectorProps &
|
|||||||
match: Object,
|
match: Object,
|
||||||
location: Object,
|
location: Object,
|
||||||
history: Object,
|
history: Object,
|
||||||
|
fetchCurrencyValues: Function,
|
||||||
}
|
}
|
||||||
|
|
||||||
const Layout = (props: Props) => {
|
const Layout = (props: Props) => {
|
||||||
@ -63,7 +64,6 @@ const Layout = (props: Props) => {
|
|||||||
blacklistedTokens,
|
blacklistedTokens,
|
||||||
createTransaction,
|
createTransaction,
|
||||||
processTransaction,
|
processTransaction,
|
||||||
fetchTransactions,
|
|
||||||
activateTokensByBalance,
|
activateTokensByBalance,
|
||||||
fetchTokens,
|
fetchTokens,
|
||||||
updateSafe,
|
updateSafe,
|
||||||
@ -77,6 +77,9 @@ const Layout = (props: Props) => {
|
|||||||
hideSendFunds,
|
hideSendFunds,
|
||||||
match,
|
match,
|
||||||
location,
|
location,
|
||||||
|
currencySelected,
|
||||||
|
fetchCurrencyValues,
|
||||||
|
currencyValues,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const handleCallToRouter = (_, value) => {
|
const handleCallToRouter = (_, value) => {
|
||||||
@ -166,6 +169,9 @@ const Layout = (props: Props) => {
|
|||||||
fetchTokens={fetchTokens}
|
fetchTokens={fetchTokens}
|
||||||
safeName={name}
|
safeName={name}
|
||||||
createTransaction={createTransaction}
|
createTransaction={createTransaction}
|
||||||
|
currencySelected={currencySelected}
|
||||||
|
fetchCurrencyValues={fetchCurrencyValues}
|
||||||
|
currencyValues={currencyValues}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -176,8 +182,8 @@ const Layout = (props: Props) => {
|
|||||||
<Transactions
|
<Transactions
|
||||||
threshold={safe.threshold}
|
threshold={safe.threshold}
|
||||||
owners={safe.owners}
|
owners={safe.owners}
|
||||||
|
nonce={safe.nonce}
|
||||||
transactions={transactions}
|
transactions={transactions}
|
||||||
fetchTransactions={fetchTransactions}
|
|
||||||
safeAddress={address}
|
safeAddress={address}
|
||||||
userAddress={userAddress}
|
userAddress={userAddress}
|
||||||
currentNetwork={network}
|
currentNetwork={network}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { storiesOf } from '@storybook/react'
|
|
||||||
import * as React from 'react'
|
|
||||||
import { List } from 'immutable'
|
|
||||||
import styles from '~/components/layout/PageFrame/index.scss'
|
|
||||||
import Component from './Layout'
|
|
||||||
|
|
||||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
|
||||||
|
|
||||||
storiesOf('Routes /safe:address', module)
|
|
||||||
.addDecorator(FrameDecorator)
|
|
||||||
.add('Safe undefined being connected', () => (
|
|
||||||
<Component userAddress="foo" safe={undefined} provider="METAMASK" activeTokens={List([])} fetchBalance={() => {}} />
|
|
||||||
))
|
|
||||||
.add('Safe undefined NOT connected', () => (
|
|
||||||
<Component userAddress="foo" safe={undefined} provider="" activeTokens={List([])} fetchBalance={() => {}} />
|
|
||||||
))
|
|
@ -1,11 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { storiesOf } from '@storybook/react'
|
|
||||||
import * as React from 'react'
|
|
||||||
import styles from '~/components/layout/PageFrame/index.scss'
|
|
||||||
import Component from './index.jsx'
|
|
||||||
|
|
||||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
|
||||||
|
|
||||||
storiesOf('Components', module)
|
|
||||||
.addDecorator(FrameDecorator)
|
|
||||||
.add('NoRights', () => <Component />)
|
|
@ -47,15 +47,15 @@ export const sendAddOwner = async (
|
|||||||
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
||||||
const txData = gnosisSafe.contract.methods.addOwnerWithThreshold(values.ownerAddress, values.threshold).encodeABI()
|
const txData = gnosisSafe.contract.methods.addOwnerWithThreshold(values.ownerAddress, values.threshold).encodeABI()
|
||||||
|
|
||||||
const txHash = await createTransaction(
|
const txHash = await createTransaction({
|
||||||
safeAddress,
|
safeAddress,
|
||||||
safeAddress,
|
to: safeAddress,
|
||||||
0,
|
valueInWei: 0,
|
||||||
txData,
|
txData,
|
||||||
TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
notifiedTransaction: TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||||
enqueueSnackbar,
|
enqueueSnackbar,
|
||||||
closeSnackbar,
|
closeSnackbar,
|
||||||
)
|
})
|
||||||
|
|
||||||
if (txHash) {
|
if (txHash) {
|
||||||
addSafeOwner({ safeAddress, ownerName: values.ownerName, ownerAddress: values.ownerAddress })
|
addSafeOwner({ safeAddress, ownerName: values.ownerName, ownerAddress: values.ownerAddress })
|
||||||
|
@ -17,7 +17,7 @@ export const styles = () => ({
|
|||||||
lineHeight: 'normal',
|
lineHeight: 'normal',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
|
@ -20,7 +20,7 @@ export const styles = () => ({
|
|||||||
lineHeight: 'normal',
|
lineHeight: 'normal',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
|
@ -17,14 +17,14 @@ export const styles = () => ({
|
|||||||
lineHeight: 'normal',
|
lineHeight: 'normal',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
},
|
},
|
||||||
headingText: {
|
headingText: {
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
},
|
},
|
||||||
formContainer: {
|
formContainer: {
|
||||||
padding: `${md} ${lg}`,
|
padding: `${md} ${lg}`,
|
||||||
|
@ -10,7 +10,7 @@ export const styles = () => ({
|
|||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
padding: `${md} ${lg}`,
|
padding: `${md} ${lg}`,
|
||||||
|
@ -62,15 +62,15 @@ export const sendRemoveOwner = async (
|
|||||||
.removeOwner(prevAddress, ownerAddressToRemove, values.threshold)
|
.removeOwner(prevAddress, ownerAddressToRemove, values.threshold)
|
||||||
.encodeABI()
|
.encodeABI()
|
||||||
|
|
||||||
const txHash = await createTransaction(
|
const txHash = await createTransaction({
|
||||||
safeAddress,
|
safeAddress,
|
||||||
safeAddress,
|
to: safeAddress,
|
||||||
0,
|
valueInWei: 0,
|
||||||
txData,
|
txData,
|
||||||
TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
notifiedTransaction: TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||||
enqueueSnackbar,
|
enqueueSnackbar,
|
||||||
closeSnackbar,
|
closeSnackbar,
|
||||||
)
|
})
|
||||||
|
|
||||||
if (txHash && safe.threshold === 1) {
|
if (txHash && safe.threshold === 1) {
|
||||||
removeSafeOwner({ safeAddress, ownerAddress: ownerAddressToRemove })
|
removeSafeOwner({ safeAddress, ownerAddress: ownerAddressToRemove })
|
||||||
|
@ -17,7 +17,7 @@ export const styles = () => ({
|
|||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
address: {
|
address: {
|
||||||
marginRight: sm,
|
marginRight: sm,
|
||||||
|
@ -20,7 +20,7 @@ export const styles = () => ({
|
|||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
|
@ -17,14 +17,14 @@ export const styles = () => ({
|
|||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
},
|
},
|
||||||
manage: {
|
manage: {
|
||||||
fontSize: '24px',
|
fontSize: lg,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
height: '35px',
|
height: '35px',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
},
|
},
|
||||||
headingText: {
|
headingText: {
|
||||||
fontSize: '16px',
|
fontSize: md,
|
||||||
},
|
},
|
||||||
formContainer: {
|
formContainer: {
|
||||||
padding: `${md} ${lg}`,
|
padding: `${md} ${lg}`,
|
||||||
|
@ -58,15 +58,15 @@ export const sendReplaceOwner = async (
|
|||||||
.swapOwner(prevAddress, ownerAddressToRemove, values.ownerAddress)
|
.swapOwner(prevAddress, ownerAddressToRemove, values.ownerAddress)
|
||||||
.encodeABI()
|
.encodeABI()
|
||||||
|
|
||||||
const txHash = await createTransaction(
|
const txHash = await createTransaction({
|
||||||
safeAddress,
|
safeAddress,
|
||||||
safeAddress,
|
to: safeAddress,
|
||||||
0,
|
valueInWei: 0,
|
||||||
txData,
|
txData,
|
||||||
TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
notifiedTransaction: TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||||
enqueueSnackbar,
|
enqueueSnackbar,
|
||||||
closeSnackbar,
|
closeSnackbar,
|
||||||
)
|
})
|
||||||
|
|
||||||
if (txHash && safe.threshold === 1) {
|
if (txHash && safe.threshold === 1) {
|
||||||
replaceSafeOwner({
|
replaceSafeOwner({
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user