From e7a7754a4f5d00fd4a4662d7ac5ef3976b697d8a Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Thu, 30 Nov 2017 22:51:55 -0500 Subject: [PATCH 01/14] shapeshift initial commit --- src/renderer/js/component/address/index.js | 7 + src/renderer/js/component/address/view.jsx | 52 +++ src/renderer/js/component/common.js | 36 -- src/renderer/js/component/common/spinner.jsx | 16 + src/renderer/js/component/link/view.jsx | 9 +- src/renderer/js/component/shapeShift/index.js | 26 ++ .../shapeShift/internal/active-shift.jsx | 125 ++++++ .../js/component/shapeShift/internal/form.jsx | 83 ++++ src/renderer/js/component/shapeShift/view.jsx | 127 ++++++ .../video/internal/loading-screen.jsx | 3 +- .../js/component/walletAddress/view.jsx | 2 +- src/renderer/js/constants/action_types.js | 15 + src/renderer/js/constants/shape_shift.js | 3 + src/renderer/js/page/receiveCredits/view.jsx | 4 +- src/renderer/js/redux/actions/shape_shift.js | 86 ++++ src/renderer/js/redux/reducers/shape_shift.js | 103 +++++ src/renderer/js/redux/selectors/navigation.js | 8 +- src/renderer/js/redux/selectors/search.js | 2 +- .../js/redux/selectors/shape_shift.js | 7 + src/renderer/js/store.js | 2 + src/renderer/js/util/shape_shift.js | 50 +++ src/renderer/package.json | 5 + src/renderer/scss/_gui.scss | 10 + src/renderer/scss/all.scss | 2 + src/renderer/scss/component/_button.scss | 2 +- src/renderer/scss/component/_card.scss | 6 + src/renderer/scss/component/_form-field.scss | 5 + src/renderer/scss/component/_header.scss | 7 + src/renderer/scss/component/_shapeshift.scss | 48 +++ src/renderer/scss/component/_spinner.scss | 58 +++ src/renderer/scss/component/_video.scss | 47 --- src/renderer/webpack.common.js | 2 +- src/renderer/yarn.lock | 372 ++++++++++++++---- 33 files changed, 1152 insertions(+), 178 deletions(-) create mode 100644 src/renderer/js/component/address/index.js create mode 100644 src/renderer/js/component/address/view.jsx create mode 100644 src/renderer/js/component/common/spinner.jsx create mode 100644 src/renderer/js/component/shapeShift/index.js create mode 100644 src/renderer/js/component/shapeShift/internal/active-shift.jsx create mode 100644 src/renderer/js/component/shapeShift/internal/form.jsx create mode 100644 src/renderer/js/component/shapeShift/view.jsx create mode 100644 src/renderer/js/constants/shape_shift.js create mode 100644 src/renderer/js/redux/actions/shape_shift.js create mode 100644 src/renderer/js/redux/reducers/shape_shift.js create mode 100644 src/renderer/js/redux/selectors/shape_shift.js create mode 100644 src/renderer/js/util/shape_shift.js create mode 100644 src/renderer/scss/component/_shapeshift.scss create mode 100644 src/renderer/scss/component/_spinner.scss diff --git a/src/renderer/js/component/address/index.js b/src/renderer/js/component/address/index.js new file mode 100644 index 000000000..00bec962e --- /dev/null +++ b/src/renderer/js/component/address/index.js @@ -0,0 +1,7 @@ +import { connect } from "react-redux"; +import { doShowSnackBar } from "redux/actions/app"; +import Address from "./view"; + +export default connect(null, { + doShowSnackBar, +})(Address); diff --git a/src/renderer/js/component/address/view.jsx b/src/renderer/js/component/address/view.jsx new file mode 100644 index 000000000..96049eb35 --- /dev/null +++ b/src/renderer/js/component/address/view.jsx @@ -0,0 +1,52 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { clipboard } from "electron"; +import Link from "component/link"; +import classnames from "classnames"; + +export default class Address extends React.PureComponent { + static propTypes = { + address: PropTypes.string, + }; + + constructor(props) { + super(props); + + this._inputElem = null; + } + + render() { + const { address, showCopyButton, doShowSnackBar } = this.props; + + return ( +
+ { + this._inputElem = input; + }} + onFocus={() => { + this._inputElem.select(); + }} + readOnly="readonly" + value={address || ""} + /> + {showCopyButton && ( + + { + clipboard.writeText(address); + doShowSnackBar({ message: __("Address copied") }); + }} + /> + + )} +
+ ); + } +} diff --git a/src/renderer/js/component/common.js b/src/renderer/js/component/common.js index c5352637b..2f8ae5489 100644 --- a/src/renderer/js/component/common.js +++ b/src/renderer/js/component/common.js @@ -137,42 +137,6 @@ export class CreditAmount extends React.PureComponent { } } -let addressStyle = { - fontFamily: - '"Consolas", "Lucida Console", "Adobe Source Code Pro", monospace', -}; -export class Address extends React.PureComponent { - static propTypes = { - address: PropTypes.string, - }; - - constructor(props) { - super(props); - - this._inputElem = null; - } - - render() { - return ( -
- { - this._inputElem = input; - }} - onFocus={() => { - this._inputElem.select(); - }} - style={addressStyle} - readOnly="readonly" - value={this.props.address || ""} - /> -
- ); - } -} - export class Thumbnail extends React.PureComponent { static propTypes = { src: PropTypes.string, diff --git a/src/renderer/js/component/common/spinner.jsx b/src/renderer/js/component/common/spinner.jsx new file mode 100644 index 000000000..8863459c8 --- /dev/null +++ b/src/renderer/js/component/common/spinner.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import classnames from "classnames"; + +export default ({ dark, className }) => { + return ( +
+ ); +}; diff --git a/src/renderer/js/component/link/view.jsx b/src/renderer/js/component/link/view.jsx index 9b949bf75..c9355f84d 100644 --- a/src/renderer/js/component/link/view.jsx +++ b/src/renderer/js/component/link/view.jsx @@ -14,11 +14,12 @@ const Link = props => { navigate, navigateParams, doNavigate, + className, } = props; - const className = - (props.className || "") + - (!props.className && !button ? "button-text" : "") + // Non-button links get the same look as text buttons + const combinedClassName = + (className || "") + + (!className && !button ? "button-text" : "") + // Non-button links get the same look as text buttons (button ? " button-block button-" + button + " button-set-item" : "") + (disabled ? " disabled" : ""); @@ -43,7 +44,7 @@ const Link = props => { return ( ({ + receiveAddress: selectReceiveAddress(state), + shapeShift: selectShapeShift(state), +}); + +export default connect(select, { + shapeShiftInit, + getCoinStats, + createShapeShift, + clearShapeShift, + getActiveShift, + doShowSnackBar, +})(ShapeShift); diff --git a/src/renderer/js/component/shapeShift/internal/active-shift.jsx b/src/renderer/js/component/shapeShift/internal/active-shift.jsx new file mode 100644 index 000000000..38c18c4d5 --- /dev/null +++ b/src/renderer/js/component/shapeShift/internal/active-shift.jsx @@ -0,0 +1,125 @@ +import React, { PureComponent } from "react"; +import QRCode from "qrcode.react"; +import * as statuses from "constants/shape_shift"; +import Address from "component/address"; +import Link from "component/link"; + +export default class ActiveShapeShift extends PureComponent { + constructor() { + super(); + this.continousFetch = undefined; + } + + componentDidMount() { + const { getActiveShift, shiftDepositAddress } = this.props; + + getActiveShift(shiftDepositAddress); + this.continousFetch = setInterval(() => { + getActiveShift(shiftDepositAddress); + }, 10000); + } + + componentWillUpdate(nextProps) { + const { shiftState } = nextProps; + if (shiftState === statuses.COMPLETE) { + this.clearContinuousFetch(); + } + } + + componentWillUnmount() { + this.clearContinuousFetch(); + } + + clearContinuousFetch() { + clearInterval(this.continousFetch); + this.continousFetch = null; + } + + render() { + const { + shiftCoinType, + shiftDepositAddress, + shiftReturnAddress, + shiftOrderId, + shiftState, + shiftDepositLimit, + clearShapeShift, + doShowSnackBar, + } = this.props; + + return ( +
+ {shiftState === statuses.NO_DEPOSITS && ( +
+

+ Send up to{" "} + + {shiftDepositLimit}{" "} + {shiftCoinType} + {" "} + to the address below. +

+ +
+
+
+ +
+
+
+ )} + + {shiftState === statuses.RECEIVED && ( +
+

+ {__( + "ShapeShift has received your payment! Sending the funds to your LBRY wallet." + )} +

+ + {__("This can take a while, especially with BTC.")} + +
+ )} + + {shiftState === statuses.COMPLETE && ( +
+

+ {__( + "Transaction complete! You should see the new LBC in your wallet." + )} +

+
+ )} +
+ + + + + {shiftState === statuses.NO_DEPOSITS && + shiftReturnAddress && ( +
+ + If the transaction doesn't go through, ShapeShift will return + your {shiftCoinType} back to {shiftReturnAddress} + +
+ )} +
+
+ ); + } +} diff --git a/src/renderer/js/component/shapeShift/internal/form.jsx b/src/renderer/js/component/shapeShift/internal/form.jsx new file mode 100644 index 000000000..bd1925738 --- /dev/null +++ b/src/renderer/js/component/shapeShift/internal/form.jsx @@ -0,0 +1,83 @@ +import React from "react"; +import Link from "component/link"; +import { getExampleAddress } from "util/shape_shift"; +import { Submit, FormRow } from "component/form"; + +export default ({ + values, + errors, + touched, + handleChange, + handleBlur, + handleSubmit, + resetForm, + isSubmitting, + shiftSupportedCoins, + originCoin, + updating, + getCoinStats, + receiveAddress, + originCoinDepositMax, + originCoinDepositMin, + originCoinDepositFee, +}) => { + return ( +
+
+ {__("Exchange")} + + {__("for LBC")} +

+ {!updating && + originCoinDepositMax && ( + + {__("Exchange max")}: {originCoinDepositMax} {originCoin} +
+ {__("Exchange minimun")}: {originCoinDepositMin} {originCoin} +
+ {__("Fee")}: {originCoinDepositFee} LBC +
+ )} +

+
+ + + + + ({__("optional but recommended")}) {__("We will return your")}{" "} + {originCoin}{" "} + {__("to this address if the transaction doesn't go through.")} + + +
+ +
+ + ); +}; diff --git a/src/renderer/js/component/shapeShift/view.jsx b/src/renderer/js/component/shapeShift/view.jsx new file mode 100644 index 000000000..f2991863f --- /dev/null +++ b/src/renderer/js/component/shapeShift/view.jsx @@ -0,0 +1,127 @@ +import React from "react"; +import { shell } from "electron"; +import { Formik } from "formik"; +import classnames from "classnames"; +import * as statuses from "constants/shape_shift"; +import { validateShapeShiftForm } from "util/shape_shift"; +import Link from "component/link"; +import Spinner from "component/common/spinner"; +import { BusyMessage } from "component/common"; +import ShapeShiftForm from "./internal/form"; +import ActiveShift from "./internal/active-shift"; + +class ShapeShift extends React.PureComponent { + componentDidMount() { + const { + shapeShiftInit, + shapeShift: { hasActiveShift, shiftSupportedCoins }, + } = this.props; + + if (!hasActiveShift && !shiftSupportedCoins.length) { + // calls shapeshift to see list of supported coins for shifting + shapeShiftInit(); + } + } + + render() { + const { + getCoinStats, + receiveAddress, + createShapeShift, + shapeShift, + clearShapeShift, + getActiveShift, + doShowSnackBar, + } = this.props; + + const { + loading, + updating, + error, + shiftSupportedCoins, + hasActiveShift, + originCoin, + // ShapeShift response values + originCoinDepositMax, + originCoinDepositMin, + originCoinDepositFee, + shiftDepositAddress, + shiftReturnAddress, + shiftCoinType, + shiftOrderId, + cancelShapeShift, + shiftState, + origin, + } = shapeShift; + + return ( + // add the "shapeshift__intital-wrapper class so we can avoid content jumping once everything loads" + // it just gives the section a min-height equal to the height of the content when the form is rendered + // if the markup below changes for the initial render (form.jsx) there will be content jumping + // the styling in shapeshift.scss will need to be updated to the correct min-height +
+
+

{__("Convert Crypto to LBC")}

+

+ {__("Powered by ShapeShift. Read our FAQ")}{" "} + {__("here")}. + {hasActiveShift && + shiftState !== "complete" && ( + {__("This will update automatically.")} + )} +

+
+ +
+ {error &&
{error}
} + {loading && } + {!loading && + !hasActiveShift && + !!shiftSupportedCoins.length && ( + ( + + )} + /> + )} + {hasActiveShift && ( + + )} +
+
+ ); + } +} + +export default ShapeShift; diff --git a/src/renderer/js/component/video/internal/loading-screen.jsx b/src/renderer/js/component/video/internal/loading-screen.jsx index bc388833c..94cc7ce4d 100644 --- a/src/renderer/js/component/video/internal/loading-screen.jsx +++ b/src/renderer/js/component/video/internal/loading-screen.jsx @@ -1,9 +1,10 @@ import React from "react"; +import Spinner from "component/common/spinner"; const LoadingScreen = ({ status, spinner = true }) => (
- {spinner &&
} + {spinner && }
{status}
diff --git a/src/renderer/js/component/walletAddress/view.jsx b/src/renderer/js/component/walletAddress/view.jsx index bdf6f81fe..63afa2b31 100644 --- a/src/renderer/js/component/walletAddress/view.jsx +++ b/src/renderer/js/component/walletAddress/view.jsx @@ -1,6 +1,6 @@ import React from "react"; import Link from "component/link"; -import { Address } from "component/common"; +import Address from "component/address"; class WalletAddress extends React.PureComponent { componentWillMount() { diff --git a/src/renderer/js/constants/action_types.js b/src/renderer/js/constants/action_types.js index b2f88f31f..3670912fd 100644 --- a/src/renderer/js/constants/action_types.js +++ b/src/renderer/js/constants/action_types.js @@ -144,3 +144,18 @@ export const FETCH_REWARD_CONTENT_COMPLETED = "FETCH_REWARD_CONTENT_COMPLETED"; //Language export const DOWNLOAD_LANGUAGE_SUCCEEDED = "DOWNLOAD_LANGUAGE_SUCCEEDED"; export const DOWNLOAD_LANGUAGE_FAILED = "DOWNLOAD_LANGUAGE_FAILED"; + +// ShapeShift +export const GET_SUPPORTED_COINS_START = "GET_SUPPORTED_COINS_START"; +export const GET_SUPPORTED_COINS_SUCCESS = "GET_SUPPORTED_COINS_SUCCESS"; +export const GET_SUPPORTED_COINS_FAIL = "GET_SUPPORTED_COINS_FAIL"; +export const GET_COIN_STATS_START = "GET_COIN_STATS_START"; +export const GET_COIN_STATS_SUCCESS = "GET_COIN_STATS_SUCCESS"; +export const GET_COIN_STATS_FAIL = "GET_COIN_STATS_FAIL"; +export const PREPARE_SHAPE_SHIFT_START = "PREPARE_SHAPE_SHIFT_START"; +export const PREPARE_SHAPE_SHIFT_SUCCESS = "PREPARE_SHAPE_SHIFT_SUCCESS"; +export const PREPARE_SHAPE_SHIFT_FAIL = "PREPARE_SHAPE_SHIFT_FAIL"; +export const GET_ACTIVE_SHIFT_START = "GET_ACTIVE_SHIFT_START"; +export const GET_ACTIVE_SHIFT_SUCCESS = "GET_ACTIVE_SHIFT_SUCCESS"; +export const GET_ACTIVE_SHIFT_FAIL = "GET_ACTIVE_SHIFT_FAIL"; +export const CLEAR_SHAPE_SHIFT = "CLEAR_SHAPE_SHIFT"; diff --git a/src/renderer/js/constants/shape_shift.js b/src/renderer/js/constants/shape_shift.js new file mode 100644 index 000000000..d898f2fc2 --- /dev/null +++ b/src/renderer/js/constants/shape_shift.js @@ -0,0 +1,3 @@ +export const NO_DEPOSITS = "no_deposits"; +export const RECEIVED = "received"; +export const COMPLETE = "complete"; diff --git a/src/renderer/js/page/receiveCredits/view.jsx b/src/renderer/js/page/receiveCredits/view.jsx index 120071748..5052b868e 100644 --- a/src/renderer/js/page/receiveCredits/view.jsx +++ b/src/renderer/js/page/receiveCredits/view.jsx @@ -2,15 +2,17 @@ import React from "react"; import SubHeader from "component/subHeader"; import Link from "component/link"; import WalletAddress from "component/walletAddress"; +import ShapeShift from "component/shapeShift"; const ReceiveCreditsPage = props => { return (
+
-

{__("Where To Find Credits")}

+

{__("More ways to get LBRY Credits")}

diff --git a/src/renderer/js/redux/actions/shape_shift.js b/src/renderer/js/redux/actions/shape_shift.js new file mode 100644 index 000000000..fc3280a6a --- /dev/null +++ b/src/renderer/js/redux/actions/shape_shift.js @@ -0,0 +1,86 @@ +import { createAction } from "util/redux-utils"; +import Promise from "bluebird"; +import * as types from "constants/action_types"; +import { coinRegexPatterns } from "util/shape_shift"; + +const shapeShift = Promise.promisifyAll(require("shapeshift.io")); + +export const shapeShiftInit = () => dispatch => { + dispatch({ type: types.GET_SUPPORTED_COINS_START }); + + return shapeShift + .coinsAsync() + .then(coinData => { + let supportedCoins = []; + Object.keys(coinData).forEach(symbol => { + if (coinData[symbol].status === "available") { + supportedCoins.push(coinData[symbol]); + } + }); + + // only use larger coins with client side validation + supportedCoins = supportedCoins + .filter(coin => coinRegexPatterns[coin.symbol]) + .map(coin => coin.symbol); + + dispatch({ + type: types.GET_SUPPORTED_COINS_SUCCESS, + data: supportedCoins, + }); + dispatch(getCoinStats(supportedCoins[0])); + }) + .catch(err => + dispatch({ type: types.GET_SUPPORTED_COINS_FAIL, data: err }) + ); +}; + +export const getCoinStats = coin => dispatch => { + // TODO: get ShapeShift fee + const pair = `${coin.toLowerCase()}_lbc`; + + dispatch({ type: types.GET_COIN_STATS_START, data: coin }); + + return shapeShift + .marketInfoAsync(pair) + .then(marketInfo => + dispatch({ type: types.GET_COIN_STATS_SUCCESS, data: marketInfo }) + ) + .catch(err => dispatch({ type: types.GET_COIN_STATS_FAIL, data: err })); +}; + +export const createShapeShift = (values, actions) => dispatch => { + const { + originCoin, + returnAddress, + receiveAddress: withdrawalAddress, + } = values; + + const pair = `${originCoin.toLowerCase()}_lbc`; + const options = { + returnAddress: returnAddress, + }; + + dispatch({ type: types.PREPARE_SHAPE_SHIFT_START }); + return shapeShift + .shiftAsync(withdrawalAddress, pair, options) + .then(res => + dispatch({ type: types.PREPARE_SHAPE_SHIFT_SUCCESS, data: res }) + ) + .catch(err => { + dispatch({ type: types.PREPARE_SHAPE_SHIFT_FAIL, data: err }); + // for formik + actions.setSubmitting(false); + }); +}; + +export const getActiveShift = depositAddress => dispatch => { + dispatch({ type: types.GET_ACTIVE_SHIFT_START }); + + return shapeShift + .statusAsync(depositAddress) + .then(res => dispatch({ type: types.GET_ACTIVE_SHIFT_SUCCESS, data: res })) + .catch(err => dispatch({ type: types.GET_ACTIVE_SHIFT_FAIL, data: err })); +}; + +export const clearShapeShift = () => dispatch => + dispatch({ type: types.CLEAR_SHAPE_SHIFT }); diff --git a/src/renderer/js/redux/reducers/shape_shift.js b/src/renderer/js/redux/reducers/shape_shift.js new file mode 100644 index 000000000..dd44378f0 --- /dev/null +++ b/src/renderer/js/redux/reducers/shape_shift.js @@ -0,0 +1,103 @@ +import { handleActions } from "util/redux-utils"; +import * as types from "constants/action_types"; +import * as statuses from "constants/shape_shift"; + +const defaultState = { + loading: true, + updating: false, + error: undefined, + shiftSupportedCoins: [], + originCoin: undefined, + hasActiveShift: false, + shiftDepositAddress: undefined, // shapeshift address to send your coins to + shiftReturnAddress: undefined, + shiftCoinType: undefined, + shiftOrderId: undefined, + shiftState: undefined, + originCoinDepositMax: undefined, + originCoinDepositMin: undefined, + originCoinDepositFee: undefined, +}; + +export default handleActions( + { + [types.GET_SUPPORTED_COINS_START]: () => ({ + loading: true, + error: undefined, + }), + [types.GET_SUPPORTED_COINS_SUCCESS]: ( + state, + { data: shiftSupportedCoins } + ) => ({ + error: undefined, + shiftSupportedCoins, + }), + [types.GET_SUPPORTED_COINS_FAIL]: () => ({ + loading: false, + error: true, + }), + + [types.GET_COIN_STATS_START]: (state, { data: coin }) => ({ + updating: true, + originCoin: coin, + }), + [types.GET_COIN_STATS_SUCCESS]: (state, { data: marketInfo }) => ({ + loading: false, + updating: false, + originCoinDepositMax: marketInfo.limit, + // this will come in scientific notation + // toFixed shows the real number, then regex to remove trailing zeros + originCoinDepositMin: marketInfo.minimum + .toFixed(10) + .replace(/\.?0+$/, ""), + originCoinDepositFee: marketInfo.minerFee, + }), + [types.GET_COIN_STATS_FAIL]: (state, { data: error }) => ({ + loading: false, + error, + }), + + [types.PREPARE_SHAPE_SHIFT_START]: () => ({ + error: undefined, + }), + [types.PREPARE_SHAPE_SHIFT_SUCCESS]: ( + state, + { data: { deposit, depositType, returnAddress, orderId } } + ) => ({ + hasActiveShift: true, + shiftDepositAddress: deposit, + shiftCoinType: depositType, + shiftReturnAddress: returnAddress, + shiftOrderId: orderId, + shiftState: statuses.NO_DEPOSITS, + }), + [types.PREPARE_SHAPE_SHIFT_FAIL]: (state, { data: error }) => ({ + error: error.message, + }), + + [types.CLEAR_SHAPE_SHIFT]: () => ({ + loading: false, + updating: false, + hasActiveShift: false, + shiftDepositAddress: undefined, + shiftReturnAddress: undefined, + shiftCoinType: undefined, + shiftOrderId: undefined, + originCoin: "BTC", + }), + + [types.GET_ACTIVE_SHIFT_START]: () => ({ + error: undefined, + updating: true, + }), + [types.GET_ACTIVE_SHIFT_SUCCESS]: (state, { data: status }) => ({ + updating: false, + shiftState: status, + }), + [types.GET_ACTIVE_SHIFT_FAIL]: (state, { data: error }) => ({ + updating: false, + error: error.message, + }), + }, + defaultState +); diff --git a/src/renderer/js/redux/selectors/navigation.js b/src/renderer/js/redux/selectors/navigation.js index 4f91467eb..7633e81c2 100644 --- a/src/renderer/js/redux/selectors/navigation.js +++ b/src/renderer/js/redux/selectors/navigation.js @@ -44,8 +44,8 @@ export const selectHeaderLinks = createSelector(selectCurrentPage, page => { return { wallet: __("Overview"), history: __("History"), - send: __("Send"), - receive: __("Receive"), + send: __("Send Credits"), + receive: __("Get Credits"), rewards: __("Rewards"), invite: __("Invites"), }; @@ -78,9 +78,9 @@ export const selectPageTitle = createSelector( case "wallet": return __("Wallet"); case "send": - return __("Send Credits"); + return __("Send LBRY Credits"); case "receive": - return __("Wallet Address"); + return __("Get LBRY Credits"); case "backup": return __("Backup Your Wallet"); case "rewards": diff --git a/src/renderer/js/redux/selectors/search.js b/src/renderer/js/redux/selectors/search.js index d64289d78..fc78e50f4 100644 --- a/src/renderer/js/redux/selectors/search.js +++ b/src/renderer/js/redux/selectors/search.js @@ -65,7 +65,7 @@ export const selectWunderBarIcon = createSelector( return "icon-envelope-open"; case "address": case "receive": - return "icon-address-book"; + return "icon-credit-card"; case "wallet": case "backup": return "icon-bank"; diff --git a/src/renderer/js/redux/selectors/shape_shift.js b/src/renderer/js/redux/selectors/shape_shift.js new file mode 100644 index 000000000..e60af9fb4 --- /dev/null +++ b/src/renderer/js/redux/selectors/shape_shift.js @@ -0,0 +1,7 @@ +import { createSelector } from "reselect"; + +const _selectState = state => state.shapeShift; + +export const selectShapeShift = createSelector(_selectState, state => ({ + ...state, +})); diff --git a/src/renderer/js/store.js b/src/renderer/js/store.js index 8d1b70363..36ea0c6a4 100644 --- a/src/renderer/js/store.js +++ b/src/renderer/js/store.js @@ -11,6 +11,7 @@ import searchReducer from "redux/reducers/search"; import settingsReducer from "redux/reducers/settings"; import userReducer from "redux/reducers/user"; import walletReducer from "redux/reducers/wallet"; +import shapeShiftReducer from "redux/reducers/shape_shift"; import { persistStore, autoRehydrate } from "redux-persist"; import createCompressor from "redux-persist-transform-compress"; import createFilter from "redux-persist-transform-filter"; @@ -67,6 +68,7 @@ const reducers = redux.combineReducers({ settings: settingsReducer, wallet: walletReducer, user: userReducer, + shapeShift: shapeShiftReducer, }); const bulkThunk = createBulkThunkMiddleware(); diff --git a/src/renderer/js/util/shape_shift.js b/src/renderer/js/util/shape_shift.js new file mode 100644 index 000000000..7adfc1abc --- /dev/null +++ b/src/renderer/js/util/shape_shift.js @@ -0,0 +1,50 @@ +// these don't need to be exact +// shapeshift does a more thourough check on validity +// just general matches to prevent unneccesary api calls +export const coinRegexPatterns = { + BTC: /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/, + BCH: /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/, + ETH: /^(0x)?[0-9a-fA-F]{40}$/, + DASH: /^X([0-9a-zA-Z]){33}/, + LTC: /^L[a-zA-Z0-9]{26,33}$/, + XMR: /^4[0-9ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{94}$/, +}; + +const validateAddress = (coinType, address) => { + if (!coinType || !address) return false; + + const coinRegex = coinRegexPatterns[coinType.toUpperCase()]; + if (!coinRegex) return false; + + return coinRegex.test(address); +}; + +export const validateShapeShiftForm = (vals, props) => { + let errors = {}; + + if (!vals.returnAddress) { + return errors; + } + + const isValidAddress = validateAddress(vals.originCoin, vals.returnAddress); + + if (!isValidAddress) { + errors.returnAddress = `Enter a valid ${vals.originCoin} address`; + } + + return errors; +}; + +const exampleCoinAddresses = { + BTC: "1745oPaHeW7Fmpb1fUKTtasYfxr4zu9bwq", + BCH: "1745oPaHeW7Fmpb1fUKTtasYfxr4zu9bwq", + ETH: "0x8507cA6a274123fC8f80d929AF9D83602bC4e8cC", + DASH: "XedBP7vLPFXbS3URjrH2Z57Fg9SWftBmQ6", + LTC: "LgZivMvFMTDoqcA5weCQ2QrmRp7pa56bBk", + XMR: + "466XMeJEcowYGx7RzUJj3VDWBZgRWErVQQX6tHYbsacS5QF6v3tidE6LZZnTJgzeEh6bKEEJ6GC9jHirrUKvJwVKVj9e7jm", +}; + +export const getExampleAddress = coin => { + return exampleCoinAddresses[coin]; +}; diff --git a/src/renderer/package.json b/src/renderer/package.json index 4a6e9f03e..4de4e9282 100644 --- a/src/renderer/package.json +++ b/src/renderer/package.json @@ -22,10 +22,14 @@ }, "homepage": "https://github.com/lbryio/lbry-app", "dependencies": { + "bluebird": "^3.5.1", + "classnames": "^2.2.5", + "formik": "^0.10.4", "from2": "^2.3.0", "jshashes": "^1.0.7", "localforage": "^1.5.0", "node-sass": "^4.5.3", + "qrcode.react": "^0.7.2", "rc-progress": "^2.0.6", "react": "^16.2.0", "react-dom": "^16.2.0", @@ -43,6 +47,7 @@ "redux-thunk": "^2.2.0", "render-media": "^2.10.0", "reselect": "^3.0.0", + "shapeshift.io": "^1.3.1", "y18n": "^3.2.1" }, "devDependencies": { diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss index 580862b54..53f8399e8 100644 --- a/src/renderer/scss/_gui.scss +++ b/src/renderer/scss/_gui.scss @@ -34,6 +34,16 @@ body color: var(--color-meta-light); } +.credit-amount--bold +{ + font-weight: 700; +} + +.credit-amount--colored +{ + color: var(--color-primary); +} + #main-content { margin: auto; diff --git a/src/renderer/scss/all.scss b/src/renderer/scss/all.scss index dc4be7179..40c63b1f4 100644 --- a/src/renderer/scss/all.scss +++ b/src/renderer/scss/all.scss @@ -26,4 +26,6 @@ @import "component/_divider.scss"; @import "component/_checkbox.scss"; @import "component/_radio.scss"; +@import "component/_shapeshift.scss"; +@import "component/_spinner.scss"; @import "page/_show.scss"; diff --git a/src/renderer/scss/component/_button.scss b/src/renderer/scss/component/_button.scss index 642e3de92..e3dad6330 100644 --- a/src/renderer/scss/component/_button.scss +++ b/src/renderer/scss/component/_button.scss @@ -98,4 +98,4 @@ $button-focus-shift: 12%; .button--submit { font-family: inherit; line-height: 0; -} +} \ No newline at end of file diff --git a/src/renderer/scss/component/_card.scss b/src/renderer/scss/component/_card.scss index a630d5558..61a23f71d 100644 --- a/src/renderer/scss/component/_card.scss +++ b/src/renderer/scss/component/_card.scss @@ -26,6 +26,7 @@ .card__actions { padding: 0 var(--card-padding); } + .card--small { .card__title-primary, .card__title-identity, @@ -72,6 +73,11 @@ margin-bottom: var(--card-margin); } } + +.card__content--extra-vertical-space { + margin: $spacing-vertical 0; +} + $font-size-subtext-multiple: 0.82; .card__subtext { color: var(--color-meta-light); diff --git a/src/renderer/scss/component/_form-field.scss b/src/renderer/scss/component/_form-field.scss index c7aedf480..1d7398d7a 100644 --- a/src/renderer/scss/component/_form-field.scss +++ b/src/renderer/scss/component/_form-field.scss @@ -56,6 +56,11 @@ padding-left: 5px; padding-right: 5px; width: 100%; + font-family: "Consolas", "Lucida Console", "Adobe Source Code Pro", monospace; + + &.input-copyable--with-copy-btn { + width: 85%; + } } input[readonly] { diff --git a/src/renderer/scss/component/_header.scss b/src/renderer/scss/component/_header.scss index 769622fd8..e1ec0a1fa 100644 --- a/src/renderer/scss/component/_header.scss +++ b/src/renderer/scss/component/_header.scss @@ -43,6 +43,8 @@ .wunderbar--active .icon-search { color: var(--color-primary); } +// below styles should be inside the common input styling +// will come back to this with the redesign - sean .wunderbar__input { background: var(--search-bg); width: 100%; @@ -61,3 +63,8 @@ border-color: var(--color-primary); } } + +.wunderbar__input--shapeshift { + padding-left: 5px; + margin-top: 5px; +} diff --git a/src/renderer/scss/component/_shapeshift.scss b/src/renderer/scss/component/_shapeshift.scss new file mode 100644 index 000000000..1683141f9 --- /dev/null +++ b/src/renderer/scss/component/_shapeshift.scss @@ -0,0 +1,48 @@ +// Can't think of a better way to do this +// The initial shapeshift form is 311px tall +// the .shapeshift__initial-wrapper class is only added when the form is being loaded +// Once the form is rendered, there is a very smooth transition because the height doesn't change +.shapeshift__wrapper.shapeshift__initial-wrapper { + min-height: 346px; +} + +.shapeshift__content { + .spinner { + margin-top: $spacing-vertical * 3; + } +} + +.shapeshift__tx-info { + min-height: 55px; +} + +.shapeshift__deposit-address-wrapper { + display: flex; + flex-direction: row; + + * { + align-self: center; + } +} + +// this should be pulled out into it's own styling when we add more qr codes +.shapeshift__qrcode { + // don't use a variable here. adds a white border for easier reading in dark mode + // needs to stay the same no matter what theme is present + background-color: #fff; + padding: 2px; + margin-left: 40px; +} + +.shapeshift__actions { + padding-top: $spacing-vertical; +} + +.shapeshift__submit, +.shapeshift__actions-help { + padding-top: $spacing-vertical / 2; +} + +.shapeshift__link { + padding-left: 10px; +} \ No newline at end of file diff --git a/src/renderer/scss/component/_spinner.scss b/src/renderer/scss/component/_spinner.scss new file mode 100644 index 000000000..ec339e5a1 --- /dev/null +++ b/src/renderer/scss/component/_spinner.scss @@ -0,0 +1,58 @@ +.spinner { + position: relative; + width: 11em; + height: 11em; + margin: 20px auto; + font-size: 3px; + border-radius: 50%; + + background: linear-gradient(to right, #fff 10%, rgba(255, 255, 255, 0) 50%); + animation: spin 1.4s infinite linear; + transform: translateZ(0); + + @keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + + &:before, + &:after { + content: ''; + position: absolute; + top: 0; + left: 0; + } + + &:before { + width: 50%; + height: 50%; + background: #fff; + border-radius: 100% 0 0 0; + } + + &:after { + height: 75%; + width: 75%; + margin: auto; + bottom: 0; + right: 0; + background: #000; + border-radius: 50%; + } +} + +.spinner.spinner--dark { + background: linear-gradient(to right, var(--button-primary-bg) 10%, var(--color-bg) 50%); + + &:before { + background: var(--button-primary-bg); + } + + &:after { + background: var(--color-bg); + } +} \ No newline at end of file diff --git a/src/renderer/scss/component/_video.scss b/src/renderer/scss/component/_video.scss index 3f3204308..d6021849e 100644 --- a/src/renderer/scss/component/_video.scss +++ b/src/renderer/scss/component/_video.scss @@ -46,53 +46,6 @@ video { align-items: center; } -.video__loading-spinner { - position: relative; - width: 11em; - height: 11em; - margin: 20px auto; - font-size: 3px; - border-radius: 50%; - - background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 50%); - animation: spin 1.4s infinite linear; - transform: translateZ(0); - - @keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } - } - - &:before, - &:after { - content: ''; - position: absolute; - top: 0; - left: 0; - } - - &:before { - width: 50%; - height: 50%; - background: #ffffff; - border-radius: 100% 0 0 0; - } - - &:after { - height: 75%; - width: 75%; - margin: auto; - bottom: 0; - right: 0; - background: black; - border-radius: 50%; - } -} - .video__loading-status { padding-top: 20px; color: white; diff --git a/src/renderer/webpack.common.js b/src/renderer/webpack.common.js index 3e843a89e..db0f69d2c 100644 --- a/src/renderer/webpack.common.js +++ b/src/renderer/webpack.common.js @@ -18,7 +18,7 @@ module.exports = { }, resolve: { modules: [appPath, "node_modules"], - extensions: [".js", ".jsx", ".css"] + extensions: [".js", ".jsx", ".css", ".json"] }, module: { rules: [ diff --git a/src/renderer/yarn.lock b/src/renderer/yarn.lock index d7049810b..21c2d6ab3 100644 --- a/src/renderer/yarn.lock +++ b/src/renderer/yarn.lock @@ -56,9 +56,9 @@ ajv@^4.7.0, ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.0.0, ajv@^5.1.5, ajv@^5.2.3: - version "5.4.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.4.0.tgz#32d1cf08dbc80c432f426f12e10b2511f6b46474" +ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5, ajv@^5.2.3: + version "5.5.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.0.tgz#eb2840746e9dc48bd5e063a36e3fd400c5eab5a9" dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" @@ -276,7 +276,11 @@ aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" -aws4@^1.2.1: +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" @@ -997,6 +1001,10 @@ block-stream@*: dependencies: inherits "~2.0.0" +bluebird@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -1033,6 +1041,18 @@ boom@2.x.x: dependencies: hoek "2.x.x" +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" @@ -1198,8 +1218,8 @@ caniuse-api@^1.5.2: lodash.uniq "^4.5.0" caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000769" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000769.tgz#c230b9c1b9e8db3e1c0d858c96e685741b96cc10" + version "1.0.30000775" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000775.tgz#04bccdd0214edf25b97f61a096609f7ad6904333" cardinal@^1.0.0: version "1.0.0" @@ -1376,8 +1396,8 @@ codemirror-spell-checker@*: typo-js "*" codemirror@*: - version "5.31.0" - resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.31.0.tgz#ecf3d057eb74174147066bfc7c5f37b4c4e07df2" + version "5.32.0" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.32.0.tgz#cb6ff5d8ef36d0b10f031130e2d9ebeee92c902e" color-convert@^1.3.0, color-convert@^1.9.0: version "1.9.1" @@ -1426,8 +1446,8 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: delayed-stream "~1.0.0" commander@^2.11.0, commander@^2.5.0, commander@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" commondir@^1.0.1: version "1.0.1" @@ -1525,8 +1545,8 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" convert-source-map@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" cookie-signature@1.0.6: version "1.0.6" @@ -1613,6 +1633,12 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + crypto-browserify@3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.3.0.tgz#b9fc75bb4a0ed61dcf1cd5dae96eb30c9c3e506c" @@ -1849,18 +1875,18 @@ detect-indent@^4.0.0: repeating "^2.0.0" detect-libc@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.2.tgz#71ad5d204bf17a6a6ca8f450c61454066ef461e1" + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" detect-node@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" detective@^4.3.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" + version "4.6.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.6.0.tgz#d1a793ad0bcc829fa225465061096b7bca040527" dependencies: - acorn "^4.0.3" + acorn "^5.2.1" defined "^1.0.0" diffie-hellman@^5.0.0: @@ -1896,11 +1922,14 @@ doctrine@1.5.0, doctrine@^1.2.2: isarray "^1.0.0" doctrine@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" + version "2.0.2" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" dependencies: esutils "^2.0.2" - isarray "^1.0.0" + +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" domain-browser@^1.1.1: version "1.1.7" @@ -2015,8 +2044,8 @@ error-ex@^1.2.0: is-arrayish "^0.2.1" es-abstract@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" + version "1.10.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -2041,8 +2070,8 @@ es3ify@^0.1.3: through "~2.3.4" es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.35" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.35.tgz#18ee858ce6a3c45c7d79e91c15fcca9ec568494f" + version "0.10.37" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" dependencies: es6-iterator "~2.0.1" es6-symbol "~3.1.1" @@ -2340,7 +2369,7 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -express@^4.13.3: +express@^4.16.2: version "4.16.2" resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" dependencies: @@ -2375,7 +2404,7 @@ express@^4.13.3: utils-merge "1.0.1" vary "~1.1.2" -extend@~3.0.0: +extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -2385,10 +2414,14 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extsprintf@1.3.0, extsprintf@^1.2.0: +extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + falafel@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/falafel/-/falafel-1.2.0.tgz#c18d24ef5091174a497f318cd24b026a25cddab4" @@ -2567,6 +2600,12 @@ flow-typed@^2.2.3: which "^1.2.14" yargs "^4.2.0" +for-each@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" + dependencies: + is-function "~1.0.0" + for-in@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2593,6 +2632,22 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +formik@^0.10.4: + version "0.10.5" + resolved "https://registry.yarnpkg.com/formik/-/formik-0.10.5.tgz#6984d2f22e918c6d2264a3cb86b8582f7277faca" + dependencies: + lodash.isequal "4.5.0" + prop-types "^15.5.10" + warning "^3.0.0" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -2773,6 +2828,13 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" +global@~4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + globals@^9.14.0, globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -2847,6 +2909,10 @@ har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + har-validator@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" @@ -2863,6 +2929,13 @@ har-validator@~4.2.1: ajv "^4.9.1" har-schema "^1.0.5" +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -2926,6 +2999,15 @@ hawk@3.1.3, hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2938,6 +3020,10 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + hoist-non-react-statics@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" @@ -3011,6 +3097,14 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" @@ -3151,8 +3245,8 @@ interpret@^0.6.4: resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" interpret@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" invariant@^2.0.0, invariant@^2.2.2: version "2.2.2" @@ -3252,6 +3346,10 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-function@^1.0.1, is-function@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -3300,8 +3398,8 @@ is-path-in-cwd@^1.0.0: is-path-inside "^1.0.0" is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" @@ -3404,8 +3502,8 @@ isurl@^1.0.0-alpha5: is-object "^1.0.1" js-base64@^2.1.8, js-base64@^2.1.9: - version "2.3.2" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf" + version "2.4.0" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.0.tgz#9e566fee624751a1d720c966cd6226d29d4025aa" js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" @@ -3673,8 +3771,8 @@ loader-utils@^1.0.2, loader-utils@^1.1.0: json5 "^0.5.0" localforage@^1.5.0: - version "1.5.3" - resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.5.3.tgz#698aa16af1022340b240be9d93192e8af022ff16" + version "1.5.5" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.5.5.tgz#55fc1c3a88a47f67f5fac6f1231b25ff13556423" dependencies: lie "3.0.2" @@ -3778,6 +3876,10 @@ lodash.isempty@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" +lodash.isequal@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" @@ -4017,7 +4119,11 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.30.0 < 2", mime-db@~1.30.0: +"mime-db@>= 1.30.0 < 2": + version "1.32.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414" + +mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" @@ -4027,10 +4133,14 @@ mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, dependencies: mime-db "~1.30.0" -mime@1.4.1, mime@^1.2.11, mime@^1.3.4: +mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime@^1.2.11, mime@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" @@ -4039,6 +4149,12 @@ mimic-response@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -4053,7 +4169,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" -minimist@0.0.8, minimist@~0.0.1: +minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -4061,6 +4177,10 @@ minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + mkdirp@0.5, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -4091,8 +4211,8 @@ multicast-dns-service-types@^1.1.0: resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" multicast-dns@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.0.tgz#13f22d0c32dc5ee82a32878e3c380d875b3eab22" + version "6.2.1" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.1.tgz#c5035defa9219d30640558a49298067352098060" dependencies: dns-packet "^1.0.1" thunky "^0.1.0" @@ -4363,7 +4483,7 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -oauth-sign@~0.8.1: +oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -4580,6 +4700,13 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" +parse-headers@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" + dependencies: + for-each "^0.3.2" + trim "0.0.1" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -4660,6 +4787,10 @@ performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -4976,6 +5107,10 @@ process@^0.11.0, process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" @@ -5047,7 +5182,18 @@ q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" -qs@6.5.1: +qr.js@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" + +qrcode.react@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-0.7.2.tgz#72a5718fd56baafe15c2c153fe436628d83aa286" + dependencies: + prop-types "^15.5.8" + qr.js "0.0.0" + +qs@6.5.1, qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" @@ -5123,8 +5269,8 @@ raw-body@2.3.2: unpipe "1.0.0" rc-progress@^2.0.6: - version "2.2.4" - resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-2.2.4.tgz#45dbdb91cdd71cb5ce22e61313a351ceb5b1488a" + version "2.2.5" + resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-2.2.5.tgz#e61d0544bf9d4208e5ba32fc50962159e7f952a3" dependencies: babel-runtime "6.x" prop-types "^15.5.8" @@ -5164,11 +5310,12 @@ react-markdown@^2.5.0: prop-types "^15.5.1" react-modal@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.1.5.tgz#9cfdb7634b5003148ffb7c8ead13a36f671d744e" + version "3.1.6" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.1.6.tgz#82e63f1ec86b80e242518250d066ee37fa035f8a" dependencies: exenv "^1.2.0" prop-types "^15.5.10" + warning "^3.0.0" react-paginate@^5.0.0: version "5.0.0" @@ -5460,32 +5607,34 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2, request@~2.79.0: - version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" +request@2, request@^2.55.0, request@^2.81.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" combined-stream "~1.0.5" - extend "~3.0.0" + extend "~3.0.1" forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" + 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.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - uuid "^3.0.0" + 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" -request@2.81.0, request@^2.81.0: +request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: @@ -5512,6 +5661,31 @@ request@2.81.0, request@^2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" +request@~2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5730,6 +5904,13 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shapeshift.io@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/shapeshift.io/-/shapeshift.io-1.3.1.tgz#939f7d89e6a93fad4b556567d3fcdab45d5cc021" + dependencies: + request "^2.55.0" + xhr "^2.0.1" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -5790,6 +5971,12 @@ sntp@1.x.x: dependencies: hoek "2.x.x" +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + sockjs-client@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" @@ -5915,7 +6102,11 @@ staged-git-files@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/staged-git-files/-/staged-git-files-0.0.4.tgz#d797e1b551ca7a639dec0237dc6eb4bb9be17d35" -"statuses@>= 1.3.1 < 2", statuses@~1.3.1: +"statuses@>= 1.3.1 < 2": + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" @@ -5991,7 +6182,7 @@ string_decoder@^1.0.0, string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4: +stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -6067,8 +6258,8 @@ svgo@^0.7.0: whet.extend "~0.9.9" symbol-observable@^1.0.1, symbol-observable@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" + version "1.1.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32" table@^3.7.8: version "3.8.3" @@ -6162,7 +6353,7 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" -tough-cookie@~2.3.0: +tough-cookie@~2.3.0, tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: @@ -6180,6 +6371,10 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + "true-case-path@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62" @@ -6371,7 +6566,7 @@ uuid@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" -uuid@^3.0.0: +uuid@^3.0.0, uuid@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -6423,6 +6618,12 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + dependencies: + loose-envify "^1.0.0" + watchpack@^0.2.1: version "0.2.9" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" @@ -6453,18 +6654,18 @@ webpack-core@~0.6.9: source-map "~0.4.1" webpack-dev-middleware@^1.11.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709" + version "1.12.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" dependencies: memory-fs "~0.4.1" - mime "^1.3.4" + mime "^1.5.0" path-is-absolute "^1.0.0" range-parser "^1.0.3" time-stamp "^2.0.0" webpack-dev-server@^2.4.4: - version "2.9.4" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.4.tgz#7883e61759c6a4b33e9b19ec4037bd4ab61428d1" + version "2.9.5" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.5.tgz#79336fba0087a66ae491f4869f6545775b18daa8" dependencies: ansi-html "0.0.7" array-includes "^3.0.3" @@ -6474,7 +6675,7 @@ webpack-dev-server@^2.4.4: connect-history-api-fallback "^1.3.0" debug "^3.1.0" del "^3.0.0" - express "^4.13.3" + express "^4.16.2" html-entities "^1.2.0" http-proxy-middleware "~0.17.4" import-local "^0.1.1" @@ -6509,8 +6710,8 @@ webpack-notifier@^1.5.0: strip-ansi "^3.0.1" webpack-sources@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.2.tgz#d0148ec083b3b5ccef1035a6b3ec16442983b27a" + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" dependencies: source-list-map "^2.0.0" source-map "~0.6.1" @@ -6542,8 +6743,8 @@ webpack@^1.12.0: webpack-core "~0.6.9" webpack@^3.0.0: - version "3.8.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.8.1.tgz#b16968a81100abe61608b0153c9159ef8bb2bd83" + version "3.9.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.9.1.tgz#9a60aa544ed5d4d454c069e3f521aa007e02643c" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" @@ -6648,6 +6849,15 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" +xhr@^2.0.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.4.0.tgz#e16e66a45f869861eeefab416d5eff722dc40993" + dependencies: + global "~4.3.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + xss-filters@^1.2.6: version "1.2.7" resolved "https://registry.yarnpkg.com/xss-filters/-/xss-filters-1.2.7.tgz#59fa1de201f36f2f3470dcac5f58ccc2830b0a9a" From c000ad1bc8723a37dae5ac2d557267af21451a43 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Sun, 3 Dec 2017 22:27:55 -0500 Subject: [PATCH 02/14] use flow --- src/renderer/.flowconfig | 3 + src/renderer/flow-typed/bluebird.js | 3 + src/renderer/flow-typed/classnames.js | 3 + src/renderer/flow-typed/formik.js | 3 + src/renderer/flow-typed/i18n.js | 1 + src/renderer/flow-typed/qrcode.react.js | 3 + src/renderer/flow-typed/shapeshift.io.js | 3 + .../shapeShift/internal/active-shift.jsx | 46 +++- .../js/component/shapeShift/internal/form.jsx | 59 ++-- src/renderer/js/component/shapeShift/view.jsx | 39 ++- src/renderer/js/redux/actions/shape_shift.js | 67 ++++- src/renderer/js/redux/reducers/shape_shift.js | 256 ++++++++++++++---- src/renderer/js/types/common.js | 3 + src/renderer/js/util/redux-utils.js | 1 + 14 files changed, 381 insertions(+), 109 deletions(-) create mode 100644 src/renderer/flow-typed/bluebird.js create mode 100644 src/renderer/flow-typed/classnames.js create mode 100644 src/renderer/flow-typed/formik.js create mode 100644 src/renderer/flow-typed/i18n.js create mode 100644 src/renderer/flow-typed/qrcode.react.js create mode 100644 src/renderer/flow-typed/shapeshift.io.js create mode 100644 src/renderer/js/types/common.js diff --git a/src/renderer/.flowconfig b/src/renderer/.flowconfig index 18e154135..21d1a300a 100644 --- a/src/renderer/.flowconfig +++ b/src/renderer/.flowconfig @@ -12,6 +12,9 @@ flow-typed suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe suppress_comment=\\(.\\|\n\\)*\\$FlowIssue module.name_mapper='^constants\(.*\)$' -> '/js/constants\1' +module.name_mapper='^util\(.*\)$' -> '/js/util\1' module.name_mapper='^redux\(.*\)$' -> '/js/redux\1' +module.name_mapper='^types\(.*\)$' -> '/js/types\1' +module.name_mapper='^component\(.*\)$' -> '/js/component\1' [strict] diff --git a/src/renderer/flow-typed/bluebird.js b/src/renderer/flow-typed/bluebird.js new file mode 100644 index 000000000..b6ea52b19 --- /dev/null +++ b/src/renderer/flow-typed/bluebird.js @@ -0,0 +1,3 @@ +declare module 'bluebird' { + declare module.exports: any; +} diff --git a/src/renderer/flow-typed/classnames.js b/src/renderer/flow-typed/classnames.js new file mode 100644 index 000000000..8ed60a607 --- /dev/null +++ b/src/renderer/flow-typed/classnames.js @@ -0,0 +1,3 @@ +declare module 'classnames' { + declare module.exports: any; +} diff --git a/src/renderer/flow-typed/formik.js b/src/renderer/flow-typed/formik.js new file mode 100644 index 000000000..020efafd4 --- /dev/null +++ b/src/renderer/flow-typed/formik.js @@ -0,0 +1,3 @@ +declare module 'formik' { + declare module.exports: any; +} diff --git a/src/renderer/flow-typed/i18n.js b/src/renderer/flow-typed/i18n.js new file mode 100644 index 000000000..cbceb4b59 --- /dev/null +++ b/src/renderer/flow-typed/i18n.js @@ -0,0 +1 @@ +declare function __(a: string): string; diff --git a/src/renderer/flow-typed/qrcode.react.js b/src/renderer/flow-typed/qrcode.react.js new file mode 100644 index 000000000..43a589258 --- /dev/null +++ b/src/renderer/flow-typed/qrcode.react.js @@ -0,0 +1,3 @@ +declare module 'qrcode.react' { + declare module.exports: any; +} diff --git a/src/renderer/flow-typed/shapeshift.io.js b/src/renderer/flow-typed/shapeshift.io.js new file mode 100644 index 000000000..2d32593ee --- /dev/null +++ b/src/renderer/flow-typed/shapeshift.io.js @@ -0,0 +1,3 @@ +declare module 'shapeshift.io' { + declare module.exports: any; +} diff --git a/src/renderer/js/component/shapeShift/internal/active-shift.jsx b/src/renderer/js/component/shapeShift/internal/active-shift.jsx index 38c18c4d5..cd8577261 100644 --- a/src/renderer/js/component/shapeShift/internal/active-shift.jsx +++ b/src/renderer/js/component/shapeShift/internal/active-shift.jsx @@ -1,12 +1,27 @@ -import React, { PureComponent } from "react"; +// @flow +import * as React from "react"; import QRCode from "qrcode.react"; import * as statuses from "constants/shape_shift"; import Address from "component/address"; import Link from "component/link"; +import type { Dispatch } from "redux/actions/shape_shift"; -export default class ActiveShapeShift extends PureComponent { +type Props = { + shiftState: ?string, + shiftCoinType: ?string, + shiftDepositAddress: ?string, + shiftReturnAddress: ?string, + shiftOrderId: ?string, + originCoinDepositMax: ?number, + clearShapeShift: Dispatch, + doShowSnackBar: Dispatch, + getActiveShift: Dispatch, +}; + +class ActiveShapeShift extends React.PureComponent { constructor() { super(); + // $FlowFixMe this.continousFetch = undefined; } @@ -14,12 +29,13 @@ export default class ActiveShapeShift extends PureComponent { const { getActiveShift, shiftDepositAddress } = this.props; getActiveShift(shiftDepositAddress); + // $FlowFixMe this.continousFetch = setInterval(() => { getActiveShift(shiftDepositAddress); }, 10000); } - componentWillUpdate(nextProps) { + componentWillUpdate(nextProps: Props) { const { shiftState } = nextProps; if (shiftState === statuses.COMPLETE) { this.clearContinuousFetch(); @@ -31,7 +47,9 @@ export default class ActiveShapeShift extends PureComponent { } clearContinuousFetch() { + /// $FlowFixMe clearInterval(this.continousFetch); + // $FlowFixMe this.continousFetch = null; } @@ -42,7 +60,7 @@ export default class ActiveShapeShift extends PureComponent { shiftReturnAddress, shiftOrderId, shiftState, - shiftDepositLimit, + originCoinDepositMax, clearShapeShift, doShowSnackBar, } = this.props; @@ -54,7 +72,7 @@ export default class ActiveShapeShift extends PureComponent {

Send up to{" "} - {shiftDepositLimit}{" "} + {originCoinDepositMax}{" "} {shiftCoinType} {" "} to the address below. @@ -102,13 +120,15 @@ export default class ActiveShapeShift extends PureComponent { : __("Cancel") } /> - - - + {shiftOrderId && ( + + + + )} {shiftState === statuses.NO_DEPOSITS && shiftReturnAddress && (

@@ -123,3 +143,5 @@ export default class ActiveShapeShift extends PureComponent { ); } } + +export default ActiveShapeShift; diff --git a/src/renderer/js/component/shapeShift/internal/form.jsx b/src/renderer/js/component/shapeShift/internal/form.jsx index bd1925738..58d17b10c 100644 --- a/src/renderer/js/component/shapeShift/internal/form.jsx +++ b/src/renderer/js/component/shapeShift/internal/form.jsx @@ -2,25 +2,48 @@ import React from "react"; import Link from "component/link"; import { getExampleAddress } from "util/shape_shift"; import { Submit, FormRow } from "component/form"; +import type { ShapeShiftFormValues, Dispatch } from "redux/actions/shape_shift"; -export default ({ - values, - errors, - touched, - handleChange, - handleBlur, - handleSubmit, - resetForm, - isSubmitting, - shiftSupportedCoins, - originCoin, - updating, - getCoinStats, - receiveAddress, - originCoinDepositMax, - originCoinDepositMin, - originCoinDepositFee, -}) => { +type ShapeShiftFormErrors = { + returnAddress?: string, +}; + +type Props = { + values: ShapeShiftFormValues, + errors: ShapeShiftFormErrors, + touched: boolean, + handleChange: Event => any, + handleBlur: Event => any, + handleSubmit: Event => any, + isSubmitting: boolean, + shiftSupportedCoins: Array, + originCoin: string, + updating: boolean, + getCoinStats: Dispatch, + receiveAddress: string, + originCoinDepositFee: number, + originCoinDepositMin: string, + originCoinDepositMax: number, +}; + +export default (props: Props) => { + const { + values, + errors, + touched, + handleChange, + handleBlur, + handleSubmit, + isSubmitting, + shiftSupportedCoins, + originCoin, + updating, + getCoinStats, + receiveAddress, + originCoinDepositMax, + originCoinDepositMin, + originCoinDepositFee, + } = props; return (
diff --git a/src/renderer/js/component/shapeShift/view.jsx b/src/renderer/js/component/shapeShift/view.jsx index f2991863f..8ca97e9c3 100644 --- a/src/renderer/js/component/shapeShift/view.jsx +++ b/src/renderer/js/component/shapeShift/view.jsx @@ -1,4 +1,5 @@ -import React from "react"; +// @flow +import * as React from "react"; import { shell } from "electron"; import { Formik } from "formik"; import classnames from "classnames"; @@ -8,9 +9,23 @@ import Link from "component/link"; import Spinner from "component/common/spinner"; import { BusyMessage } from "component/common"; import ShapeShiftForm from "./internal/form"; -import ActiveShift from "./internal/active-shift"; +import ActiveShapeShift from "./internal/active-shift"; -class ShapeShift extends React.PureComponent { +import type { ShapeShiftState } from "redux/reducers/shape_shift"; +import type { Dispatch, ShapeShiftFormValues } from "redux/actions/shape_shift"; + +type Props = { + shapeShift: ShapeShiftState, + getCoinStats: Dispatch, + createShapeShift: Dispatch, + clearShapeShift: Dispatch, + getActiveShift: Dispatch, + doShowSnackBar: Dispatch, + shapeShiftInit: Dispatch, + receiveAddress: string, +}; + +class ShapeShift extends React.PureComponent { componentDidMount() { const { shapeShiftInit, @@ -49,11 +64,15 @@ class ShapeShift extends React.PureComponent { shiftReturnAddress, shiftCoinType, shiftOrderId, - cancelShapeShift, shiftState, - origin, } = shapeShift; + const initialFormValues: ShapeShiftFormValues = { + receiveAddress, + originCoin: "BTC", + returnAddress: "", + }; + return ( // add the "shapeshift__intital-wrapper class so we can avoid content jumping once everything loads" // it just gives the section a min-height equal to the height of the content when the form is rendered @@ -85,11 +104,7 @@ class ShapeShift extends React.PureComponent { ( )} {hasActiveShift && ( - dispatch => { +// All ShapeShift actions +// Action types defined in the reducer will contain some payload +export type Action = + | { type: types.GET_SUPPORTED_COINS_START } + | { type: types.GET_SUPPORTED_COINS_FAIL } + | GetSupportedCoinsSuccess + | GetCoinStatsStart + | { type: types.GET_COIN_STATS_START } + | GetCoinStatsFail + | GetCoinStatsSuccess + | { type: types.PREPARE_SHAPE_SHIFT_START } + | PrepareShapeShiftFail + | PrepareShapeShiftSuccess + | { type: types.GET_ACTIVE_SHIFT_START } + | GetActiveShiftFail + | GetActiveShiftSuccess; + +// Basic thunk types +// It would be nice to import these from types/common +// Not sure how that would work since they rely on the Action type +type PromiseAction = Promise; +type ThunkAction = (dispatch: Dispatch) => any; +export type Dispatch = ( + action: Action | ThunkAction | PromiseAction | Array +) => any; + +// ShapeShift form values +export type ShapeShiftFormValues = { + originCoin: string, + returnAddress: ?string, + receiveAddress: string, +}; + +export const shapeShiftInit = () => (dispatch: Dispatch): ThunkAction => { dispatch({ type: types.GET_SUPPORTED_COINS_START }); return shapeShift @@ -34,8 +79,9 @@ export const shapeShiftInit = () => dispatch => { ); }; -export const getCoinStats = coin => dispatch => { - // TODO: get ShapeShift fee +export const getCoinStats = (coin: string) => ( + dispatch: Dispatch +): ThunkAction => { const pair = `${coin.toLowerCase()}_lbc`; dispatch({ type: types.GET_COIN_STATS_START, data: coin }); @@ -48,7 +94,10 @@ export const getCoinStats = coin => dispatch => { .catch(err => dispatch({ type: types.GET_COIN_STATS_FAIL, data: err })); }; -export const createShapeShift = (values, actions) => dispatch => { +export const createShapeShift = ( + values: ShapeShiftFormValues, + actions: FormikActions +) => (dispatch: Dispatch): ThunkAction => { const { originCoin, returnAddress, @@ -68,12 +117,14 @@ export const createShapeShift = (values, actions) => dispatch => { ) .catch(err => { dispatch({ type: types.PREPARE_SHAPE_SHIFT_FAIL, data: err }); - // for formik + // for formik to stop the submit actions.setSubmitting(false); }); }; -export const getActiveShift = depositAddress => dispatch => { +export const getActiveShift = (depositAddress: string) => ( + dispatch: Dispatch +): ThunkAction => { dispatch({ type: types.GET_ACTIVE_SHIFT_START }); return shapeShift @@ -82,5 +133,5 @@ export const getActiveShift = depositAddress => dispatch => { .catch(err => dispatch({ type: types.GET_ACTIVE_SHIFT_FAIL, data: err })); }; -export const clearShapeShift = () => dispatch => +export const clearShapeShift = () => (dispatch: Dispatch): Action => dispatch({ type: types.CLEAR_SHAPE_SHIFT }); diff --git a/src/renderer/js/redux/reducers/shape_shift.js b/src/renderer/js/redux/reducers/shape_shift.js index dd44378f0..78542f48e 100644 --- a/src/renderer/js/redux/reducers/shape_shift.js +++ b/src/renderer/js/redux/reducers/shape_shift.js @@ -1,14 +1,88 @@ +// @flow import { handleActions } from "util/redux-utils"; -import * as types from "constants/action_types"; +import * as actions from "constants/action_types"; import * as statuses from "constants/shape_shift"; -const defaultState = { +export type ShapeShiftState = { + loading: boolean, + updating: boolean, + shiftSupportedCoins: Array, + hasActiveShift: boolean, + originCoin: ?string, + error: ?string, + shiftDepositAddress: ?string, + shiftReturnAddress: ?string, + shiftCoinType: ?string, + shiftOrderId: ?string, + shiftState: ?string, + originCoinDepositMax: ?number, + // originCoinDepositMin is a string because we need to convert it from scientifc notation + // it will usually be something like 0.00000001 coins + // using Number(x) or parseInt(x) will either change it back to scientific notation or round to zero + originCoinDepositMin: ?string, + originCoinDepositFee: ?number, +}; + +// All ShapeShift actions that will have some payload +export type GetSupportedCoinsSuccess = { + type: actions.GET_SUPPORTED_COINS_SUCCESS, + data: Array, +}; +export type GetCoinStatsStart = { + type: actions.GET_SUPPORTED_COINS_SUCCESS, + data: string, +}; +export type GetCoinStatsSuccess = { + type: actions.GET_COIN_STATS_SUCCESS, + data: ShapeShiftMarketInfo, +}; +export type GetCoinStatsFail = { + type: actions.GET_COIN_STATS_FAIL, + data: string, +}; +export type PrepareShapeShiftSuccess = { + type: actions.PREPARE_SHAPE_SHIFT_SUCCESS, + data: ActiveShiftInfo, +}; +export type PrepareShapeShiftFail = { + type: actions.PREPARE_SHAPE_SHIFT_FAIL, + data: ShapeShiftErrorResponse, +}; +export type GetActiveShiftSuccess = { + type: actions.GET_ACTIVE_SHIFT_SUCCESS, + data: string, +}; +export type GetActiveShiftFail = { + type: actions.GET_ACTIVE_SHIFT_FAIL, + data: ShapeShiftErrorResponse, +}; + +// ShapeShift sub-types +// Defined for actions that contain an object in the payload +type ShapeShiftMarketInfo = { + limit: number, + minimum: number, + minerFee: number, +}; + +type ActiveShiftInfo = { + deposit: string, + depositType: string, + returnAddress: string, + orderId: string, +}; + +type ShapeShiftErrorResponse = { + message: string, +}; + +const defaultState: ShapeShiftState = { loading: true, updating: false, - error: undefined, shiftSupportedCoins: [], - originCoin: undefined, hasActiveShift: false, + originCoin: undefined, + error: undefined, shiftDepositAddress: undefined, // shapeshift address to send your coins to shiftReturnAddress: undefined, shiftCoinType: undefined, @@ -21,61 +95,108 @@ const defaultState = { export default handleActions( { - [types.GET_SUPPORTED_COINS_START]: () => ({ + [actions.GET_SUPPORTED_COINS_START]: ( + state: ShapeShiftState + ): ShapeShiftState => ({ + ...state, loading: true, error: undefined, }), - [types.GET_SUPPORTED_COINS_SUCCESS]: ( - state, - { data: shiftSupportedCoins } - ) => ({ - error: undefined, - shiftSupportedCoins, - }), - [types.GET_SUPPORTED_COINS_FAIL]: () => ({ + [actions.GET_SUPPORTED_COINS_SUCCESS]: ( + state: ShapeShiftState, + action: GetSupportedCoinsSuccess + ): ShapeShiftState => { + const shiftSupportedCoins = action.data; + return { + ...state, + error: undefined, + shiftSupportedCoins, + }; + }, + [actions.GET_SUPPORTED_COINS_FAIL]: ( + state: ShapeShiftState + ): ShapeShiftState => ({ + ...state, loading: false, - error: true, + error: "Error getting available coins", }), - [types.GET_COIN_STATS_START]: (state, { data: coin }) => ({ - updating: true, - originCoin: coin, - }), - [types.GET_COIN_STATS_SUCCESS]: (state, { data: marketInfo }) => ({ - loading: false, - updating: false, - originCoinDepositMax: marketInfo.limit, - // this will come in scientific notation - // toFixed shows the real number, then regex to remove trailing zeros - originCoinDepositMin: marketInfo.minimum - .toFixed(10) - .replace(/\.?0+$/, ""), - originCoinDepositFee: marketInfo.minerFee, - }), - [types.GET_COIN_STATS_FAIL]: (state, { data: error }) => ({ - loading: false, - error, - }), + [actions.GET_COIN_STATS_START]: ( + state: ShapeShiftState, + action: GetCoinStatsStart + ): ShapeShiftState => { + const coin = action.data; + return { + ...state, + updating: true, + originCoin: coin, + }; + }, + [actions.GET_COIN_STATS_SUCCESS]: ( + state: ShapeShiftState, + action: GetCoinStatsSuccess + ): ShapeShiftState => { + const marketInfo: ShapeShiftMarketInfo = action.data; - [types.PREPARE_SHAPE_SHIFT_START]: () => ({ + return { + ...state, + loading: false, + updating: false, + originCoinDepositMax: marketInfo.limit, + // this will come in scientific notation + // toFixed shows the real number, then regex to remove trailing zeros + originCoinDepositMin: marketInfo.minimum + .toFixed(10) + .replace(/\.?0+$/, ""), + originCoinDepositFee: marketInfo.minerFee, + }; + }, + [actions.GET_COIN_STATS_FAIL]: ( + state: ShapeShiftState, + action: GetCoinStatsFail + ): ShapeShiftState => { + const error = action.data; + return { + ...state, + loading: false, + error, + }; + }, + + [actions.PREPARE_SHAPE_SHIFT_START]: ( + state: ShapeShiftState + ): ShapeShiftState => ({ + ...state, error: undefined, }), - [types.PREPARE_SHAPE_SHIFT_SUCCESS]: ( - state, - { data: { deposit, depositType, returnAddress, orderId } } - ) => ({ - hasActiveShift: true, - shiftDepositAddress: deposit, - shiftCoinType: depositType, - shiftReturnAddress: returnAddress, - shiftOrderId: orderId, - shiftState: statuses.NO_DEPOSITS, - }), - [types.PREPARE_SHAPE_SHIFT_FAIL]: (state, { data: error }) => ({ - error: error.message, - }), + [actions.PREPARE_SHAPE_SHIFT_SUCCESS]: ( + state: ShapeShiftState, + action: PrepareShapeShiftSuccess + ) => { + const activeShiftInfo: ActiveShiftInfo = action.data; + return { + ...state, + hasActiveShift: true, + shiftDepositAddress: activeShiftInfo.deposit, + shiftCoinType: activeShiftInfo.depositType, + shiftReturnAddress: activeShiftInfo.returnAddress, + shiftOrderId: activeShiftInfo.orderId, + shiftState: statuses.NO_DEPOSITS, + }; + }, + [actions.PREPARE_SHAPE_SHIFT_FAIL]: ( + state: ShapeShiftState, + action: PrepareShapeShiftFail + ) => { + const error: ShapeShiftErrorResponse = action.data; + return { + ...state, + error: error.message, + }; + }, - [types.CLEAR_SHAPE_SHIFT]: () => ({ + [actions.CLEAR_SHAPE_SHIFT]: (state: ShapeShiftState): ShapeShiftState => ({ + ...state, loading: false, updating: false, hasActiveShift: false, @@ -83,21 +204,38 @@ export default handleActions( shiftReturnAddress: undefined, shiftCoinType: undefined, shiftOrderId: undefined, - originCoin: "BTC", + originCoin: state.shiftSupportedCoins[0], }), - [types.GET_ACTIVE_SHIFT_START]: () => ({ + [actions.GET_ACTIVE_SHIFT_START]: ( + state: ShapeShiftState + ): ShapeShiftState => ({ + ...state, error: undefined, updating: true, }), - [types.GET_ACTIVE_SHIFT_SUCCESS]: (state, { data: status }) => ({ - updating: false, - shiftState: status, - }), - [types.GET_ACTIVE_SHIFT_FAIL]: (state, { data: error }) => ({ - updating: false, - error: error.message, - }), + [actions.GET_ACTIVE_SHIFT_SUCCESS]: ( + state: ShapeShiftState, + action: GetActiveShiftSuccess + ): ShapeShiftState => { + const status = action.data; + return { + ...state, + updating: false, + shiftState: status, + }; + }, + [actions.GET_ACTIVE_SHIFT_FAIL]: ( + state: ShapeShiftState, + action: GetActiveShiftFail + ): ShapeShiftState => { + const error: ShapeShiftErrorResponse = action.data; + return { + ...state, + updating: false, + error: error.message, + }; + }, }, defaultState ); diff --git a/src/renderer/js/types/common.js b/src/renderer/js/types/common.js new file mode 100644 index 000000000..ea8c0d815 --- /dev/null +++ b/src/renderer/js/types/common.js @@ -0,0 +1,3 @@ +export type FormikActions = { + setSubmitting: boolean => mixed, +}; diff --git a/src/renderer/js/util/redux-utils.js b/src/renderer/js/util/redux-utils.js index 6875ec550..17aa4fdaf 100644 --- a/src/renderer/js/util/redux-utils.js +++ b/src/renderer/js/util/redux-utils.js @@ -1,6 +1,7 @@ // util for creating reducers // based off of redux-actions // https://redux-actions.js.org/docs/api/handleAction.html#handleactions + export const handleActions = (actionMap, defaultState) => { return (state = defaultState, action) => { const handler = actionMap[action.type]; From 6aefb0653db0971809cd9db1ac1303c7161206c8 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Sun, 3 Dec 2017 22:31:35 -0500 Subject: [PATCH 03/14] add faq link --- src/renderer/js/component/shapeShift/view.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/js/component/shapeShift/view.jsx b/src/renderer/js/component/shapeShift/view.jsx index 8ca97e9c3..678cdaf7a 100644 --- a/src/renderer/js/component/shapeShift/view.jsx +++ b/src/renderer/js/component/shapeShift/view.jsx @@ -87,7 +87,7 @@ class ShapeShift extends React.PureComponent {

{__("Convert Crypto to LBC")}

{__("Powered by ShapeShift. Read our FAQ")}{" "} - {__("here")}. + {__("here")}. {hasActiveShift && shiftState !== "complete" && ( {__("This will update automatically.")} From a7e788fd16ac43b5735f5e3e4d5a6cdd55f36307 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Sun, 3 Dec 2017 22:41:15 -0500 Subject: [PATCH 04/14] remove unused style --- src/renderer/scss/component/_header.scss | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/renderer/scss/component/_header.scss b/src/renderer/scss/component/_header.scss index e1ec0a1fa..bdc72dcbd 100644 --- a/src/renderer/scss/component/_header.scss +++ b/src/renderer/scss/component/_header.scss @@ -63,8 +63,3 @@ border-color: var(--color-primary); } } - -.wunderbar__input--shapeshift { - padding-left: 5px; - margin-top: 5px; -} From d0432330949f1c646fc0c677ce9dce0751bbb331 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Mon, 4 Dec 2017 11:49:10 -0500 Subject: [PATCH 05/14] use common styles --- .../js/component/shapeShift/internal/active-shift.jsx | 7 +++---- src/renderer/js/component/shapeShift/internal/form.jsx | 4 ++-- src/renderer/scss/_gui.scss | 5 ----- src/renderer/scss/component/_card.scss | 9 ++++++++- src/renderer/scss/component/_shapeshift.scss | 10 +--------- 5 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/renderer/js/component/shapeShift/internal/active-shift.jsx b/src/renderer/js/component/shapeShift/internal/active-shift.jsx index cd8577261..baab82194 100644 --- a/src/renderer/js/component/shapeShift/internal/active-shift.jsx +++ b/src/renderer/js/component/shapeShift/internal/active-shift.jsx @@ -72,8 +72,7 @@ class ActiveShapeShift extends React.PureComponent {

Send up to{" "} - {originCoinDepositMax}{" "} - {shiftCoinType} + {originCoinDepositMax} {shiftCoinType} {" "} to the address below.

@@ -109,9 +108,9 @@ class ActiveShapeShift extends React.PureComponent {

)} -
+
{ onBlur={handleBlur} value={values.returnAddress} errorMessage={errors.returnAddress} - hasError={touched.returnAddress && errors.returnAddress} + hasError={touched.returnAddress && !!errors.returnAddress} /> @@ -95,7 +95,7 @@ export default (props: Props) => { {__("to this address if the transaction doesn't go through.")} -
+
Date: Mon, 4 Dec 2017 12:18:34 -0500 Subject: [PATCH 06/14] show shapeshift rate --- .../shapeShift/internal/active-shift.jsx | 15 ++++++++ .../js/component/shapeShift/internal/form.jsx | 21 +++++++----- .../shapeShift/internal/market_info.jsx | 34 +++++++++++++++++++ src/renderer/js/component/shapeShift/view.jsx | 8 +++++ src/renderer/js/redux/reducers/shape_shift.js | 4 +++ 5 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 src/renderer/js/component/shapeShift/internal/market_info.jsx diff --git a/src/renderer/js/component/shapeShift/internal/active-shift.jsx b/src/renderer/js/component/shapeShift/internal/active-shift.jsx index baab82194..79e691ddb 100644 --- a/src/renderer/js/component/shapeShift/internal/active-shift.jsx +++ b/src/renderer/js/component/shapeShift/internal/active-shift.jsx @@ -5,6 +5,7 @@ import * as statuses from "constants/shape_shift"; import Address from "component/address"; import Link from "component/link"; import type { Dispatch } from "redux/actions/shape_shift"; +import ShiftMarketInfo from "./market_info"; type Props = { shiftState: ?string, @@ -16,6 +17,10 @@ type Props = { clearShapeShift: Dispatch, doShowSnackBar: Dispatch, getActiveShift: Dispatch, + shapeShiftRate: ?number, + originCoinDepositMax: ?number, + originCoinDepositFee: ?number, + originCoinDepositMin: ?string, }; class ActiveShapeShift extends React.PureComponent { @@ -63,6 +68,9 @@ class ActiveShapeShift extends React.PureComponent { originCoinDepositMax, clearShapeShift, doShowSnackBar, + shapeShiftRate, + originCoinDepositFee, + originCoinDepositMin, } = this.props; return ( @@ -76,6 +84,13 @@ class ActiveShapeShift extends React.PureComponent { {" "} to the address below.

+
diff --git a/src/renderer/js/component/shapeShift/internal/form.jsx b/src/renderer/js/component/shapeShift/internal/form.jsx index 201bfb394..8a59c3a4c 100644 --- a/src/renderer/js/component/shapeShift/internal/form.jsx +++ b/src/renderer/js/component/shapeShift/internal/form.jsx @@ -3,6 +3,7 @@ import Link from "component/link"; import { getExampleAddress } from "util/shape_shift"; import { Submit, FormRow } from "component/form"; import type { ShapeShiftFormValues, Dispatch } from "redux/actions/shape_shift"; +import ShiftMarketInfo from "./market_info"; type ShapeShiftFormErrors = { returnAddress?: string, @@ -24,6 +25,7 @@ type Props = { originCoinDepositFee: number, originCoinDepositMin: string, originCoinDepositMax: number, + shapeShiftRate: number, }; export default (props: Props) => { @@ -43,6 +45,7 @@ export default (props: Props) => { originCoinDepositMax, originCoinDepositMin, originCoinDepositFee, + shapeShiftRate, } = props; return ( @@ -63,18 +66,18 @@ export default (props: Props) => { ))} {__("for LBC")} -

+

{!updating && originCoinDepositMax && ( - - {__("Exchange max")}: {originCoinDepositMax} {originCoin} -
- {__("Exchange minimun")}: {originCoinDepositMin} {originCoin} -
- {__("Fee")}: {originCoinDepositFee} LBC -
+ )} -

+
{ + const { + shapeShiftRate, + originCoin, + originCoinDepositFee, + originCoinDepositMax, + originCoinDepositMin, + } = props; + + return ( +
+ + {__("Receive")} {shapeShiftRate} LBC + {" / "} + {"1"} {originCoin} {__("less")} {originCoinDepositFee} LBC {__("fee")}. +
+ {__("Exchange max")}: {originCoinDepositMax} {originCoin} +
+ {__("Exchange min")}: {originCoinDepositMin} {originCoin} +
+
+ ); +}; diff --git a/src/renderer/js/component/shapeShift/view.jsx b/src/renderer/js/component/shapeShift/view.jsx index 678cdaf7a..a90a203cb 100644 --- a/src/renderer/js/component/shapeShift/view.jsx +++ b/src/renderer/js/component/shapeShift/view.jsx @@ -65,6 +65,7 @@ class ShapeShift extends React.PureComponent { shiftCoinType, shiftOrderId, shiftState, + shapeShiftRate, } = shapeShift; const initialFormValues: ShapeShiftFormValues = { @@ -116,6 +117,8 @@ class ShapeShift extends React.PureComponent { originCoinDepositMax={originCoinDepositMax} originCoinDepositMin={originCoinDepositMin} originCoinDepositFee={originCoinDepositFee} + shapeShiftRate={shapeShiftRate} + updating={updating} /> )} /> @@ -131,6 +134,11 @@ class ShapeShift extends React.PureComponent { shiftState={shiftState} clearShapeShift={clearShapeShift} doShowSnackBar={doShowSnackBar} + originCoinDepositMax={originCoinDepositMax} + originCoinDepositMin={originCoinDepositMin} + originCoinDepositFee={originCoinDepositFee} + shapeShiftRate={shapeShiftRate} + updating={updating} /> )}
diff --git a/src/renderer/js/redux/reducers/shape_shift.js b/src/renderer/js/redux/reducers/shape_shift.js index 78542f48e..71b59addd 100644 --- a/src/renderer/js/redux/reducers/shape_shift.js +++ b/src/renderer/js/redux/reducers/shape_shift.js @@ -21,6 +21,7 @@ export type ShapeShiftState = { // using Number(x) or parseInt(x) will either change it back to scientific notation or round to zero originCoinDepositMin: ?string, originCoinDepositFee: ?number, + shapeShiftRate: ?number, }; // All ShapeShift actions that will have some payload @@ -63,6 +64,7 @@ type ShapeShiftMarketInfo = { limit: number, minimum: number, minerFee: number, + rate: number, }; type ActiveShiftInfo = { @@ -91,6 +93,7 @@ const defaultState: ShapeShiftState = { originCoinDepositMax: undefined, originCoinDepositMin: undefined, originCoinDepositFee: undefined, + shapeShiftRate: undefined, }; export default handleActions( @@ -149,6 +152,7 @@ export default handleActions( .toFixed(10) .replace(/\.?0+$/, ""), originCoinDepositFee: marketInfo.minerFee, + shapeShiftRate: marketInfo.rate, }; }, [actions.GET_COIN_STATS_FAIL]: ( From 6f4e35ac90228d1763fba3a46992e363fef7e239 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Mon, 4 Dec 2017 18:32:11 -0500 Subject: [PATCH 07/14] fix flow usage for continousFetch --- .../component/shapeShift/internal/active-shift.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/renderer/js/component/shapeShift/internal/active-shift.jsx b/src/renderer/js/component/shapeShift/internal/active-shift.jsx index 79e691ddb..40e5cad40 100644 --- a/src/renderer/js/component/shapeShift/internal/active-shift.jsx +++ b/src/renderer/js/component/shapeShift/internal/active-shift.jsx @@ -24,9 +24,10 @@ type Props = { }; class ActiveShapeShift extends React.PureComponent { + continousFetch: ?number; + constructor() { super(); - // $FlowFixMe this.continousFetch = undefined; } @@ -34,7 +35,6 @@ class ActiveShapeShift extends React.PureComponent { const { getActiveShift, shiftDepositAddress } = this.props; getActiveShift(shiftDepositAddress); - // $FlowFixMe this.continousFetch = setInterval(() => { getActiveShift(shiftDepositAddress); }, 10000); @@ -52,10 +52,10 @@ class ActiveShapeShift extends React.PureComponent { } clearContinuousFetch() { - /// $FlowFixMe - clearInterval(this.continousFetch); - // $FlowFixMe - this.continousFetch = null; + if (this.continousFetch) { + clearInterval(this.continousFetch); + this.continousFetch = null; + } } render() { From 62889a9f8a839a213f671ce6e745c78ee01770e4 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Tue, 5 Dec 2017 00:04:00 -0800 Subject: [PATCH 08/14] Added navigation logging --- src/renderer/js/main.js | 18 +- src/renderer/js/redux/reducers/navigation.js | 11 +- src/renderer/package.json | 1 + src/renderer/yarn.lock | 314 ++++++++++++++----- 4 files changed, 257 insertions(+), 87 deletions(-) diff --git a/src/renderer/js/main.js b/src/renderer/js/main.js index 759b2a179..cd691a62a 100644 --- a/src/renderer/js/main.js +++ b/src/renderer/js/main.js @@ -9,6 +9,8 @@ import { doDaemonReady } from "redux/actions/app"; import { doNavigate } from "redux/actions/navigation"; import { doDownloadLanguages } from "redux/actions/settings"; import * as types from "constants/action_types"; +import amplitude from "amplitude-js"; +import lbry from "lbry.js"; const env = ENV; const { remote, ipcRenderer, shell } = require("electron"); @@ -48,6 +50,9 @@ ipcRenderer.on("window-is-focused", (event, data) => { document.addEventListener("click", event => { var target = event.target; while (target && target !== document) { + if (target.matches("a") || target.matches("button")) { + // TODO: Log event + } if ( target.matches('a[href^="http"]') || target.matches('a[href^="mailto"]') @@ -92,4 +97,15 @@ var init = function() { } }; -init(); +lbry.status({ session_status: true }).then(info => { + amplitude + .getInstance() + .init( + "0b130efdcbdbf86ec2f7f9eff354033e", + null, + { deviceId: info.lbry_id }, + function() { + init(); + } + ); +}); diff --git a/src/renderer/js/redux/reducers/navigation.js b/src/renderer/js/redux/reducers/navigation.js index 00453f9de..e32658b76 100644 --- a/src/renderer/js/redux/reducers/navigation.js +++ b/src/renderer/js/redux/reducers/navigation.js @@ -1,5 +1,6 @@ import * as types from "constants/action_types"; import { parseQueryParams } from "util/query_params"; +import amplitude from "amplitude-js"; const currentPath = () => { const hash = document.location.hash; @@ -69,6 +70,14 @@ reducers[types.WINDOW_SCROLLED] = (state, action) => { export default function reducer(state = defaultState, action) { const handler = reducers[action.type]; - if (handler) return handler(state, action); + if (handler) { + let nextState = handler(state, action); + if (nextState.currentPath !== state.currentPath) { + amplitude + .getInstance() + .logEvent("NAVIGATION", { destination: nextState.currentPath }); + } + return nextState; + } return state; } diff --git a/src/renderer/package.json b/src/renderer/package.json index 4a6e9f03e..50e40f883 100644 --- a/src/renderer/package.json +++ b/src/renderer/package.json @@ -22,6 +22,7 @@ }, "homepage": "https://github.com/lbryio/lbry-app", "dependencies": { + "amplitude-js": "^4.0.0", "from2": "^2.3.0", "jshashes": "^1.0.7", "localforage": "^1.5.0", diff --git a/src/renderer/yarn.lock b/src/renderer/yarn.lock index d7049810b..6faa612e4 100644 --- a/src/renderer/yarn.lock +++ b/src/renderer/yarn.lock @@ -2,6 +2,13 @@ # yarn lockfile v1 +"@segment/top-domain@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@segment/top-domain/-/top-domain-3.0.0.tgz#02e5a5a4fd42a9f6cf886b05e82f104012a3c3a7" + dependencies: + component-cookie "^1.1.2" + component-url "^0.2.1" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -56,9 +63,9 @@ ajv@^4.7.0, ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.0.0, ajv@^5.1.5, ajv@^5.2.3: - version "5.4.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.4.0.tgz#32d1cf08dbc80c432f426f12e10b2511f6b46474" +ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5, ajv@^5.2.3: + version "5.5.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.0.tgz#eb2840746e9dc48bd5e063a36e3fd400c5eab5a9" dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" @@ -81,6 +88,16 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" +amplitude-js@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/amplitude-js/-/amplitude-js-4.0.0.tgz#70bbc0ec893b01d00453d3765f78bc0f32a395cc" + dependencies: + "@segment/top-domain" "^3.0.0" + blueimp-md5 "^2.10.0" + json3 "^3.3.2" + lodash "^4.17.4" + ua-parser-js "github:amplitude/ua-parser-js#ed538f1" + ansi-escapes@^1.0.0, ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -276,7 +293,11 @@ aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" -aws4@^1.2.1: +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" @@ -997,6 +1018,10 @@ block-stream@*: dependencies: inherits "~2.0.0" +blueimp-md5@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.10.0.tgz#02f0843921f90dca14f5b8920a38593201d6964d" + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -1033,6 +1058,18 @@ boom@2.x.x: dependencies: hoek "2.x.x" +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" @@ -1198,8 +1235,8 @@ caniuse-api@^1.5.2: lodash.uniq "^4.5.0" caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000769" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000769.tgz#c230b9c1b9e8db3e1c0d858c96e685741b96cc10" + version "1.0.30000777" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000777.tgz#2e19adba63bdd7c501df637a862adead7f4bc054" cardinal@^1.0.0: version "1.0.0" @@ -1376,8 +1413,8 @@ codemirror-spell-checker@*: typo-js "*" codemirror@*: - version "5.31.0" - resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.31.0.tgz#ecf3d057eb74174147066bfc7c5f37b4c4e07df2" + version "5.32.0" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.32.0.tgz#cb6ff5d8ef36d0b10f031130e2d9ebeee92c902e" color-convert@^1.3.0, color-convert@^1.9.0: version "1.9.1" @@ -1426,8 +1463,8 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: delayed-stream "~1.0.0" commander@^2.11.0, commander@^2.5.0, commander@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" commondir@^1.0.1: version "1.0.1" @@ -1464,6 +1501,16 @@ commonmark@^0.24.0: mdurl "~ 1.0.1" string.prototype.repeat "^0.2.0" +component-cookie@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/component-cookie/-/component-cookie-1.1.3.tgz#053e14a3bd7748154f55724fd39a60c01994ebed" + dependencies: + debug "*" + +component-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/component-url/-/component-url-0.2.1.tgz#4e4f4799c43ead9fd3ce91b5a305d220208fee47" + compressible@~2.0.11: version "2.0.12" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66" @@ -1525,8 +1572,8 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" convert-source-map@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" cookie-signature@1.0.6: version "1.0.6" @@ -1613,6 +1660,12 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + crypto-browserify@3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.3.0.tgz#b9fc75bb4a0ed61dcf1cd5dae96eb30c9c3e506c" @@ -1747,15 +1800,15 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.5.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" +debug@*, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" -debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" +debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.5.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" @@ -1849,18 +1902,18 @@ detect-indent@^4.0.0: repeating "^2.0.0" detect-libc@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.2.tgz#71ad5d204bf17a6a6ca8f450c61454066ef461e1" + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" detect-node@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" detective@^4.3.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" + version "4.7.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.0.tgz#6276e150f9e50829ad1f90ace4d9a2304188afcf" dependencies: - acorn "^4.0.3" + acorn "^5.2.1" defined "^1.0.0" diffie-hellman@^5.0.0: @@ -1896,11 +1949,10 @@ doctrine@1.5.0, doctrine@^1.2.2: isarray "^1.0.0" doctrine@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" + version "2.0.2" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" dependencies: esutils "^2.0.2" - isarray "^1.0.0" domain-browser@^1.1.1: version "1.1.7" @@ -2015,8 +2067,8 @@ error-ex@^1.2.0: is-arrayish "^0.2.1" es-abstract@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" + version "1.10.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -2041,8 +2093,8 @@ es3ify@^0.1.3: through "~2.3.4" es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.35" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.35.tgz#18ee858ce6a3c45c7d79e91c15fcca9ec568494f" + version "0.10.37" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" dependencies: es6-iterator "~2.0.1" es6-symbol "~3.1.1" @@ -2340,7 +2392,7 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -express@^4.13.3: +express@^4.16.2: version "4.16.2" resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" dependencies: @@ -2375,7 +2427,7 @@ express@^4.13.3: utils-merge "1.0.1" vary "~1.1.2" -extend@~3.0.0: +extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -2593,6 +2645,14 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -2847,6 +2907,10 @@ har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + har-validator@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" @@ -2863,6 +2927,13 @@ har-validator@~4.2.1: ajv "^4.9.1" har-schema "^1.0.5" +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -2926,6 +2997,15 @@ hawk@3.1.3, hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2938,6 +3018,10 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + hoist-non-react-statics@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" @@ -3011,6 +3095,14 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" @@ -3151,8 +3243,8 @@ interpret@^0.6.4: resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" interpret@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" invariant@^2.0.0, invariant@^2.2.2: version "2.2.2" @@ -3300,8 +3392,8 @@ is-path-in-cwd@^1.0.0: is-path-inside "^1.0.0" is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" @@ -3404,8 +3496,8 @@ isurl@^1.0.0-alpha5: is-object "^1.0.1" js-base64@^2.1.8, js-base64@^2.1.9: - version "2.3.2" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf" + version "2.4.0" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.0.tgz#9e566fee624751a1d720c966cd6226d29d4025aa" js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" @@ -3673,8 +3765,8 @@ loader-utils@^1.0.2, loader-utils@^1.1.0: json5 "^0.5.0" localforage@^1.5.0: - version "1.5.3" - resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.5.3.tgz#698aa16af1022340b240be9d93192e8af022ff16" + version "1.5.5" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.5.5.tgz#55fc1c3a88a47f67f5fac6f1231b25ff13556423" dependencies: lie "3.0.2" @@ -4027,10 +4119,14 @@ mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, dependencies: mime-db "~1.30.0" -mime@1.4.1, mime@^1.2.11, mime@^1.3.4: +mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime@^1.2.11, mime@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" @@ -4091,8 +4187,8 @@ multicast-dns-service-types@^1.1.0: resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" multicast-dns@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.0.tgz#13f22d0c32dc5ee82a32878e3c380d875b3eab22" + version "6.2.1" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.1.tgz#c5035defa9219d30640558a49298067352098060" dependencies: dns-packet "^1.0.1" thunky "^0.1.0" @@ -4363,7 +4459,7 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -oauth-sign@~0.8.1: +oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -4660,6 +4756,10 @@ performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -4825,8 +4925,8 @@ postcss-minify-selectors@^2.0.4: postcss-selector-parser "^2.0.0" postcss-modules-extract-imports@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz#b614c9720be6816eaee35fb3a5faa1dba6a05ddb" + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" dependencies: postcss "^6.0.1" @@ -5047,7 +5147,7 @@ q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" -qs@6.5.1: +qs@6.5.1, qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" @@ -5123,8 +5223,8 @@ raw-body@2.3.2: unpipe "1.0.0" rc-progress@^2.0.6: - version "2.2.4" - resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-2.2.4.tgz#45dbdb91cdd71cb5ce22e61313a351ceb5b1488a" + version "2.2.5" + resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-2.2.5.tgz#e61d0544bf9d4208e5ba32fc50962159e7f952a3" dependencies: babel-runtime "6.x" prop-types "^15.5.8" @@ -5164,11 +5264,12 @@ react-markdown@^2.5.0: prop-types "^15.5.1" react-modal@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.1.5.tgz#9cfdb7634b5003148ffb7c8ead13a36f671d744e" + version "3.1.6" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.1.6.tgz#82e63f1ec86b80e242518250d066ee37fa035f8a" dependencies: exenv "^1.2.0" prop-types "^15.5.10" + warning "^3.0.0" react-paginate@^5.0.0: version "5.0.0" @@ -5460,32 +5561,34 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2, request@~2.79.0: - version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" +request@2, request@^2.81.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" combined-stream "~1.0.5" - extend "~3.0.0" + extend "~3.0.1" forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" + 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.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - uuid "^3.0.0" + 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" -request@2.81.0, request@^2.81.0: +request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: @@ -5512,6 +5615,31 @@ request@2.81.0, request@^2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" +request@~2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5790,6 +5918,12 @@ sntp@1.x.x: dependencies: hoek "2.x.x" +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + sockjs-client@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" @@ -5991,7 +6125,7 @@ string_decoder@^1.0.0, string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4: +stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -6067,8 +6201,8 @@ svgo@^0.7.0: whet.extend "~0.9.9" symbol-observable@^1.0.1, symbol-observable@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" + version "1.1.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32" table@^3.7.8: version "3.8.3" @@ -6162,7 +6296,7 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" -tough-cookie@~2.3.0: +tough-cookie@~2.3.0, tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: @@ -6233,6 +6367,10 @@ ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" +"ua-parser-js@github:amplitude/ua-parser-js#ed538f1": + version "0.7.10" + resolved "https://codeload.github.com/amplitude/ua-parser-js/tar.gz/ed538f1" + uglify-js@^2.8.29: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -6371,7 +6509,7 @@ uuid@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" -uuid@^3.0.0: +uuid@^3.0.0, uuid@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -6423,6 +6561,12 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + dependencies: + loose-envify "^1.0.0" + watchpack@^0.2.1: version "0.2.9" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" @@ -6453,18 +6597,18 @@ webpack-core@~0.6.9: source-map "~0.4.1" webpack-dev-middleware@^1.11.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709" + version "1.12.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" dependencies: memory-fs "~0.4.1" - mime "^1.3.4" + mime "^1.5.0" path-is-absolute "^1.0.0" range-parser "^1.0.3" time-stamp "^2.0.0" webpack-dev-server@^2.4.4: - version "2.9.4" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.4.tgz#7883e61759c6a4b33e9b19ec4037bd4ab61428d1" + version "2.9.5" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.5.tgz#79336fba0087a66ae491f4869f6545775b18daa8" dependencies: ansi-html "0.0.7" array-includes "^3.0.3" @@ -6474,7 +6618,7 @@ webpack-dev-server@^2.4.4: connect-history-api-fallback "^1.3.0" debug "^3.1.0" del "^3.0.0" - express "^4.13.3" + express "^4.16.2" html-entities "^1.2.0" http-proxy-middleware "~0.17.4" import-local "^0.1.1" @@ -6509,8 +6653,8 @@ webpack-notifier@^1.5.0: strip-ansi "^3.0.1" webpack-sources@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.2.tgz#d0148ec083b3b5ccef1035a6b3ec16442983b27a" + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" dependencies: source-list-map "^2.0.0" source-map "~0.6.1" @@ -6542,8 +6686,8 @@ webpack@^1.12.0: webpack-core "~0.6.9" webpack@^3.0.0: - version "3.8.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.8.1.tgz#b16968a81100abe61608b0153c9159ef8bb2bd83" + version "3.9.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.9.1.tgz#9a60aa544ed5d4d454c069e3f521aa007e02643c" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" From 080dd1c05d341661800a552d18b93ffa12f088c6 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Tue, 5 Dec 2017 00:31:34 -0800 Subject: [PATCH 09/14] Fixed loading screen problem --- src/renderer/js/main.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/renderer/js/main.js b/src/renderer/js/main.js index cd691a62a..ba4eb4c77 100644 --- a/src/renderer/js/main.js +++ b/src/renderer/js/main.js @@ -10,7 +10,6 @@ import { doNavigate } from "redux/actions/navigation"; import { doDownloadLanguages } from "redux/actions/settings"; import * as types from "constants/action_types"; import amplitude from "amplitude-js"; -import lbry from "lbry.js"; const env = ENV; const { remote, ipcRenderer, shell } = require("electron"); @@ -97,15 +96,8 @@ var init = function() { } }; -lbry.status({ session_status: true }).then(info => { - amplitude - .getInstance() - .init( - "0b130efdcbdbf86ec2f7f9eff354033e", - null, - { deviceId: info.lbry_id }, - function() { - init(); - } - ); -}); +amplitude + .getInstance() + .init("0b130efdcbdbf86ec2f7f9eff354033e", null, null, function() { + init(); + }); From 1479b9e4af8878b051c382246d5c07db69088b31 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Tue, 5 Dec 2017 13:05:59 -0800 Subject: [PATCH 10/14] Added user ID logging --- src/renderer/js/main.js | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/renderer/js/main.js b/src/renderer/js/main.js index ba4eb4c77..d6f02341a 100644 --- a/src/renderer/js/main.js +++ b/src/renderer/js/main.js @@ -10,6 +10,7 @@ import { doNavigate } from "redux/actions/navigation"; import { doDownloadLanguages } from "redux/actions/settings"; import * as types from "constants/action_types"; import amplitude from "amplitude-js"; +import lbry from "lbry"; const env = ENV; const { remote, ipcRenderer, shell } = require("electron"); @@ -70,18 +71,29 @@ var init = function() { app.store.dispatch(doDownloadLanguages()); function onDaemonReady() { - window.sessionStorage.setItem("loaded", "y"); //once we've made it here once per session, we don't need to show splash again - app.store.dispatch(doDaemonReady()); + lbry.status().then(info => { + amplitude + .getInstance() + .init( + "0b130efdcbdbf86ec2f7f9eff354033e", + info.lbry_id, + null, + function() { + window.sessionStorage.setItem("loaded", "y"); //once we've made it here once per session, we don't need to show splash again + app.store.dispatch(doDaemonReady()); - ReactDOM.render( - -
- - -
-
, - canvas - ); + ReactDOM.render( + +
+ + +
+
, + canvas + ); + } + ); + }); } if (window.sessionStorage.getItem("loaded") == "y") { @@ -96,8 +108,4 @@ var init = function() { } }; -amplitude - .getInstance() - .init("0b130efdcbdbf86ec2f7f9eff354033e", null, null, function() { - init(); - }); +init(); From f80a13e8eae20dbc84560a74f476525bff79e74d Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Tue, 5 Dec 2017 16:16:54 -0800 Subject: [PATCH 11/14] Log all clicks --- src/renderer/js/main.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/renderer/js/main.js b/src/renderer/js/main.js index d6f02341a..4bfd824e9 100644 --- a/src/renderer/js/main.js +++ b/src/renderer/js/main.js @@ -51,7 +51,25 @@ document.addEventListener("click", event => { var target = event.target; while (target && target !== document) { if (target.matches("a") || target.matches("button")) { - // TODO: Log event + // TODO: Look into using accessiblity labels (this would also make the app more accessible) + let hrefParts = window.location.href.split("#"); + let element = target.title || target.text.trim(); + if (element) { + amplitude + .getInstance() + .logEvent("CLICK", { + target: element, + location: + hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : "/", + }); + } else { + amplitude + .getInstance() + .logEvent("UNMARKED_CLICK", { + location: + hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : "/", + }); + } } if ( target.matches('a[href^="http"]') || From 17b38d687be8a29611e687b235b39f9709e174c9 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Tue, 5 Dec 2017 19:41:24 -0500 Subject: [PATCH 12/14] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1273376a1..9de0e171f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Web UI version numbers should always match the corresponding version of LBRY App ## [Unreleased] ### Added - * + * ShapeShift integration * ### Changed From 920a54c810e49f0b98e109d807537f1054be6ef0 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Tue, 5 Dec 2017 17:16:06 -0800 Subject: [PATCH 13/14] Added comment to indicate API key --- src/renderer/js/main.js | 61 +++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/src/renderer/js/main.js b/src/renderer/js/main.js index 4bfd824e9..9c63a17f0 100644 --- a/src/renderer/js/main.js +++ b/src/renderer/js/main.js @@ -55,20 +55,16 @@ document.addEventListener("click", event => { let hrefParts = window.location.href.split("#"); let element = target.title || target.text.trim(); if (element) { - amplitude - .getInstance() - .logEvent("CLICK", { - target: element, - location: - hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : "/", - }); + amplitude.getInstance().logEvent("CLICK", { + target: element, + location: + hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : "/", + }); } else { - amplitude - .getInstance() - .logEvent("UNMARKED_CLICK", { - location: - hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : "/", - }); + amplitude.getInstance().logEvent("UNMARKED_CLICK", { + location: + hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : "/", + }); } } if ( @@ -90,27 +86,26 @@ var init = function() { function onDaemonReady() { lbry.status().then(info => { - amplitude - .getInstance() - .init( - "0b130efdcbdbf86ec2f7f9eff354033e", - info.lbry_id, - null, - function() { - window.sessionStorage.setItem("loaded", "y"); //once we've made it here once per session, we don't need to show splash again - app.store.dispatch(doDaemonReady()); + amplitude.getInstance().init( + // Amplitude API Key + "0b130efdcbdbf86ec2f7f9eff354033e", + info.lbry_id, + null, + function() { + window.sessionStorage.setItem("loaded", "y"); //once we've made it here once per session, we don't need to show splash again + app.store.dispatch(doDaemonReady()); - ReactDOM.render( - -
- - -
-
, - canvas - ); - } - ); + ReactDOM.render( + +
+ + +
+
, + canvas + ); + } + ); }); } From 0b3e9f1179d83399286bf6c439e658fc313e7a88 Mon Sep 17 00:00:00 2001 From: hackrush Date: Wed, 6 Dec 2017 01:04:32 +0530 Subject: [PATCH 14/14] Channel names in pages appear highlighted Used classnames library for determining classname changes --- CHANGELOG.md | 2 ++ src/renderer/js/component/uriIndicator/view.jsx | 10 ++++++++-- src/renderer/scss/component/_channel-indicator.scss | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1273376a1..ac595bc6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ Web UI version numbers should always match the corresponding version of LBRY App ### Changed * The credit balance displayed in the main app navigation displays two decimal places instead of one. * Moved all redux code into /redux folder + * Channel names in pages are highlighted to indicate them being clickable(#814) + * ### Fixed * Long channel names causing inconsistent thumbnail sizes (#721) diff --git a/src/renderer/js/component/uriIndicator/view.jsx b/src/renderer/js/component/uriIndicator/view.jsx index cff4bd073..3bf850d11 100644 --- a/src/renderer/js/component/uriIndicator/view.jsx +++ b/src/renderer/js/component/uriIndicator/view.jsx @@ -1,7 +1,8 @@ import React from "react"; import { Icon } from "component/common"; import Link from "component/link"; -import lbryuri from "lbryuri.js"; +import lbryuri from "lbryuri"; +import classnames from "classnames"; class UriIndicator extends React.PureComponent { componentWillMount() { @@ -60,7 +61,12 @@ class UriIndicator extends React.PureComponent { const inner = ( - + {channelName} {" "} {!signatureIsValid ? ( diff --git a/src/renderer/scss/component/_channel-indicator.scss b/src/renderer/scss/component/_channel-indicator.scss index 6c63a4235..50b7648d0 100644 --- a/src/renderer/scss/component/_channel-indicator.scss +++ b/src/renderer/scss/component/_channel-indicator.scss @@ -1,9 +1,9 @@ .channel-name { - display: inline-block; + display: inline-flex; overflow: hidden; white-space: nowrap; - text-overflow: ellipsis + text-overflow: ellipsis; } // this shouldn't know about the card width