Merge pull request #635 from 0xProject/feature/website/custom-onboarding-tooltip
Remove react-joyride and some more refactoring
This commit is contained in:
@@ -1,4 +1,12 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "0.5.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add types for `react-popper`, remove types for `react-joyride`"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -1,86 +0,0 @@
|
|||||||
// Type definitions for react-joyride 2.0.0-11
|
|
||||||
// Project: https://github.com/gilbarbara/react-joyride
|
|
||||||
|
|
||||||
declare module 'react-joyride' {
|
|
||||||
import * as React from 'react';
|
|
||||||
export interface StyleOptions {
|
|
||||||
arrowColor?: string;
|
|
||||||
backgroundColor?: string;
|
|
||||||
primaryColor?: string;
|
|
||||||
textColor?: string;
|
|
||||||
overlayColor?: string;
|
|
||||||
spotlightShadow?: string;
|
|
||||||
beaconSize?: number;
|
|
||||||
zIndex?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Placement =
|
|
||||||
| 'top'
|
|
||||||
| 'top-left'
|
|
||||||
| 'top-right'
|
|
||||||
| 'bottom'
|
|
||||||
| 'bottom-left'
|
|
||||||
| 'bottom-right'
|
|
||||||
| 'right'
|
|
||||||
| 'left';
|
|
||||||
|
|
||||||
export interface Step {
|
|
||||||
title?: string;
|
|
||||||
content: React.ReactNode;
|
|
||||||
target: string;
|
|
||||||
placement?: Placement;
|
|
||||||
type?: 'click' | 'hover';
|
|
||||||
isFixed?: boolean;
|
|
||||||
allowClicksThruHole?: boolean;
|
|
||||||
disableBeacon?: boolean;
|
|
||||||
style?: StyleOptions;
|
|
||||||
[prop: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StyleOptionsProp {
|
|
||||||
options: StyleOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CallbackMetadata {
|
|
||||||
type:
|
|
||||||
| 'tour:start'
|
|
||||||
| 'step:before'
|
|
||||||
| 'beacon'
|
|
||||||
| 'tooltip'
|
|
||||||
| 'close'
|
|
||||||
| 'step:after'
|
|
||||||
| 'tour:end'
|
|
||||||
| 'tour:status'
|
|
||||||
| 'error:target_not_found'
|
|
||||||
| 'error';
|
|
||||||
step: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CallbackData = CallbackMetadata & State;
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
steps?: Step[];
|
|
||||||
beaconComponent?: React.ReactNode;
|
|
||||||
disableOverlayClose?: boolean;
|
|
||||||
run?: boolean;
|
|
||||||
stepIndex?: number;
|
|
||||||
callback?: (data: CallbackData) => void;
|
|
||||||
debug?: boolean;
|
|
||||||
styles?: StyleOptionsProp;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface State {
|
|
||||||
action: string;
|
|
||||||
controlled: boolean;
|
|
||||||
index: number;
|
|
||||||
lifecycle: string;
|
|
||||||
size: 0;
|
|
||||||
status: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Joyride extends React.Component<Props, State> {
|
|
||||||
constructor(props: Props);
|
|
||||||
|
|
||||||
static defaultProps: Props;
|
|
||||||
}
|
|
||||||
}
|
|
49
packages/typescript-typings/types/react-popper/index.d.ts
vendored
Normal file
49
packages/typescript-typings/types/react-popper/index.d.ts
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Type definitions for react-popper 1.0.0-beta.6
|
||||||
|
// Project: https://github.com/gilbarbara/react-joyride
|
||||||
|
|
||||||
|
declare module 'react-popper' {
|
||||||
|
import * as React from 'react';
|
||||||
|
import * as PopperJS from 'popper.js';
|
||||||
|
|
||||||
|
interface ManagerProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
export class Manager extends React.Component<ManagerProps, {}> {}
|
||||||
|
|
||||||
|
type RefHandler = (ref: HTMLElement | null) => void;
|
||||||
|
|
||||||
|
export interface ReferenceChildrenProps {
|
||||||
|
ref: RefHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReferenceProps {
|
||||||
|
children: (props: ReferenceChildrenProps) => React.ReactNode;
|
||||||
|
}
|
||||||
|
export class Reference extends React.Component<ReferenceProps, {}> {}
|
||||||
|
|
||||||
|
export interface PopperArrowProps {
|
||||||
|
ref: RefHandler;
|
||||||
|
style: React.CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Placement = PopperJS.Placement;
|
||||||
|
|
||||||
|
export interface PopperChildrenProps {
|
||||||
|
arrowProps: PopperArrowProps;
|
||||||
|
outOfBoundaries: boolean | null;
|
||||||
|
placement: PopperJS.Placement;
|
||||||
|
ref: RefHandler;
|
||||||
|
scheduleUpdate: () => void;
|
||||||
|
style: React.CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PopperProps {
|
||||||
|
children: (props: PopperChildrenProps) => React.ReactNode;
|
||||||
|
eventsEnabled?: boolean;
|
||||||
|
modifiers?: PopperJS.Modifiers;
|
||||||
|
placement?: PopperJS.Placement;
|
||||||
|
positionFixed?: boolean;
|
||||||
|
referenceElement?: Element;
|
||||||
|
}
|
||||||
|
export class Popper extends React.Component<PopperProps, {}> {}
|
||||||
|
}
|
@@ -11,22 +11,19 @@
|
|||||||
"clean": "shx rm -f public/bundle*",
|
"clean": "shx rm -f public/bundle*",
|
||||||
"lint": "tslint --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
|
"lint": "tslint --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
|
||||||
"watch": "webpack-dev-server --content-base public --https",
|
"watch": "webpack-dev-server --content-base public --https",
|
||||||
"deploy_dogfood":
|
"deploy_dogfood": "npm run build; aws s3 sync ./public/. s3://dogfood.0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
||||||
"npm run build; aws s3 sync ./public/. s3://dogfood.0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
"deploy_staging": "npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
||||||
"deploy_staging":
|
"deploy_live": "npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers"
|
||||||
"npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
|
||||||
"deploy_live":
|
|
||||||
"npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers"
|
|
||||||
},
|
},
|
||||||
"author": "Fabio Berger",
|
"author": "Fabio Berger",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@0xproject/contract-wrappers": "^0.0.2",
|
||||||
"@0xproject/react-docs": "^0.0.12",
|
"@0xproject/react-docs": "^0.0.12",
|
||||||
"@0xproject/react-shared": "^0.1.7",
|
"@0xproject/react-shared": "^0.1.7",
|
||||||
"@0xproject/subproviders": "^0.10.2",
|
"@0xproject/subproviders": "^0.10.2",
|
||||||
"@0xproject/contract-wrappers": "^0.0.2",
|
|
||||||
"@0xproject/typescript-typings": "^0.3.2",
|
|
||||||
"@0xproject/types": "0.7.0",
|
"@0xproject/types": "0.7.0",
|
||||||
|
"@0xproject/typescript-typings": "^0.3.2",
|
||||||
"@0xproject/utils": "^0.6.2",
|
"@0xproject/utils": "^0.6.2",
|
||||||
"@0xproject/web3-wrapper": "^0.6.4",
|
"@0xproject/web3-wrapper": "^0.6.4",
|
||||||
"accounting": "^0.4.1",
|
"accounting": "^0.4.1",
|
||||||
@@ -46,7 +43,7 @@
|
|||||||
"react-document-title": "^2.0.3",
|
"react-document-title": "^2.0.3",
|
||||||
"react-dom": "15.6.1",
|
"react-dom": "15.6.1",
|
||||||
"react-ga": "^2.4.1",
|
"react-ga": "^2.4.1",
|
||||||
"react-joyride": "^2.0.0-11",
|
"react-popper": "^1.0.0-beta.6",
|
||||||
"react-redux": "^5.0.3",
|
"react-redux": "^5.0.3",
|
||||||
"react-router-dom": "^4.1.1",
|
"react-router-dom": "^4.1.1",
|
||||||
"react-scroll": "^1.5.2",
|
"react-scroll": "^1.5.2",
|
||||||
|
@@ -26,49 +26,49 @@
|
|||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-98720122-1"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-98720122-1"></script>
|
||||||
<script>
|
<script>
|
||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag() {
|
function gtag() {
|
||||||
dataLayer.push(arguments);
|
dataLayer.push(arguments);
|
||||||
}
|
}
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
|
|
||||||
gtag('config', 'UA-98720122-1');
|
gtag('config', 'UA-98720122-1');
|
||||||
</script>
|
</script>
|
||||||
<!-- End Google Analytics -->
|
<!-- End Google Analytics -->
|
||||||
<!-- Facebook SDK -->
|
<!-- Facebook SDK -->
|
||||||
<div id="fb-root"></div>
|
<div id="fb-root"></div>
|
||||||
<script>
|
<script>
|
||||||
(function(d, s, id) {
|
(function (d, s, id) {
|
||||||
var js,
|
var js,
|
||||||
fjs = d.getElementsByTagName(s)[0];
|
fjs = d.getElementsByTagName(s)[0];
|
||||||
if (d.getElementById(id)) return;
|
if (d.getElementById(id)) return;
|
||||||
js = d.createElement(s);
|
js = d.createElement(s);
|
||||||
js.id = id;
|
js.id = id;
|
||||||
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8&appId=1687545238205192';
|
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8&appId=1687545238205192';
|
||||||
fjs.parentNode.insertBefore(js, fjs);
|
fjs.parentNode.insertBefore(js, fjs);
|
||||||
})(document, 'script', 'facebook-jssdk');
|
})(document, 'script', 'facebook-jssdk');
|
||||||
</script>
|
</script>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<!-- End Facebook SDK -->
|
<!-- End Facebook SDK -->
|
||||||
<!-- Twitter SDK -->
|
<!-- Twitter SDK -->
|
||||||
<script>
|
<script>
|
||||||
window.twttr = (function(d, s, id) {
|
window.twttr = (function (d, s, id) {
|
||||||
var js,
|
var js,
|
||||||
fjs = d.getElementsByTagName(s)[0],
|
fjs = d.getElementsByTagName(s)[0],
|
||||||
t = window.twttr || {};
|
t = window.twttr || {};
|
||||||
if (d.getElementById(id)) return t;
|
if (d.getElementById(id)) return t;
|
||||||
js = d.createElement(s);
|
js = d.createElement(s);
|
||||||
js.id = id;
|
js.id = id;
|
||||||
js.src = 'https://platform.twitter.com/widgets.js';
|
js.src = 'https://platform.twitter.com/widgets.js';
|
||||||
fjs.parentNode.insertBefore(js, fjs);
|
fjs.parentNode.insertBefore(js, fjs);
|
||||||
|
|
||||||
t._e = [];
|
t._e = [];
|
||||||
t.ready = function(f) {
|
t.ready = function (f) {
|
||||||
t._e.push(f);
|
t._e.push(f);
|
||||||
};
|
};
|
||||||
return t;
|
return t;
|
||||||
})(document, 'script', 'twitter-wjs');
|
})(document, 'script', 'twitter-wjs');
|
||||||
</script>
|
</script>
|
||||||
<!-- End Twitter SDK -->
|
<!-- End Twitter SDK -->
|
||||||
|
|
||||||
<!-- Main -->
|
<!-- Main -->
|
||||||
|
@@ -1,39 +1,96 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Joyride, { CallbackData, Step, StyleOptions } from 'react-joyride';
|
import { Placement, Popper, PopperChildrenProps } from 'react-popper';
|
||||||
|
|
||||||
|
import { ContinueButtonDisplay, OnboardingTooltip } from 'ts/components/onboarding/onboarding_tooltip';
|
||||||
|
import { Container } from 'ts/components/ui/container';
|
||||||
|
import { Overlay } from 'ts/components/ui/overlay';
|
||||||
import { zIndex } from 'ts/utils/style';
|
import { zIndex } from 'ts/utils/style';
|
||||||
|
|
||||||
|
export interface Step {
|
||||||
|
target: string;
|
||||||
|
title?: string;
|
||||||
|
content: React.ReactNode;
|
||||||
|
placement?: Placement;
|
||||||
|
hideBackButton?: boolean;
|
||||||
|
hideNextButton?: boolean;
|
||||||
|
continueButtonDisplay?: ContinueButtonDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OnboardingFlowProps {
|
export interface OnboardingFlowProps {
|
||||||
steps: Step[];
|
steps: Step[];
|
||||||
stepIndex: number;
|
stepIndex: number;
|
||||||
isRunning: boolean;
|
isRunning: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
updateOnboardingStep: (stepIndex: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const joyrideStyleOptions: StyleOptions = {
|
|
||||||
zIndex: zIndex.overlay,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wrapper around Joyride with defaults and styles set
|
|
||||||
export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
|
export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
|
if (!this.props.isRunning) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Joyride
|
<Overlay>
|
||||||
run={this.props.isRunning}
|
<Popper referenceElement={this._getElementForStep()} placement={this._getCurrentStep().placement}>
|
||||||
debug={true}
|
{this._renderPopperChildren.bind(this)}
|
||||||
steps={this.props.steps}
|
</Popper>
|
||||||
stepIndex={this.props.stepIndex}
|
</Overlay>
|
||||||
styles={{ options: joyrideStyleOptions }}
|
|
||||||
callback={this._handleChange.bind(this)}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleChange(data: CallbackData): void {
|
private _getElementForStep(): Element {
|
||||||
switch (data.action) {
|
return document.querySelector(this._getCurrentStep().target);
|
||||||
case 'close':
|
}
|
||||||
this.props.onClose();
|
|
||||||
|
private _renderPopperChildren(props: PopperChildrenProps): React.ReactNode {
|
||||||
|
return (
|
||||||
|
<div ref={props.ref} style={props.style} data-placement={props.placement}>
|
||||||
|
{this._renderToolTip()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderToolTip(): React.ReactNode {
|
||||||
|
const { steps, stepIndex } = this.props;
|
||||||
|
const step = steps[stepIndex];
|
||||||
|
const isLastStep = steps.length - 1 === stepIndex;
|
||||||
|
return (
|
||||||
|
<Container marginLeft="15px">
|
||||||
|
<OnboardingTooltip
|
||||||
|
title={step.title}
|
||||||
|
content={step.content}
|
||||||
|
isLastStep={isLastStep}
|
||||||
|
hideBackButton={step.hideBackButton}
|
||||||
|
hideNextButton={step.hideNextButton}
|
||||||
|
onClose={this.props.onClose}
|
||||||
|
onClickNext={this._goToNextStep.bind(this)}
|
||||||
|
onClickBack={this._goToPrevStep.bind(this)}
|
||||||
|
continueButtonDisplay={step.continueButtonDisplay}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getCurrentStep(): Step {
|
||||||
|
return this.props.steps[this.props.stepIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private _goToNextStep(): void {
|
||||||
|
const nextStep = this.props.stepIndex + 1;
|
||||||
|
if (nextStep < this.props.steps.length) {
|
||||||
|
this.props.updateOnboardingStep(nextStep);
|
||||||
|
} else {
|
||||||
|
this.props.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _goToPrevStep(): void {
|
||||||
|
const nextStep = this.props.stepIndex - 1;
|
||||||
|
if (nextStep >= 0) {
|
||||||
|
this.props.updateOnboardingStep(nextStep);
|
||||||
|
} else {
|
||||||
|
this.props.onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,56 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { colors } from '@0xproject/react-shared';
|
||||||
|
import { Container } from 'ts/components/ui/container';
|
||||||
|
import { Island } from 'ts/components/ui/island';
|
||||||
|
|
||||||
|
export type ContinueButtonDisplay = 'enabled' | 'disabled';
|
||||||
|
|
||||||
|
export interface OnboardingTooltipProps {
|
||||||
|
title?: string;
|
||||||
|
content: React.ReactNode;
|
||||||
|
isLastStep: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onClickNext: () => void;
|
||||||
|
onClickBack: () => void;
|
||||||
|
continueButtonDisplay?: ContinueButtonDisplay;
|
||||||
|
hideBackButton?: boolean;
|
||||||
|
hideNextButton?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Make this more general button.
|
||||||
|
export interface ContinueButtonProps {
|
||||||
|
display: ContinueButtonDisplay;
|
||||||
|
children?: string;
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ContinueButton: React.StatelessComponent<ContinueButtonProps> = (props: ContinueButtonProps) => {
|
||||||
|
const isDisabled = props.display === 'disabled';
|
||||||
|
return (
|
||||||
|
<button disabled={isDisabled} onClick={isDisabled ? undefined : props.onClick}>
|
||||||
|
{props.children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const OnboardingTooltip: React.StatelessComponent<OnboardingTooltipProps> = (props: OnboardingTooltipProps) => (
|
||||||
|
<Island>
|
||||||
|
<Container paddingRight="30px" paddingLeft="30px" maxWidth={350} paddingTop="15px" paddingBottom="15px">
|
||||||
|
<div className="flex flex-column">
|
||||||
|
{props.title}
|
||||||
|
{props.content}
|
||||||
|
{props.continueButtonDisplay && (
|
||||||
|
<ContinueButton onClick={props.onClickNext} display={props.continueButtonDisplay}>
|
||||||
|
Continue
|
||||||
|
</ContinueButton>
|
||||||
|
)}
|
||||||
|
{!props.hideBackButton && <button onClick={props.onClickBack}>Back</button>}
|
||||||
|
{!props.hideNextButton && <button onClick={props.onClickNext}>Skip</button>}
|
||||||
|
<button onClick={props.onClose}>Close</button>
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
</Island>
|
||||||
|
);
|
||||||
|
|
||||||
|
OnboardingTooltip.displayName = 'OnboardingTooltip';
|
@@ -1,32 +1,123 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Step } from 'react-joyride';
|
|
||||||
|
|
||||||
import { OnboardingFlow } from 'ts/components/onboarding/onboarding_flow';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
import { OnboardingFlow, Step } from 'ts/components/onboarding/onboarding_flow';
|
||||||
|
import { ProviderType, TokenByAddress } from 'ts/types';
|
||||||
|
import { utils } from 'ts/utils/utils';
|
||||||
|
|
||||||
export interface PortalOnboardingFlowProps {
|
export interface PortalOnboardingFlowProps {
|
||||||
stepIndex: number;
|
stepIndex: number;
|
||||||
isRunning: boolean;
|
isRunning: boolean;
|
||||||
onClose: () => void;
|
userAddress: string;
|
||||||
|
hasBeenSeen: boolean;
|
||||||
|
providerType: ProviderType;
|
||||||
|
injectedProviderName: string;
|
||||||
|
blockchainIsLoaded: boolean;
|
||||||
|
userEthBalanceInWei: BigNumber;
|
||||||
|
tokenByAddress: TokenByAddress;
|
||||||
|
updateIsRunning: (isRunning: boolean) => void;
|
||||||
|
updateOnboardingStep: (stepIndex: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const steps: Step[] = [
|
|
||||||
{
|
|
||||||
target: '.wallet',
|
|
||||||
content: 'You are onboarding right now!',
|
|
||||||
placement: 'right',
|
|
||||||
disableBeacon: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export class PortalOnboardingFlow extends React.Component<PortalOnboardingFlowProps> {
|
export class PortalOnboardingFlow extends React.Component<PortalOnboardingFlowProps> {
|
||||||
|
public componentDidMount(): void {
|
||||||
|
this._overrideOnboardingStateIfShould();
|
||||||
|
}
|
||||||
|
public componentDidUpdate(): void {
|
||||||
|
this._overrideOnboardingStateIfShould();
|
||||||
|
}
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<OnboardingFlow
|
<OnboardingFlow
|
||||||
steps={steps}
|
steps={this._getSteps()}
|
||||||
stepIndex={this.props.stepIndex}
|
stepIndex={this.props.stepIndex}
|
||||||
isRunning={this.props.isRunning}
|
isRunning={this.props.isRunning}
|
||||||
onClose={this.props.onClose}
|
onClose={this.props.updateIsRunning.bind(this, false)}
|
||||||
|
updateOnboardingStep={this.props.updateOnboardingStep}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getSteps(): Step[] {
|
||||||
|
const steps: Step[] = [
|
||||||
|
{
|
||||||
|
target: '.wallet',
|
||||||
|
content:
|
||||||
|
'Before you begin, you need to connect to a wallet. This will be used across all 0x relayers and dApps',
|
||||||
|
placement: 'right',
|
||||||
|
hideBackButton: true,
|
||||||
|
hideNextButton: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: '.wallet',
|
||||||
|
content: 'Unlock your metamask extension to begin',
|
||||||
|
placement: 'right',
|
||||||
|
hideBackButton: true,
|
||||||
|
hideNextButton: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: '.wallet',
|
||||||
|
content:
|
||||||
|
'In order to start trading on any 0x relayer in the 0x ecosystem, you need to complete two simple steps',
|
||||||
|
placement: 'right',
|
||||||
|
hideBackButton: true,
|
||||||
|
continueButtonDisplay: 'enabled',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: '.eth-row',
|
||||||
|
content: 'Before you begin you will need to send some ETH to your metamask wallet',
|
||||||
|
placement: 'right',
|
||||||
|
continueButtonDisplay: this._userHasEth() ? 'enabled' : 'disabled',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: '.weth-row',
|
||||||
|
content: 'You need to convert some of your ETH into tradeable Wrapped ETH (WETH)',
|
||||||
|
placement: 'right',
|
||||||
|
continueButtonDisplay: this._userHasWeth() ? 'enabled' : 'disabled',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _isAddressAvailable(): boolean {
|
||||||
|
return !_.isEmpty(this.props.userAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _userHasEth(): boolean {
|
||||||
|
return this.props.userEthBalanceInWei > new BigNumber(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _userHasWeth(): boolean {
|
||||||
|
// TODO: https://app.asana.com/0/681385331277907/690722374136933
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _overrideOnboardingStateIfShould(): void {
|
||||||
|
this._autoStartOnboardingIfShould();
|
||||||
|
this._adjustStepIfShould();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _adjustStepIfShould(): void {
|
||||||
|
if (this._isAddressAvailable()) {
|
||||||
|
if (this.props.stepIndex < 2) {
|
||||||
|
this.props.updateOnboardingStep(2);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isExternallyInjected = utils.isExternallyInjected(
|
||||||
|
this.props.providerType,
|
||||||
|
this.props.injectedProviderName,
|
||||||
|
);
|
||||||
|
if (isExternallyInjected) {
|
||||||
|
this.props.updateOnboardingStep(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.props.updateOnboardingStep(0);
|
||||||
|
}
|
||||||
|
private _autoStartOnboardingIfShould(): void {
|
||||||
|
if (!this.props.isRunning && !this.props.hasBeenSeen && this.props.blockchainIsLoaded) {
|
||||||
|
this.props.updateIsRunning(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@ import { Dispatcher } from 'ts/redux/dispatcher';
|
|||||||
import { ProviderType } from 'ts/types';
|
import { ProviderType } from 'ts/types';
|
||||||
import { colors } from 'ts/utils/colors';
|
import { colors } from 'ts/utils/colors';
|
||||||
import { constants } from 'ts/utils/constants';
|
import { constants } from 'ts/utils/constants';
|
||||||
|
import { zIndex } from 'ts/utils/style';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
|
|
||||||
const ROOT_HEIGHT = 24;
|
const ROOT_HEIGHT = 24;
|
||||||
@@ -39,8 +40,10 @@ const styles: Styles = {
|
|||||||
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
|
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const isAddressAvailable = !_.isEmpty(this.props.userAddress);
|
const isAddressAvailable = !_.isEmpty(this.props.userAddress);
|
||||||
const isExternallyInjectedProvider =
|
const isExternallyInjectedProvider = utils.isExternallyInjected(
|
||||||
this.props.providerType === ProviderType.Injected && this.props.injectedProviderName !== '0x Public';
|
this.props.providerType,
|
||||||
|
this.props.injectedProviderName,
|
||||||
|
);
|
||||||
const displayAddress = isAddressAvailable
|
const displayAddress = isAddressAvailable
|
||||||
? utils.getAddressBeginAndEnd(this.props.userAddress)
|
? utils.getAddressBeginAndEnd(this.props.userAddress)
|
||||||
: isExternallyInjectedProvider
|
: isExternallyInjectedProvider
|
||||||
@@ -69,15 +72,13 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
const hasInjectedProvider =
|
|
||||||
this.props.injectedProviderName !== '0x Public' && this.props.providerType === ProviderType.Injected;
|
|
||||||
const hasLedgerProvider = this.props.providerType === ProviderType.Ledger;
|
const hasLedgerProvider = this.props.providerType === ProviderType.Ledger;
|
||||||
const horizontalPosition = hasInjectedProvider || hasLedgerProvider ? 'left' : 'middle';
|
const horizontalPosition = isExternallyInjectedProvider || hasLedgerProvider ? 'left' : 'middle';
|
||||||
return (
|
return (
|
||||||
<div style={{ width: 'fit-content', height: 48, float: 'right' }}>
|
<div style={{ width: 'fit-content', height: 48, float: 'right' }}>
|
||||||
<DropDown
|
<DropDown
|
||||||
hoverActiveNode={hoverActiveNode}
|
hoverActiveNode={hoverActiveNode}
|
||||||
popoverContent={this.renderPopoverContent(hasInjectedProvider, hasLedgerProvider)}
|
popoverContent={this.renderPopoverContent(isExternallyInjectedProvider, hasLedgerProvider)}
|
||||||
anchorOrigin={{ horizontal: horizontalPosition, vertical: 'bottom' }}
|
anchorOrigin={{ horizontal: horizontalPosition, vertical: 'bottom' }}
|
||||||
targetOrigin={{ horizontal: horizontalPosition, vertical: 'top' }}
|
targetOrigin={{ horizontal: horizontalPosition, vertical: 'top' }}
|
||||||
zDepth={1}
|
zDepth={1}
|
||||||
|
@@ -1,10 +1,17 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
type StringOrNum = string | number;
|
||||||
|
|
||||||
export interface ContainerProps {
|
export interface ContainerProps {
|
||||||
marginTop?: string | number;
|
marginTop?: StringOrNum;
|
||||||
marginBottom?: string | number;
|
marginBottom?: StringOrNum;
|
||||||
marginRight?: string | number;
|
marginRight?: StringOrNum;
|
||||||
marginLeft?: string | number;
|
marginLeft?: StringOrNum;
|
||||||
|
paddingTop?: StringOrNum;
|
||||||
|
paddingBottom?: StringOrNum;
|
||||||
|
paddingRight?: StringOrNum;
|
||||||
|
paddingLeft?: StringOrNum;
|
||||||
|
maxWidth?: StringOrNum;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
packages/website/ts/components/ui/overlay.tsx
Normal file
34
packages/website/ts/components/ui/overlay.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { colors } from '@0xproject/react-shared';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { zIndex } from 'ts/utils/style';
|
||||||
|
|
||||||
|
export interface OverlayProps {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const style: React.CSSProperties = {
|
||||||
|
position: 'fixed',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
zIndex: zIndex.overlay,
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Overlay: React.StatelessComponent = (props: OverlayProps) => (
|
||||||
|
<div style={{ ...style, ...props.style }} onClick={props.onClick}>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
Overlay.defaultProps = {
|
||||||
|
style: {},
|
||||||
|
onClick: _.noop,
|
||||||
|
};
|
||||||
|
|
||||||
|
Overlay.displayName = 'Overlay';
|
@@ -46,6 +46,7 @@ import {
|
|||||||
import { backendClient } from 'ts/utils/backend_client';
|
import { backendClient } from 'ts/utils/backend_client';
|
||||||
import { colors } from 'ts/utils/colors';
|
import { colors } from 'ts/utils/colors';
|
||||||
import { constants } from 'ts/utils/constants';
|
import { constants } from 'ts/utils/constants';
|
||||||
|
import { zIndex } from 'ts/utils/style';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
import { styles as walletItemStyles } from 'ts/utils/wallet_item_styles';
|
import { styles as walletItemStyles } from 'ts/utils/wallet_item_styles';
|
||||||
|
|
||||||
@@ -88,6 +89,8 @@ interface AccessoryItemConfig {
|
|||||||
const styles: Styles = {
|
const styles: Styles = {
|
||||||
root: {
|
root: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
zIndex: zIndex.aboveOverlay,
|
||||||
|
position: 'relative',
|
||||||
},
|
},
|
||||||
headerItemInnerDiv: {
|
headerItemInnerDiv: {
|
||||||
paddingLeft: 65,
|
paddingLeft: 65,
|
||||||
@@ -129,9 +132,6 @@ const styles: Styles = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ETHER_ICON_PATH = '/images/ether.png';
|
const ETHER_ICON_PATH = '/images/ether.png';
|
||||||
const ETHER_TOKEN_SYMBOL = 'WETH';
|
|
||||||
const ZRX_TOKEN_SYMBOL = 'ZRX';
|
|
||||||
const ETHER_SYMBOL = 'ETH';
|
|
||||||
const ICON_DIMENSION = 24;
|
const ICON_DIMENSION = 24;
|
||||||
const TOKEN_AMOUNT_DISPLAY_PRECISION = 3;
|
const TOKEN_AMOUNT_DISPLAY_PRECISION = 3;
|
||||||
const BODY_ITEM_KEY = 'BODY';
|
const BODY_ITEM_KEY = 'BODY';
|
||||||
@@ -322,7 +322,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
|||||||
const primaryText = this._renderAmount(
|
const primaryText = this._renderAmount(
|
||||||
this.props.userEtherBalanceInWei,
|
this.props.userEtherBalanceInWei,
|
||||||
constants.DECIMAL_PLACES_ETH,
|
constants.DECIMAL_PLACES_ETH,
|
||||||
ETHER_SYMBOL,
|
constants.ETHER_SYMBOL,
|
||||||
);
|
);
|
||||||
const etherToken = this._getEthToken();
|
const etherToken = this._getEthToken();
|
||||||
const etherPrice = this.state.trackedTokenStateByAddress[etherToken.address].price;
|
const etherPrice = this.state.trackedTokenStateByAddress[etherToken.address].price;
|
||||||
@@ -341,13 +341,13 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
|||||||
? { ...walletItemStyles.focusedItem, ...styles.paddedItem }
|
? { ...walletItemStyles.focusedItem, ...styles.paddedItem }
|
||||||
: { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
|
: { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
|
||||||
const key = ETHER_ITEM_KEY;
|
const key = ETHER_ITEM_KEY;
|
||||||
return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig);
|
return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig, 'eth-row');
|
||||||
}
|
}
|
||||||
private _renderTokenRows(): React.ReactNode {
|
private _renderTokenRows(): React.ReactNode {
|
||||||
const trackedTokens = this.props.trackedTokens;
|
const trackedTokens = this.props.trackedTokens;
|
||||||
const trackedTokensStartingWithEtherToken = trackedTokens.sort(
|
const trackedTokensStartingWithEtherToken = trackedTokens.sort(
|
||||||
firstBy((t: Token) => t.symbol !== ETHER_TOKEN_SYMBOL)
|
firstBy((t: Token) => t.symbol !== constants.ETHER_TOKEN_SYMBOL)
|
||||||
.thenBy((t: Token) => t.symbol !== ZRX_TOKEN_SYMBOL)
|
.thenBy((t: Token) => t.symbol !== constants.ZRX_TOKEN_SYMBOL)
|
||||||
.thenBy('address'),
|
.thenBy('address'),
|
||||||
);
|
);
|
||||||
return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
|
return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
|
||||||
@@ -362,7 +362,8 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
|||||||
const icon = <TokenIcon token={token} diameter={ICON_DIMENSION} link={tokenLink} />;
|
const icon = <TokenIcon token={token} diameter={ICON_DIMENSION} link={tokenLink} />;
|
||||||
const primaryText = this._renderAmount(tokenState.balance, token.decimals, token.symbol);
|
const primaryText = this._renderAmount(tokenState.balance, token.decimals, token.symbol);
|
||||||
const secondaryText = this._renderValue(tokenState.balance, token.decimals, tokenState.price);
|
const secondaryText = this._renderValue(tokenState.balance, token.decimals, tokenState.price);
|
||||||
const wrappedEtherDirection = token.symbol === ETHER_TOKEN_SYMBOL ? Side.Receive : undefined;
|
const isWeth = token.symbol === constants.ETHER_TOKEN_SYMBOL;
|
||||||
|
const wrappedEtherDirection = isWeth ? Side.Receive : undefined;
|
||||||
const accessoryItemConfig: AccessoryItemConfig = {
|
const accessoryItemConfig: AccessoryItemConfig = {
|
||||||
wrappedEtherDirection,
|
wrappedEtherDirection,
|
||||||
allowanceToggleConfig: {
|
allowanceToggleConfig: {
|
||||||
@@ -371,7 +372,14 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
const key = token.address;
|
const key = token.address;
|
||||||
return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig);
|
return this._renderBalanceRow(
|
||||||
|
key,
|
||||||
|
icon,
|
||||||
|
primaryText,
|
||||||
|
secondaryText,
|
||||||
|
accessoryItemConfig,
|
||||||
|
isWeth ? 'weth-row' : undefined,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
private _renderBalanceRow(
|
private _renderBalanceRow(
|
||||||
key: string,
|
key: string,
|
||||||
@@ -379,6 +387,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
|||||||
primaryText: React.ReactNode,
|
primaryText: React.ReactNode,
|
||||||
secondaryText: React.ReactNode,
|
secondaryText: React.ReactNode,
|
||||||
accessoryItemConfig: AccessoryItemConfig,
|
accessoryItemConfig: AccessoryItemConfig,
|
||||||
|
className?: string,
|
||||||
): React.ReactNode {
|
): React.ReactNode {
|
||||||
const shouldShowWrapEtherItem =
|
const shouldShowWrapEtherItem =
|
||||||
!_.isUndefined(this.state.wrappedEtherDirection) &&
|
!_.isUndefined(this.state.wrappedEtherDirection) &&
|
||||||
@@ -388,7 +397,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
|||||||
: { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
|
: { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
|
||||||
const etherToken = this._getEthToken();
|
const etherToken = this._getEthToken();
|
||||||
return (
|
return (
|
||||||
<div key={key} className="flex flex-column">
|
<div key={key} className={`flex flex-column ${className || ''}`}>
|
||||||
<div className="flex items-center" style={style}>
|
<div className="flex items-center" style={style}>
|
||||||
<div className="px2">{icon}</div>
|
<div className="px2">{icon}</div>
|
||||||
<div className="flex-none pr2 pt2 pb2">
|
<div className="flex-none pr2 pt2 pb2">
|
||||||
@@ -578,8 +587,6 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
private _getEthToken(): Token {
|
private _getEthToken(): Token {
|
||||||
const tokens = _.values(this.props.tokenByAddress);
|
return utils.getEthToken(this.props.tokenByAddress);
|
||||||
const etherToken = _.find(tokens, { symbol: ETHER_TOKEN_SYMBOL });
|
|
||||||
return etherToken;
|
|
||||||
}
|
}
|
||||||
} // tslint:disable:max-file-line-count
|
} // tslint:disable:max-file-line-count
|
||||||
|
@@ -6,6 +6,7 @@ import * as React from 'react';
|
|||||||
import { ProviderType } from 'ts/types';
|
import { ProviderType } from 'ts/types';
|
||||||
import { colors } from 'ts/utils/colors';
|
import { colors } from 'ts/utils/colors';
|
||||||
import { constants } from 'ts/utils/constants';
|
import { constants } from 'ts/utils/constants';
|
||||||
|
import { utils } from 'ts/utils/utils';
|
||||||
|
|
||||||
export interface WalletDisconnectedItemProps {
|
export interface WalletDisconnectedItemProps {
|
||||||
providerType: ProviderType;
|
providerType: ProviderType;
|
||||||
@@ -38,8 +39,7 @@ const BUTTON_BOTTOM_PADDING = 80;
|
|||||||
export const WalletDisconnectedItem: React.StatelessComponent<WalletDisconnectedItemProps> = (
|
export const WalletDisconnectedItem: React.StatelessComponent<WalletDisconnectedItemProps> = (
|
||||||
props: WalletDisconnectedItemProps,
|
props: WalletDisconnectedItemProps,
|
||||||
) => {
|
) => {
|
||||||
const isExternallyInjectedProvider =
|
const isExternallyInjectedProvider = utils.isExternallyInjected(props.providerType, props.injectedProviderName);
|
||||||
props.providerType === ProviderType.Injected && props.injectedProviderName !== '0x Public';
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-center">
|
<div className="flex flex-center">
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { ActionTypes } from 'ts/types';
|
import { ActionTypes, ProviderType, TokenByAddress } from 'ts/types';
|
||||||
|
|
||||||
import { PortalOnboardingFlow as PortalOnboardingFlowComponent } from 'ts/components/onboarding/portal_onboarding_flow';
|
import { PortalOnboardingFlow as PortalOnboardingFlowComponent } from 'ts/components/onboarding/portal_onboarding_flow';
|
||||||
import { State } from 'ts/redux/reducer';
|
import { State } from 'ts/redux/reducer';
|
||||||
@@ -11,22 +12,43 @@ interface PortalOnboardingFlowProps {}
|
|||||||
interface ConnectedState {
|
interface ConnectedState {
|
||||||
stepIndex: number;
|
stepIndex: number;
|
||||||
isRunning: boolean;
|
isRunning: boolean;
|
||||||
|
userAddress: string;
|
||||||
|
hasBeenSeen: boolean;
|
||||||
|
providerType: ProviderType;
|
||||||
|
injectedProviderName: string;
|
||||||
|
blockchainIsLoaded: boolean;
|
||||||
|
userEthBalanceInWei: BigNumber;
|
||||||
|
tokenByAddress: TokenByAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConnectedDispatch {
|
interface ConnectedDispatch {
|
||||||
onClose: () => void;
|
updateIsRunning: (isRunning: boolean) => void;
|
||||||
|
updateOnboardingStep: (stepIndex: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: State): ConnectedState => ({
|
const mapStateToProps = (state: State): ConnectedState => ({
|
||||||
stepIndex: state.portalOnboardingStep,
|
stepIndex: state.portalOnboardingStep,
|
||||||
isRunning: state.isPortalOnboardingShowing,
|
isRunning: state.isPortalOnboardingShowing,
|
||||||
|
userAddress: state.userAddress,
|
||||||
|
providerType: state.providerType,
|
||||||
|
injectedProviderName: state.injectedProviderName,
|
||||||
|
blockchainIsLoaded: state.blockchainIsLoaded,
|
||||||
|
userEthBalanceInWei: state.userEtherBalanceInWei,
|
||||||
|
tokenByAddress: state.tokenByAddress,
|
||||||
|
hasBeenSeen: state.hasPortalOnboardingBeenSeen,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
|
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
|
||||||
onClose: (): void => {
|
updateIsRunning: (isRunning: boolean): void => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.UpdatePortalOnboardingShowing,
|
type: ActionTypes.UpdatePortalOnboardingShowing,
|
||||||
data: false,
|
data: isRunning,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateOnboardingStep: (stepIndex: number): void => {
|
||||||
|
dispatch({
|
||||||
|
type: ActionTypes.UpdatePortalOnboardingStep,
|
||||||
|
data: stepIndex,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -1,12 +1,9 @@
|
|||||||
// Polyfills
|
|
||||||
import { MuiThemeProvider } from 'material-ui/styles';
|
import { MuiThemeProvider } from 'material-ui/styles';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom';
|
import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom';
|
||||||
import * as injectTapEventPlugin from 'react-tap-event-plugin';
|
import * as injectTapEventPlugin from 'react-tap-event-plugin';
|
||||||
import { createStore, Store as ReduxStore } from 'redux';
|
|
||||||
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
|
|
||||||
import { Redirecter } from 'ts/components/redirecter';
|
import { Redirecter } from 'ts/components/redirecter';
|
||||||
import { About } from 'ts/containers/about';
|
import { About } from 'ts/containers/about';
|
||||||
import { FAQ } from 'ts/containers/faq';
|
import { FAQ } from 'ts/containers/faq';
|
||||||
@@ -16,11 +13,12 @@ import { Wiki } from 'ts/containers/wiki';
|
|||||||
import { createLazyComponent } from 'ts/lazy_component';
|
import { createLazyComponent } from 'ts/lazy_component';
|
||||||
import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
|
import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
|
||||||
import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage';
|
import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage';
|
||||||
import { reducer, State } from 'ts/redux/reducer';
|
import { store } from 'ts/redux/store';
|
||||||
import { WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
|
import { WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
|
||||||
import { analytics } from 'ts/utils/analytics';
|
import { analytics } from 'ts/utils/analytics';
|
||||||
import { muiTheme } from 'ts/utils/mui_theme';
|
import { muiTheme } from 'ts/utils/mui_theme';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
|
// Polyfills
|
||||||
import 'whatwg-fetch';
|
import 'whatwg-fetch';
|
||||||
injectTapEventPlugin();
|
injectTapEventPlugin();
|
||||||
|
|
||||||
@@ -75,7 +73,7 @@ const LazyOrderUtilsDocumentation = createLazyComponent('Documentation', async (
|
|||||||
analytics.init();
|
analytics.init();
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
analytics.logProviderAsync((window as any).web3);
|
analytics.logProviderAsync((window as any).web3);
|
||||||
const store: ReduxStore<State> = createStore(reducer, devToolsEnhancer({ name: '0x Website Redux Store' }));
|
|
||||||
render(
|
render(
|
||||||
<Router>
|
<Router>
|
||||||
<div>
|
<div>
|
||||||
|
@@ -26,6 +26,16 @@ export const localStorage = {
|
|||||||
}
|
}
|
||||||
window.localStorage.removeItem(key);
|
window.localStorage.removeItem(key);
|
||||||
},
|
},
|
||||||
|
getObject(key: string): object | undefined {
|
||||||
|
const item = localStorage.getItemIfExists(key);
|
||||||
|
if (item) {
|
||||||
|
return JSON.parse(item);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
setObject(key: string, value: object): void {
|
||||||
|
localStorage.setItem(key, JSON.stringify(value));
|
||||||
|
},
|
||||||
getAllKeys(): string[] {
|
getAllKeys(): string[] {
|
||||||
if (!this.doesExist) {
|
if (!this.doesExist) {
|
||||||
return [];
|
return [];
|
||||||
|
16
packages/website/ts/local_storage/state_storage.ts
Normal file
16
packages/website/ts/local_storage/state_storage.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { localStorage } from 'ts/local_storage/local_storage';
|
||||||
|
import { INITIAL_STATE, State } from 'ts/redux/reducer';
|
||||||
|
|
||||||
|
const STORAGE_NAME = 'persistedState';
|
||||||
|
|
||||||
|
export const stateStorage = {
|
||||||
|
saveState(partialState: Partial<State>): void {
|
||||||
|
localStorage.setObject(STORAGE_NAME, partialState);
|
||||||
|
},
|
||||||
|
getPersistedState(): Partial<State> {
|
||||||
|
return localStorage.getObject(STORAGE_NAME);
|
||||||
|
},
|
||||||
|
getPersistedDefaultState(): State {
|
||||||
|
return { ...INITIAL_STATE, ...stateStorage.getPersistedState() };
|
||||||
|
},
|
||||||
|
};
|
@@ -42,6 +42,7 @@ export interface State {
|
|||||||
userEtherBalanceInWei: BigNumber;
|
userEtherBalanceInWei: BigNumber;
|
||||||
portalOnboardingStep: number;
|
portalOnboardingStep: number;
|
||||||
isPortalOnboardingShowing: boolean;
|
isPortalOnboardingShowing: boolean;
|
||||||
|
hasPortalOnboardingBeenSeen: boolean;
|
||||||
// Note: cache of supplied orderJSON in fill order step. Do not use for anything else.
|
// Note: cache of supplied orderJSON in fill order step. Do not use for anything else.
|
||||||
userSuppliedOrderCache: Order;
|
userSuppliedOrderCache: Order;
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ export interface State {
|
|||||||
translate: Translate;
|
translate: Translate;
|
||||||
}
|
}
|
||||||
|
|
||||||
const INITIAL_STATE: State = {
|
export const INITIAL_STATE: State = {
|
||||||
// Portal
|
// Portal
|
||||||
blockchainErr: BlockchainErrs.NoError,
|
blockchainErr: BlockchainErrs.NoError,
|
||||||
blockchainIsLoaded: false,
|
blockchainIsLoaded: false,
|
||||||
@@ -84,6 +85,7 @@ const INITIAL_STATE: State = {
|
|||||||
userSuppliedOrderCache: undefined,
|
userSuppliedOrderCache: undefined,
|
||||||
portalOnboardingStep: 0,
|
portalOnboardingStep: 0,
|
||||||
isPortalOnboardingShowing: false,
|
isPortalOnboardingShowing: false,
|
||||||
|
hasPortalOnboardingBeenSeen: false,
|
||||||
// Docs
|
// Docs
|
||||||
docsVersion: DEFAULT_DOCS_VERSION,
|
docsVersion: DEFAULT_DOCS_VERSION,
|
||||||
availableDocVersions: [DEFAULT_DOCS_VERSION],
|
availableDocVersions: [DEFAULT_DOCS_VERSION],
|
||||||
@@ -309,6 +311,7 @@ export function reducer(state: State = INITIAL_STATE, action: Action): State {
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isPortalOnboardingShowing,
|
isPortalOnboardingShowing,
|
||||||
|
hasPortalOnboardingBeenSeen: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
packages/website/ts/redux/store.ts
Normal file
21
packages/website/ts/redux/store.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
|
import { createStore, Store as ReduxStore } from 'redux';
|
||||||
|
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
|
||||||
|
import { stateStorage } from 'ts/local_storage/state_storage';
|
||||||
|
import { reducer, State } from 'ts/redux/reducer';
|
||||||
|
|
||||||
|
const ONE_SECOND = 1000;
|
||||||
|
|
||||||
|
export const store: ReduxStore<State> = createStore(
|
||||||
|
reducer,
|
||||||
|
stateStorage.getPersistedDefaultState(),
|
||||||
|
devToolsEnhancer({ name: '0x Website Redux Store' }),
|
||||||
|
);
|
||||||
|
store.subscribe(
|
||||||
|
_.throttle(() => {
|
||||||
|
// Persisted state
|
||||||
|
stateStorage.saveState({
|
||||||
|
hasPortalOnboardingBeenSeen: store.getState().hasPortalOnboardingBeenSeen,
|
||||||
|
});
|
||||||
|
}, ONE_SECOND),
|
||||||
|
);
|
@@ -4,6 +4,9 @@ import { BigNumber } from '@0xproject/utils';
|
|||||||
export const constants = {
|
export const constants = {
|
||||||
DECIMAL_PLACES_ETH: 18,
|
DECIMAL_PLACES_ETH: 18,
|
||||||
DECIMAL_PLACES_ZRX: 18,
|
DECIMAL_PLACES_ZRX: 18,
|
||||||
|
ETHER_TOKEN_SYMBOL: 'WETH',
|
||||||
|
ZRX_TOKEN_SYMBOL: 'ZRX',
|
||||||
|
ETHER_SYMBOL: 'ETH',
|
||||||
GENESIS_ORDER_BLOCK_BY_NETWORK_ID: {
|
GENESIS_ORDER_BLOCK_BY_NETWORK_ID: {
|
||||||
1: 4145578,
|
1: 4145578,
|
||||||
42: 3117574,
|
42: 3117574,
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const zIndex = {
|
export const zIndex = {
|
||||||
topBar: 1100,
|
topBar: 1100,
|
||||||
overlay: 1101,
|
overlay: 1105,
|
||||||
|
aboveOverlay: 1106,
|
||||||
};
|
};
|
||||||
|
@@ -11,6 +11,7 @@ import {
|
|||||||
Environments,
|
Environments,
|
||||||
Order,
|
Order,
|
||||||
Providers,
|
Providers,
|
||||||
|
ProviderType,
|
||||||
ScreenWidths,
|
ScreenWidths,
|
||||||
Side,
|
Side,
|
||||||
SideToAssetToken,
|
SideToAssetToken,
|
||||||
@@ -313,8 +314,16 @@ export const utils = {
|
|||||||
isStaging(): boolean {
|
isStaging(): boolean {
|
||||||
return _.includes(window.location.href, configs.DOMAIN_STAGING);
|
return _.includes(window.location.href, configs.DOMAIN_STAGING);
|
||||||
},
|
},
|
||||||
|
isExternallyInjected(providerType: ProviderType, injectedProviderName: string): boolean {
|
||||||
|
return providerType === ProviderType.Injected && injectedProviderName !== constants.PROVIDER_NAME_PUBLIC;
|
||||||
|
},
|
||||||
isDogfood,
|
isDogfood,
|
||||||
shouldShowPortalV2(): boolean {
|
shouldShowPortalV2(): boolean {
|
||||||
return this.isDevelopment() || this.isStaging() || this.isDogfood();
|
return this.isDevelopment() || this.isStaging() || this.isDogfood();
|
||||||
},
|
},
|
||||||
|
getEthToken(tokenByAddress: TokenByAddress): Token {
|
||||||
|
const tokens = _.values(tokenByAddress);
|
||||||
|
const etherToken = _.find(tokens, { symbol: constants.ETHER_TOKEN_SYMBOL });
|
||||||
|
return etherToken;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
109
yarn.lock
109
yarn.lock
@@ -1443,7 +1443,7 @@ babel-register@^6.26.0, babel-register@^6.9.0:
|
|||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
source-map-support "^0.4.15"
|
source-map-support "^0.4.15"
|
||||||
|
|
||||||
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
babel-runtime@6.x.x, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
||||||
version "6.26.0"
|
version "6.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2890,6 +2890,13 @@ create-react-class@^15.5.2, create-react-class@^15.6.0:
|
|||||||
loose-envify "^1.3.1"
|
loose-envify "^1.3.1"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
|
create-react-context@^0.2.1:
|
||||||
|
version "0.2.2"
|
||||||
|
resolved "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.2.tgz#9836542f9aaa22868cd7d4a6f82667df38019dca"
|
||||||
|
dependencies:
|
||||||
|
fbjs "^0.8.0"
|
||||||
|
gud "^1.0.0"
|
||||||
|
|
||||||
cross-fetch@^2.1.0:
|
cross-fetch@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.1.0.tgz#7d4ea7e10a4f3bb73d5c2f0a3791ec3752d39b50"
|
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.1.0.tgz#7d4ea7e10a4f3bb73d5c2f0a3791ec3752d39b50"
|
||||||
@@ -3246,14 +3253,6 @@ dedent@^0.7.0:
|
|||||||
version "0.7.0"
|
version "0.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
|
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
|
||||||
|
|
||||||
deep-diff@^0.3.8:
|
|
||||||
version "0.3.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84"
|
|
||||||
|
|
||||||
deep-diff@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-1.0.0.tgz#0dd55f9412f22a07b2edbfbb11bb4633be6be40b"
|
|
||||||
|
|
||||||
deep-eql@^0.1.3:
|
deep-eql@^0.1.3:
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2"
|
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2"
|
||||||
@@ -3286,10 +3285,6 @@ deep-is@~0.1.3:
|
|||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||||
|
|
||||||
deepmerge@^2.1.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.0.tgz#511a54fff405fc346f0240bb270a3e9533a31102"
|
|
||||||
|
|
||||||
default-require-extensions@^1.0.0:
|
default-require-extensions@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
|
resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
|
||||||
@@ -4203,7 +4198,7 @@ execa@^0.8.0:
|
|||||||
signal-exit "^3.0.0"
|
signal-exit "^3.0.0"
|
||||||
strip-eof "^1.0.0"
|
strip-eof "^1.0.0"
|
||||||
|
|
||||||
exenv@^1.2.1, exenv@^1.2.2:
|
exenv@^1.2.1:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||||
|
|
||||||
@@ -4395,7 +4390,7 @@ faye-websocket@~0.11.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
websocket-driver ">=0.5.1"
|
websocket-driver ">=0.5.1"
|
||||||
|
|
||||||
fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.6, fbjs@^0.8.9:
|
fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.6, fbjs@^0.8.9:
|
||||||
version "0.8.16"
|
version "0.8.16"
|
||||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
|
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5219,6 +5214,10 @@ growl@1.9.2:
|
|||||||
version "1.9.2"
|
version "1.9.2"
|
||||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
|
resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
|
||||||
|
|
||||||
|
gud@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
|
||||||
|
|
||||||
gulp-sourcemaps@1.6.0:
|
gulp-sourcemaps@1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
|
resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
|
||||||
@@ -6041,10 +6040,6 @@ is-installed-globally@^0.1.0:
|
|||||||
global-dirs "^0.1.0"
|
global-dirs "^0.1.0"
|
||||||
is-path-inside "^1.0.0"
|
is-path-inside "^1.0.0"
|
||||||
|
|
||||||
is-lite@^0.2.0:
|
|
||||||
version "0.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-lite/-/is-lite-0.2.0.tgz#1532415467f1fd49aa693ba013a8669575df7cf3"
|
|
||||||
|
|
||||||
is-mobile@^0.2.2:
|
is-mobile@^0.2.2:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/is-mobile/-/is-mobile-0.2.2.tgz#0e2e006d99ed2c2155b761df80f2a3619ae2ad9f"
|
resolved "https://registry.yarnpkg.com/is-mobile/-/is-mobile-0.2.2.tgz#0e2e006d99ed2c2155b761df80f2a3619ae2ad9f"
|
||||||
@@ -7760,10 +7755,6 @@ neo-async@^2.5.0:
|
|||||||
version "2.5.1"
|
version "2.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee"
|
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee"
|
||||||
|
|
||||||
nested-property@0.0.7, nested-property@^0.0.7:
|
|
||||||
version "0.0.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/nested-property/-/nested-property-0.0.7.tgz#ff222f233ca8793c6828b4117091bea597130f4f"
|
|
||||||
|
|
||||||
newman@^3.9.3:
|
newman@^3.9.3:
|
||||||
version "3.9.3"
|
version "3.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/newman/-/newman-3.9.3.tgz#939356026942474ba15482bd37a15c60bb200ca0"
|
resolved "https://registry.yarnpkg.com/newman/-/newman-3.9.3.tgz#939356026942474ba15482bd37a15c60bb200ca0"
|
||||||
@@ -8612,7 +8603,7 @@ plur@^2.1.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
irregular-plurals "^1.0.0"
|
irregular-plurals "^1.0.0"
|
||||||
|
|
||||||
popper.js@^1.14.3:
|
popper.js@^1.14.1:
|
||||||
version "1.14.3"
|
version "1.14.3"
|
||||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.3.tgz#1438f98d046acf7b4d78cd502bf418ac64d4f095"
|
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.3.tgz#1438f98d046acf7b4d78cd502bf418ac64d4f095"
|
||||||
|
|
||||||
@@ -9318,12 +9309,6 @@ quick-lru@^1.0.0:
|
|||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
|
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
|
||||||
|
|
||||||
rafl@~1.2.1:
|
|
||||||
version "1.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/rafl/-/rafl-1.2.2.tgz#fe930f758211020d47e38815f5196a8be4150740"
|
|
||||||
dependencies:
|
|
||||||
global "~4.3.0"
|
|
||||||
|
|
||||||
randomatic@^1.1.3:
|
randomatic@^1.1.3:
|
||||||
version "1.1.7"
|
version "1.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
|
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
|
||||||
@@ -9430,16 +9415,6 @@ react-event-listener@^0.4.5:
|
|||||||
prop-types "^15.5.4"
|
prop-types "^15.5.4"
|
||||||
warning "^3.0.0"
|
warning "^3.0.0"
|
||||||
|
|
||||||
react-floater@^0.5.4:
|
|
||||||
version "0.5.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-floater/-/react-floater-0.5.4.tgz#411a57fd8631e96466e035ee6c91f1f118c8782a"
|
|
||||||
dependencies:
|
|
||||||
deepmerge "^2.1.0"
|
|
||||||
exenv "^1.2.2"
|
|
||||||
is-lite "^0.2.0"
|
|
||||||
popper.js "^1.14.3"
|
|
||||||
react-proptype-conditional-require "^1.0.4"
|
|
||||||
|
|
||||||
react-ga@^2.4.1:
|
react-ga@^2.4.1:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.4.1.tgz#dfbd5f028ed39a07067f7a8bf57dc0d240000767"
|
resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.4.1.tgz#dfbd5f028ed39a07067f7a8bf57dc0d240000767"
|
||||||
@@ -9456,22 +9431,6 @@ react-highlight@0xproject/react-highlight:
|
|||||||
react "^15.5.4"
|
react "^15.5.4"
|
||||||
react-dom "^15.5.4"
|
react-dom "^15.5.4"
|
||||||
|
|
||||||
react-joyride@^2.0.0-11:
|
|
||||||
version "2.0.0-11"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-joyride/-/react-joyride-2.0.0-11.tgz#5cbf4f86b83dfbf9242e7d19482a0fd7cc69ad52"
|
|
||||||
dependencies:
|
|
||||||
deep-diff "^1.0.0"
|
|
||||||
deepmerge "^2.1.0"
|
|
||||||
exenv "^1.2.2"
|
|
||||||
is-lite "^0.2.0"
|
|
||||||
nested-property "^0.0.7"
|
|
||||||
react-floater "^0.5.4"
|
|
||||||
react-proptype-conditional-require "^1.0.4"
|
|
||||||
scroll "^2.0.3"
|
|
||||||
scroll-doc "^0.2.1"
|
|
||||||
scrollparent "^2.0.1"
|
|
||||||
tree-changes "^0.3.2"
|
|
||||||
|
|
||||||
react-markdown@^3.2.2:
|
react-markdown@^3.2.2:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-3.3.0.tgz#a87cdd822aa9302d6add9687961dd1a82a45d02e"
|
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-3.3.0.tgz#a87cdd822aa9302d6add9687961dd1a82a45d02e"
|
||||||
@@ -9482,9 +9441,16 @@ react-markdown@^3.2.2:
|
|||||||
unist-util-visit "^1.3.0"
|
unist-util-visit "^1.3.0"
|
||||||
xtend "^4.0.1"
|
xtend "^4.0.1"
|
||||||
|
|
||||||
react-proptype-conditional-require@^1.0.4:
|
react-popper@^1.0.0-beta.6:
|
||||||
version "1.0.4"
|
version "1.0.0-beta.6"
|
||||||
resolved "https://registry.yarnpkg.com/react-proptype-conditional-require/-/react-proptype-conditional-require-1.0.4.tgz#69c2d5741e6df5e08f230f36bbc2944ee1222555"
|
resolved "https://registry.npmjs.org/react-popper/-/react-popper-1.0.0-beta.6.tgz#cb27a2ac56adccbaf5f9c4132387289069240834"
|
||||||
|
dependencies:
|
||||||
|
babel-runtime "6.x.x"
|
||||||
|
create-react-context "^0.2.1"
|
||||||
|
popper.js "^1.14.1"
|
||||||
|
prop-types "^15.6.1"
|
||||||
|
typed-styles "^0.0.5"
|
||||||
|
warning "^3.0.0"
|
||||||
|
|
||||||
react-redux@^5.0.3:
|
react-redux@^5.0.3:
|
||||||
version "5.0.7"
|
version "5.0.7"
|
||||||
@@ -10175,20 +10141,6 @@ scoped-regex@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
|
resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
|
||||||
|
|
||||||
scroll-doc@^0.2.1:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/scroll-doc/-/scroll-doc-0.2.1.tgz#168f9e9ac598743dd682c992839b44a38ce4dd91"
|
|
||||||
|
|
||||||
scroll@^2.0.3:
|
|
||||||
version "2.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/scroll/-/scroll-2.0.3.tgz#0951b785544205fd17753bc3d294738ba16fc2ab"
|
|
||||||
dependencies:
|
|
||||||
rafl "~1.2.1"
|
|
||||||
|
|
||||||
scrollparent@^2.0.1:
|
|
||||||
version "2.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/scrollparent/-/scrollparent-2.0.1.tgz#715d5b9cc57760fb22bdccc3befb5bfe06b1a317"
|
|
||||||
|
|
||||||
scrypt-js@2.0.3:
|
scrypt-js@2.0.3:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4"
|
resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4"
|
||||||
@@ -11491,13 +11443,6 @@ traverse-chain@~0.1.0:
|
|||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
|
resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
|
||||||
|
|
||||||
tree-changes@^0.3.2:
|
|
||||||
version "0.3.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/tree-changes/-/tree-changes-0.3.2.tgz#ad7d3b499155bd6176f2c9c6a472d8155df0a9ce"
|
|
||||||
dependencies:
|
|
||||||
deep-diff "^0.3.8"
|
|
||||||
nested-property "0.0.7"
|
|
||||||
|
|
||||||
treeify@^1.0.1:
|
treeify@^1.0.1:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8"
|
resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8"
|
||||||
@@ -11663,6 +11608,10 @@ type-is@~1.6.15, type-is@~1.6.16:
|
|||||||
media-typer "0.3.0"
|
media-typer "0.3.0"
|
||||||
mime-types "~2.1.18"
|
mime-types "~2.1.18"
|
||||||
|
|
||||||
|
typed-styles@^0.0.5:
|
||||||
|
version "0.0.5"
|
||||||
|
resolved "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.5.tgz#a60df245d482a9b1adf9c06c078d0f06085ed1cf"
|
||||||
|
|
||||||
typedarray-to-buffer@^3.1.2:
|
typedarray-to-buffer@^3.1.2:
|
||||||
version "3.1.5"
|
version "3.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
||||||
|
Reference in New Issue
Block a user