diff options
105 files changed, 6807 insertions, 558 deletions
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 621775592..936af914c 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -40,6 +40,9 @@ "message": "MetaMask", "description": "The name of the application" }, + "approve": { + "message": "Approve" + }, "approved": { "message": "Approved" }, @@ -89,6 +92,9 @@ "buyCoinbaseExplainer": { "message": "Coinbase is the world’s most popular way to buy and sell bitcoin, ethereum, and litecoin." }, + "bytes": { + "message": "Bytes" + }, "ok": { "message": "Ok" }, @@ -149,6 +155,9 @@ "copyContractAddress": { "message": "Copy Contract Address" }, + "copyAddress": { + "message": "Copy address to clipboard" + }, "copyToClipboard": { "message": "Copy to clipboard" }, @@ -318,6 +327,9 @@ "fromShapeShift": { "message": "From ShapeShift" }, + "functionType": { + "message": "Function Type" + }, "gas": { "message": "Gas", "description": "Short indication of gas cost" @@ -370,6 +382,9 @@ "hereList": { "message": "Here's a list!!!!" }, + "hexData": { + "message": "Hex Data" + }, "hide": { "message": "Hide" }, @@ -582,6 +597,9 @@ "message": "or", "description": "choice between creating or importing a new account" }, + "origin": { + "message": "Origin" + }, "password": { "message": "Password" }, @@ -911,6 +929,9 @@ "transactionNumber": { "message": "Transaction Number" }, + "transfer": { + "message": "Transfer" + }, "transfers": { "message": "Transfers" }, diff --git a/app/images/alert-red.svg b/app/images/alert-red.svg new file mode 100644 index 000000000..ac5b30e27 --- /dev/null +++ b/app/images/alert-red.svg @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch --> + <title>Artboard Copy</title> + <desc>Created with Sketch.</desc> + <defs></defs> + <g id="Artboard-Copy" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="Group-48"> + <circle id="Oval" fill="#D0021B" cx="8" cy="8" r="8"></circle> + <rect id="Rectangle-41" fill="#FFFFFF" x="7" y="3" width="2" height="7" rx="1"></rect> + <rect id="Rectangle-41" fill="#FFFFFF" x="7" y="11" width="2" height="2" rx="1"></rect> + </g> + </g> +</svg>
\ No newline at end of file diff --git a/app/images/alert.svg b/app/images/alert.svg new file mode 100644 index 000000000..534eda194 --- /dev/null +++ b/app/images/alert.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="29px" height="29px" viewBox="0 0 29 29" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <!-- Generator: sketchtool 50.2 (55047) - http://www.bohemiancoding.com/sketch --> + <title>7414FFD8-B28A-4593-9D7E-19E73D687B50</title> + <desc>Created with sketchtool.</desc> + <defs></defs> + <g id="Action-Screens" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="Approve---insufficient-amount" transform="translate(-69.000000, -166.000000)"> + <g id="Group-7" transform="translate(53.000000, 51.000000)"> + <g id="Group-34" transform="translate(0.000000, 91.000000)"> + <g id="alert" transform="translate(16.000000, 24.000000)"> + <circle id="Oval" fill="#605A1C" cx="14.5" cy="14.5" r="14.5"></circle> + <path d="M16,16.8282967 L14,16.8282967 L14,7 L16,7 L16,16.8282967 Z M16,21 L14,21 L14,19 L16,19 L16,21 Z" id="!" fill="#FFFCDB"></path> + </g> + </g> + </g> + </g> + </g> +</svg>
\ No newline at end of file diff --git a/app/images/caret-left.svg b/app/images/caret-left.svg new file mode 100644 index 000000000..0ea266161 --- /dev/null +++ b/app/images/caret-left.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="9px" height="15px" viewBox="0 0 9 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <!-- Generator: sketchtool 50.2 (55047) - http://www.bohemiancoding.com/sketch --> + <title>8439120D-5704-4273-B416-FEE134322584</title> + <desc>Created with sketchtool.</desc> + <defs></defs> + <g id="Action-Screens" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="Approve---insufficient-amount" transform="translate(-75.000000, -69.000000)" stroke="#3099F2" stroke-width="2"> + <g id="Group-7" transform="translate(53.000000, 51.000000)"> + <g id="cancel" transform="translate(24.000000, 14.000000)"> + <g id="Group"> + <polyline id="Path-8" points="6.1263881 18.0633906 0 11.6306831 6.31493631 5"></polyline> + </g> + </g> + </g> + </g> + </g> +</svg>
\ No newline at end of file diff --git a/app/scripts/controllers/network/enums.js b/app/scripts/controllers/network/enums.js index 9da7f309c..3190eb37c 100644 --- a/app/scripts/controllers/network/enums.js +++ b/app/scripts/controllers/network/enums.js @@ -4,6 +4,7 @@ const KOVAN = 'kovan' const MAINNET = 'mainnet' const LOCALHOST = 'localhost' +const MAINNET_CODE = 1 const ROPSTEN_CODE = 3 const RINKEYBY_CODE = 4 const KOVAN_CODE = 42 @@ -13,13 +14,13 @@ const RINKEBY_DISPLAY_NAME = 'Rinkeby' const KOVAN_DISPLAY_NAME = 'Kovan' const MAINNET_DISPLAY_NAME = 'Main Ethereum Network' - module.exports = { ROPSTEN, RINKEBY, KOVAN, MAINNET, LOCALHOST, + MAINNET_CODE, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 0aae4774b..b4d751830 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -399,19 +399,17 @@ class TransactionStateManager extends EventEmitter { _setTxStatus (txId, status) { const txMeta = this.getTx(txId) txMeta.status = status - setTimeout(() => { - try { - this.updateTx(txMeta, `txStateManager: setting status to ${status}`) - this.emit(`${txMeta.id}:${status}`, txId) - this.emit(`tx:status-update`, txId, status) - if (['submitted', 'rejected', 'failed'].includes(status)) { - this.emit(`${txMeta.id}:finished`, txMeta) - } - this.emit('update:badge') - } catch (error) { - log.error(error) + try { + this.updateTx(txMeta, `txStateManager: setting status to ${status}`) + this.emit(`${txMeta.id}:${status}`, txId) + this.emit(`tx:status-update`, txId, status) + if (['submitted', 'rejected', 'failed'].includes(status)) { + this.emit(`${txMeta.id}:finished`, txMeta) } - }) + this.emit('update:badge') + } catch (error) { + log.error(error) + } } /** diff --git a/package-lock.json b/package-lock.json index d2852f29a..8ed5ca9f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -280,6 +280,7 @@ } } }, +<<<<<<< HEAD "@gulp-sourcemaps/identity-map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.1.tgz", @@ -306,6 +307,196 @@ "dev": true } } +======= + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "4.2.0", + "debug": "3.1.0" + } + } + } + }, + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, + "@sinonjs/formatio": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "dev": true, + "requires": { + "samsam": "1.3.0" + } + }, + "@storybook/addon-actions": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-3.4.3.tgz", + "integrity": "sha512-1Du2SIXeJElOXor03Gc+n49sWv8R0OOKs4BvQPcmdw6uRL8ow917dXr5nQOAmZjXILPpZJOkpJE5BWPPqE+0LQ==", + "dev": true, + "requires": { + "@storybook/components": "3.4.3", + "babel-runtime": "6.26.0", + "deep-equal": "1.0.1", + "glamor": "2.20.40", + "glamorous": "4.12.5", + "global": "4.3.2", + "make-error": "1.3.4", + "prop-types": "15.6.1", + "react-inspector": "2.3.0", + "uuid": "3.2.1" + }, + "dependencies": { + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true + } + } + }, + "@storybook/addon-info": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/addon-info/-/addon-info-3.4.3.tgz", + "integrity": "sha512-En4Bc3V9yeG/Va0KvWXLtlREH26xrosrCq9LMNe5EgXwngLTKsgXZ897zOo8nXaNJvBua8UaiFnYDXiFRXSvZg==", + "dev": true, + "requires": { + "@storybook/client-logger": "3.4.3", + "@storybook/components": "3.4.3", + "babel-runtime": "6.26.0", + "glamor": "2.20.40", + "glamorous": "4.12.5", + "global": "4.3.2", + "marksy": "6.0.3", + "nested-object-assign": "1.0.2", + "prop-types": "15.6.1", + "react-addons-create-fragment": "15.6.2", + "util-deprecate": "1.0.2" + } + }, + "@storybook/addon-knobs": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-3.4.3.tgz", + "integrity": "sha512-H/cq7zw435liFeL4zDwcNSH4pTjJtBwW6LekYUg9CrOkwTAN9Q165k48gbmZFoJU26hYuNonhaZUzMWzdKIrdQ==", + "dev": true, + "requires": { + "@storybook/components": "3.4.3", + "babel-runtime": "6.26.0", + "deep-equal": "1.0.1", + "global": "4.3.2", + "insert-css": "2.0.0", + "lodash.debounce": "4.0.8", + "moment": "2.22.1", + "prop-types": "15.6.1", + "react-color": "2.14.1", + "react-datetime": "2.14.0", + "react-textarea-autosize": "5.2.1", + "util-deprecate": "1.0.2" + } + }, + "@storybook/addon-links": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-3.4.3.tgz", + "integrity": "sha512-TGOI4arJfYmqizSedx6WOGxtnZrYR1i4RUQJt6wdizQzelgZSyoXN2AyuFzX0RH5IlEmfdCyvnv2jw7mTDNMEg==", + "dev": true, + "requires": { + "@storybook/components": "3.4.3", + "babel-runtime": "6.26.0", + "global": "4.3.2", + "prop-types": "15.6.1" + } + }, + "@storybook/addons": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-3.4.3.tgz", + "integrity": "sha512-vi2E2f+QFt1sp1mMJBdb0wdfmopE+Oprr1sLYEM9+E3eV9eh1stu/WBelk8Es3KsPh6vrJw8dy/rHIrIcUUSyQ==", + "dev": true + }, + "@storybook/channel-postmessage": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-3.4.3.tgz", + "integrity": "sha512-fWFCIEHtRk0inHuz6c91v5UlL+fB6RRZQZQkMrnFCZPCYpjtcJYBWp2mX+Pv1UFga57+d1NJKd/M0Jpy+xXLBA==", + "dev": true, + "requires": { + "@storybook/channels": "3.4.3", + "global": "4.3.2", + "json-stringify-safe": "5.0.1" + } + }, + "@storybook/channels": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-3.4.3.tgz", + "integrity": "sha512-x6ika4smvYOcmjoPGzZpitRpKiNfpHeovLPhnWdGGHm5IiC/Z0up9qvM4yxGfDuQvxCQ70nT+8f8Jo3SlqtTMw==", + "dev": true + }, + "@storybook/client-logger": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-3.4.3.tgz", + "integrity": "sha512-QUD0/iJsPhtBYexo/MAwpkO8i+ChS/kKdlzoGOY9pC/XjQALk24BJDT4EVk0VbDdDqp2K0Pvc+ShIBtEm34AzA==", + "dev": true + }, + "@storybook/components": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-3.4.3.tgz", + "integrity": "sha512-++sBqTD6V6nZ5EaY8ecW+rMtgLEQBP18d2b2OYAdMuDffIKL7olfcgmlW9bchm40zLecbV5TGTjZFGbXXJ4sWw==", + "dev": true, + "requires": { + "glamor": "2.20.40", + "glamorous": "4.12.5", + "prop-types": "15.6.1" + } + }, + "@storybook/core": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-3.4.3.tgz", + "integrity": "sha512-92mFUf+W2hac36x9N7r8VjuUJwKHL/c5k6Jbri0quJTcPRvrypIO3UmwAxon+9z+eNmWKi+bQGFayMxHlDEDkw==", + "dev": true, + "requires": { + "@storybook/addons": "3.4.3", + "@storybook/channel-postmessage": "3.4.3", + "@storybook/client-logger": "3.4.3", + "@storybook/node-logger": "3.4.3", + "@storybook/ui": "3.4.3", + "autoprefixer": "7.2.6", + "babel-runtime": "6.26.0", + "chalk": "2.4.1", + "commander": "2.15.1", + "css-loader": "0.28.11", + "dotenv": "5.0.1", + "events": "2.0.0", + "express": "4.16.3", + "file-loader": "1.1.11", + "global": "4.3.2", + "json-loader": "0.5.7", + "postcss-flexbugs-fixes": "3.3.1", + "postcss-loader": "2.1.5", + "prop-types": "15.6.1", + "qs": "6.5.1", + "serve-favicon": "2.5.0", + "shelljs": "0.8.2", + "style-loader": "0.20.3", + "url-loader": "0.6.2", + "webpack": "3.11.0", + "webpack-dev-middleware": "1.12.2", + "webpack-hot-middleware": "2.22.1" + }, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "2.1.18", + "negotiator": "0.6.1" + } +>>>>>>> Refactor and redesign confirm transaction views }, "@gulp-sourcemaps/map-sources": { "version": "1.0.0", @@ -2983,6 +3174,7 @@ "babel-helper-is-void-0": "^0.3.0" } }, +<<<<<<< HEAD "babel-plugin-minify-guarded-expressions": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.3.0.tgz", @@ -2991,6 +3183,484 @@ "requires": { "babel-helper-flip-expressions": "^0.3.0" } +======= + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "common-tags": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.7.2.tgz", + "integrity": "sha512-joj9ZlUOjCrwdbmiLqafeUSgkUM74NqhLsZtSqDmhKudaIY197zTrb8JMl31fMnCUuxwFT23eC/oWvrZzDLRJQ==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "commondir": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-0.0.1.tgz", + "integrity": "sha1-ifAP3NUbUZxXhzP+xWPmptp/W+I=" + }, + "commoner": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz", + "integrity": "sha1-NPw2cs0kOT6LtH5wyqApOBH08sU=", + "requires": { + "commander": "2.11.0", + "detective": "4.7.1", + "glob": "5.0.15", + "graceful-fs": "4.1.11", + "iconv-lite": "0.4.19", + "mkdirp": "0.5.1", + "private": "0.1.8", + "q": "1.5.1", + "recast": "0.11.23" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "compare-semver": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/compare-semver/-/compare-semver-1.1.0.tgz", + "integrity": "sha1-fAp5onu4C2xplERfgpWCWdPQIVM=", + "requires": { + "semver": "5.4.1" + } + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.12.tgz", + "integrity": "sha1-xZpcmdt2dn6YdlAOJx72OzSTvWY=", + "requires": { + "mime-db": "1.30.0" + } + }, + "compression": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz", + "integrity": "sha1-7/JgPvwuIs+G810uuTWJ+YdTc9s=", + "requires": { + "accepts": "1.3.4", + "bytes": "3.0.0", + "compressible": "2.0.12", + "debug": "2.6.9", + "on-headers": "1.0.1", + "safe-buffer": "5.1.1", + "vary": "1.1.2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, + "config-chain": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", + "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", + "dev": true, + "requires": { + "ini": "1.3.5", + "proto-list": "1.2.4" +<<<<<<< HEAD + } + }, + "configstore": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz", + "integrity": "sha1-c3o6cDbpiGECqmCZ5HuzOrGroaE=", + "requires": { + "dot-prop": "3.0.0", + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "object-assign": "4.1.1", + "os-tmpdir": "1.0.2", + "osenv": "0.1.5", + "uuid": "2.0.3", + "write-file-atomic": "1.3.4", + "xdg-basedir": "2.0.0" +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "1.3.2", + "utils-merge": "1.0.1" + } + }, + "connect-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/connect-query/-/connect-query-1.0.0.tgz", + "integrity": "sha1-3kT1dyCdokBNH8BGktGkEY5YIRk=", + "requires": { + "qs": "6.4.0" + }, + "dependencies": { + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + } + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "requires": { + "date-now": "0.1.4" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "consolidate": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz", + "integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=", + "dev": true, + "requires": { + "bluebird": "3.5.1" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "content-type-parser": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", + "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==", + "dev": true + }, + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "1.2.0", + "fs-write-stream-atomic": "1.0.10", + "iferr": "0.1.5", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "run-queue": "1.0.3" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "requires": { + "each-props": "1.3.2", + "is-plain-object": "2.0.4" + } + }, + "copy-to-clipboard": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz", + "integrity": "sha512-c3GdeY8qxCHGezVb1EFQfHYK/8NZRemgcTIzPq7PuxjHAf/raKibn2QdhHPb/y6q74PMgH6yizaDZlRmw6QyKw==", + "requires": { + "toggle-selection": "1.0.6" + } + }, + "core-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cors": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", + "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", + "requires": { + "object-assign": "4.1.1", + "vary": "1.1.2" + } + }, + "corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true + }, + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "0.3.1", + "js-yaml": "3.10.0", + "minimist": "1.2.0", + "object-assign": "4.1.1", + "os-homedir": "1.0.2", + "parse-json": "2.2.0", + "require-from-string": "1.2.1" + } + }, + "coveralls": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.0.tgz", + "integrity": "sha512-ZppXR9y5PraUOrf/DzHJY6gzNUhXYE3b9D43xEXs4QYZ7/Oe0Gy0CS+IPKWFfvQFXB3RG9QduaQUFehzSpGAFw==", + "dev": true, + "requires": { + "js-yaml": "3.10.0", + "lcov-parse": "0.0.10", + "log-driver": "1.2.5", + "minimist": "1.2.0", + "request": "2.83.0" + } + }, + "create-ecdh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "requires": { + "bn.js": "4.11.8", + "elliptic": "6.4.0" + } + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "requires": { + "capture-stack-trace": "1.0.0" + } + }, + "create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "sha.js": "2.4.9" + } + }, + "create-hmac": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", + "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.9" + } + }, + "create-react-class": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.2.tgz", + "integrity": "sha1-zx7RXxKq1/FO9fLf4F5sQvke8Co=", + "requires": { + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" + } + }, + "cross-env": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.1.4.tgz", + "integrity": "sha512-Mx8mw6JWhfpYoEk7PGvHxJMLQwQHORAs8+2bX+C1lGQ4h3GkDb1zbzC2Nw85YH9ZQMlO0BHZxMacgrfPmMFxbg==", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "is-windows": "1.0.2" + } + }, + "cross-fetch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.1.0.tgz", + "integrity": "sha512-FTIt2WK44RiafWQ62xIvd+oBoVd392abh1lF872trLlA74JCR1s4oTHlixwoIKy44ehn8WbQ0Ds2P16sw7ZQxg==", + "requires": { + "node-fetch": "2.1.1", + "whatwg-fetch": "2.0.3" + }, + "dependencies": { + "node-fetch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.1.tgz", + "integrity": "sha1-NpynC4L1DIZJYQSmx3bSdPTkotQ=" + } + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "1.0.0", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.0", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "diffie-hellman": "5.0.2", + "inherits": "2.0.3", + "pbkdf2": "3.0.14", + "public-encrypt": "4.0.0", + "randombytes": "2.0.5", + "randomfill": "1.0.3" + } + }, + "crypto-js": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", + "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=" + }, + "css": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.1.tgz", + "integrity": "sha1-c6TIHehdtmTU7mdPfUcIXjstVdw=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "source-map": "0.1.43", + "source-map-resolve": "0.3.1", + "urix": "0.1.0" + }, + "dependencies": { + "atob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/atob/-/atob-1.1.3.tgz", + "integrity": "sha1-lfE2KbEsOlGl0hWr3OKqnzL4B3M=", + "dev": true +>>>>>>> Refactor and redesign confirm transaction views }, "babel-plugin-minify-infinity": { "version": "0.3.0", @@ -3420,6 +4090,7 @@ "babel-runtime": "^6.22.0" } }, +<<<<<<< HEAD "babel-plugin-transform-export-extensions": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz", @@ -3429,6 +4100,217 @@ "babel-plugin-syntax-export-extensions": "^6.8.0", "babel-runtime": "^6.22.0" } +======= + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "duplexify": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.1.tgz", + "integrity": "sha512-j5goxHTwVED1Fpe5hh3q9R93Kip0Bg2KVAt4f8CEYM3UEwYcPSvWbXaUQOzdX/HtiNomipv+gU7ASQPDbV7pGQ==", + "requires": { + "end-of-stream": "1.4.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "stream-shift": "1.0.0" + } + }, + "each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "requires": { + "is-plain-object": "2.0.4", + "object.defaults": "1.1.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" +<<<<<<< HEAD + } + }, + "ecstatic": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.2.0.tgz", + "integrity": "sha512-Goilx/2cfU9vvfQjgtNgc2VmJAD8CasQ6rZDqCd2u4Hsyd/qFET6nBf60jiHodevR3nl3IGzNKtrzPXWP88utQ==", + "dev": true, + "requires": { + "he": "1.1.1", + "mime": "1.4.1", + "minimist": "1.2.0", + "url-join": "2.0.5" +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", + "dev": true + }, + "editorconfig": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.13.3.tgz", + "integrity": "sha512-WkjsUNVCu+ITKDj73QDvi0trvpdDWdkDyHybDGSXPfekLCqwmpD7CP7iPbvBgosNuLcI96XTDwNa75JyFl7tEQ==", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "commander": "2.11.0", + "lru-cache": "3.2.0", + "semver": "5.4.1", + "sigmund": "1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", + "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", + "dev": true, + "requires": { + "pseudomap": "1.0.2" + } + } + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "ejs": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.8.tgz", + "integrity": "sha512-QIDZL54fyV8MDcAsO91BMH1ft2qGGaHIJsJIA/+t+7uvXol1dm413fPcUgUb4k8F/9457rx4/KFE4XfDifrQxQ==", + "dev": true + }, + "electron-releases": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/electron-releases/-/electron-releases-2.1.0.tgz", + "integrity": "sha512-cyKFD1bTE/UgULXfaueIN1k5EPFzs+FRc/rvCY5tIynefAPqopQEgjr0EzY+U3Dqrk/G4m9tXSPuZ77v6dL/Rw==" + }, + "electron-to-chromium": { + "version": "1.3.30", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.30.tgz", + "integrity": "sha512-zx1Prv7kYLfc4OA60FhxGbSo4qrEjgSzpo1/37i7l9ltXPYOoQBtjQxY9KmsgfHnBxHlBGXwLlsbt/gub1w5lw==", + "requires": { + "electron-releases": "2.1.0" + } + }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "encodeurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "0.4.19" + } + }, + "end-of-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "requires": { + "once": "1.4.0" + } + }, + "engine.io": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.5.tgz", + "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", + "dev": true, + "requires": { + "accepts": "1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "3.1.0", + "engine.io-parser": "2.1.2", + "uws": "9.14.0", + "ws": "3.3.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-client": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.5.tgz", + "integrity": "sha512-Rv9vgb83zrNVhRircUXHi4mtbJhgy2oWtJOCZEbCLFs2HiDSWmh/aOEj8TwoKsn8zXGqTuQuPSoU4v3E10bR6A==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "3.1.0", + "engine.io-parser": "2.1.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "3.3.3", + "xmlhttprequest-ssl": "1.5.5", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } +>>>>>>> Refactor and redesign confirm transaction views }, "babel-plugin-transform-flow-strip-types": { "version": "6.22.0", @@ -4155,6 +5037,7 @@ "safe-buffer": "^5.0.1" } }, +<<<<<<< HEAD "bitsyntax": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.0.4.tgz", @@ -4164,6 +5047,182 @@ "requires": { "buffer-more-ints": "0.0.2" } +======= + "ethjs-util": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz", + "integrity": "sha1-39XqSkANxeQhqInK9H4IGtp4u1U=", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + } + } + }, + "ethjs-rpc": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.1.5.tgz", + "integrity": "sha1-CZ4i8n3EwYtpeKSF/DaxsPeWkIA=" + }, + "ethjs-schema": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-schema/-/ethjs-schema-0.2.1.tgz", + "integrity": "sha512-DXd8lwNrhT9sjsh/Vd2Z+4pfyGxhc0POVnLBUfwk5udtdoBzADyq+sK39dcb48+ZU+2VgtwHxtGWnLnCfmfW5g==" + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + } + } + }, + "ethjs-util": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.4.tgz", + "integrity": "sha1-HItoeSV0RO9NPz+7rC3tEs2ZfZM=", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "eve-raphael": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/eve-raphael/-/eve-raphael-0.5.0.tgz", + "integrity": "sha1-F8dUt5K+7z+maE15z1pHxjxM2jA=" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.37" + } + }, + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "dev": true, + "requires": { + "duplexer": "0.1.1", + "from": "0.1.7", + "map-stream": "0.1.0", + "pause-stream": "0.0.11", + "split": "0.3.3", + "stream-combiner": "0.0.4", + "through": "2.3.8" + } + }, + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "events-to-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", + "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=", + "dev": true + }, + "eventsource": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", + "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", + "dev": true, + "requires": { + "original": "1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "1.3.4", + "safe-buffer": "5.1.1" + } + }, + "execa": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", + "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "execall": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execall/-/execall-1.0.0.tgz", + "integrity": "sha1-c9CQTjlbPKsGWLCNCewlMH8pu3M=", + "dev": true, + "requires": { + "clone-regexp": "1.0.0" + } + }, + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=", + "dev": true + }, + "exists-stat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/exists-stat/-/exists-stat-1.0.0.tgz", + "integrity": "sha1-BmDjUlouidnkRhKUQMJy7foktSk=", + "dev": true + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "expand-braces": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", + "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "dev": true, + "requires": { + "array-slice": "0.2.3", + "array-unique": "0.2.1", + "braces": "0.1.5" + }, + "dependencies": { + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true +>>>>>>> Refactor and redesign confirm transaction views }, "bl": { "version": "1.2.1", @@ -6158,6 +7217,7 @@ "boom": "2.x.x" } }, +<<<<<<< HEAD "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -6175,6 +7235,79 @@ "randombytes": "^2.0.0", "randomfill": "^1.0.3" } +======= + "yargs": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.2.6.tgz", + "integrity": "sha1-nHtKgv1dWVsr8Xq23MQxNUMv40s=", + "dev": true, + "requires": { + "minimist": "0.1.0" + } + } + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "2.0.1" +<<<<<<< HEAD + } + }, + "glob-slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glob-slash/-/glob-slash-1.0.0.tgz", + "integrity": "sha1-/lLvpDMjP3Si/mTHq7m8hIICq5U=" + }, + "glob-slasher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/glob-slasher/-/glob-slasher-1.0.1.tgz", + "integrity": "sha1-dHoOW7IiZC7hDT4FRD4QlJPLD44=", + "requires": { + "glob-slash": "1.0.0", + "lodash.isobject": "2.4.1", + "toxic": "1.0.1" +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "requires": { + "extend": "3.0.1", + "glob": "7.1.2", + "glob-parent": "3.1.0", + "is-negated-glob": "1.0.0", + "ordered-read-streams": "1.0.1", + "pumpify": "1.3.5", + "readable-stream": "2.3.3", + "remove-trailing-separator": "1.1.0", + "to-absolute-glob": "2.0.2", + "unique-stream": "2.2.1" + }, + "dependencies": { + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "3.1.0", + "path-dirname": "1.0.2" + } +>>>>>>> Refactor and redesign confirm transaction views }, "crypto-js": { "version": "3.1.8", @@ -7981,6 +9114,7 @@ "event-emitter": "~0.3.5" } }, +<<<<<<< HEAD "es6-shim": { "version": "0.35.3", "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.3.tgz", @@ -7995,6 +9129,131 @@ "d": "1", "es5-ext": "~0.10.14" } +======= + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "requires": { + "object-keys": "0.4.0" + } + } + } + }, + "html-webpack-plugin": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz", + "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "html-minifier": "3.5.15", + "loader-utils": "0.2.17", + "lodash": "4.17.10", + "pretty-error": "2.1.1", + "toposort": "1.0.7" + } + }, + "htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", + "dev": true + }, + "htmlparser2": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.4.1", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + }, + "dependencies": { + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, + "http-parser-js": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.9.tgz", + "integrity": "sha1-6hoE+2St/wJC6ZdPKX3Uw8rSceE=", + "dev": true + }, + "http-proxy": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", + "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", + "dev": true, + "requires": { + "eventemitter3": "1.2.0", + "requires-port": "1.0.0" + } + }, + "http-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz", + "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.9", + "extend": "3.0.1" +<<<<<<< HEAD + } + }, + "http-server": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz", + "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==", + "dev": true, + "requires": { + "colors": "1.0.3", + "corser": "2.0.1", + "ecstatic": "3.2.0", + "http-proxy": "1.16.2", + "opener": "1.4.3", + "optimist": "0.6.1", + "portfinder": "1.0.13", + "union": "0.4.6" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true +>>>>>>> Refactor and redesign confirm transaction views }, "es6-templates": { "version": "0.2.3", @@ -8006,6 +9265,7 @@ "through": "~2.3.6" } }, +<<<<<<< HEAD "es6-weak-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", @@ -8016,6 +9276,132 @@ "es6-iterator": "^2.0.1", "es6-symbol": "^3.1.1" } +======= + "portfinder": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz", + "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", + "dev": true, + "requires": { + "async": "1.5.2", + "debug": "2.6.9", + "mkdirp": "0.5.1" + } + } +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" + } + }, + "httpntlm": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", + "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", + "dev": true, + "requires": { + "httpreq": "0.4.24", + "underscore": "1.7.0" + }, + "dependencies": { + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "dev": true + } + } + }, + "httpreq": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", + "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", + "dev": true + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.9", + "extend": "3.0.1" + } + }, + "human-standard-token-abi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/human-standard-token-abi/-/human-standard-token-abi-1.0.2.tgz", + "integrity": "sha1-IH14Rnlu5buF/dM252nLOARbKuA=" + }, + "humble-localstorage": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/humble-localstorage/-/humble-localstorage-1.4.2.tgz", + "integrity": "sha1-0Fqw1SbE7b3b98amDfb/WAUoNGk=", + "requires": { + "has-localstorage": "1.0.1", + "localstorage-memory": "1.0.2" + } + }, + "hyphenate-style-name": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz", + "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=" + }, + "i": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", + "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" + }, + "icss-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", + "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", + "requires": { + "postcss": "6.0.19" + } + }, + "idb-global": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/idb-global/-/idb-global-2.1.0.tgz", + "integrity": "sha512-tJPsvisI6A1xQ6y+orXavjgm/7O6v0YT4wKfw8rwv635pIhsc1Wi2ZhcS+6nYmpyyeaTBC/xG0MWcD9iwCD3xg==", + "requires": { + "obs-store": "2.4.1" + }, + "dependencies": { + "babelify": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "6.26.0", + "object-assign": "4.1.1" + } +>>>>>>> Refactor and redesign confirm transaction views }, "escape-html": { "version": "1.0.3", @@ -8264,6 +9650,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" }, +<<<<<<< HEAD "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", @@ -8282,6 +9669,740 @@ "ethereumjs-vm": "^2.0.0", "tape": "^4.6.2" } +======= + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "2.3.0", + "p-is-promise": "1.1.0" + } + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.0.1.tgz", + "integrity": "sha1-x+NWzeoiWucbNtcPLnGpK6TkJZA=", + "dev": true, + "optional": true + }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" + }, + "irregular-plurals": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz", + "integrity": "sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "1.0.0", + "is-windows": "1.0.2" + } + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "is-alphabetical": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.1.tgz", + "integrity": "sha1-x3B5zJHU76x3W+EDS/LSQ/lebwg=" + }, + "is-alphanumerical": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.1.tgz", + "integrity": "sha1-37SqTRCF4zvbYcLe6cgOnGwZ9Ts=", + "requires": { + "is-alphabetical": "1.0.1", + "is-decimal": "1.0.1" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "1.11.0" + } + }, + "is-boolean-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.0.tgz", + "integrity": "sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=" + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, + "is-decimal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.1.tgz", + "integrity": "sha1-9ftqlJlq2ejjdh+/vQkfH8qMToI=" + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-dom": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/is-dom/-/is-dom-1.0.9.tgz", + "integrity": "sha1-SDgy1SlyBz3hK5/j9gMghw2oNw0=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fn/-/is-fn-1.0.0.tgz", + "integrity": "sha1-lUPV3nvPWwiiLsiiC65uKG1RDYw=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", + "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" + }, + "is-hexadecimal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz", + "integrity": "sha1-bghLvJIGH7sJcexYts5tQE4k2mk=" + }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==" + }, + "is-my-json-valid": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", + "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "is-my-ip-valid": "1.0.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" + }, + "is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "requires": { + "kind-of": "3.2.2" + } + }, + "is-number-object": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.3.tgz", + "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=", + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" + }, + "is-observable": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-0.2.0.tgz", + "integrity": "sha1-s2ExHYPG5dcmyr9eJQsCNxBvWuI=", + "dev": true, + "requires": { + "symbol-observable": "0.2.4" + }, + "dependencies": { + "symbol-observable": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-0.2.4.tgz", + "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A=", + "dev": true + } + } + }, + "is-odd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", + "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", + "requires": { + "is-number": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + } + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "1.0.0" + } + }, + "is-resolvable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", + "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==" + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + }, + "is-root": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-1.0.0.tgz", + "integrity": "sha1-B7bCM7w5TNnQK6FclmvWZg1jQtU=", + "dev": true + }, + "is-scoped": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", + "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", + "dev": true, + "requires": { + "scoped-regex": "1.0.0" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-string": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.4.tgz", + "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=", + "dev": true + }, + "is-subset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", + "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", + "dev": true + }, + "is-supported-regexp-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.0.tgz", + "integrity": "sha1-i1IMhfrnolM4LUsCZS4EVXbhO7g=", + "dev": true + }, + "is-svg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", + "requires": { + "html-comment-regex": "1.1.1" + } + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=" + }, + "is-type": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz", + "integrity": "sha1-9lHYXDZdRJVdFKUdjXBh8/a0d5w=", + "dev": true, + "requires": { + "core-util-is": "1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "0.1.2" + } + }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=" + }, + "is-whitespace-character": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.1.tgz", + "integrity": "sha1-muAXbzKCtlRXoZks2whPil+DPjs=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-word-character": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.1.tgz", + "integrity": "sha1-WgP6HqkazopusMfNdw64bWXIvvs=" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isbinaryfile": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", + "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.3" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istextorbinary": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz", + "integrity": "sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8=", + "dev": true, + "requires": { + "binaryextensions": "1.0.1", + "textextensions": "1.0.2" + } + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "requires": { + "has-to-string-tag-x": "1.4.1", + "is-object": "1.0.1" + } + }, + "jazzicon": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jazzicon/-/jazzicon-1.5.0.tgz", + "integrity": "sha1-1/NrUWAj2znubqwRf0BU6Te2Xpk=", + "requires": { + "color": "0.11.4", + "mersenne-twister": "1.1.0", + "raphael": "2.2.7" +<<<<<<< HEAD + } + }, + "join-path": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/join-path/-/join-path-1.1.1.tgz", + "integrity": "sha1-EFNaEm0ky9Zff/zfFe8uYxB2tQU=", + "requires": { + "as-array": "2.0.0", + "url-join": "0.0.1", + "valid-url": "1.0.9" + }, + "dependencies": { + "url-join": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-0.0.1.tgz", + "integrity": "sha1-HbSK1CLTQCRpqH99l73r/k+x48g=" + } +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "js-base64": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", + "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==" + }, + "js-beautify": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.5.10.tgz", + "integrity": "sha1-TZU3FwJpk0SlFsomv1nwonu3Vxk=", + "dev": true, + "requires": { + "config-chain": "1.1.11", + "mkdirp": "0.5.1", + "nopt": "3.0.6" + } + }, + "js-reporters": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.0.tgz", + "integrity": "sha1-fPLLaYGWaEeQNQ0MTKB/Su2ewX4=", + "dev": true + }, + "js-scrypt": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/js-scrypt/-/js-scrypt-0.2.0.tgz", + "integrity": "sha1-emK3AbRhbnCtDN5URiequ5nX/jk=", + "requires": { + "generic-pool": "2.0.4" + } + }, + "js-sha3": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz", + "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", + "dev": true, + "requires": { + "xmlcreate": "1.0.2" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "jscodeshift": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.5.0.tgz", + "integrity": "sha512-JAcQINNMFpdzzpKJN8k5xXjF3XDuckB1/48uScSzcnNyK199iWEc9AxKL9OoX5144M2w5zEx9Qs4/E/eBZZUlw==", + "dev": true, + "requires": { + "babel-plugin-transform-flow-strip-types": "6.22.0", + "babel-preset-es2015": "6.24.1", + "babel-preset-stage-1": "6.24.1", + "babel-register": "6.26.0", + "babylon": "7.0.0-beta.43", + "colors": "1.2.1", + "flow-parser": "0.69.0", + "lodash": "4.17.10", + "micromatch": "2.3.11", + "neo-async": "2.5.0", + "node-dir": "0.1.8", + "nomnom": "1.8.1", + "recast": "0.14.7", + "temp": "0.8.3", + "write-file-atomic": "1.3.4" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true +>>>>>>> Refactor and redesign confirm transaction views }, "eth-block-tracker": { "version": "2.3.0", @@ -9682,10 +11803,95 @@ "vary": "~1.1.2" } }, +<<<<<<< HEAD "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" +======= + "stream-splicer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", + "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + } + } + }, + "last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "requires": { + "default-resolution": "2.0.0", + "es6-weak-map": "2.0.2" +<<<<<<< HEAD + } + }, + "latest-version": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-2.0.0.tgz", + "integrity": "sha1-VvjWE5YghHuAF/jx9NeOIRMkFos=", + "requires": { + "package-json": "2.4.0" +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", + "requires": { + "set-getter": "0.1.0" + } + }, + "lazy-req": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lazy-req/-/lazy-req-1.1.0.tgz", + "integrity": "sha1-va6+rTD42CQDnODOFJ1Nqge6H6w=" + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "1.0.0" + } + }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, + "ldjson-stream": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz", + "integrity": "sha1-kb7O2lrE7SsX5kn7d356v6AYnCs=", + "dev": true, + "requires": { + "split2": "0.2.1", + "through2": "0.6.5" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true +>>>>>>> Refactor and redesign confirm transaction views }, "extend-shallow": { "version": "2.0.1", @@ -21145,6 +23351,7 @@ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" }, +<<<<<<< HEAD "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -21165,6 +23372,316 @@ "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" } } +======= + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "1.4.0" + } + }, + "recompose": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.25.1.tgz", + "integrity": "sha512-EwFAv6UBrHbLIsIKHUZJ+BKdjTmyEsIrRlGO3R7PKu0S7hkgNznVDRvb+1upQUntURtBvxhYnTVQ3AcWOlsmWA==", + "requires": { + "change-emitter": "0.1.6", + "fbjs": "0.8.16", + "hoist-non-react-statics": "2.3.1", + "symbol-observable": "1.1.0" + } + }, + "recursive-readdir": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha1-kO8jHQd4xc4JPJpI105cVCLROpk=", + "dev": true, + "requires": { + "minimatch": "3.0.3" + }, + "dependencies": { + "minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + } + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "redis": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", + "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "dev": true, + "optional": true, + "requires": { + "double-ended-queue": "2.1.0-0", + "redis-commands": "1.3.5", + "redis-parser": "2.6.0" + } + }, + "redis-commands": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.5.tgz", + "integrity": "sha512-foGF8u6MXGFF++1TZVC6icGXuMYPftKXt1FBT2vrfU9ZATNtZJ8duRC5d1lEfE8hyVe3jhelHGB91oB7I6qLsA==", + "dev": true, + "optional": true + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", + "dev": true, + "optional": true + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "requires": { + "balanced-match": "0.4.2", + "math-expression-evaluator": "1.2.17", + "reduce-function-call": "1.0.2" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + } + } + }, + "reduce-function-call": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", + "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "requires": { + "balanced-match": "0.4.2" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + } + } + }, + "redux": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", + "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", + "requires": { + "lodash": "4.17.10", + "lodash-es": "4.17.4", + "loose-envify": "1.3.1", + "symbol-observable": "1.1.0" + } + }, + "redux-logger": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz", + "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=", + "requires": { + "deep-diff": "0.3.8" + } + }, + "redux-test-utils": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/redux-test-utils/-/redux-test-utils-0.2.2.tgz", + "integrity": "sha512-+YsUHpzZJ7G85wYgllmGLJ75opIlWrCuKThaVTsHW5xLOrzaLE4abQ3AbYcHkx/vFOReG2D8XUwMfGnFKH8hGw==", + "dev": true + }, + "redux-thunk": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.2.0.tgz", + "integrity": "sha1-5hWhbha0ehmlFXZhM9Hj6Zt4UuU=" + }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.8" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regex-not": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.0.tgz", + "integrity": "sha1-Qvg+OXcWIt+CawKvF2Ul1qXxV/k=", + "requires": { + "extend-shallow": "2.0.1" + } + }, + "regex-parser": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.9.tgz", + "integrity": "sha512-VncXxOF6uFlYog5prG2j+e2UGJeam5MfNiJnB/qEgo4KTnMm2XrELCg4rNZ6IlaEUZnGlb8aB6lXowCRQtTkkA==", + "dev": true + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "requires": { + "regenerate": "1.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" +<<<<<<< HEAD + } + }, + "registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "requires": { + "rc": "1.2.8", + "safe-buffer": "5.1.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "requires": { + "rc": "1.2.8" +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remark-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-4.0.0.tgz", + "integrity": "sha512-XZgICP2gJ1MHU7+vQaRM+VA9HEL3X253uwUM/BGgx3iv6TH2B3bF3B8q00DKcyP9YrJV+/7WOWEWBFF/u8cIsw==", + "requires": { + "collapse-white-space": "1.0.3", + "is-alphabetical": "1.0.1", + "is-decimal": "1.0.1", + "is-whitespace-character": "1.0.1", + "is-word-character": "1.0.1", + "markdown-escapes": "1.0.1", + "parse-entities": "1.1.1", + "repeat-string": "1.6.1", + "state-toggle": "1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "1.1.0", + "unherit": "1.1.0", + "unist-util-remove-position": "1.1.1", + "vfile-location": "2.0.2", + "xtend": "4.0.1" + } + }, + "remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "requires": { + "is-buffer": "1.1.6", + "is-utf8": "0.2.1" + } + }, + "remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "requires": { + "remove-bom-buffer": "3.0.0", + "safe-buffer": "5.1.1", + "through2": "2.0.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "renderkid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz", + "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-converter": "0.1.4", + "htmlparser2": "3.3.0", + "strip-ansi": "3.0.1", + "utila": "0.3.3" + }, + "dependencies": { + "domhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } +>>>>>>> Refactor and redesign confirm transaction views }, "nwmatcher": { "version": "1.4.3", @@ -22365,6 +24882,7 @@ "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", "dev": true }, +<<<<<<< HEAD "object-keys": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", @@ -22390,6 +24908,276 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } +======= + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "1.0.2" + } + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" + }, + "replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "requires": { + "homedir-polyfill": "1.0.1", + "is-absolute": "1.0.0", + "remove-trailing-separator": "1.1.0" + } + }, + "replaceall": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/replaceall/-/replaceall-0.1.6.tgz", + "integrity": "sha1-gdgax663LX9cSUKt8ml6MiBojY4=", + "dev": true + }, + "replacestream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", + "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1", + "readable-stream": "2.3.3" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + }, + "dependencies": { + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + } + } + }, + "request-promise": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", + "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", + "requires": { + "bluebird": "3.5.1", + "request-promise-core": "1.1.1", + "stealthy-require": "1.1.1", + "tough-cookie": "2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "requires": { + "lodash": "4.17.10" + } + }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "dev": true, + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "1.1.1", + "tough-cookie": "2.3.3" + } + }, + "requestretry": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", + "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", + "dev": true, + "optional": true, + "requires": { + "extend": "3.0.1", + "lodash": "4.17.10", + "request": "2.83.0", + "when": "3.7.8" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "requizzle": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", + "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", + "dev": true, + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, + "reselect": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", + "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=" + }, + "resolve": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", + "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "2.0.2", + "global-modules": "1.0.0" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" + }, + "resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "requires": { + "value-or-function": "3.0.0" + } + }, + "resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "resolve-url-loader": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-2.3.0.tgz", + "integrity": "sha512-RaEUWgF/B6aTg9VKaOv2o6dfm5f75/lGh8S+SQwoMcBm48WkA2nhLR+V7KEawkxXjU4lLB16IVeHCe7F69nyVw==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "1.2.0", + "camelcase": "4.1.0", + "convert-source-map": "1.5.1", + "loader-utils": "1.1.0", + "lodash.defaults": "4.2.0", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.5.7", + "urix": "0.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true +>>>>>>> Refactor and redesign confirm transaction views }, "object.assign": { "version": "4.1.0", @@ -29933,6 +32721,7 @@ "inherits": "2" } }, +<<<<<<< HEAD "tar-stream": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz", @@ -29947,6 +32736,61 @@ "to-buffer": "^1.1.0", "xtend": "^4.0.0" } +======= + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" +<<<<<<< HEAD + } + } + } + }, + "superstatic": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/superstatic/-/superstatic-5.0.2.tgz", + "integrity": "sha1-186TKe4w2qp2KwHUO1SNC3MGulQ=", + "requires": { + "as-array": "2.0.0", + "async": "1.5.2", + "basic-auth-connect": "1.0.0", + "chalk": "1.1.3", + "char-spinner": "1.0.1", + "compare-semver": "1.1.0", + "compression": "1.7.1", + "connect": "3.6.6", + "connect-query": "1.0.0", + "destroy": "1.0.4", + "fast-url-parser": "1.1.3", + "fs-extra": "0.30.0", + "glob": "7.1.2", + "glob-slasher": "1.0.1", + "home-dir": "1.0.0", + "is-url": "1.2.4", + "join-path": "1.1.1", + "lodash": "4.17.10", + "mime-types": "2.1.17", + "minimatch": "3.0.4", + "morgan": "1.9.0", + "nash": "2.0.4", + "on-finished": "2.3.0", + "on-headers": "1.0.1", + "path-to-regexp": "1.7.0", + "router": "1.3.2", + "rsvp": "3.6.2", + "string-length": "1.0.1", + "try-require": "1.2.1", + "update-notifier": "1.0.3" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" +>>>>>>> Refactor and redesign confirm transaction views }, "tar.gz": { "version": "1.0.7", @@ -29969,6 +32813,7 @@ } } }, +<<<<<<< HEAD "temp": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", @@ -29986,6 +32831,64 @@ "dev": true } } +======= + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" +======= +>>>>>>> Refactor and redesign confirm transaction views + } + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "svg-tag-names": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/svg-tag-names/-/svg-tag-names-1.1.1.tgz", + "integrity": "sha1-lkGynvcQJe4JTHBD983efZn71Qo=", + "dev": true + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "dev": true + }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "requires": { + "coa": "1.0.4", + "colors": "1.1.2", + "csso": "2.3.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "sax": "1.2.4", + "whet.extend": "0.9.9" + }, + "dependencies": { + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" +>>>>>>> Refactor and redesign confirm transaction views }, "testem": { "version": "2.8.0", @@ -30528,6 +33431,7 @@ } } }, +<<<<<<< HEAD "trumpet": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/trumpet/-/trumpet-1.7.2.tgz", @@ -30577,6 +33481,165 @@ } } } +======= + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "3.0.0", + "repeat-string": "1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "3.2.2" + } + } + } + }, + "to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "requires": { + "through2": "2.0.3" + } + }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" +<<<<<<< HEAD + } + }, + "toxic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toxic/-/toxic-1.0.1.tgz", + "integrity": "sha512-WI3rIGdcaKULYg7KVoB0zcjikqvcYYvcuT6D89bFPz2rVR0Rl0PK6x8/X62rtdLtBKIE985NzVf/auTtGegIIg==", + "requires": { + "lodash": "4.17.10" +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", + "dev": true + } + } + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + }, + "treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==" + }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "trim-trailing-lines": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.0.tgz", + "integrity": "sha1-eu+7eAjfnWafbaLkOMrIxGradoQ=" + }, + "trough": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.1.tgz", + "integrity": "sha1-qf2LA5Swro//guBjOgo2zK1bX4Y=" + }, + "true-case-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", + "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "requires": { + "glob": "6.0.4" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "trumpet": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/trumpet/-/trumpet-1.7.2.tgz", + "integrity": "sha1-sCxp5GXRcfVeRJJL+bW90gl0yDA=", + "dev": true, + "requires": { + "duplexer2": "0.0.2", + "html-select": "2.3.24", + "html-tokenize": "1.2.5", + "inherits": "2.0.3", + "readable-stream": "1.1.14", + "through2": "1.1.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true +>>>>>>> Refactor and redesign confirm transaction views }, "try-require": { "version": "1.2.1", @@ -30677,6 +33740,7 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz", "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g==" }, +<<<<<<< HEAD "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", @@ -30735,6 +33799,249 @@ "window-size": "0.1.0" } } +======= + "buffer": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "requires": { + "base64-js": "0.0.8", + "ieee754": "1.1.8", + "isarray": "1.0.0" + } + } + } + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", + "dev": true + }, + "underscore-contrib": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", + "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", + "dev": true, + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, + "undertaker": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.0.tgz", + "integrity": "sha1-M52kZGJS0ILcN45wgGcpl1DhG0k=", + "requires": { + "arr-flatten": "1.1.0", + "arr-map": "2.0.2", + "bach": "1.2.0", + "collection-map": "1.0.0", + "es6-weak-map": "2.0.2", + "last-run": "1.1.1", + "object.defaults": "1.1.0", + "object.reduce": "1.0.1", + "undertaker-registry": "1.0.1" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=" + }, + "unherit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.0.tgz", + "integrity": "sha1-a5qu379z3xdWrZ4xbdmBiFhAzX0=", + "requires": { + "inherits": "2.0.3", + "xtend": "4.0.1" + } + }, + "unified": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/unified/-/unified-6.1.6.tgz", + "integrity": "sha512-pW2f82bCIo2ifuIGYcV12fL96kMMYgw7JKVEgh7ODlrM9rj6vXSY3BV+H6lCcv1ksxynFf582hwWLnA1qRFy4w==", + "requires": { + "bail": "1.0.2", + "extend": "3.0.1", + "is-plain-obj": "1.1.0", + "trough": "1.0.1", + "vfile": "2.3.0", + "x-is-function": "1.0.4", + "x-is-string": "0.1.0" +<<<<<<< HEAD + } + }, + "union": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz", + "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=", + "dev": true, + "requires": { + "qs": "2.3.3" + }, + "dependencies": { + "qs": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz", + "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=", + "dev": true + } +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "requires": { + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" + }, + "dependencies": { + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" + } + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" + }, + "uniqid": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", + "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", + "requires": { + "macaddress": "0.2.8" + } + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" + }, + "unique-filename": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", + "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", + "dev": true, + "requires": { + "unique-slug": "2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", + "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "dev": true, + "requires": { + "imurmurhash": "0.1.4" + } + }, + "unique-stream": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", + "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", + "requires": { + "json-stable-stringify": "1.0.1", + "through2-filter": "2.0.0" + } + }, + "unist-util-is": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-2.1.1.tgz", + "integrity": "sha1-DDEmKeP5YMZukx6BLT2A53AQlHs=" + }, + "unist-util-remove-position": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.1.tgz", + "integrity": "sha1-WoXBVV/BugwQG4ZwfRXlD6TIcbs=", + "requires": { + "unist-util-visit": "1.3.0" + } + }, + "unist-util-stringify-position": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.1.tgz", + "integrity": "sha1-PMvcU2ee7W7PN3fdf14yKcG2qjw=" + }, + "unist-util-visit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.3.0.tgz", + "integrity": "sha512-9ntYcxPFtl44gnwXrQKZ5bMqXMY0ZHzUpqMFiU4zcc8mmf/jzYm8GhYgezuUlX4cJIM1zIDYaO6fG/fI+L6iiQ==", + "requires": { + "unist-util-is": "2.1.1" + } + }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "dev": true + }, + "unorm": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", + "integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "0.3.1", + "isobject": "3.0.1" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } +>>>>>>> Refactor and redesign confirm transaction views } }, "uglify-to-browserify": { @@ -33257,6 +36564,7 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" }, +<<<<<<< HEAD "wide-align": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", @@ -33264,6 +36572,165 @@ "requires": { "string-width": "^1.0.2" } +======= + "time-stamp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz", + "integrity": "sha1-lcakRTDhW6jW9KPsuMOj+sRto1c=", + "dev": true + } + } + }, + "webpack-hot-middleware": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.22.1.tgz", + "integrity": "sha512-wbjnvcc3HOPKRE/L0KmTv2MrByfLFOJlVFNKo5Svxy+1plR/bMIMYQDgB4pUOzJXhiBLU7Clp6P1SSzS89iKxA==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "html-entities": "1.2.1", + "querystring": "0.2.0", + "strip-ansi": "3.0.1" + } + }, + "webpack-sources": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", + "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", + "requires": { + "source-list-map": "2.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "websocket": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.26.tgz", + "integrity": "sha512-fjcrYDPIQxpTnqFQ9JjxUQcdvR89MFAOjPBlF+vjOt49w/XW4fJknUoMz/mDIn2eK1AdslVojcaOxOqyZZV8rw==", + "requires": { + "debug": "2.6.9", + "nan": "2.8.0", + "typedarray-to-buffer": "3.1.5", + "yaeti": "0.0.6" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": "0.4.9", + "websocket-extensions": "0.1.3" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz", + "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.19" + } + }, + "whatwg-fetch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", + "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=" + }, + "whatwg-url": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.4.0.tgz", + "integrity": "sha512-Z0CVh/YE217Foyb488eo+iBv+r7eAQ0wSTyApi9n06jhcA3z6Nidg/EGvl0UFkg7kMdKxfBzzr+o9JF+cevgMg==", + "dev": true, + "requires": { + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" + } + }, + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "dev": true, + "optional": true + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=" + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "requires": { + "string-width": "1.0.2" +<<<<<<< HEAD + } + }, + "widest-line": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-1.0.0.tgz", + "integrity": "sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=", + "requires": { + "string-width": "1.0.2" +======= +>>>>>>> Refactor and redesign confirm transaction views + } + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" + }, + "winston": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.1.1.tgz", + "integrity": "sha1-PJNJ0ZYgf9G9/51LxD73JRDjoS4=", + "dev": true, + "requires": { + "async": "1.0.0", + "colors": "1.0.3", + "cycle": "1.0.3", + "eyes": "0.1.8", + "isstream": "0.1.2", + "pkginfo": "0.3.1", + "stack-trace": "0.0.10" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true +>>>>>>> Refactor and redesign confirm transaction views }, "widest-line": { "version": "1.0.0", diff --git a/package.json b/package.json index 6a5e63992..3b51267ff 100644 --- a/package.json +++ b/package.json @@ -179,6 +179,7 @@ "redux-logger": "^3.0.6", "redux-thunk": "^2.2.0", "request-promise": "^4.2.1", + "reselect": "^3.0.1", "sandwich-expando": "^1.1.3", "semaphore": "^1.0.5", "semver": "^5.4.1", diff --git a/ui/app/actions.js b/ui/app/actions.js index ad890f565..1fb49c920 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -704,11 +704,10 @@ function signTypedMsg (msgData) { function signTx (txData) { return (dispatch) => { - dispatch(actions.showLoadingIndication()) global.ethQuery.sendTransaction(txData, (err, data) => { - dispatch(actions.hideLoadingIndication()) - if (err) return dispatch(actions.displayWarning(err.message)) - dispatch(actions.hideWarning()) + if (err) { + return dispatch(actions.displayWarning(err.message)) + } }) dispatch(actions.showConfTxPage({})) } @@ -910,29 +909,41 @@ function signTokenTx (tokenAddress, toAddress, amount, txData) { function updateTransaction (txData) { log.info('actions: updateTx: ' + JSON.stringify(txData)) - return (dispatch) => { + return dispatch => { log.debug(`actions calling background.updateTx`) - background.updateTransaction(txData, (err) => { - dispatch(actions.hideLoadingIndication()) - dispatch(actions.updateTransactionParams(txData.id, txData.txParams)) - if (err) { - dispatch(actions.txError(err)) - dispatch(actions.goHome()) - return log.error(err.message) - } - dispatch(actions.showConfTxPage({ id: txData.id })) + dispatch(actions.showLoadingIndication()) + + return new Promise((resolve, reject) => { + background.updateTransaction(txData, (err) => { + dispatch(actions.updateTransactionParams(txData.id, txData.txParams)) + if (err) { + dispatch(actions.txError(err)) + dispatch(actions.goHome()) + log.error(err.message) + return reject(err) + } + + resolve(txData) + }) }) + .then(() => updateMetamaskStateFromBackground()) + .then(newState => dispatch(actions.updateMetamaskState(newState))) + .then(() => { + dispatch(actions.showConfTxPage({ id: txData.id })) + dispatch(actions.hideLoadingIndication()) + return txData + }) } } function updateAndApproveTx (txData) { log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData)) - return (dispatch) => { + return dispatch => { log.debug(`actions calling background.updateAndApproveTx`) + dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { background.updateAndApproveTransaction(txData, err => { - dispatch(actions.hideLoadingIndication()) dispatch(actions.updateTransactionParams(txData.id, txData.txParams)) dispatch(actions.clearSend()) @@ -943,10 +954,17 @@ function updateAndApproveTx (txData) { reject(err) } - dispatch(actions.completedTx(txData.id)) resolve(txData) }) }) + .then(() => updateMetamaskStateFromBackground()) + .then(newState => dispatch(actions.updateMetamaskState(newState))) + .then(() => { + dispatch(actions.clearSend()) + dispatch(actions.completedTx(txData.id)) + dispatch(actions.hideLoadingIndication()) + return txData + }) } } @@ -1038,13 +1056,25 @@ function cancelTypedMsg (msgData) { function cancelTx (txData) { return dispatch => { log.debug(`background.cancelTransaction`) + dispatch(actions.showLoadingIndication()) + return new Promise((resolve, reject) => { - background.cancelTransaction(txData.id, () => { + background.cancelTransaction(txData.id, err => { + if (err) { + return reject(err) + } + + resolve() + }) + }) + .then(() => updateMetamaskStateFromBackground()) + .then(newState => dispatch(actions.updateMetamaskState(newState))) + .then(() => { dispatch(actions.clearSend()) dispatch(actions.completedTx(txData.id)) - resolve(txData) + dispatch(actions.hideLoadingIndication()) + return txData }) - }) } } diff --git a/ui/app/app.js b/ui/app/app.js index 670b7e2d0..4e600fe26 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -12,7 +12,7 @@ const log = require('loglevel') const InitializeScreen = require('../../mascara/src/app/first-time').default // accounts const SendTransactionScreen = require('./components/send_/send.container') -const ConfirmTxScreen = require('./conf-tx') +const ConfirmTransaction = require('./components/pages/confirm-transaction') // slideout menu const WalletView = require('./components/wallet-view') @@ -76,7 +76,10 @@ class App extends Component { h(Authenticated, { path: REVEAL_SEED_ROUTE, exact, component: RevealSeedConfirmation }), h(Authenticated, { path: SETTINGS_ROUTE, component: Settings }), h(Authenticated, { path: NOTICE_ROUTE, exact, component: NoticeScreen }), - h(Authenticated, { path: `${CONFIRM_TRANSACTION_ROUTE}/:id?`, component: ConfirmTxScreen }), + h(Authenticated, { + path: `${CONFIRM_TRANSACTION_ROUTE}/:id?`, + component: ConfirmTransaction, + }), h(Authenticated, { path: SEND_ROUTE, exact, component: SendTransactionScreen }), h(Authenticated, { path: ADD_TOKEN_ROUTE, exact, component: AddTokenPage }), h(Authenticated, { path: CONFIRM_ADD_TOKEN_ROUTE, exact, component: ConfirmAddTokenPage }), diff --git a/ui/app/components/button/button.component.js b/ui/app/components/button/button.component.js index e8e798445..1e0ef1b64 100644 --- a/ui/app/components/button/button.component.js +++ b/ui/app/components/button/button.component.js @@ -5,15 +5,24 @@ import classnames from 'classnames' const CLASSNAME_DEFAULT = 'btn-default' const CLASSNAME_PRIMARY = 'btn-primary' const CLASSNAME_SECONDARY = 'btn-secondary' +const CLASSNAME_CONFIRM = 'btn-confirm' const CLASSNAME_LARGE = 'btn--large' const typeHash = { default: CLASSNAME_DEFAULT, primary: CLASSNAME_PRIMARY, secondary: CLASSNAME_SECONDARY, + confirm: CLASSNAME_CONFIRM, } -class Button extends Component { +export default class Button extends Component { + static propTypes = { + type: PropTypes.string, + large: PropTypes.bool, + className: PropTypes.string, + children: PropTypes.string, + } + render () { const { type, large, className, ...buttonProps } = this.props @@ -31,13 +40,3 @@ class Button extends Component { ) } } - -Button.propTypes = { - type: PropTypes.string, - large: PropTypes.bool, - className: PropTypes.string, - children: PropTypes.string, -} - -export default Button - diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js b/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js new file mode 100644 index 000000000..631cf5803 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js @@ -0,0 +1,52 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' + +const ConfirmDetailRow = props => { + const { + label, + fiatFee, + ethFee, + onHeaderClick, + fiatFeeColor, + headerText, + headerTextClassName, + } = props + + return ( + <div className="confirm-detail-row"> + <div className="confirm-detail-row__label"> + { label } + </div> + <div className="confirm-detail-row__details"> + <div + className={classnames('confirm-detail-row__header-text', headerTextClassName)} + onClick={() => onHeaderClick && onHeaderClick()} + > + { headerText } + </div> + <div + className="confirm-detail-row__fiat" + style={{ color: fiatFeeColor }} + > + { fiatFee } + </div> + <div className="confirm-detail-row__eth"> + { `\u2666 ${ethFee}` } + </div> + </div> + </div> + ) +} + +ConfirmDetailRow.propTypes = { + label: PropTypes.string, + fiatFee: PropTypes.string, + ethFee: PropTypes.string, + fiatFeeColor: PropTypes.string, + onHeaderClick: PropTypes.func, + headerText: PropTypes.string, + headerTextClassName: PropTypes.string, +} + +export default ConfirmDetailRow diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/index.js b/ui/app/components/confirm-page-container/confirm-detail-row/index.js new file mode 100644 index 000000000..056afff04 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-detail-row/index.js @@ -0,0 +1 @@ +export { default } from './confirm-detail-row.component' diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/index.scss b/ui/app/components/confirm-page-container/confirm-detail-row/index.scss new file mode 100644 index 000000000..84d0d56ed --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-detail-row/index.scss @@ -0,0 +1,43 @@ +.confirm-detail-row { + padding: 14px 0; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + &__label { + font-size: .75rem; + font-weight: 500; + color: $scorpion; + text-transform: uppercase; + } + + &__details { + flex: 1; + text-align: end; + } + + &__fiat { + font-size: 1.5rem; + } + + &__eth { + color: $oslo-gray; + } + + &__header-text { + font-size: .75rem; + text-transform: uppercase; + margin-bottom: 6px; + color: $scorpion; + + &--edit { + color: $curious-blue; + cursor: pointer; + } + + &--total { + font-size: .625rem; + } + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js new file mode 100644 index 000000000..7c7550170 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -0,0 +1,100 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { Tabs, Tab } from '../../tabs' +import { + ConfirmPageContainerSummary, + ConfirmPageContainerError, + ConfirmPageContainerWarning, +} from './' + +export default class ConfirmPageContainerContent extends Component { + static propTypes = { + action: PropTypes.string, + title: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + titleComponent: PropTypes.func, + subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + hideSubtitle: PropTypes.bool, + errorMessage: PropTypes.string, + summaryComponent: PropTypes.node, + detailsComponent: PropTypes.node, + dataComponent: PropTypes.node, + identiconAddress: PropTypes.string, + nonce: PropTypes.string, + warning: PropTypes.string, + } + + renderContent () { + const { detailsComponent, dataComponent } = this.props + + if (detailsComponent && dataComponent) { + return this.renderTabs() + } else { + return detailsComponent || dataComponent + } + } + + renderTabs () { + const { detailsComponent, dataComponent } = this.props + + return ( + <Tabs> + <Tab name="Details"> + { detailsComponent } + </Tab> + <Tab name="Data"> + { dataComponent } + </Tab> + </Tabs> + ) + } + + render () { + const { + action, + title, + subtitle, + hideSubtitle, + errorMessage, + identiconAddress, + nonce, + summaryComponent, + detailsComponent, + dataComponent, + warning, + } = this.props + + return ( + <div className="confirm-page-container-content"> + { + warning && ( + <ConfirmPageContainerWarning warning={warning} /> + ) + } + { + summaryComponent || ( + <ConfirmPageContainerSummary + className={classnames({ + 'confirm-page-container-summary--border': !detailsComponent || !dataComponent, + })} + action={action} + title={title} + subtitle={subtitle} + hideSubtitle={hideSubtitle} + identiconAddress={identiconAddress} + nonce={nonce} + /> + ) + } + { this.renderContent() } + { + errorMessage && ( + <div className="confirm-page-container-content__error-container"> + <ConfirmPageContainerError error={errorMessage} /> + </div> + ) + } + </div> + ) + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js new file mode 100644 index 000000000..dc5b9b935 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js @@ -0,0 +1,20 @@ +import React from 'react' +import PropTypes from 'prop-types' + +const ConfirmPageContainerError = props => { + return ( + <div className="confirm-page-container-error"> + <img + src="/images/alert-red.svg" + className="confirm-page-container-error__icon" + /> + { `ALERT: ${props.error}` } + </div> + ) +} + +ConfirmPageContainerError.propTypes = { + error: PropTypes.string, +} + +export default ConfirmPageContainerError diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js new file mode 100644 index 000000000..4ac95d0e3 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-error.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss new file mode 100644 index 000000000..e99b0f631 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss @@ -0,0 +1,17 @@ +.confirm-page-container-error { + height: 32px; + border: 1px solid $monzo; + color: $monzo; + background: lighten($monzo, 56%); + border-radius: 4px; + font-size: .75rem; + display: flex; + justify-content: flex-start; + align-items: center; + padding-left: 16px; + + &__icon { + margin-right: 8px; + flex: 0 0 auto; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js new file mode 100644 index 000000000..3b1ee62c5 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js @@ -0,0 +1,56 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import Identicon from '../../../identicon' + +const ConfirmPageContainerSummary = props => { + const { action, title, subtitle, hideSubtitle, className, identiconAddress, nonce } = props + + return ( + <div className={classnames('confirm-page-container-summary', className)}> + <div className="confirm-page-container-summary__action-row"> + <div className="confirm-page-container-summary__action"> + { action } + </div> + { + nonce && ( + <div className="confirm-page-container-summary__nonce"> + { `#${nonce}` } + </div> + ) + } + </div> + <div className="confirm-page-container-summary__title"> + { + identiconAddress && ( + <Identicon + className="confirm-page-container-summary__identicon" + diameter={36} + address={identiconAddress} + /> + ) + } + <div className="confirm-page-container-summary__title-text"> + { title } + </div> + </div> + { + hideSubtitle || <div className="confirm-page-container-summary__subtitle"> + { subtitle } + </div> + } + </div> + ) +} + +ConfirmPageContainerSummary.propTypes = { + action: PropTypes.string, + title: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + hideSubtitle: PropTypes.bool, + className: PropTypes.string, + identiconAddress: PropTypes.string, + nonce: PropTypes.string, +} + +export default ConfirmPageContainerSummary diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.js new file mode 100644 index 000000000..ed1b28cf2 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-summary.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.scss new file mode 100644 index 000000000..7f0f5d37a --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.scss @@ -0,0 +1,54 @@ +.confirm-page-container-summary { + padding: 16px 24px 0; + background-color: #f9fafa; + height: 133px; + box-sizing: border-box; + + &__action-row { + display: flex; + justify-content: space-between; + } + + &__action { + text-transform: uppercase; + color: $oslo-gray; + font-size: .75rem; + padding: 3px 8px; + border: 1px solid $oslo-gray; + border-radius: 4px; + display: inline-block; + } + + &__nonce { + color: $oslo-gray; + } + + &__title { + padding: 4px 0; + display: flex; + align-items: center; + } + + &__identicon { + flex: 0 0 auto; + margin-right: 8px; + } + + &__title-text { + font-size: 2.25rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__subtitle { + color: $oslo-gray; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &--border { + border-bottom: 1px solid $geyser; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js new file mode 100644 index 000000000..79901c8fc --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js @@ -0,0 +1,22 @@ +import React from 'react' +import PropTypes from 'prop-types' + +const ConfirmPageContainerWarning = props => { + return ( + <div className="confirm-page-container-warning"> + <img + className="confirm-page-container-warning__icon" + src="/images/alert.svg" + /> + <div className="confirm-page-container-warning__warning"> + { props.warning } + </div> + </div> + ) +} + +ConfirmPageContainerWarning.propTypes = { + warning: PropTypes.string, +} + +export default ConfirmPageContainerWarning diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.js new file mode 100644 index 000000000..6e48bd144 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-warning.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.scss new file mode 100644 index 000000000..189a5c5c6 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.scss @@ -0,0 +1,18 @@ +.confirm-page-container-warning { + background-color: #fffcdb; + display: flex; + justify-content: center; + align-items: center; + border-bottom: 1px solid $geyser; + padding: 12px 24px; + + &__icon { + flex: 0 0 auto; + margin-right: 16px; + } + + &__warning { + font-size: .75rem; + color: $oslo-gray; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/index.js new file mode 100644 index 000000000..1469dd438 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/index.js @@ -0,0 +1,4 @@ +export { default } from './confirm-page-container-content.component' +export { default as ConfirmPageContainerSummary } from './confirm-page-container-summary' +export { default as ConfirmPageContainerError } from './confirm-page-container-error' +export { default as ConfirmPageContainerWarning } from './confirm-page-container-warning' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss new file mode 100644 index 000000000..39797a43f --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss @@ -0,0 +1,66 @@ +@import './confirm-page-container-error/index'; + +@import './confirm-page-container-warning/index'; + +@import './confirm-page-container-summary/index'; + +.confirm-page-container-content { + overflow-y: auto; + flex: 1; + + &__error-container { + padding: 0 16px 16px 16px; + } + + &__details { + box-sizing: border-box; + padding: 0 24px; + } + + &__data { + padding: 16px; + color: $oslo-gray; + } + + &__data-box { + background-color: #f9fafa; + padding: 12px; + font-size: .75rem; + margin-bottom: 16px; + word-wrap: break-word; + max-height: 200px; + overflow-y: auto; + + &-label { + text-transform: uppercase; + padding: 8px 0 12px; + font-size: 12px; + } + } + + &__data-field { + display: flex; + flex-direction: row; + + &-label { + font-weight: 500; + padding-right: 16px; + } + + &:not(:last-child) { + margin-bottom: 5px; + } + } + + &__gas-fee { + border-bottom: 1px solid $geyser; + } + + &__function-type { + font-size: .875rem; + font-weight: 500; + text-transform: capitalize; + color: $black; + padding-left: 5px; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js b/ui/app/components/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js new file mode 100644 index 000000000..e6fe8f82c --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js @@ -0,0 +1,63 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { + ENVIRONMENT_TYPE_POPUP, + ENVIRONMENT_TYPE_NOTIFICATION, +} from '../../../../../app/scripts/lib/enums' +import NetworkDisplay from '../../network-display' + +export default class ConfirmPageContainer extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + showEdit: PropTypes.bool, + onEdit: PropTypes.func, + children: PropTypes.node, + } + + renderTop () { + const { onEdit, showEdit } = this.props + const windowType = window.METAMASK_UI_TYPE + const isFullScreen = windowType !== ENVIRONMENT_TYPE_NOTIFICATION && + windowType !== ENVIRONMENT_TYPE_POPUP + + if (!showEdit && isFullScreen) { + return null + } + + return ( + <div className="confirm-page-container-header__row"> + <div + className="confirm-page-container-header__back-button-container" + style={{ + visibility: showEdit ? 'initial' : 'hidden', + }} + > + <img + src="/images/caret-left.svg" + /> + <span + className="confirm-page-container-header__back-button" + onClick={() => onEdit()} + > + { this.context.t('edit') } + </span> + </div> + { !isFullScreen && <NetworkDisplay /> } + </div> + ) + } + + render () { + const { children } = this.props + + return ( + <div className="confirm-page-container-header"> + { this.renderTop() } + { children } + </div> + ) + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-header/index.js b/ui/app/components/confirm-page-container/confirm-page-container-header/index.js new file mode 100644 index 000000000..71feb6931 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-header/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-header.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-header/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-header/index.scss new file mode 100644 index 000000000..43e1e4427 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-header/index.scss @@ -0,0 +1,27 @@ +.confirm-page-container-header { + display: flex; + flex-direction: column; + flex: 0 0 auto; + + &__row { + display: flex; + justify-content: space-between; + border-bottom: 1px solid $geyser; + padding: 13px 13px 13px 24px; + flex: 0 0 auto; + } + + &__back-button-container { + display: flex; + justify-content: center; + align-items: center; + } + + &__back-button { + color: #2f9ae0; + font-size: 1rem; + cursor: pointer; + font-weight: 400; + padding-left: 5px; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container.component.js b/ui/app/components/confirm-page-container/confirm-page-container.component.js new file mode 100644 index 000000000..d5247f83b --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container.component.js @@ -0,0 +1,116 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import SenderToRecipient from '../sender-to-recipient' +import { PageContainerFooter } from '../page-container' +import { ConfirmPageContainerHeader, ConfirmPageContainerContent } from './' + +export default class ConfirmPageContainer extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + showEdit: PropTypes.bool, + onEdit: PropTypes.func, + // Sender to Recipient + fromName: PropTypes.string, + fromAddress: PropTypes.string, + toName: PropTypes.string, + toAddress: PropTypes.string, + + valid: PropTypes.bool, + errorMessage: PropTypes.string, + // Header + action: PropTypes.string, + title: PropTypes.string, + titleComponent: PropTypes.func, + subtitle: PropTypes.string, + hideSubtitle: PropTypes.bool, + // Content + summaryComponent: PropTypes.node, + contentComponent: PropTypes.node, + fiatTransactionAmount: PropTypes.string, + fiatTransactionFee: PropTypes.string, + fiatTransactionTotal: PropTypes.string, + ethTransactionAmount: PropTypes.string, + ethTransactionFee: PropTypes.string, + ethTransactionTotal: PropTypes.string, + onEditGas: PropTypes.func, + detailsComponent: PropTypes.node, + dataComponent: PropTypes.node, + identiconAddress: PropTypes.string, + nonce: PropTypes.string, + warning: PropTypes.string, + // Footer + onCancel: PropTypes.func, + onSubmit: PropTypes.func, + } + + render () { + const { + showEdit, + onEdit, + fromName, + fromAddress, + toName, + toAddress, + valid, + errorMessage, + contentComponent, + action, + title, + titleComponent, + subtitle, + hideSubtitle, + summaryComponent, + detailsComponent, + dataComponent, + onCancel, + onSubmit, + identiconAddress, + nonce, + warning, + } = this.props + + return ( + <div className="page-container"> + <ConfirmPageContainerHeader + showEdit={showEdit} + onEdit={() => onEdit()} + > + <SenderToRecipient + senderName={fromName} + senderAddress={fromAddress} + recipientName={toName} + recipientAddress={toAddress} + /> + </ConfirmPageContainerHeader> + { + contentComponent || ( + <ConfirmPageContainerContent + action={action} + title={title} + titleComponent={titleComponent} + subtitle={subtitle} + hideSubtitle={hideSubtitle} + summaryComponent={summaryComponent} + detailsComponent={detailsComponent} + dataComponent={dataComponent} + errorMessage={errorMessage} + identiconAddress={identiconAddress} + nonce={nonce} + warning={warning} + /> + ) + } + <PageContainerFooter + onCancel={() => onCancel()} + onSubmit={() => onSubmit()} + submitText={this.context.t('confirm')} + submitButtonType="confirm" + disabled={!valid} + /> + </div> + ) + } +} diff --git a/ui/app/components/confirm-page-container/index.js b/ui/app/components/confirm-page-container/index.js new file mode 100644 index 000000000..ee88aa5d3 --- /dev/null +++ b/ui/app/components/confirm-page-container/index.js @@ -0,0 +1,8 @@ +export { default } from './confirm-page-container.component' +export { default as ConfirmPageContainerHeader } from './confirm-page-container-header' +export { default as ConfirmDetailRow } from './confirm-detail-row' +export { + default as ConfirmPageContainerContent, + ConfirmPageContainerSummary, + ConfirmPageContainerError, +} from './confirm-page-container-content' diff --git a/ui/app/components/confirm-page-container/index.scss b/ui/app/components/confirm-page-container/index.scss new file mode 100644 index 000000000..af7a5b555 --- /dev/null +++ b/ui/app/components/confirm-page-container/index.scss @@ -0,0 +1,5 @@ +@import './confirm-page-container-content/index'; + +@import './confirm-page-container-header/index'; + +@import './confirm-detail-row/index'; diff --git a/ui/app/components/dropdowns/components/network-dropdown-icon.js b/ui/app/components/dropdowns/components/network-dropdown-icon.js index 7e94e0af5..a45da4c10 100644 --- a/ui/app/components/dropdowns/components/network-dropdown-icon.js +++ b/ui/app/components/dropdowns/components/network-dropdown-icon.js @@ -15,6 +15,7 @@ NetworkDropdownIcon.prototype.render = function () { backgroundColor, isSelected, innerBorder = 'none', + diameter = '12', } = this.props return h(`.menu-icon-circle${isSelected ? '--active' : ''}`, {}, @@ -22,6 +23,8 @@ NetworkDropdownIcon.prototype.render = function () { style: { background: backgroundColor, border: innerBorder, + height: `${diameter}px`, + width: `${diameter}px`, }, }) ) diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index 351640f6e..32f0e90e4 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -4,6 +4,16 @@ @import './info-box/index'; +@import './network-display/index'; + +@import './confirm-page-container/index'; + +@import './page-container/index'; + @import './pages/index'; @import './modals/index'; + +@import './sender-to-recipient/index'; + +@import './tabs/index'; diff --git a/ui/app/components/input-number.js b/ui/app/components/input-number.js index 59c6842ef..01f751b69 100644 --- a/ui/app/components/input-number.js +++ b/ui/app/components/input-number.js @@ -2,10 +2,8 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const { - addCurrencies, conversionGTE, conversionLTE, - subtractCurrencies, } = require('../conversion-util') module.exports = InputNumber @@ -51,7 +49,11 @@ InputNumber.prototype.setValue = function (newValue) { } InputNumber.prototype.render = function () { +<<<<<<< HEAD const { unitLabel, step = 1, placeholder, value } = this.props +======= + const { unitLabel, step = 1, placeholder, value = 0, min = -1, max = Infinity } = this.props +>>>>>>> Refactor and redesign confirm transaction views return h('div.customize-gas-input-wrapper', {}, [ h('input', { @@ -67,11 +69,19 @@ InputNumber.prototype.render = function () { h('span.gas-tooltip-input-detail', {}, [unitLabel]), h('div.gas-tooltip-input-arrows', {}, [ h('i.fa.fa-angle-up', { +<<<<<<< HEAD onClick: () => this.setValue(addCurrencies(value, step, { toNumericBase: 'dec' })), }), h('i.fa.fa-angle-down', { style: { cursor: 'pointer' }, onClick: () => this.setValue(subtractCurrencies(value, step, { toNumericBase: 'dec' })), +======= + onClick: () => this.setValue(Math.min(+value + step, max)), + }), + h('i.fa.fa-angle-down', { + style: { cursor: 'pointer' }, + onClick: () => this.setValue(Math.max(+value - step, min)), +>>>>>>> Refactor and redesign confirm transaction views }), ]), ]) diff --git a/ui/app/components/modals/customize-gas/customize-gas.component.js b/ui/app/components/modals/customize-gas/customize-gas.component.js new file mode 100644 index 000000000..cfaafd2b9 --- /dev/null +++ b/ui/app/components/modals/customize-gas/customize-gas.component.js @@ -0,0 +1,140 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import GasModalCard from '../../customize-gas-modal/gas-modal-card' +import { MIN_GAS_PRICE_GWEI } from '../../send_/send.constants' + +import { + getDecimalGasLimit, + getDecimalGasPrice, + getPrefixedHexGasLimit, + getPrefixedHexGasPrice, +} from './customize-gas.util' + +export default class CustomizeGas extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + txData: PropTypes.object.isRequired, + hideModal: PropTypes.func, + validate: PropTypes.func, + onSubmit: PropTypes.func, + } + + state = { + gasPrice: 0, + gasLimit: 0, + originalGasPrice: 0, + originalGasLimit: 0, + } + + componentDidMount () { + const { txData = {} } = this.props + const { txParams: { gas: hexGasLimit, gasPrice: hexGasPrice } = {} } = txData + + const gasLimit = getDecimalGasLimit(hexGasLimit) + const gasPrice = getDecimalGasPrice(hexGasPrice) + + this.setState({ + gasPrice, + gasLimit, + originalGasPrice: gasPrice, + originalGasLimit: gasLimit, + }) + } + + handleRevert () { + const { originalGasPrice, originalGasLimit } = this.state + + this.setState({ + gasPrice: originalGasPrice, + gasLimit: originalGasLimit, + }) + } + + handleSave () { + const { onSubmit, hideModal } = this.props + const { gasLimit, gasPrice } = this.state + const prefixedHexGasPrice = getPrefixedHexGasPrice(gasPrice) + const prefixedHexGasLimit = getPrefixedHexGasLimit(gasLimit) + + Promise.resolve(onSubmit({ gasPrice: prefixedHexGasPrice, gasLimit: prefixedHexGasLimit })) + .then(() => hideModal()) + } + + validate () { + const { gasLimit, gasPrice } = this.state + return this.props.validate({ + gasPrice: getPrefixedHexGasPrice(gasPrice), + gasLimit: getPrefixedHexGasLimit(gasLimit), + }) + } + + render () { + const { t } = this.context + const { hideModal } = this.props + const { gasPrice, gasLimit } = this.state + const { valid, errorMessage } = this.validate() + + return ( + <div className="customize-gas"> + <div className="customize-gas__content"> + <div className="customize-gas__header"> + <div className="customize-gas__title"> + { this.context.t('customGas') } + </div> + <div + className="customize-gas__close" + onClick={() => hideModal()} + /> + </div> + <div className="customize-gas__body"> + <GasModalCard + value={gasPrice} + min={MIN_GAS_PRICE_GWEI} + step={1} + onChange={value => this.setState({ gasPrice: value })} + title={t('gasPrice')} + copy={t('gasPriceCalculation')} + /> + <GasModalCard + value={gasLimit} + min={1} + step={1} + onChange={value => this.setState({ gasLimit: value })} + title={t('gasLimit')} + copy={t('gasLimitCalculation')} + /> + </div> + <div className="customize-gas__footer"> + { !valid && <div className="customize-gas__error-message">{ errorMessage }</div> } + <div + className="customize-gas__revert" + onClick={() => this.handleRevert()} + > + { t('revert') } + </div> + <div className="customize-gas__buttons"> + <button + className="btn-default customize-gas__cancel" + onClick={() => hideModal()} + style={{ marginRight: '10px' }} + > + { t('cancel') } + </button> + <button + className="btn-primary customize-gas__save" + onClick={() => this.handleSave()} + style={{ marginRight: '10px' }} + disabled={!valid} + > + { t('save') } + </button> + </div> + </div> + </div> + </div> + ) + } +} diff --git a/ui/app/components/modals/customize-gas/customize-gas.container.js b/ui/app/components/modals/customize-gas/customize-gas.container.js new file mode 100644 index 000000000..46a799795 --- /dev/null +++ b/ui/app/components/modals/customize-gas/customize-gas.container.js @@ -0,0 +1,22 @@ +import { connect } from 'react-redux' +import CustomizeGas from './customize-gas.component' +import { hideModal } from '../../../actions' + +const mapStateToProps = state => { + const { appState: { modal: { modalState: { props } } } } = state + const { txData, onSubmit, validate } = props + + return { + txData, + onSubmit, + validate, + } +} + +const mapDispatchToProps = dispatch => { + return { + hideModal: () => dispatch(hideModal()), + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(CustomizeGas) diff --git a/ui/app/components/modals/customize-gas/customize-gas.util.js b/ui/app/components/modals/customize-gas/customize-gas.util.js new file mode 100644 index 000000000..6ba4a7705 --- /dev/null +++ b/ui/app/components/modals/customize-gas/customize-gas.util.js @@ -0,0 +1,34 @@ +import ethUtil from 'ethereumjs-util' +import { conversionUtil } from '../../../conversion-util' + +export function getDecimalGasLimit (hexGasLimit) { + return conversionUtil(hexGasLimit, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + }) +} + +export function getDecimalGasPrice (hexGasPrice) { + return conversionUtil(hexGasPrice, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + fromDenomination: 'WEI', + toDenomination: 'GWEI', + }) +} + +export function getPrefixedHexGasLimit (gasLimit) { + return ethUtil.addHexPrefix(conversionUtil(gasLimit, { + fromNumericBase: 'dec', + toNumericBase: 'hex', + })) +} + +export function getPrefixedHexGasPrice (gasPrice) { + return ethUtil.addHexPrefix(conversionUtil(gasPrice, { + fromNumericBase: 'dec', + toNumericBase: 'hex', + fromDenomination: 'GWEI', + toDenomination: 'WEI', + })) +} diff --git a/ui/app/components/modals/customize-gas/index.js b/ui/app/components/modals/customize-gas/index.js new file mode 100644 index 000000000..3a0ab7edc --- /dev/null +++ b/ui/app/components/modals/customize-gas/index.js @@ -0,0 +1 @@ +export { default } from './customize-gas.container' diff --git a/ui/app/components/modals/customize-gas/index.scss b/ui/app/components/modals/customize-gas/index.scss new file mode 100644 index 000000000..e10452691 --- /dev/null +++ b/ui/app/components/modals/customize-gas/index.scss @@ -0,0 +1,110 @@ +.customize-gas { + border: 1px solid #D8D8D8; + border-radius: 4px; + background-color: #FFFFFF; + box-shadow: 0 2px 4px 0 rgba(0,0,0,0.14); + font-family: Roboto; + display: flex; + flex-flow: column; + + @media screen and (max-width: $break-small) { + width: 100vw; + height: 100vh; + } + + &__header { + height: 52px; + border-bottom: 1px solid $alto; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 22px; + + @media screen and (max-width: $break-small) { + flex: 0 0 auto; + } + } + + &__title { + margin-left: 19.25px; + } + + &__close::after { + content: '\00D7'; + font-size: 1.8em; + color: $dusty-gray; + font-family: sans-serif; + cursor: pointer; + margin-right: 19.25px; + } + + &__content { + display: flex; + flex-flow: column nowrap; + height: 100%; + } + + &__body { + display: flex; + margin-bottom: 24px; + + @media screen and (max-width: $break-small) { + flex-flow: column; + flex: 1 1 auto; + } + } + + &__footer { + height: 75px; + border-top: 1px solid $alto; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 22px; + position: relative; + + @media screen and (max-width: $break-small) { + flex: 0 0 auto; + } + } + + &__buttons { + display: flex; + justify-content: space-between; + margin-right: 21.25px; + } + + &__revert, &__cancel, &__save, &__save__error { + display: flex; + justify-content: center; + align-items: center; + padding: 0 3px; + cursor: pointer; + } + + &__revert { + color: $silver-chalice; + font-size: 16px; + margin-left: 21.25px; + } + + &__cancel, &__save, &__save__error { + width: 85.74px; + min-width: initial; + } + + &__save__error { + opacity: 0.5; + cursor: auto; + } + + &__error-message { + display: block; + position: absolute; + top: 4px; + right: 4px; + font-size: 12px; + line-height: 12px; + color: $red; + } +} diff --git a/ui/app/components/modals/index.scss b/ui/app/components/modals/index.scss index ad6fe16d3..160911c10 100644 --- a/ui/app/components/modals/index.scss +++ b/ui/app/components/modals/index.scss @@ -1,3 +1,5 @@ +@import './customize-gas/index'; + .modal-container { width: 100%; height: 100%; diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 85e85597a..973438b6b 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -24,6 +24,8 @@ const TransactionConfirmed = require('./transaction-confirmed') const WelcomeBeta = require('./welcome-beta') const Notification = require('./notification') +import ConfirmCustomizeGasModal from './customize-gas' + const modalContainerBaseStyle = { transform: 'translate3d(-50%, 0, 0px)', border: '1px solid #CCCFD1', @@ -267,7 +269,31 @@ const MODALS = { CUSTOMIZE_GAS: { contents: [ - h(CustomizeGasModal, {}, []), + h(CustomizeGasModal), + ], + mobileModalStyle: { + width: '100vw', + height: '100vh', + top: '0', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + }, + laptopModalStyle: { + width: '720px', + height: '377px', + top: '80px', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + }, + }, + + CONFIRM_CUSTOMIZE_GAS: { + contents: [ + h(ConfirmCustomizeGasModal), ], mobileModalStyle: { width: '100vw', diff --git a/ui/app/components/network-display.js b/ui/app/components/network-display.js deleted file mode 100644 index 59719d9a4..000000000 --- a/ui/app/components/network-display.js +++ /dev/null @@ -1,56 +0,0 @@ -const { Component } = require('react') -const h = require('react-hyperscript') -const PropTypes = require('prop-types') -const connect = require('react-redux').connect -const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') - -const networkToColorHash = { - 1: '#038789', - 3: '#e91550', - 42: '#690496', - 4: '#ebb33f', -} - -class NetworkDisplay extends Component { - renderNetworkIcon () { - const { network } = this.props - const networkColor = networkToColorHash[network] - - return networkColor - ? h(NetworkDropdownIcon, { backgroundColor: networkColor }) - : h('i.fa.fa-question-circle.fa-med', { - style: { - margin: '0 4px', - color: 'rgb(125, 128, 130)', - }, - }) - } - - render () { - const { provider: { type } } = this.props - return h('.network-display__container', [ - this.renderNetworkIcon(), - h('.network-name', this.context.t(type)), - ]) - } -} - -NetworkDisplay.propTypes = { - network: PropTypes.string, - provider: PropTypes.object, - t: PropTypes.func, -} - -const mapStateToProps = ({ metamask: { network, provider } }) => { - return { - network, - provider, - } -} - -NetworkDisplay.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps)(NetworkDisplay) - diff --git a/ui/app/components/network-display/index.js b/ui/app/components/network-display/index.js new file mode 100644 index 000000000..f6878ae5b --- /dev/null +++ b/ui/app/components/network-display/index.js @@ -0,0 +1,2 @@ +import NetworkDisplay from './network-display.container' +module.exports = NetworkDisplay diff --git a/ui/app/components/network-display/index.scss b/ui/app/components/network-display/index.scss new file mode 100644 index 000000000..3bce81aaa --- /dev/null +++ b/ui/app/components/network-display/index.scss @@ -0,0 +1,54 @@ +.network-display { + &__container { + display: flex; + align-items: center; + justify-content: flex-start; + background-color: lighten(rgb(125, 128, 130), 45%); + padding: 0 10px; + border-radius: 4px; + height: 25px; + + &--mainnet { + background-color: lighten($blue-lagoon, 45%); + } + + &--ropsten { + background-color: lighten($crimson, 45%); + } + + &--kovan { + background-color: lighten($purple, 45%); + } + + &--rinkeby { + background-color: lighten($tulip-tree, 45%); + } + } + + &__name { + font-size: .875rem; + padding-left: 5px; + } + + &__icon { + height: 10px; + width: 10px; + border-radius: 10px; + + &--mainnet { + background-color: $blue-lagoon; + } + + &--ropsten { + background-color: $crimson; + } + + &--kovan { + background-color: $purple; + } + + &--rinkeby { + background-color: $tulip-tree; + } + } +} diff --git a/ui/app/components/network-display/network-display.component.js b/ui/app/components/network-display/network-display.component.js new file mode 100644 index 000000000..38626af20 --- /dev/null +++ b/ui/app/components/network-display/network-display.component.js @@ -0,0 +1,69 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { + MAINNET_CODE, + ROPSTEN_CODE, + RINKEYBY_CODE, + KOVAN_CODE, +} from '../../../../app/scripts/controllers/network/enums' + +const networkToClassHash = { + [MAINNET_CODE]: 'mainnet', + [ROPSTEN_CODE]: 'ropsten', + [RINKEYBY_CODE]: 'rinkeby', + [KOVAN_CODE]: 'kovan', +} + +export default class NetworkDisplay extends Component { + static propTypes = { + network: PropTypes.string, + provider: PropTypes.object, + } + + static contextTypes = { + t: PropTypes.func, + } + + renderNetworkIcon () { + const { network } = this.props + const networkClass = networkToClassHash[network] + + return networkClass + ? <div className={`network-display__icon network-display__icon--${networkClass}`} /> + : <div + className="i fa fa-question-circle fa-med" + style={{ + margin: '0 4px', + color: 'rgb(125, 128, 130)', + }} + /> + } + + render () { + const { network, provider: { type } } = this.props + const networkClass = networkToClassHash[network] + + return ( + <div className={classnames( + 'network-display__container', + networkClass && ('network-display__container--' + networkClass) + )}> + { + networkClass + ? <div className={`network-display__icon network-display__icon--${networkClass}`} /> + : <div + className="i fa fa-question-circle fa-med" + style={{ + margin: '0 4px', + color: 'rgb(125, 128, 130)', + }} + /> + } + <div className="network-display__name"> + { this.context.t(type) } + </div> + </div> + ) + } +} diff --git a/ui/app/components/network-display/network-display.container.js b/ui/app/components/network-display/network-display.container.js new file mode 100644 index 000000000..99a14fff4 --- /dev/null +++ b/ui/app/components/network-display/network-display.container.js @@ -0,0 +1,11 @@ +import { connect } from 'react-redux' +import NetworkDisplay from './network-display.component' + +const mapStateToProps = ({ metamask: { network, provider } }) => { + return { + network, + provider, + } +} + +export default connect(mapStateToProps)(NetworkDisplay) diff --git a/ui/app/components/page-container/index.js b/ui/app/components/page-container/index.js index 415870b37..913b8c9c6 100644 --- a/ui/app/components/page-container/index.js +++ b/ui/app/components/page-container/index.js @@ -1 +1,4 @@ +import PageContainerHeader from './page-container-header' +import PageContainerFooter from './page-container-footer' export { default } from './page-container.component' +export { PageContainerHeader, PageContainerFooter } diff --git a/ui/app/components/page-container/index.scss b/ui/app/components/page-container/index.scss new file mode 100644 index 000000000..06c3ef709 --- /dev/null +++ b/ui/app/components/page-container/index.scss @@ -0,0 +1,186 @@ +.page-container { + width: 408px; + background-color: $white; + box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08); + z-index: 25; + display: flex; + flex-flow: column; + border-radius: 8px; + + &__header { + display: flex; + flex-flow: column; + border-bottom: 1px solid $geyser; + padding: 16px; + flex: 0 0 auto; + position: relative; + + &--no-padding-bottom { + padding-bottom: 0; + } + } + + &__header-close { + color: $tundora; + position: absolute; + top: 16px; + right: 16px; + cursor: pointer; + overflow: hidden; + + &::after { + content: '\00D7'; + font-size: 40px; + line-height: 20px; + } + } + + &__header-row { + padding-bottom: 10px; + display: flex; + justify-content: space-between; + } + + &__footer { + display: flex; + flex-flow: row; + justify-content: center; + border-top: 1px solid $geyser; + padding: 16px; + flex: 0 0 auto; + + .btn-default, + .btn-confirm { + font-size: 1rem; + } + } + + &__footer-button { + height: 55px; + font-size: 1rem; + text-transform: uppercase; + margin-right: 16px; + + &:last-of-type { + margin-right: 0; + } + } + + &__back-button { + color: #2f9ae0; + font-size: 1rem; + cursor: pointer; + font-weight: 400; + } + + &__title { + color: $black; + font-size: 2rem; + font-weight: 500; + line-height: 2rem; + } + + &__subtitle { + padding-top: .5rem; + line-height: initial; + font-size: .9rem; + color: $gray; + } + + &__tabs { + display: flex; + margin-top: 16px; + } + + &__tab { + min-width: 5rem; + padding: 8px; + color: $dusty-gray; + font-family: Roboto; + font-size: 1rem; + text-align: center; + cursor: pointer; + border-bottom: none; + margin-right: 16px; + + &:last-of-type { + margin-right: 0; + } + + &--selected { + color: $curious-blue; + border-bottom: 3px solid $curious-blue; + } + } + + &--full-width { + width: 100% !important; + } + + &--full-height { + height: 100% !important; + max-height: initial !important; + min-height: initial !important; + } + + &__content { + overflow-y: auto; + flex: 1; + } + + &__warning-container { + background: $linen; + padding: 20px; + display: flex; + align-items: start; + } + + &__warning-message { + padding-left: 15px; + } + + &__warning-title { + font-weight: 500; + } + + &__warning-icon { + padding-top: 5px; + } +} + +@media screen and (max-width: 250px) { + .page-container { + &__footer { + flex-flow: column-reverse; + } + + &__footer-button { + width: 100%; + margin-bottom: 1rem; + margin-right: 0; + + &:first-of-type { + margin-bottom: 0; + } + } + } +} + +@media screen and (max-width: 575px) { + .page-container { + height: 100%; + width: 100%; + overflow-y: auto; + background-color: $white; + border-radius: 0; + flex: 1; + } +} + +@media screen and (min-width: 576px) { + .page-container { + max-height: 82vh; + min-height: 570px; + flex: 0 0 auto; + } +} diff --git a/ui/app/components/page-container/page-container-footer/page-container-footer.component.js b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js index 0458ae78a..3d15df294 100644 --- a/ui/app/components/page-container/page-container-footer/page-container-footer.component.js +++ b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js @@ -10,6 +10,7 @@ export default class PageContainerFooter extends Component { onSubmit: PropTypes.func, submitText: PropTypes.string, disabled: PropTypes.bool, + submitButtonType: PropTypes.string, } static contextTypes = { @@ -23,6 +24,7 @@ export default class PageContainerFooter extends Component { onSubmit, submitText, disabled, + submitButtonType, } = this.props return ( @@ -30,16 +32,16 @@ export default class PageContainerFooter extends Component { <Button type="default" - large={true} + large className="page-container__footer-button" - onClick={() => onCancel()} + onClick={e => onCancel(e)} > { cancelText || this.context.t('cancel') } </Button> <Button - type="primary" - large={true} + type={submitButtonType || 'primary'} + large className="page-container__footer-button" disabled={disabled} onClick={e => onSubmit(e)} diff --git a/ui/app/components/page-container/page-container-header.component.js b/ui/app/components/page-container/page-container-header.component.js deleted file mode 100644 index 5c9d63221..000000000 --- a/ui/app/components/page-container/page-container-header.component.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' - -export default class PageContainerHeader extends Component { - - static propTypes = { - title: PropTypes.string, - subtitle: PropTypes.string, - onClose: PropTypes.func, - }; - - render () { - const { title, subtitle, onClose } = this.props - - return ( - <div className="page-container__header"> - - <div className="page-container__title"> - {title} - </div> - - <div className="page-container__subtitle"> - {subtitle} - </div> - - <div - className="page-container__header-close" - onClick={() => onClose()} - /> - - </div> - ) - } - -} diff --git a/ui/app/components/page-container/page-container-header/page-container-header.component.js b/ui/app/components/page-container/page-container-header/page-container-header.component.js index 28882edce..5a5de1e5a 100644 --- a/ui/app/components/page-container/page-container-header/page-container-header.component.js +++ b/ui/app/components/page-container/page-container-header/page-container-header.component.js @@ -4,13 +4,14 @@ import PropTypes from 'prop-types' export default class PageContainerHeader extends Component { static propTypes = { - title: PropTypes.string.isRequired, + title: PropTypes.string, subtitle: PropTypes.string, onClose: PropTypes.func, showBackButton: PropTypes.bool, onBackButtonClick: PropTypes.func, backButtonStyles: PropTypes.object, backButtonString: PropTypes.string, + children: PropTypes.node, }; renderHeaderRow () { @@ -30,25 +31,33 @@ export default class PageContainerHeader extends Component { } render () { - const { title, subtitle, onClose } = this.props + const { title, subtitle, onClose, children } = this.props return ( <div className="page-container__header"> { this.renderHeaderRow() } - <div className="page-container__title"> - {title} - </div> + { children } - <div className="page-container__subtitle"> - {subtitle} - </div> + { + title && <div className="page-container__title"> + { title } + </div> + } - <div - className="page-container__header-close" - onClick={() => onClose()} - /> + { + subtitle && <div className="page-container__subtitle"> + { subtitle } + </div> + } + + { + onClose && <div + className="page-container__header-close" + onClick={() => onClose()} + /> + } </div> ) diff --git a/ui/app/components/pages/confirm-approve/confirm-approve.component.js b/ui/app/components/pages/confirm-approve/confirm-approve.component.js new file mode 100644 index 000000000..d775b0362 --- /dev/null +++ b/ui/app/components/pages/confirm-approve/confirm-approve.component.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import ConfirmTransactionBase from '../confirm-transaction-base' + +export default class ConfirmApprove extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + tokenAddress: PropTypes.string, + toAddress: PropTypes.string, + tokenAmount: PropTypes.string, + tokenSymbol: PropTypes.string, + } + + render () { + const { toAddress, tokenAddress, tokenAmount, tokenSymbol } = this.props + + return ( + <ConfirmTransactionBase + toAddress={toAddress} + identiconAddress={tokenAddress} + title={`${tokenAmount} ${tokenSymbol}`} + warning={`By approving this action, you grant permission for this contract to spend up to ${tokenAmount} of your ${tokenSymbol}.`} + hideSubtitle + /> + ) + } +} diff --git a/ui/app/components/pages/confirm-approve/confirm-approve.container.js b/ui/app/components/pages/confirm-approve/confirm-approve.container.js new file mode 100644 index 000000000..040e499ae --- /dev/null +++ b/ui/app/components/pages/confirm-approve/confirm-approve.container.js @@ -0,0 +1,28 @@ +import { connect } from 'react-redux' +import ConfirmApprove from './confirm-approve.component' + +const mapStateToProps = state => { + const { confirmTransaction } = state + const { + tokenData = {}, + txData: { txParams: { to: tokenAddress } = {} } = {}, + tokenProps: { tokenSymbol } = {}, + } = confirmTransaction + const { params = [] } = tokenData + + let toAddress = '' + let tokenAmount = '' + + if (params && params.length === 2) { + [{ value: toAddress }, { value: tokenAmount }] = params + } + + return { + toAddress, + tokenAddress, + tokenAmount, + tokenSymbol, + } +} + +export default connect(mapStateToProps)(ConfirmApprove) diff --git a/ui/app/components/pages/confirm-approve/index.js b/ui/app/components/pages/confirm-approve/index.js new file mode 100644 index 000000000..791297be7 --- /dev/null +++ b/ui/app/components/pages/confirm-approve/index.js @@ -0,0 +1 @@ +export { default } from './confirm-approve.container' diff --git a/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js new file mode 100644 index 000000000..9bc0daab9 --- /dev/null +++ b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js @@ -0,0 +1,64 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import ethUtil from 'ethereumjs-util' +import ConfirmTransactionBase from '../confirm-transaction-base' + +export default class ConfirmDeployContract extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + txData: PropTypes.object, + } + + renderData () { + const { t } = this.context + const { + txData: { + origin, + txParams: { + data, + } = {}, + } = {}, + } = this.props + + return ( + <div className="confirm-page-container-content__data"> + <div className="confirm-page-container-content__data-box"> + <div className="confirm-page-container-content__data-field"> + <div className="confirm-page-container-content__data-field-label"> + { `${t('origin')}:` } + </div> + <div> + { origin } + </div> + </div> + <div className="confirm-page-container-content__data-field"> + <div className="confirm-page-container-content__data-field-label"> + { `${t('bytes')}:` } + </div> + <div> + { ethUtil.toBuffer(data).length } + </div> + </div> + </div> + <div className="confirm-page-container-content__data-box-label"> + { `${t('hexData')}:` } + </div> + <div className="confirm-page-container-content__data-box"> + { data } + </div> + </div> + ) + } + + render () { + return ( + <ConfirmTransactionBase + action={this.context.t('contractDeployment')} + dataComponent={this.renderData()} + /> + ) + } +} diff --git a/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js new file mode 100644 index 000000000..336ee83ea --- /dev/null +++ b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux' +import ConfirmDeployContract from './confirm-deploy-contract.component' + +const mapStateToProps = state => { + const { confirmTransaction: { txData } = {} } = state + + return { + txData, + } +} + +export default connect(mapStateToProps)(ConfirmDeployContract) diff --git a/ui/app/components/pages/confirm-deploy-contract/index.js b/ui/app/components/pages/confirm-deploy-contract/index.js new file mode 100644 index 000000000..c4fb01b52 --- /dev/null +++ b/ui/app/components/pages/confirm-deploy-contract/index.js @@ -0,0 +1 @@ +export { default } from './confirm-deploy-contract.container' diff --git a/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js new file mode 100644 index 000000000..c590bacf3 --- /dev/null +++ b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js @@ -0,0 +1,31 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import ConfirmTransactionBase from '../confirm-transaction-base' +import { SEND_ROUTE } from '../../../routes' + +export default class ConfirmSendEther extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + editTransaction: PropTypes.func, + history: PropTypes.object, + } + + handleEdit ({ txData }) { + const { editTransaction, history } = this.props + editTransaction(txData) + history.push(SEND_ROUTE) + } + + render () { + return ( + <ConfirmTransactionBase + action={this.context.t('confirm')} + hideData + onEdit={confirmTransactionData => this.handleEdit(confirmTransactionData)} + /> + ) + } +} diff --git a/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js new file mode 100644 index 000000000..898735d1a --- /dev/null +++ b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js @@ -0,0 +1,37 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import { withRouter } from 'react-router-dom' +import { updateSend } from '../../../actions' +import { clearConfirmTransaction } from '../../../ducks/confirm-transaction.duck' +import ConfirmSendEther from './confirm-send-ether.component' + +const mapDispatchToProps = dispatch => { + return { + editTransaction: txData => { + const { id, txParams } = txData + const { + gas: gasLimit, + gasPrice, + to, + value: amount, + } = txParams + + dispatch(updateSend({ + gasLimit, + gasPrice, + gasTotal: null, + to, + amount, + errors: { to: null, amount: null }, + editingTransactionId: id && id.toString(), + })) + + dispatch(clearConfirmTransaction()) + }, + } +} + +export default compose( + withRouter, + connect(null, mapDispatchToProps) +)(ConfirmSendEther) diff --git a/ui/app/components/pages/confirm-send-ether/index.js b/ui/app/components/pages/confirm-send-ether/index.js new file mode 100644 index 000000000..2d5767c39 --- /dev/null +++ b/ui/app/components/pages/confirm-send-ether/index.js @@ -0,0 +1 @@ +export { default } from './confirm-send-ether.container' diff --git a/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js b/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js new file mode 100644 index 000000000..46ad9ccab --- /dev/null +++ b/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js @@ -0,0 +1,39 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import ConfirmTransactionBase from '../confirm-transaction-base' +import { SEND_ROUTE } from '../../../routes' + +export default class ConfirmSendToken extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + history: PropTypes.object, + tokenAddress: PropTypes.string, + toAddress: PropTypes.string, + numberOfTokens: PropTypes.number, + tokenSymbol: PropTypes.string, + editTransaction: PropTypes.func, + } + + handleEdit (confirmTransactionData) { + const { editTransaction, history } = this.props + editTransaction(confirmTransactionData) + history.push(SEND_ROUTE) + } + + render () { + const { toAddress, tokenAddress, tokenSymbol, numberOfTokens } = this.props + + return ( + <ConfirmTransactionBase + toAddress={toAddress} + identiconAddress={tokenAddress} + title={`${numberOfTokens} ${tokenSymbol}`} + onEdit={confirmTransactionData => this.handleEdit(confirmTransactionData)} + hideSubtitle + /> + ) + } +} diff --git a/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js b/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js new file mode 100644 index 000000000..2d7efeed6 --- /dev/null +++ b/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js @@ -0,0 +1,72 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import { withRouter } from 'react-router-dom' +import ConfirmSendToken from './confirm-send-token.component' +import { calcTokenAmount } from '../../../token-util' +import { clearConfirmTransaction } from '../../../ducks/confirm-transaction.duck' +import { setSelectedToken, updateSend, showSendTokenPage } from '../../../actions' +import { conversionUtil } from '../../../conversion-util' + +const mapStateToProps = state => { + const { confirmTransaction } = state + const { + tokenData = {}, + tokenProps: { tokenSymbol, tokenDecimals } = {}, + txData: { txParams: { to: tokenAddress } = {} } = {}, + } = confirmTransaction + const { params = [] } = tokenData + + let toAddress = '' + let tokenAmount = '' + + if (params && params.length === 2) { + [{ value: toAddress }, { value: tokenAmount }] = params + } + + const numberOfTokens = tokenAmount && tokenDecimals + ? calcTokenAmount(tokenAmount, tokenDecimals) + : 0 + + return { + toAddress, + tokenAddress, + tokenSymbol, + numberOfTokens, + } +} + +const mapDispatchToProps = dispatch => { + return { + editTransaction: ({ txData, tokenData, tokenProps }) => { + const { txParams: { to: tokenAddress, gas: gasLimit, gasPrice } = {}, id } = txData + const { params = [] } = tokenData + const { value: to } = params[0] || {} + const { value: tokenAmountInDec } = params[1] || {} + const tokenAmountInHex = conversionUtil(tokenAmountInDec, { + fromNumericBase: 'dec', + toNumericBase: 'hex', + }) + dispatch(setSelectedToken(tokenAddress)) + dispatch(updateSend({ + gasLimit, + gasPrice, + gasTotal: null, + to, + amount: tokenAmountInHex, + errors: { to: null, amount: null }, + editingTransactionId: id && id.toString(), + token: { + ...tokenProps, + address: tokenAddress, + }, + })) + dispatch(clearConfirmTransaction()) + dispatch(showSendTokenPage()) + }, + } +} + +export default compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps) +)(ConfirmSendToken) diff --git a/ui/app/components/pages/confirm-send-token/index.js b/ui/app/components/pages/confirm-send-token/index.js new file mode 100644 index 000000000..409b6ef3d --- /dev/null +++ b/ui/app/components/pages/confirm-send-token/index.js @@ -0,0 +1 @@ +export { default } from './confirm-send-token.container' diff --git a/ui/app/components/pages/confirm-send-token/index.scss b/ui/app/components/pages/confirm-send-token/index.scss new file mode 100644 index 000000000..0476749f6 --- /dev/null +++ b/ui/app/components/pages/confirm-send-token/index.scss @@ -0,0 +1,19 @@ +.confirm-send-token { + &__title { + padding: 4px 0; + display: flex; + align-items: center; + } + + &__identicon { + flex: 0 0 auto; + } + + &__title-text { + font-size: 2.25rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding-left: 8px; + } +} diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js new file mode 100644 index 000000000..3b60a5d5d --- /dev/null +++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -0,0 +1,382 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import ConfirmPageContainer, { ConfirmDetailRow } from '../../confirm-page-container' +import { formatCurrency, getHexGasTotal } from '../../../helpers/confirm-transaction/util' +import { isBalanceSufficient } from '../../send_/send.utils' +import { DEFAULT_ROUTE } from '../../../routes' +import { conversionGreaterThan } from '../../../conversion-util' +import { MIN_GAS_LIMIT_DEC } from '../../send_/send.constants' + +export default class ConfirmTransactionBase extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + match: PropTypes.object, + history: PropTypes.object, + // Redux props + txData: PropTypes.object, + tokenData: PropTypes.object, + tokenProps: PropTypes.object, + isTxReprice: PropTypes.bool, + nonce: PropTypes.string, + fromName: PropTypes.string, + fromAddress: PropTypes.string, + toName: PropTypes.string, + toAddress: PropTypes.string, + transactionStatus: PropTypes.string, + ethTransactionAmount: PropTypes.string, + ethTransactionFee: PropTypes.string, + ethTransactionTotal: PropTypes.string, + fiatTransactionAmount: PropTypes.string, + fiatTransactionFee: PropTypes.string, + fiatTransactionTotal: PropTypes.string, + hexGasTotal: PropTypes.string, + balance: PropTypes.string, + currentCurrency: PropTypes.string, + conversionRate: PropTypes.number, + setTransactionToConfirm: PropTypes.func, + clearConfirmTransaction: PropTypes.func, + cancelTransaction: PropTypes.func, + clearSend: PropTypes.func, + sendTransaction: PropTypes.func, + editTransaction: PropTypes.func, + showCustomizeGasModal: PropTypes.func, + updateGasAndCalculate: PropTypes.func, + showTransactionConfirmedModal: PropTypes.func, + // Component props + action: PropTypes.string, + hideDetails: PropTypes.bool, + hideData: PropTypes.bool, + detailsComponent: PropTypes.node, + dataComponent: PropTypes.node, + summaryComponent: PropTypes.node, + contentComponent: PropTypes.node, + title: PropTypes.string, + subtitle: PropTypes.string, + hideSubtitle: PropTypes.bool, + valid: PropTypes.bool, + errorMessage: PropTypes.string, + warning: PropTypes.string, + identiconAddress: PropTypes.string, + onEdit: PropTypes.func, + onEditGas: PropTypes.func, + onCancel: PropTypes.func, + onSubmit: PropTypes.func, + } + + componentDidMount () { + const { match: { params: { id } = {} }, setTransactionToConfirm } = this.props + setTransactionToConfirm(id) + } + + componentDidUpdate (prevProps) { + const { + transactionStatus, + showTransactionConfirmedModal, + history, + clearConfirmTransaction, + match: { params: { id } = {} }, + setTransactionToConfirm, + txData, + } = this.props + + if (transactionStatus === 'dropped') { + showTransactionConfirmedModal({ + onHide: () => { + clearConfirmTransaction() + history.push(DEFAULT_ROUTE) + }, + }) + + return + } + + if (id && id !== txData.id + '') { + setTransactionToConfirm(id) + } + } + + getError () { + const INSUFFICIENT_FUNDS_ERROR = this.context.t('insufficientFunds') + const TRANSACTION_ERROR = this.context.t('transactionError') + const { + balance, + conversionRate, + hexGasTotal, + txData: { + simulationFails, + txParams: { + value: amount, + } = {}, + } = {}, + } = this.props + + const insufficientBalance = balance && !isBalanceSufficient({ + amount, + gasTotal: hexGasTotal || '0x0', + balance, + conversionRate, + }) + + if (insufficientBalance) { + return { + valid: false, + errorMessage: INSUFFICIENT_FUNDS_ERROR, + } + } + + if (simulationFails) { + return { + valid: false, + errorMessage: TRANSACTION_ERROR, + } + } + + return { + valid: true, + } + } + + validateEditGas ({ gasLimit, gasPrice }) { + const { t } = this.context + const { + balance, + conversionRate, + txData: { + txParams: { + value: amount, + } = {}, + } = {}, + } = this.props + + const INSUFFICIENT_FUNDS_ERROR = t('insufficientFunds') + const GAS_LIMIT_TOO_LOW_ERROR = t('gasLimitTooLow') + + const gasTotal = getHexGasTotal({ gasLimit, gasPrice }) + const hasSufficientBalance = isBalanceSufficient({ + amount, + gasTotal, + balance, + conversionRate, + }) + + if (!hasSufficientBalance) { + return { + valid: false, + errorMessage: INSUFFICIENT_FUNDS_ERROR, + } + } + + const gasLimitTooLow = gasLimit && conversionGreaterThan( + { + value: MIN_GAS_LIMIT_DEC, + fromNumericBase: 'dec', + conversionRate, + }, + { + value: gasLimit, + fromNumericBase: 'hex', + }, + ) + + if (gasLimitTooLow) { + return { + valid: false, + errorMessage: GAS_LIMIT_TOO_LOW_ERROR, + } + } + + return { + valid: true, + } + } + + handleEditGas () { + const { onEditGas, showCustomizeGasModal, txData, updateGasAndCalculate } = this.props + + if (onEditGas) { + onEditGas() + } else { + showCustomizeGasModal({ + txData, + onSubmit: txData => updateGasAndCalculate(txData), + validate: ({ gasLimit, gasPrice }) => this.validateEditGas({ gasLimit, gasPrice }), + }) + } + } + + renderDetails () { + const { + detailsComponent, + fiatTransactionFee, + ethTransactionFee, + currentCurrency, + fiatTransactionTotal, + ethTransactionTotal, + hideDetails, + } = this.props + + if (hideDetails) { + return null + } + + return ( + detailsComponent || ( + <div className="confirm-page-container-content__details"> + <div className="confirm-page-container-content__gas-fee"> + <ConfirmDetailRow + label="Gas Fee" + fiatFee={formatCurrency(fiatTransactionFee, currentCurrency)} + ethFee={ethTransactionFee} + headerText="Edit" + headerTextClassName="confirm-detail-row__header-text--edit" + onHeaderClick={() => this.handleEditGas()} + /> + </div> + <div> + <ConfirmDetailRow + label="Total" + fiatFee={formatCurrency(fiatTransactionTotal, currentCurrency)} + ethFee={ethTransactionTotal} + headerText="Amount + Gas Fee" + headerTextClassName="confirm-detail-row__header-text--total" + fiatFeeColor="#2f9ae0" + /> + </div> + </div> + ) + ) + } + + renderData () { + const { t } = this.context + const { + txData: { + txParams: { + data, + } = {}, + } = {}, + tokenData: { + name, + params, + } = {}, + hideData, + dataComponent, + } = this.props + + if (hideData) { + return null + } + + return dataComponent || ( + <div className="confirm-page-container-content__data"> + <div className="confirm-page-container-content__data-box-label"> + {`${t('functionType')}:`} + <span className="confirm-page-container-content__function-type"> + { name } + </span> + </div> + <div className="confirm-page-container-content__data-box"> + { JSON.stringify(params, null, 2) } + </div> + <div className="confirm-page-container-content__data-box-label"> + {`${t('hexData')}:`} + </div> + <div className="confirm-page-container-content__data-box"> + { data } + </div> + </div> + ) + } + + handleEdit () { + const { txData, tokenData, tokenProps, onEdit } = this.props + onEdit({ txData, tokenData, tokenProps }) + } + + handleCancel () { + const { onCancel, txData, cancelTransaction, history, clearConfirmTransaction } = this.props + + if (onCancel) { + onCancel(txData) + } else { + cancelTransaction(txData) + .then(() => { + clearConfirmTransaction() + history.push(DEFAULT_ROUTE) + }) + } + } + + handleSubmit () { + const { sendTransaction, clearConfirmTransaction, txData, history, onSubmit } = this.props + + if (onSubmit) { + onSubmit(txData) + } else { + sendTransaction(txData) + .then(() => { + clearConfirmTransaction() + history.push(DEFAULT_ROUTE) + }) + } + } + + render () { + const { + isTxReprice, + fromName, + fromAddress, + toName, + toAddress, + tokenData, + ethTransactionAmount, + fiatTransactionAmount, + valid: propsValid, + errorMessage: propsErrorMessage, + currentCurrency, + action, + title, + subtitle, + hideSubtitle, + identiconAddress, + summaryComponent, + contentComponent, + onEdit, + nonce, + warning, + } = this.props + + const { name } = tokenData + const fiatConvertedAmount = formatCurrency(fiatTransactionAmount, currentCurrency) + const { valid, errorMessage } = this.getError() + + return ( + <ConfirmPageContainer + fromName={fromName} + fromAddress={fromAddress} + toName={toName} + toAddress={toAddress} + showEdit={onEdit && !isTxReprice} + action={action || name} + title={title || `${fiatConvertedAmount} ${currentCurrency.toUpperCase()}`} + subtitle={subtitle || `\u2666 ${ethTransactionAmount}`} + hideSubtitle={hideSubtitle} + summaryComponent={summaryComponent} + detailsComponent={this.renderDetails()} + dataComponent={this.renderData()} + contentComponent={contentComponent} + nonce={nonce} + identiconAddress={identiconAddress} + errorMessage={propsErrorMessage || errorMessage} + warning={warning} + valid={propsValid || valid} + onEdit={() => this.handleEdit()} + onCancel={() => this.handleCancel()} + onSubmit={() => this.handleSubmit()} + /> + ) + } +} diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js new file mode 100644 index 000000000..ea1a1d296 --- /dev/null +++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -0,0 +1,95 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import { withRouter } from 'react-router-dom' +import R from 'ramda' +import ConfirmTransactionBase from './confirm-transaction-base.component' +import { + setTransactionToConfirm, + clearConfirmTransaction, + updateGasAndCalculate, +} from '../../../ducks/confirm-transaction.duck' +import { clearSend, cancelTx, updateAndApproveTx, showModal } from '../../../actions' + +const mapStateToProps = (state, props) => { + const { toAddress: propsToAddress } = props + const { confirmTransaction, metamask } = state + const { + ethTransactionAmount, + ethTransactionFee, + ethTransactionTotal, + fiatTransactionAmount, + fiatTransactionFee, + fiatTransactionTotal, + hexGasTotal, + tokenData, + txData, + tokenProps, + nonce, + } = confirmTransaction + const { txParams = {}, lastGasPrice, id: transactionId } = txData + const { from: fromAddress, to: txParamsToAddress } = txParams + const { + conversionRate, + identities, + currentCurrency, + accounts, + selectedAddress, + selectedAddressTxList, + } = metamask + + const { balance } = accounts[selectedAddress] + const { name: fromName } = identities[selectedAddress] + const toAddress = propsToAddress || txParamsToAddress + const toName = identities[toAddress] && identities[toAddress].name + const isTxReprice = Boolean(lastGasPrice) + + const transaction = R.find(({ id }) => id === transactionId)(selectedAddressTxList) + const transactionStatus = transaction ? transaction.status : '' + + return { + balance, + fromAddress, + fromName, + toAddress, + toName, + ethTransactionAmount, + ethTransactionFee, + ethTransactionTotal, + fiatTransactionAmount, + fiatTransactionFee, + fiatTransactionTotal, + hexGasTotal, + txData, + tokenData, + tokenProps, + isTxReprice, + currentCurrency, + conversionRate, + transactionStatus, + nonce, + } +} + +const mapDispatchToProps = dispatch => { + return { + setTransactionToConfirm: transactionId => dispatch(setTransactionToConfirm(transactionId)), + clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), + clearSend: () => dispatch(clearSend()), + showTransactionConfirmedModal: ({ onHide }) => { + return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onHide })) + }, + showCustomizeGasModal: ({ txData, onSubmit, validate }) => { + return dispatch(showModal({ name: 'CONFIRM_CUSTOMIZE_GAS', txData, onSubmit, validate })) + }, + updateGasAndCalculate: ({ gasLimit, gasPrice }) => { + return dispatch(updateGasAndCalculate({ gasLimit, gasPrice })) + }, + cancelTransaction: ({ id }) => dispatch(cancelTx({ id })), + sendTransaction: txData => dispatch(updateAndApproveTx(txData)), + } +} + +export default compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps) +)(ConfirmTransactionBase) diff --git a/ui/app/components/pages/confirm-transaction-base/index.js b/ui/app/components/pages/confirm-transaction-base/index.js new file mode 100644 index 000000000..9996e9aeb --- /dev/null +++ b/ui/app/components/pages/confirm-transaction-base/index.js @@ -0,0 +1 @@ +export { default } from './confirm-transaction-base.container' diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js new file mode 100644 index 000000000..5f337ab61 --- /dev/null +++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js @@ -0,0 +1,71 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { Redirect } from 'react-router-dom' +import R from 'ramda' +import Loading from '../../loading-screen' +import { + CONFIRM_DEPLOY_CONTRACT_ROUTE, + CONFIRM_SEND_ETHER_ROUTE, + CONFIRM_SEND_TOKEN_ROUTE, + CONFIRM_APPROVE_ROUTE, + CONFIRM_TOKEN_METHOD_ROUTE, + SIGNATURE_REQUEST_ROUTE, +} from '../../../routes' +import { isConfirmDeployContract, getTokenData } from './confirm-transaction-switch.util' +import { TOKEN_METHOD_TRANSFER, TOKEN_METHOD_APPROVE } from './confirm-transaction-switch.constants' + +export default class ConfirmTransactionSwitch extends Component { + static propTypes = { + unconfirmedTransactions: PropTypes.array, + match: PropTypes.object, + } + + getTransaction () { + const { unconfirmedTransactions, match } = this.props + const { params: { id: paramsTransactionId } = {} } = match + + return paramsTransactionId + ? R.find(({ id }) => id + '' === paramsTransactionId)(unconfirmedTransactions) + : unconfirmedTransactions[0] + } + + redirectToTransaction (txData) { + const { id, txParams: { data } } = txData + + if (isConfirmDeployContract(txData)) { + return <Redirect to={{ pathname: `${CONFIRM_DEPLOY_CONTRACT_ROUTE}/${id}` }} /> + } + + if (data) { + const tokenData = getTokenData(data) + const { name: tokenMethodName } = tokenData || {} + + switch (tokenMethodName) { + case TOKEN_METHOD_TRANSFER: + return <Redirect to={{ pathname: `${CONFIRM_SEND_TOKEN_ROUTE}/${id}` }} /> + case TOKEN_METHOD_APPROVE: + return <Redirect to={{ pathname: `${CONFIRM_APPROVE_ROUTE}/${id}` }} /> + default: + return <Redirect to={{ pathname: `${CONFIRM_TOKEN_METHOD_ROUTE}/${id}` }} /> + } + } + + return <Redirect to={{ pathname: `${CONFIRM_SEND_ETHER_ROUTE}/${id}` }} /> + } + + render () { + const txData = this.getTransaction() + + if (!txData) { + return <Loading /> + } + + if (txData.txParams) { + return this.redirectToTransaction(txData) + } else if (txData.msgParams) { + return <Redirect to={{ pathname: SIGNATURE_REQUEST_ROUTE }} /> + } + + return <Loading /> + } +} diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js new file mode 100644 index 000000000..622d2a37a --- /dev/null +++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js @@ -0,0 +1,2 @@ +export const TOKEN_METHOD_TRANSFER = 'transfer' +export const TOKEN_METHOD_APPROVE = 'approve' diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js new file mode 100644 index 000000000..cb6008acb --- /dev/null +++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js @@ -0,0 +1,11 @@ +import { connect } from 'react-redux' +import ConfirmTransactionSwitch from './confirm-transaction-switch.component' +import { unconfirmedTransactionsListSelector } from '../../../selectors/confirm-transaction' + +const mapStateToProps = state => { + return { + unconfirmedTransactions: unconfirmedTransactionsListSelector(state), + } +} + +export default connect(mapStateToProps)(ConfirmTransactionSwitch) diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js new file mode 100644 index 000000000..dd1dec6ae --- /dev/null +++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js @@ -0,0 +1,12 @@ +import abi from 'human-standard-token-abi' +import abiDecoder from 'abi-decoder' +abiDecoder.addABI(abi) + +export function isConfirmDeployContract (txData = {}) { + const { txParams = {} } = txData + return !txParams.to +} + +export function getTokenData (data = {}) { + return abiDecoder.decodeMethod(data) +} diff --git a/ui/app/components/pages/confirm-transaction-switch/index.js b/ui/app/components/pages/confirm-transaction-switch/index.js new file mode 100644 index 000000000..c288acb1a --- /dev/null +++ b/ui/app/components/pages/confirm-transaction-switch/index.js @@ -0,0 +1,2 @@ +import ConfirmTransactionSwitch from './confirm-transaction-switch.container' +module.exports = ConfirmTransactionSwitch diff --git a/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js b/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js new file mode 100644 index 000000000..cc0b019e0 --- /dev/null +++ b/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js @@ -0,0 +1,59 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { Switch, Route } from 'react-router-dom' +import ConfirmTransactionSwitch from '../confirm-transaction-switch' +import ConfirmTransactionBase from '../confirm-transaction-base' +import ConfirmSendEther from '../confirm-send-ether' +import ConfirmSendToken from '../confirm-send-token' +import ConfirmDeployContract from '../confirm-deploy-contract' +import ConfirmApprove from '../confirm-approve' +import ConfTx from '../../../conf-tx' +import { + DEFAULT_ROUTE, + CONFIRM_TRANSACTION_ROUTE, + CONFIRM_DEPLOY_CONTRACT_ROUTE, + CONFIRM_SEND_ETHER_ROUTE, + CONFIRM_SEND_TOKEN_ROUTE, + CONFIRM_APPROVE_ROUTE, + CONFIRM_TOKEN_METHOD_ROUTE, + SIGNATURE_REQUEST_ROUTE, +} from '../../../routes' + +export default class ConfirmTransaction extends Component { + static propTypes = { + history: PropTypes.object.isRequired, + totalUnapprovedCount: PropTypes.number.isRequired, + match: PropTypes.object, + send: PropTypes.object, + } + + componentDidMount () { + const { totalUnapprovedCount = 0, send = {}, history } = this.props + + if (!totalUnapprovedCount && !send.to) { + history.replace(DEFAULT_ROUTE) + } + } + + render () { + return ( + <Switch> + <Route + exact + path={`${CONFIRM_DEPLOY_CONTRACT_ROUTE}/:id?`} + component={ConfirmDeployContract} + /> + <Route + exact + path={`${CONFIRM_TOKEN_METHOD_ROUTE}/:id?`} + component={ConfirmTransactionBase} + /> + <Route exact path={`${CONFIRM_SEND_ETHER_ROUTE}/:id?`} component={ConfirmSendEther} /> + <Route exact path={`${CONFIRM_SEND_TOKEN_ROUTE}/:id?`} component={ConfirmSendToken} /> + <Route exact path={`${CONFIRM_APPROVE_ROUTE}/:id?`} component={ConfirmApprove} /> + <Route exact path={SIGNATURE_REQUEST_ROUTE} component={ConfTx} /> + <Route path={`${CONFIRM_TRANSACTION_ROUTE}/:id?`} component={ConfirmTransactionSwitch} /> + </Switch> + ) + } +} diff --git a/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js b/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js new file mode 100644 index 000000000..6779e69b7 --- /dev/null +++ b/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js @@ -0,0 +1,19 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import { withRouter } from 'react-router-dom' +import ConfirmTransaction from './confirm-transaction.component' +import { getTotalUnapprovedCount } from '../../../selectors' + +const mapStateToProps = (state, props) => { + const { metamask: { send } } = state + + return { + totalUnapprovedCount: getTotalUnapprovedCount(state), + send, + } +} + +export default compose( + withRouter, + connect(mapStateToProps), +)(ConfirmTransaction) diff --git a/ui/app/components/pages/confirm-transaction/index.js b/ui/app/components/pages/confirm-transaction/index.js new file mode 100644 index 000000000..4bf42d85c --- /dev/null +++ b/ui/app/components/pages/confirm-transaction/index.js @@ -0,0 +1,2 @@ +import ConfirmTransaction from './confirm-transaction.container' +module.exports = ConfirmTransaction diff --git a/ui/app/components/pages/home.js b/ui/app/components/pages/home.js index c53413d3b..86bd32c8a 100644 --- a/ui/app/components/pages/home.js +++ b/ui/app/components/pages/home.js @@ -83,51 +83,6 @@ class Home extends Component { }) } - // if (!props.noActiveNotices) { - // log.debug('rendering notice screen for unread notices.') - // return h(NoticeScreen, { - // notice: props.nextUnreadNotice, - // key: 'NoticeScreen', - // onConfirm: () => props.dispatch(actions.markNoticeRead(props.nextUnreadNotice)), - // }) - // } else if (props.lostAccounts && props.lostAccounts.length > 0) { - // log.debug('rendering notice screen for lost accounts view.') - // return h(NoticeScreen, { - // notice: generateLostAccountsNotice(props.lostAccounts), - // key: 'LostAccountsNotice', - // onConfirm: () => props.dispatch(actions.markAccountsFound()), - // }) - // } - - // if (props.seedWords) { - // log.debug('rendering seed words') - // return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'}) - // } - - // show initialize screen - // if (!isInitialized || forgottenPassword) { - // // show current view - // log.debug('rendering an initialize screen') - // // switch (props.currentView.name) { - - // // case 'restoreVault': - // // log.debug('rendering restore vault screen') - // // return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) - - // // default: - // // log.debug('rendering menu screen') - // // return h(InitializeScreen, {key: 'menuScreenInit'}) - // // } - // } - - // // show unlock screen - // if (!props.isUnlocked) { - // return h(MainContainer, { - // currentViewName: props.currentView.name, - // isUnlocked: props.isUnlocked, - // }) - // } - // show current view switch (currentView.name) { @@ -135,59 +90,10 @@ class Home extends Component { log.debug('rendering main container') return h(MainContainer, {key: 'account-detail'}) - // case 'sendTransaction': - // log.debug('rendering send tx screen') - - // // Going to leave this here until we are ready to delete SendTransactionScreen v1 - // // const SendComponentToRender = checkFeatureToggle('send-v2') - // // ? SendTransactionScreen2 - // // : SendTransactionScreen - - // return h(SendTransactionScreen2, {key: 'send-transaction'}) - - // case 'sendToken': - // log.debug('rendering send token screen') - - // // Going to leave this here until we are ready to delete SendTransactionScreen v1 - // // const SendTokenComponentToRender = checkFeatureToggle('send-v2') - // // ? SendTransactionScreen2 - // // : SendTokenScreen - - // return h(SendTransactionScreen2, {key: 'sendToken'}) - case 'newKeychain': log.debug('rendering new keychain screen') return h(NewKeyChainScreen, {key: 'new-keychain'}) - // case 'confTx': - // log.debug('rendering confirm tx screen') - // return h(Redirect, { - // to: { - // pathname: CONFIRM_TRANSACTION_ROUTE, - // }, - // }) - // return h(ConfirmTxScreen, {key: 'confirm-tx'}) - - // case 'add-token': - // log.debug('rendering add-token screen from unlock screen.') - // return h(AddTokenScreen, {key: 'add-token'}) - - // case 'config': - // log.debug('rendering config screen') - // return h(Settings, {key: 'config'}) - - // case 'import-menu': - // log.debug('rendering import screen') - // return h(Import, {key: 'import-menu'}) - - // case 'reveal-seed-conf': - // log.debug('rendering reveal seed confirmation screen') - // return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'}) - - // case 'info': - // log.debug('rendering info screen') - // return h(Settings, {key: 'info', tab: 'info'}) - case 'buyEth': log.debug('rendering buy ether screen') return h(BuyView, {key: 'buyEthView'}) diff --git a/ui/app/components/pages/index.scss b/ui/app/components/pages/index.scss index b15c59863..8b333b6a8 100644 --- a/ui/app/components/pages/index.scss +++ b/ui/app/components/pages/index.scss @@ -3,3 +3,5 @@ @import './add-token/index'; @import './confirm-add-token/index'; + +@import './confirm-send-token/index'; diff --git a/ui/app/components/send_/send-footer/send-footer.component.js b/ui/app/components/send_/send-footer/send-footer.component.js index 6471ae1a3..ff42e58de 100644 --- a/ui/app/components/send_/send-footer/send-footer.component.js +++ b/ui/app/components/send_/send-footer/send-footer.component.js @@ -48,6 +48,7 @@ export default class SendFooter extends Component { // updateTx, update, toAccounts, + history, } = this.props // Should not be needed because submit should be disabled if there are errors. @@ -60,7 +61,7 @@ export default class SendFooter extends Component { // TODO: add nickname functionality addToAddressBookIfNew(to, toAccounts) - editingTransactionId + const promise = editingTransactionId ? update({ amount, editingTransactionId, @@ -73,7 +74,8 @@ export default class SendFooter extends Component { }) : sign({ selectedToken, to, amount, from, gas, gasPrice }) - this.props.history.push(CONFIRM_TRANSACTION_ROUTE) + Promise.resolve(promise) + .then(() => history.push(CONFIRM_TRANSACTION_ROUTE)) } formShouldBeDisabled () { diff --git a/ui/app/components/send_/send-footer/send-footer.container.js b/ui/app/components/send_/send-footer/send-footer.container.js index 260ff40bc..0af6fcfa1 100644 --- a/ui/app/components/send_/send-footer/send-footer.container.js +++ b/ui/app/components/send_/send-footer/send-footer.container.js @@ -87,7 +87,7 @@ function mapDispatchToProps (dispatch) { unapprovedTxs, }) - dispatch(updateTransaction(editingTx)) + return dispatch(updateTransaction(editingTx)) }, addToAddressBookIfNew: (newAddress, toAccounts, nickname = '') => { const hexPrefixedAddress = ethUtil.addHexPrefix(newAddress) diff --git a/ui/app/components/send_/send.utils.js b/ui/app/components/send_/send.utils.js index c4537f335..aa255c3d4 100644 --- a/ui/app/components/send_/send.utils.js +++ b/ui/app/components/send_/send.utils.js @@ -37,7 +37,7 @@ module.exports = { removeLeadingZeroes, } -function calcGasTotal (gasLimit, gasPrice) { +function calcGasTotal (gasLimit = '0', gasPrice = '0') { return multiplyCurrencies(gasLimit, gasPrice, { toNumericBase: 'hex', multiplicandBase: 16, @@ -47,9 +47,9 @@ function calcGasTotal (gasLimit, gasPrice) { function isBalanceSufficient ({ amount = '0x0', - amountConversionRate = 0, - balance, - conversionRate, + amountConversionRate = 1, + balance = '0x0', + conversionRate = 1, gasTotal = '0x0', primaryCurrency, }) { diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js deleted file mode 100644 index 9cef8e401..000000000 --- a/ui/app/components/sender-to-recipient.js +++ /dev/null @@ -1,72 +0,0 @@ -const { Component } = require('react') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const PropTypes = require('prop-types') -const Identicon = require('./identicon') - -class SenderToRecipient extends Component { - renderRecipientIcon () { - const { recipientAddress } = this.props - return ( - recipientAddress - ? h(Identicon, { address: recipientAddress, diameter: 20 }) - : h('i.fa.fa-file-text-o') - ) - } - - renderRecipient () { - const { recipientName } = this.props - return ( - h('.sender-to-recipient__recipient', [ - this.renderRecipientIcon(), - h( - '.sender-to-recipient__name.sender-to-recipient__recipient-name', - recipientName || this.context.t('newContract') - ), - ]) - ) - } - - render () { - const { senderName, senderAddress } = this.props - - return ( - h('.sender-to-recipient__container', [ - h('.sender-to-recipient__sender', [ - h('.sender-to-recipient__sender-icon', [ - h(Identicon, { - address: senderAddress, - diameter: 20, - }), - ]), - h('.sender-to-recipient__name.sender-to-recipient__sender-name', senderName), - ]), - h('.sender-to-recipient__arrow-container', [ - h('.sender-to-recipient__arrow-circle', [ - h('img', { - height: 15, - width: 15, - src: './images/arrow-right.svg', - }), - ]), - ]), - this.renderRecipient(), - ]) - ) - } -} - -SenderToRecipient.propTypes = { - senderName: PropTypes.string, - senderAddress: PropTypes.string, - recipientName: PropTypes.string, - recipientAddress: PropTypes.string, - t: PropTypes.func, -} - -SenderToRecipient.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect()(SenderToRecipient) - diff --git a/ui/app/components/sender-to-recipient/index.js b/ui/app/components/sender-to-recipient/index.js new file mode 100644 index 000000000..f515c4ac4 --- /dev/null +++ b/ui/app/components/sender-to-recipient/index.js @@ -0,0 +1 @@ +export { default } from './sender-to-recipient.component' diff --git a/ui/app/css/itcss/components/sender-to-recipient.scss b/ui/app/components/sender-to-recipient/index.scss index f16013cdf..a97393b8f 100644 --- a/ui/app/css/itcss/components/sender-to-recipient.scss +++ b/ui/app/components/sender-to-recipient/index.scss @@ -6,6 +6,16 @@ justify-content: center; border-bottom: 1px solid $geyser; position: relative; + flex: 0 0 auto; + height: 42px; + } + + &__tooltip-wrapper { + min-width: 0; + } + + &__tooltip-container { + max-width: 100%; } &__sender, @@ -14,7 +24,7 @@ flex-direction: row; align-items: center; flex: 1; - padding: 10px 20px; + padding: 0 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -22,11 +32,16 @@ &__sender { padding-right: 30px; + cursor: pointer; } &__recipient { - border-left: 1px solid $geyser; padding-left: 30px; + border-left: 1px solid $geyser; + + &--with-address { + cursor: pointer; + } } &__arrow-container { @@ -42,17 +57,18 @@ padding: 5px; border: 1px solid $geyser; border-radius: 20px; - height: 30px; - width: 30px; + height: 32px; + width: 32px; display: flex; justify-content: center; align-items: center; } &__name { - padding-left: 5px; + padding-left: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + font-size: .875rem; } } diff --git a/ui/app/components/sender-to-recipient/sender-to-recipient.component.js b/ui/app/components/sender-to-recipient/sender-to-recipient.component.js new file mode 100644 index 000000000..cae173b56 --- /dev/null +++ b/ui/app/components/sender-to-recipient/sender-to-recipient.component.js @@ -0,0 +1,117 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import Identicon from '../identicon' +import Tooltip from '../tooltip-v2' +import copyToClipboard from 'copy-to-clipboard' + +export default class SenderToRecipient extends Component { + static propTypes = { + senderName: PropTypes.string, + senderAddress: PropTypes.string, + recipientName: PropTypes.string, + recipientAddress: PropTypes.string, + t: PropTypes.func, + } + + static contextTypes = { + t: PropTypes.func, + } + + state = { + senderAddressCopied: false, + recipientAddressCopied: false, + } + + renderRecipientWithAddress () { + const { t } = this.context + const { recipientName, recipientAddress } = this.props + + return ( + <div + className="sender-to-recipient__recipient sender-to-recipient__recipient--with-address" + onClick={() => { + this.setState({ recipientAddressCopied: true }) + copyToClipboard(recipientAddress) + }} + > + <div className="sender-to-recipient__sender-icon"> + <Identicon + address={recipientAddress} + diameter={24} + /> + </div> + <Tooltip + position="bottom" + title={this.state.recipientAddressCopied ? t('copiedExclamation') : t('copyAddress')} + wrapperClassName="sender-to-recipient__tooltip-wrapper" + containerClassName="sender-to-recipient__tooltip-container" + onHidden={() => this.setState({ recipientAddressCopied: false })} + > + <div className="sender-to-recipient__name sender-to-recipient__recipient-name"> + { recipientName || this.context.t('newContract') } + </div> + </Tooltip> + </div> + ) + } + + renderRecipientWithoutAddress () { + return ( + <div className="sender-to-recipient__recipient"> + <i className="fa fa-file-text-o" /> + <div className="sender-to-recipient__name sender-to-recipient__recipient-name"> + { this.context.t('newContract') } + </div> + </div> + ) + } + + render () { + const { t } = this.context + const { senderName, senderAddress, recipientAddress } = this.props + + return ( + <div className="sender-to-recipient__container"> + <div + className="sender-to-recipient__sender" + onClick={() => { + this.setState({ senderAddressCopied: true }) + copyToClipboard(senderAddress) + }} + > + <div className="sender-to-recipient__sender-icon"> + <Identicon + address={senderAddress} + diameter={24} + /> + </div> + <Tooltip + position="bottom" + title={this.state.senderAddressCopied ? t('copiedExclamation') : t('copyAddress')} + wrapperClassName="sender-to-recipient__tooltip-wrapper" + containerClassName="sender-to-recipient__tooltip-container" + onHidden={() => this.setState({ senderAddressCopied: false })} + > + <div className="sender-to-recipient__name sender-to-recipient__sender-name"> + { senderName } + </div> + </Tooltip> + </div> + <div className="sender-to-recipient__arrow-container"> + <div className="sender-to-recipient__arrow-circle"> + <img + height={15} + width={15} + src="./images/arrow-right.svg" + /> + </div> + </div> + { + recipientAddress + ? this.renderRecipientWithAddress() + : this.renderRecipientWithoutAddress() + } + </div> + ) + } +} diff --git a/ui/app/components/tabs/index.js b/ui/app/components/tabs/index.js new file mode 100644 index 000000000..3a8d18248 --- /dev/null +++ b/ui/app/components/tabs/index.js @@ -0,0 +1,3 @@ +import Tabs from './tabs.component' +import Tab from './tab' +export { Tabs, Tab } diff --git a/ui/app/components/tabs/index.scss b/ui/app/components/tabs/index.scss new file mode 100644 index 000000000..a3b42f8e3 --- /dev/null +++ b/ui/app/components/tabs/index.scss @@ -0,0 +1,11 @@ +@import './tab/index'; + +.tabs { + &__list { + display: flex; + justify-content: flex-start; + background-color: #f9fafa; + border-bottom: 1px solid $geyser; + padding: 0 16px; + } +} diff --git a/ui/app/components/tabs/tab/index.js b/ui/app/components/tabs/tab/index.js new file mode 100644 index 000000000..fbc309e8e --- /dev/null +++ b/ui/app/components/tabs/tab/index.js @@ -0,0 +1,2 @@ +import Tab from './tab.component' +module.exports = Tab diff --git a/ui/app/components/tabs/tab/index.scss b/ui/app/components/tabs/tab/index.scss new file mode 100644 index 000000000..1de6ffa0e --- /dev/null +++ b/ui/app/components/tabs/tab/index.scss @@ -0,0 +1,15 @@ +.tab { + color: #8C8E94; + font-size: .75rem; + text-transform: uppercase; + cursor: pointer; + padding: 8px 0; + margin: 0 8px; + min-width: 50px; + text-align: center; + + &--active { + color: $black; + border-bottom: 2px solid $curious-blue; + } +} diff --git a/ui/app/components/tabs/tab/tab.component.js b/ui/app/components/tabs/tab/tab.component.js new file mode 100644 index 000000000..a59da8904 --- /dev/null +++ b/ui/app/components/tabs/tab/tab.component.js @@ -0,0 +1,31 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' + +const Tab = props => { + const { name, onClick, isActive, tabIndex } = props + + return ( + <li + className={classnames( + 'tab', + isActive && 'tab--active', + )} + onClick={event => { + event.preventDefault() + onClick(tabIndex) + }} + > + { name } + </li> + ) +} + +Tab.propTypes = { + name: PropTypes.string.isRequired, + onClick: PropTypes.func, + isActive: PropTypes.bool, + tabIndex: PropTypes.number, +} + +export default Tab diff --git a/ui/app/components/tabs/tabs.component.js b/ui/app/components/tabs/tabs.component.js new file mode 100644 index 000000000..d28f3695e --- /dev/null +++ b/ui/app/components/tabs/tabs.component.js @@ -0,0 +1,63 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' + +export default class Tabs extends Component { + static propTypes = { + defaultActiveTabIndex: PropTypes.number, + children: PropTypes.node, + } + + constructor (props) { + super(props) + + this.state = { + activeTabIndex: props.defaultActiveTabIndex || 0, + } + } + + handleTabClick (tabIndex) { + const { activeTabIndex } = this.state + + if (tabIndex !== activeTabIndex) { + this.setState({ + activeTabIndex: tabIndex, + }) + } + } + + renderTabs () { + // const { children } = this.props + const numberOfTabs = React.Children.count(this.props.children) + + return React.Children.map(this.props.children, (child, index) => { + return child && React.cloneElement(child, { + onClick: index => this.handleTabClick(index), + tabIndex: index, + isActive: numberOfTabs > 1 && index === this.state.activeTabIndex, + key: index, + }) + }) + } + + renderActiveTabContent () { + const { children } = this.props + const { activeTabIndex } = this.state + + return children[activeTabIndex] + ? children[activeTabIndex].props.children + : children.props.children + } + + render () { + return ( + <div className="tabs"> + <ul className="tabs__list"> + { this.renderTabs() } + </ul> + <div className="tabs__content"> + { this.renderActiveTabContent() } + </div> + </div> + ) + } +} diff --git a/ui/app/components/tooltip-v2.js b/ui/app/components/tooltip-v2.js index 133a0f16a..05a5efc80 100644 --- a/ui/app/components/tooltip-v2.js +++ b/ui/app/components/tooltip-v2.js @@ -12,7 +12,7 @@ function Tooltip () { Tooltip.prototype.render = function () { const props = this.props - const { position, title, children, wrapperClassName } = props + const { position, title, children, wrapperClassName, containerClassName, onHidden } = props return h('div', { className: wrapperClassName, @@ -25,6 +25,8 @@ Tooltip.prototype.render = function () { hideOnClick: false, size: 'small', arrow: true, + className: containerClassName, + onHidden, }, children), ]) diff --git a/ui/app/conversion-util.js b/ui/app/conversion-util.js index a7a226cc5..cf084988c 100644 --- a/ui/app/conversion-util.js +++ b/ui/app/conversion-util.js @@ -28,6 +28,8 @@ const BN = ethUtil.BN const R = require('ramda') const { stripHexPrefix } = require('ethereumjs-util') +global.BigNumber = BigNumber + BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_HALF_DOWN, }) diff --git a/ui/app/css/itcss/components/buttons.scss b/ui/app/css/itcss/components/buttons.scss index f93daec04..34565767f 100644 --- a/ui/app/css/itcss/components/buttons.scss +++ b/ui/app/css/itcss/components/buttons.scss @@ -4,7 +4,8 @@ .btn-default, .btn-primary, -.btn-secondary { +.btn-secondary, +.btn-confirm { height: 44px; background: $white; display: flex; @@ -13,13 +14,14 @@ box-sizing: border-box; border-radius: 4px; font-size: 14px; - font-weight: 500; + font-weight: 400; transition: border-color .3s ease; padding: 0 16px; min-width: 140px; width: 100%; text-transform: uppercase; outline: none; + font-family: Roboto; &--disabled, &[disabled] { @@ -71,6 +73,12 @@ } } +.btn-confirm { + color: $white; + border: 2px solid $curious-blue; + background-color: $curious-blue; +} + .btn--large { height: 54px; } @@ -119,19 +127,6 @@ } } -.btn-confirm { - background-color: $caribbean-green; // TODO: reusable color in colors.css - text-align: center; - padding: .8rem 1rem; - color: $white; - border: 2px solid $caribbean-green; - border-radius: 4px; - font-size: .85rem; - font-weight: 400; - transition: border-color .3s ease; - width: 100%; -} - // No longer used in flat design, remove when modal buttons done // div.wallet-btn { // border: 1px solid rgb(91, 93, 103); diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss index 1d87b8004..5be040906 100644 --- a/ui/app/css/itcss/components/index.scss +++ b/ui/app/css/itcss/components/index.scss @@ -58,6 +58,4 @@ @import './welcome-screen.scss'; -@import './sender-to-recipient.scss'; - @import '../../../components/index'; diff --git a/ui/app/css/itcss/components/network.scss b/ui/app/css/itcss/components/network.scss index 6c8be0b6d..545a2a940 100644 --- a/ui/app/css/itcss/components/network.scss +++ b/ui/app/css/itcss/components/network.scss @@ -159,15 +159,3 @@ .network-caret { margin: 0 8px 2px; } - -.network-display { - &__container { - display: flex; - align-items: center; - justify-content: flex-start; - - @media screen and (min-width: 576px) { - display: none; - } - } -} diff --git a/ui/app/css/itcss/generic/index.scss b/ui/app/css/itcss/generic/index.scss index 3525d2003..d1c65afed 100644 --- a/ui/app/css/itcss/generic/index.scss +++ b/ui/app/css/itcss/generic/index.scss @@ -73,195 +73,6 @@ input.large-input { text-transform: uppercase; } -.page-container { - width: 408px; - background-color: $white; - box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08); - z-index: 25; - display: flex; - flex-flow: column; - border-radius: 8px; - - &__header { - display: flex; - flex-flow: column; - border-bottom: 1px solid $geyser; - padding: 16px; - flex: 0 0 auto; - position: relative; - - &--no-padding-bottom { - padding-bottom: 0; - } - } - - &__header-close { - color: $tundora; - position: absolute; - top: 16px; - right: 16px; - cursor: pointer; - overflow: hidden; - - &::after { - content: '\00D7'; - font-size: 40px; - line-height: 20px; - } - } - - &__header-row { - padding-bottom: 10px; - display: flex; - justify-content: space-between; - } - - &__footer { - display: flex; - flex-flow: row; - justify-content: center; - border-top: 1px solid $geyser; - padding: 16px; - flex: 0 0 auto; - - .btn-clear, - .btn-cancel, - .btn-confirm { - font-size: 1rem; - } - } - - &__footer-button { - height: 55px; - font-size: 1rem; - text-transform: uppercase; - margin-right: 16px; - border-radius: 2px; - - &:last-of-type { - margin-right: 0; - } - } - - &__back-button { - color: #2f9ae0; - font-size: 1rem; - cursor: pointer; - font-weight: 400; - } - - &__title { - color: $black; - font-size: 2rem; - font-weight: 500; - line-height: 2rem; - } - - &__subtitle { - padding-top: .5rem; - line-height: initial; - font-size: .9rem; - color: $gray; - } - - &__tabs { - display: flex; - margin-top: 16px; - } - - &__tab { - min-width: 5rem; - padding: 8px; - color: $dusty-gray; - font-family: Roboto; - font-size: 1rem; - text-align: center; - cursor: pointer; - border-bottom: none; - margin-right: 16px; - - &:last-of-type { - margin-right: 0; - } - - &--selected { - color: $curious-blue; - border-bottom: 3px solid $curious-blue; - } - } - - &--full-width { - width: 100% !important; - } - - &--full-height { - height: 100% !important; - max-height: initial !important; - min-height: initial !important; - } - - &__content { - overflow-y: auto; - flex: 1; - } - - &__warning-container { - background: $linen; - padding: 20px; - display: flex; - align-items: start; - } - - &__warning-message { - padding-left: 15px; - } - - &__warning-title { - font-weight: 500; - } - - &__warning-icon { - padding-top: 5px; - } -} - -@media screen and (max-width: 250px) { - .page-container { - &__footer { - flex-flow: column-reverse; - } - - &__footer-button { - width: 100%; - margin-bottom: 1rem; - margin-right: 0; - - &:first-of-type { - margin-bottom: 0; - } - } - } -} - -@media screen and (max-width: 575px) { - .page-container { - height: 100%; - width: 100%; - overflow-y: auto; - background-color: $white; - border-radius: 0; - flex: 1; - } -} - -@media screen and (min-width: 576px) { - .page-container { - max-height: 82vh; - min-height: 570px; - flex: 0 0 auto; - } -} - .input-label { padding-bottom: 10px; font-weight: 400; diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss index 814d7a382..f90c8edc3 100644 --- a/ui/app/css/itcss/settings/variables.scss +++ b/ui/app/css/itcss/settings/variables.scss @@ -55,6 +55,7 @@ $dodger-blue: #3099f2; $zumthor: #edf7ff; $ecstasy: #f7861c; $linen: #fdf4f4; +$oslo-gray: #8C8E94; /* Z-Indicies diff --git a/ui/app/css/itcss/tools/utilities.scss b/ui/app/css/itcss/tools/utilities.scss index ee867640d..209614c6b 100644 --- a/ui/app/css/itcss/tools/utilities.scss +++ b/ui/app/css/itcss/tools/utilities.scss @@ -165,7 +165,7 @@ } .bold { - font-weight: 700; + font-weight: 500; } .text-transform-uppercase { diff --git a/ui/app/ducks/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction.duck.js new file mode 100644 index 000000000..6df1333dd --- /dev/null +++ b/ui/app/ducks/confirm-transaction.duck.js @@ -0,0 +1,319 @@ +import { + conversionRateSelector, + currentCurrencySelector, + unconfirmedTransactionsHashSelector, +} from '../selectors/confirm-transaction' + +import { + getTokenData, + getTransactionAmount, + getTransactionFee, + getHexGasTotal, + addFiat, + addEth, + increaseLastGasPrice, + hexGreaterThan, +} from '../helpers/confirm-transaction/util' + +import { getSymbolAndDecimals } from '../token-util' +import { conversionUtil } from '../conversion-util' + +// Actions +const createActionType = action => `metamask/confirm-transaction/${action}` + +const UPDATE_TX_DATA = createActionType('UPDATE_TX_DATA') +const CLEAR_TX_DATA = createActionType('CLEAR_TX_DATA') +const UPDATE_TOKEN_DATA = createActionType('UPDATE_TOKEN_DATA') +const CLEAR_TOKEN_DATA = createActionType('CLEAR_TOKEN_DATA') +const CLEAR_CONFIRM_TRANSACTION = createActionType('CLEAR_CONFIRM_TRANSACTION') +const UPDATE_TRANSACTION_AMOUNTS = createActionType('UPDATE_TRANSACTION_AMOUNTS') +const UPDATE_TRANSACTION_FEES = createActionType('UPDATE_TRANSACTION_FEES') +const UPDATE_TRANSACTION_TOTALS = createActionType('UPDATE_TRANSACTION_TOTALS') +const UPDATE_HEX_GAS_TOTAL = createActionType('UPDATE_HEX_GAS_TOTAL') +const UPDATE_TOKEN_PROPS = createActionType('UPDATE_TOKEN_PROPS') +const UPDATE_NONCE = createActionType('UPDATE_NONCE') + +// Initial state +const initState = { + txData: {}, + tokenData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + fiatTransactionAmount: '', + fiatTransactionFee: '', + fiatTransactionTotal: '', + ethTransactionAmount: '', + ethTransactionFee: '', + ethTransactionTotal: '', + hexGasTotal: '', + nonce: '', +} + +// Reducer +export default function reducer ({ confirmTransaction: confirmState = initState }, action = {}) { + switch (action.type) { + case UPDATE_TX_DATA: + return { + ...confirmState, + txData: { + ...action.payload, + }, + } + case CLEAR_TX_DATA: + return { + ...confirmState, + txData: {}, + } + case UPDATE_TOKEN_DATA: + return { + ...confirmState, + tokenData: { + ...action.payload, + }, + } + case CLEAR_TOKEN_DATA: + return { + ...confirmState, + tokenData: {}, + } + case UPDATE_TRANSACTION_AMOUNTS: + const { fiatTransactionAmount, ethTransactionAmount } = action.payload + return { + ...confirmState, + fiatTransactionAmount: fiatTransactionAmount || confirmState.fiatTransactionAmount, + ethTransactionAmount: ethTransactionAmount || confirmState.ethTransactionAmount, + } + case UPDATE_TRANSACTION_FEES: + const { fiatTransactionFee, ethTransactionFee } = action.payload + return { + ...confirmState, + fiatTransactionFee: fiatTransactionFee || confirmState.fiatTransactionFee, + ethTransactionFee: ethTransactionFee || confirmState.ethTransactionFee, + } + case UPDATE_TRANSACTION_TOTALS: + const { fiatTransactionTotal, ethTransactionTotal } = action.payload + return { + ...confirmState, + fiatTransactionTotal: fiatTransactionTotal || confirmState.fiatTransactionTotal, + ethTransactionTotal: ethTransactionTotal || confirmState.ethTransactionTotal, + } + case UPDATE_HEX_GAS_TOTAL: + return { + ...confirmState, + hexGasTotal: action.payload, + } + case UPDATE_TOKEN_PROPS: + const { tokenSymbol = '', tokenDecimals = '' } = action.payload + return { + ...confirmState, + tokenProps: { + ...confirmState.tokenProps, + tokenSymbol, + tokenDecimals, + }, + } + case UPDATE_NONCE: + return { + ...confirmState, + nonce: action.payload, + } + case CLEAR_CONFIRM_TRANSACTION: + return initState + default: + return confirmState + } +} + +// Action Creators +export function updateTxData (txData) { + return { + type: UPDATE_TX_DATA, + payload: txData, + } +} + +export function clearTxData () { + return { + type: CLEAR_TX_DATA, + } +} + +export function updateTokenData (tokenData) { + return { + type: UPDATE_TOKEN_DATA, + payload: tokenData, + } +} + +export function clearTokenData () { + return { + type: CLEAR_TOKEN_DATA, + } +} + +export function updateTransactionAmounts (amounts) { + return { + type: UPDATE_TRANSACTION_AMOUNTS, + payload: amounts, + } +} + +export function updateTransactionFees (fees) { + return { + type: UPDATE_TRANSACTION_FEES, + payload: fees, + } +} + +export function updateTransactionTotals (totals) { + return { + type: UPDATE_TRANSACTION_TOTALS, + payload: totals, + } +} + +export function updateHexGasTotal (hexGasTotal) { + return { + type: UPDATE_HEX_GAS_TOTAL, + payload: hexGasTotal, + } +} + +export function updateTokenProps (tokenProps) { + return { + type: UPDATE_TOKEN_PROPS, + payload: tokenProps, + } +} + +export function updateNonce (nonce) { + return { + type: UPDATE_NONCE, + payload: nonce, + } +} + +export function updateGasAndCalculate ({ gasLimit, gasPrice }) { + return (dispatch, getState) => { + const { confirmTransaction: { txData } } = getState() + const newTxData = { + ...txData, + txParams: { + ...txData.txParams, + gas: gasLimit, + gasPrice, + }, + } + + dispatch(updateTxDataAndCalculate(newTxData)) + } +} + +function increaseFromLastGasPrice (txData) { + const { lastGasPrice, txParams: { gasPrice: previousGasPrice } = {} } = txData + + // Set the minimum to a 10% increase from the lastGasPrice. + const minimumGasPrice = increaseLastGasPrice(lastGasPrice) + const gasPriceBelowMinimum = hexGreaterThan(minimumGasPrice, previousGasPrice) + const gasPrice = (!previousGasPrice || gasPriceBelowMinimum) ? minimumGasPrice : previousGasPrice + + return { + ...txData, + txParams: { + ...txData.txParams, + gasPrice, + }, + } +} + +export function updateTxDataAndCalculate (txData) { + return (dispatch, getState) => { + const state = getState() + const currentCurrency = currentCurrencySelector(state) + const conversionRate = conversionRateSelector(state) + + dispatch(updateTxData(txData)) + + const { txParams: { value, gas: gasLimit, gasPrice } = {} } = txData + + const fiatTransactionAmount = getTransactionAmount({ + value, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2, + }) + const ethTransactionAmount = getTransactionAmount({ + value, toCurrency: 'ETH', conversionRate, numberOfDecimals: 6, + }) + + dispatch(updateTransactionAmounts({ fiatTransactionAmount, ethTransactionAmount })) + + const hexGasTotal = getHexGasTotal({ gasLimit, gasPrice }) + + dispatch(updateHexGasTotal(hexGasTotal)) + + const fiatTransactionFee = getTransactionFee({ + value: hexGasTotal, + toCurrency: currentCurrency, + numberOfDecimals: 2, + conversionRate, + }) + const ethTransactionFee = getTransactionFee({ + value: hexGasTotal, + toCurrency: 'ETH', + numberOfDecimals: 6, + conversionRate, + }) + + dispatch(updateTransactionFees({ fiatTransactionFee, ethTransactionFee })) + + const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount) + const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount) + + dispatch(updateTransactionTotals({ fiatTransactionTotal, ethTransactionTotal })) + } +} + +export function setTransactionToConfirm (transactionId) { + return async (dispatch, getState) => { + const state = getState() + const unconfirmedTransactionsHash = unconfirmedTransactionsHashSelector(state) + const transaction = unconfirmedTransactionsHash[transactionId] + + if (!transaction) { + console.error(`Transaction with id ${transactionId} not found`) + return + } + + const { lastGasPrice } = transaction + const txData = lastGasPrice ? increaseFromLastGasPrice(transaction) : transaction + dispatch(updateTxDataAndCalculate(txData)) + + const { txParams } = transaction + + if (txParams.data) { + const { tokens: existingTokens } = state + const { data, to: tokenAddress } = txParams + const tokenData = getTokenData(data) + dispatch(updateTokenData(tokenData)) + + const tokenSymbolData = await getSymbolAndDecimals(tokenAddress, existingTokens) || {} + const { symbol: tokenSymbol = '', decimals: tokenDecimals = '' } = tokenSymbolData + dispatch(updateTokenProps({ tokenSymbol, tokenDecimals })) + } + + if (txParams.nonce) { + const nonce = conversionUtil(txParams.nonce, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + }) + + dispatch(updateNonce(nonce)) + } + } +} + +export function clearConfirmTransaction () { + return { + type: CLEAR_CONFIRM_TRANSACTION, + } +} diff --git a/ui/app/helpers/confirm-transaction/util.js b/ui/app/helpers/confirm-transaction/util.js new file mode 100644 index 000000000..fa748ca46 --- /dev/null +++ b/ui/app/helpers/confirm-transaction/util.js @@ -0,0 +1,101 @@ +import currencyFormatter from 'currency-formatter' +import currencies from 'currency-formatter/currencies' +import abi from 'human-standard-token-abi' +import abiDecoder from 'abi-decoder' +import ethUtil from 'ethereumjs-util' + +abiDecoder.addABI(abi) + +import { + conversionUtil, + addCurrencies, + multiplyCurrencies, + conversionGreaterThan, +} from '../../conversion-util' + +export function getTokenData (data = {}) { + return abiDecoder.decodeMethod(data) +} + +export function increaseLastGasPrice (lastGasPrice) { + return ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, { + multiplicandBase: 16, + multiplierBase: 10, + toNumericBase: 'hex', + })) +} + +export function hexGreaterThan (a, b) { + return conversionGreaterThan( + { value: a, fromNumericBase: 'hex' }, + { value: b, fromNumericBase: 'hex' }, + ) +} + +export function getHexGasTotal ({ gasLimit, gasPrice }) { + return ethUtil.addHexPrefix(multiplyCurrencies(gasLimit, gasPrice, { + toNumericBase: 'hex', + multiplicandBase: 16, + multiplierBase: 16, + })) +} + +export function addEth (...args) { + return args.reduce((acc, base) => { + return addCurrencies(acc, base, { + toNumericBase: 'dec', + numberOfDecimals: 6, + }) + }) +} + +export function addFiat (...args) { + return args.reduce((acc, base) => { + return addCurrencies(acc, base, { + toNumericBase: 'dec', + numberOfDecimals: 2, + }) + }) +} + +export function getTransactionAmount ({ + value, + toCurrency, + conversionRate, + numberOfDecimals, +}) { + return conversionUtil(value, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + fromCurrency: 'ETH', + toCurrency, + numberOfDecimals, + fromDenomination: 'WEI', + conversionRate, + }) +} + +export function getTransactionFee ({ + value, + toCurrency, + conversionRate, + numberOfDecimals, +}) { + return conversionUtil(value, { + fromNumericBase: 'BN', + toNumericBase: 'dec', + fromDenomination: 'WEI', + fromCurrency: 'ETH', + toCurrency, + numberOfDecimals, + conversionRate, + }) +} + +export function formatCurrency (value, currencyCode) { + const upperCaseCurrencyCode = currencyCode.toUpperCase() + + return currencies.find(currency => currency.code === upperCaseCurrencyCode) + ? currencyFormatter.format(Number(value), { code: upperCaseCurrencyCode }) + : value +} diff --git a/ui/app/reducers.js b/ui/app/reducers.js index 0b158a778..80e76d570 100644 --- a/ui/app/reducers.js +++ b/ui/app/reducers.js @@ -8,6 +8,7 @@ const reduceMetamask = require('./reducers/metamask') const reduceApp = require('./reducers/app') const reduceLocale = require('./reducers/locale') const reduceSend = require('./ducks/send.duck').default +import reduceConfirmTransaction from './ducks/confirm-transaction.duck' window.METAMASK_CACHED_LOG_STATE = null @@ -45,6 +46,8 @@ function rootReducer (state, action) { state.send = reduceSend(state, action) + state.confirmTransaction = reduceConfirmTransaction(state, action) + window.METAMASK_CACHED_LOG_STATE = state return state } diff --git a/ui/app/routes.js b/ui/app/routes.js index 0ff3f644d..2d73bc768 100644 --- a/ui/app/routes.js +++ b/ui/app/routes.js @@ -10,8 +10,6 @@ const CONFIRM_ADD_TOKEN_ROUTE = '/confirm-add-token' const NEW_ACCOUNT_ROUTE = '/new-account' const IMPORT_ACCOUNT_ROUTE = '/new-account/import' const SEND_ROUTE = '/send' -const CONFIRM_TRANSACTION_ROUTE = '/confirm-transaction' -const SIGNATURE_REQUEST_ROUTE = '/confirm-transaction/signature-request' const NOTICE_ROUTE = '/notice' const WELCOME_ROUTE = '/welcome' const INITIALIZE_ROUTE = '/initialize' @@ -23,6 +21,15 @@ const INITIALIZE_NOTICE_ROUTE = '/initialize/notice' const INITIALIZE_BACKUP_PHRASE_ROUTE = '/initialize/backup-phrase' const INITIALIZE_CONFIRM_SEED_ROUTE = '/initialize/confirm-phrase' +const CONFIRM_TRANSACTION_BASE = '/confirm-transaction' +const CONFIRM_TRANSACTION_ROUTE = `${CONFIRM_TRANSACTION_BASE}` +const CONFIRM_SEND_ETHER_ROUTE = `${CONFIRM_TRANSACTION_BASE}/send-ether` +const CONFIRM_SEND_TOKEN_ROUTE = `${CONFIRM_TRANSACTION_BASE}/send-token` +const CONFIRM_DEPLOY_CONTRACT_ROUTE = `${CONFIRM_TRANSACTION_BASE}/deploy-contract` +const CONFIRM_APPROVE_ROUTE = `${CONFIRM_TRANSACTION_BASE}/approve` +const CONFIRM_TOKEN_METHOD_ROUTE = `${CONFIRM_TRANSACTION_BASE}/token-method` +const SIGNATURE_REQUEST_ROUTE = `${CONFIRM_TRANSACTION_BASE}/signature-request` + module.exports = { DEFAULT_ROUTE, UNLOCK_ROUTE, @@ -36,9 +43,7 @@ module.exports = { NEW_ACCOUNT_ROUTE, IMPORT_ACCOUNT_ROUTE, SEND_ROUTE, - CONFIRM_TRANSACTION_ROUTE, NOTICE_ROUTE, - SIGNATURE_REQUEST_ROUTE, WELCOME_ROUTE, INITIALIZE_ROUTE, INITIALIZE_CREATE_PASSWORD_ROUTE, @@ -48,4 +53,11 @@ module.exports = { INITIALIZE_NOTICE_ROUTE, INITIALIZE_BACKUP_PHRASE_ROUTE, INITIALIZE_CONFIRM_SEED_ROUTE, + CONFIRM_TRANSACTION_ROUTE, + CONFIRM_SEND_ETHER_ROUTE, + CONFIRM_SEND_TOKEN_ROUTE, + CONFIRM_DEPLOY_CONTRACT_ROUTE, + CONFIRM_APPROVE_ROUTE, + CONFIRM_TOKEN_METHOD_ROUTE, + SIGNATURE_REQUEST_ROUTE, } diff --git a/ui/app/selectors.js b/ui/app/selectors.js index 3e2253550..d86462275 100644 --- a/ui/app/selectors.js +++ b/ui/app/selectors.js @@ -27,6 +27,7 @@ const selectors = { autoAddToBetaUI, getSendMaxModeState, getCurrentViewContext, + getTotalUnapprovedCount, } module.exports = selectors @@ -181,3 +182,15 @@ function getCurrentViewContext (state) { const { currentView = {} } = state.appState return currentView.context } + +function getTotalUnapprovedCount ({ metamask }) { + const { + unapprovedTxs = {}, + unapprovedMsgCount, + unapprovedPersonalMsgCount, + unapprovedTypedMessagesCount, + } = metamask + + return Object.keys(unapprovedTxs).length + unapprovedMsgCount + unapprovedPersonalMsgCount + + unapprovedTypedMessagesCount +} diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js new file mode 100644 index 000000000..cde83804d --- /dev/null +++ b/ui/app/selectors/confirm-transaction.js @@ -0,0 +1,65 @@ +import { createSelector } from 'reselect' +import txHelper from '../../lib/tx-helper' + +const unapprovedTxsSelector = state => state.metamask.unapprovedTxs +const unapprovedMsgsSelector = state => state.metamask.unapprovedMsgs +const unapprovedPersonalMsgsSelector = state => state.metamask.unapprovedPersonalMsgs +const unapprovedTypedMessagesSelector = state => state.metamask.unapprovedTypedMessages +const networkSelector = state => state.metamask.network + +export const unconfirmedTransactionsListSelector = createSelector( + unapprovedTxsSelector, + unapprovedMsgsSelector, + unapprovedPersonalMsgsSelector, + unapprovedTypedMessagesSelector, + networkSelector, + ( + unapprovedTxs = {}, + unapprovedMsgs = {}, + unapprovedPersonalMsgs = {}, + unapprovedTypedMessages = {}, + network + ) => txHelper( + unapprovedTxs, + unapprovedMsgs, + unapprovedPersonalMsgs, + unapprovedTypedMessages, + network + ) || [] +) + +export const unconfirmedTransactionsHashSelector = createSelector( + unapprovedTxsSelector, + unapprovedMsgsSelector, + unapprovedPersonalMsgsSelector, + unapprovedTypedMessagesSelector, + networkSelector, + ( + unapprovedTxs = {}, + unapprovedMsgs = {}, + unapprovedPersonalMsgs = {}, + unapprovedTypedMessages = {}, + network + ) => { + const filteredUnapprovedTxs = Object.keys(unapprovedTxs).reduce((acc, address) => { + const { metamaskNetworkId } = unapprovedTxs[address] + const transactions = { ...acc } + + if (metamaskNetworkId === network) { + transactions[address] = unapprovedTxs[address] + } + + return transactions + }, {}) + + return { + ...filteredUnapprovedTxs, + ...unapprovedMsgs, + ...unapprovedPersonalMsgs, + ...unapprovedTypedMessages, + } + } +) + +export const currentCurrencySelector = state => state.metamask.currentCurrency +export const conversionRateSelector = state => state.metamask.conversionRate |