Production Release Changes (#1673)

* Remove beta agreement, move modals to Root, and initial work on welcome modal.

* Local storage detection for welcome modal

* Remove announcement from header. Allow tooltips to point in non-top directions.

* Show modal fade at bottom on non-footer modals

* Update README

* Update all links back to old mycrypto to classic.mycrypto, add footer link too.

* Localize welcome modal

* Remove release candidate version text, change to legacy.mycrypto instead of classic.mycrypto.

* update banner; add hackerone link
This commit is contained in:
William O'Beirne 2018-05-11 11:15:32 -04:00 committed by Daniel Ternyak
parent 1e9fe1b394
commit ae2ac4f2c6
28 changed files with 233 additions and 223 deletions

View File

@ -1,8 +1,11 @@
# MyCrypto Beta RC (VISIT [MyCryptoHQ/mycrypto.com](https://github.com/MyCryptoHQ/mycrypto.com) for the current site)<br/>Just looking to download? Grab our [latest release](https://github.com/MyCryptoHQ/MyCrypto/releases)
# MyCrypto Web & Desktop Apps
[![Greenkeeper badge](https://badges.greenkeeper.io/MyCryptoHq/MyCrypto.svg)](https://greenkeeper.io/)
[![Coverage Status](https://coveralls.io/repos/github/MyCryptoHQ/MyCrypto/badge.svg?branch=develop)](https://coveralls.io/github/MyCryptoHQ/MyCrypto?branch=develop)
* **Just looking to download?** Grab our [latest release](https://github.com/MyCryptoHQ/MyCrypto/releases).
* **Looking for the old site?** Check out [https://legacy.mycrypto.com](https://legacy.mycrypto.com) or the source at [MyCryptoHQ/mycrypto.com](https://github.com/MyCryptoHQ/mycrypto.com)
## Running the App
This codebase targets Node 8.9.4 (LTS). After `npm install`ing all dependencies (You may be required to install additional system dependencies, due to some node modules relying on them) you can run various commands depending on what you want to do:
@ -132,3 +135,4 @@ npm run test:int
</a>
Cross browser testing and debugging provided by the very lovely team at BrowserStack.

View File

@ -15,8 +15,9 @@ import ErrorScreen from 'components/ErrorScreen';
import PageNotFound from 'components/PageNotFound';
import LogOutPrompt from 'components/LogOutPrompt';
import QrSignerModal from 'containers/QrSignerModal';
import OnboardModal from 'containers/OnboardModal';
import WelcomeModal from 'components/WelcomeModal';
import NewAppReleaseModal from 'components/NewAppReleaseModal';
import { TitleBar } from 'components/ui';
import { Store } from 'redux';
import { pollOfflineStatus, TPollOfflineStatus } from 'actions/config';
import { AppState } from 'reducers';
@ -104,12 +105,17 @@ class RootClass extends Component<Props, State> {
<Provider store={store} key={Math.random()}>
<Router key={Math.random()}>
<React.Fragment>
{process.env.BUILD_ELECTRON && <TitleBar />}
{routes}
<LegacyRoutes />
<LogOutPrompt />
<QrSignerModal />
{process.env.BUILD_ELECTRON && <NewAppReleaseModal />}
{!process.env.DOWNLOADABLE_BUILD && (
<React.Fragment>
<OnboardModal />
<WelcomeModal />
</React.Fragment>
)}
</React.Fragment>
</Router>
</Provider>

View File

@ -1,66 +0,0 @@
@import 'common/sass/variables';
@import 'common/sass/mixins';
.BetaAgreement {
@include cover-message;
background: $brand-info;
&-content {
h2 {
text-align: center;
}
&-buttons {
padding-top: 20px;
&-btn {
display: block;
width: 100%;
max-width: 280px;
margin: 0 auto;
border: none;
padding: 0;
transition: $transition;
&.is-continue {
height: 60px;
line-height: 60px;
font-size: 22px;
background: rgba(#fff, 0.96);
color: $gray-dark;
border-radius: 4px;
margin-bottom: 20px;
&:hover {
background: #fff;
color: $gray-darker;
}
}
&.is-reject {
background: none;
color: #fff;
opacity: 0.7;
&:hover {
opacity: 1;
}
}
}
}
}
// Fade out
&.is-fading {
pointer-events: none;
opacity: 0;
background: #fff;
transition: all 500ms ease 400ms;
.BetaAgreement-content {
opacity: 0;
transform: translateY(15px);
transition: all 500ms ease;
}
}
}

View File

@ -1,73 +0,0 @@
import React from 'react';
import { NewTabLink } from 'components/ui';
import { discordURL } from 'config';
import './index.scss';
const LS_KEY = 'acknowledged-beta';
interface State {
isFading: boolean;
hasAcknowledged: boolean;
}
export default class BetaAgreement extends React.PureComponent<{}, State> {
public state = {
hasAcknowledged: !!localStorage.getItem(LS_KEY),
isFading: false
};
public render() {
if (this.state.hasAcknowledged) {
return null;
}
const isFading = this.state.isFading ? 'is-fading' : '';
return (
<div className={`BetaAgreement ${isFading}`}>
<div className="BetaAgreement-content">
<h2>Welcome to the New MyCrypto Beta Release Candidate!</h2>
<p>
You are about to use the new MyCrypto Beta Release Candidate. Although this is a release
candidate for production, we encourage caution while using this unreleased version of
MyCrypto.
</p>
<p>We hope to move this version of MyCrypto into production in the near future!</p>
<p>
Feedback and bug reports are greatly appreciated. You can file issues on our{' '}
<NewTabLink href="https://github.com/MyCryptoHQ/MyCrypto/issues">
GitHub repository
</NewTabLink>{' '}
or join our <NewTabLink href={discordURL}>Discord server</NewTabLink> to discuss the
beta.
</p>
<p>Are you sure you would like to continue?</p>
<div className="BetaAgreement-content-buttons">
<button
className="BetaAgreement-content-buttons-btn is-continue"
onClick={this.doContinue}
>
Yes, continue to the Beta RC
</button>
<button className="BetaAgreement-content-buttons-btn is-reject" onClick={this.reject}>
No, take me to the production site
</button>
</div>
</div>
</div>
);
}
private doContinue = () => {
localStorage.setItem(LS_KEY, 'true');
this.setState({ isFading: true });
setTimeout(() => {
this.setState({ hasAcknowledged: true });
}, 1000);
};
private reject = () => {
window.location.assign('https://mycrypto.com');
};
}

View File

@ -12,7 +12,6 @@ import React from 'react';
import PreFooter from './PreFooter';
import DisclaimerModal from 'components/DisclaimerModal';
import { NewTabLink } from 'components/ui';
import OnboardModal from 'containers/OnboardModal';
import './index.scss';
import { translateRaw } from 'translations';
@ -133,8 +132,6 @@ export default class Footer extends React.PureComponent<Props, State> {
</div>
</div>
</footer>
<OnboardModal />
<DisclaimerModal isOpen={this.state.isDisclaimerOpen} handleClose={this.toggleModal} />
</div>
);

View File

@ -12,7 +12,6 @@
.OnlineStatus {
position: relative;
top: -2px;
width: 12px;
height: 12px;
text-align: center;

View File

@ -7,8 +7,8 @@ interface Props {
}
const OnlineStatus: React.SFC<Props> = ({ isOffline }) => (
<div className={`OnlineStatus fa-stack ${isOffline ? 'is-offline' : 'is-online'}`}>
<Tooltip>{isOffline ? 'Offline' : 'Online'}</Tooltip>
<div className={`OnlineStatus ${isOffline ? 'is-offline' : 'is-online'}`}>
<Tooltip direction="left">{isOffline ? 'Offline' : 'Online'}</Tooltip>
</div>
);

View File

@ -0,0 +1,26 @@
@import 'common/sass/variables';
.WelcomeModal {
font-size: $font-size-bump-more;
&-logo {
display: block;
max-width: 380px;
margin: $space auto $space * 2;
}
&-beta {
margin-top: -$space-md;
font-size: $font-size-base;
text-align: center;
}
&-continue {
display: block;
margin: $space * 2 auto 0;
}
p, ul {
margin-bottom: $space;
}
}

View File

@ -0,0 +1,62 @@
import React from 'react';
import translate from 'translations';
import { Modal, NewTabLink } from 'components/ui';
import { isLegacyUser, isBetaUser } from 'utils/localStorage';
import Logo from 'assets/images/logo-mycrypto-transparent.svg';
import './WelcomeModal.scss';
const LS_KEY = 'acknowledged-welcome';
interface State {
isOpen: boolean;
}
export default class WelcomeModal extends React.Component<{}, State> {
public state: State = {
isOpen: false
};
public componentDidMount() {
if (isLegacyUser() && !localStorage.getItem(LS_KEY)) {
this.setState({ isOpen: true });
}
}
public render() {
return (
<Modal isOpen={this.state.isOpen} handleClose={this.close} maxWidth={660}>
<div className="WelcomeModal">
<img className="WelcomeModal-logo" src={Logo} />
{isBetaUser() && (
<p className="WelcomeModal-beta alert alert-success">
💖 {translate('WELCOME_MODAL_BETA')} 🚀
</p>
)}
<p>{translate('WELCOME_MODAL_INTRO')}</p>
<ul>
<li>{translate('WELCOME_MODAL_FEATURE_1')}</li>
<li>{translate('WELCOME_MODAL_FEATURE_2')}</li>
<li>{translate('WELCOME_MODAL_FEATURE_3')}</li>
<li>{translate('WELCOME_MODAL_FEATURE_4')}</li>
<li>
<NewTabLink href="https://download.mycrypto.com/">
{translate('WELCOME_MODAL_FEATURE_5')}
</NewTabLink>
</li>
<li>{translate('WELCOME_MODAL_FEATURE_MORE')}</li>
</ul>
<p>{translate('WELCOME_MODAL_LINKS')}</p>
<button className="WelcomeModal-continue btn btn-lg btn-primary" onClick={this.close}>
{translate('WELCOME_MODAL_CONTINUE')}
</button>
</div>
</Modal>
);
}
private close = () => {
this.setState({ isOpen: false });
localStorage.setItem(LS_KEY, 'true');
};
}

View File

@ -14,7 +14,6 @@ export { default as Header } from './Header';
export { default as Footer } from './Footer';
export { default as BalanceSidebar } from './BalanceSidebar';
export { default as PaperWallet } from './PaperWallet';
export { default as BetaAgreement } from './BetaAgreement';
export { default as TXMetaDataPanel } from './TXMetaDataPanel';
export { default as WalletDecrypt } from './WalletDecrypt';
export { default as TogglablePassword } from './TogglablePassword';

View File

@ -3,8 +3,8 @@ import closeIcon from 'assets/images/close.svg';
import { IButton } from 'components/ui/Modal';
interface Props {
title?: string;
children: any;
title?: React.ReactNode;
children: React.ReactNode;
modalStyle?: CSSProperties;
hasButtons?: number;
buttons?: IButton[];
@ -67,7 +67,7 @@ export default class ModalBody extends React.Component<Props> {
<div className="Modal-content" ref={div => (this.modalContent = div as HTMLElement)}>
{children}
<div className="Modal-fade" />
<div className={`Modal-fade ${!hasButtons ? 'has-no-footer' : ''}`} />
</div>
{hasButtons && <div className="Modal-footer">{this.renderButtons()}</div>}
</div>

View File

@ -53,6 +53,10 @@ $m-anim-speed: 400ms;
bottom: 4.5rem;
left: 50%;
transform: translateX(-50%);
&.has-no-footer {
bottom: 0;
}
}
&-header {

View File

@ -12,9 +12,9 @@ export interface IButton {
}
interface Props {
isOpen?: boolean;
title?: string;
title?: React.ReactNode;
disableButtons?: boolean;
children: any;
children: React.ReactNode;
buttons?: IButton[];
maxWidth?: number;
handleClose(): void;

View File

@ -1,27 +0,0 @@
@import 'common/sass/variables';
$height: 22px;
// TODO - Implement styles for custom title bar on all platforms
.TitleBar,
.TitleBarPlaceholder {
display: none;
}
.TitleBar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: $height;
line-height: $height;
-webkit-user-select: none;
-webkit-app-region: drag;
background: $body-bg;
z-index: $zindex-top;
box-shadow: 0 1px 1px rgba(#000, 0.08);
}
.TitleBarPlaceholder {
height: $height;
}

View File

@ -1,11 +0,0 @@
import React from 'react';
import './TitleBar.scss';
const TitleBar: React.SFC<{}> = () => (
<React.Fragment>
<div className="TitleBar" />
<div className="TitleBarPlaceholder" />
</React.Fragment>
);
export default TitleBar;

View File

@ -1,9 +1,9 @@
@import 'common/sass/variables';
@import 'common/sass/mixins';
$tooltip-bg: rgba(#222, 0.95);
.Tooltip {
display: flex;
justify-content: center;
position: absolute;
top: 0;
left: 50%;
@ -14,7 +14,7 @@ $tooltip-bg: rgba(#222, 0.95);
pointer-events: none;
opacity: 0;
visibility: hidden;
transform: translate(-50%, -100%) translateY(-5px);
transform: translate(-50%, -100%) translateY(-$tooltip-start-distance);
transition-property: opacity, transform, visibility;
transition-duration: 100ms, 100ms, 0ms;
transition-delay: 0ms, 0ms, 100ms;
@ -32,7 +32,7 @@ $tooltip-bg: rgba(#222, 0.95);
bottom: 0;
left: 50%;
transform: translate(-50%, 100%);
@include triangle(10px, $tooltip-bg, down);
@include triangle($tooltip-arrow-size * 2, $tooltip-bg, down);
}
}
@ -46,7 +46,7 @@ $tooltip-bg: rgba(#222, 0.95);
border-radius: 2px;
&:after {
@include triangle(8px, $tooltip-bg, down);
border-width: $tooltip-arrow-size - 1;
}
}
}
@ -60,8 +60,55 @@ $tooltip-bg: rgba(#222, 0.95);
border-radius: 4px;
&:after {
@include triangle(12px, $tooltip-bg, down);
border-width: $tooltip-arrow-size + 1;
}
}
}
// Direction, top is default
&.is-direction-left {
left: 0;
top: 50%;
justify-content: flex-end;
transform: translate(-100%, -50%) translateX(-$tooltip-start-distance);
> span:after {
bottom: 50%;
right: 0;
left: auto;
transform: translate(100%, 50%);
border-top-color: transparent;
border-left-color: $tooltip-bg;
}
}
&.is-direction-right {
left: auto;
right: 0;
top: 50%;
justify-content: flex-start;
transform: translate(100%, -50%) translateX($tooltip-start-distance);
> span:after {
bottom: 50%;
left: 0;
transform: translate(-100%, 50%);
border-top-color: transparent;
border-right-color: $tooltip-bg;
}
}
&.is-direction-bottom {
top: auto;
bottom: 0;
transform: translate(-50%, 100%) translateY($tooltip-start-distance);
> span:after {
bottom: auto;
top: 0;
transform: translate(-50%, -100%);
border-top-color: transparent;
border-bottom-color: $tooltip-bg;
}
}
}

View File

@ -5,13 +5,15 @@ import './Tooltip.scss';
interface Props {
children: React.ReactElement<string> | string;
size?: 'sm' | 'md' | 'lg';
direction?: 'top' | 'bottom' | 'left' | 'right';
}
const Tooltip: React.SFC<Props> = ({ size, children }) => (
const Tooltip: React.SFC<Props> = ({ size, direction, children }) => (
<div
className={classnames({
Tooltip: true,
[`is-size-${size}`]: !!size
[`is-size-${size}`]: !!size,
[`is-direction-${direction}`]: !!direction
})}
>
<span className="Tooltip-text">{children}</span>

View File

@ -11,7 +11,6 @@ export { default as UnitDisplay } from './UnitDisplay';
export { default as Spinner } from './Spinner';
export { default as SwapDropdown } from './SwapDropdown';
export { default as Tooltip } from './Tooltip';
export { default as TitleBar } from './TitleBar';
export { default as HelpLink } from './HelpLink';
export { default as Input } from './Input';
export { default as TextArea } from './TextArea';

View File

@ -1,16 +1,15 @@
import React from 'react'; // For ANNOUNCEMENT_MESSAGE jsx
import NewTabLink from 'components/ui/NewTabLink';
import { getValues } from '../utils/helpers';
import packageJson from '../../package.json';
import { GasPriceSetting } from 'types/network';
import { makeExplorer } from 'utils/helpers';
import NewTabLink from 'components/ui/NewTabLink';
export const languages = require('./languages.json');
export const discordURL = 'https://discord.gg/VSaTXEA';
// Displays in the footer
export const VERSION_RAW = packageJson.version;
export const VERSION = `${VERSION_RAW} (Release Candidate 2)`;
export const VERSION = packageJson.version;
export const N_FACTOR = 8192;
// Bricks the app once this date has been exceeded. Remember to update these 2
@ -26,10 +25,8 @@ export const VERSION_RC = `${packageJson.version}-RC.0`;
export const ANNOUNCEMENT_TYPE = '';
export const ANNOUNCEMENT_MESSAGE = (
<React.Fragment>
This is a Beta Release Candidate of the new MyCrypto. Please submit any bug reports to our{' '}
<NewTabLink href="https://github.com/MyCryptoHQ/MyCrypto/issues">GitHub</NewTabLink> and use{' '}
<NewTabLink href="https://hackerone.com/mycrypto">HackerOne</NewTabLink> for critical
vulnerabilities. Join the discussion on <NewTabLink href={discordURL}>Discord</NewTabLink>.
Welcome to the new MyCrypto. We hope you like it! If it's urgent and you need the old site, you
can still use <NewTabLink href="https://legacy.mycrypto.com">MyCrypto Legacy</NewTabLink>
</React.Fragment>
);

View File

@ -47,6 +47,10 @@ export const socialMediaLinks: Link[] = [
];
export const productLinks: Link[] = [
{
link: 'https://legacy.mycrypto.com/',
text: translateRaw('OLD_MYCRYPTO')
},
{
link:
'https://chrome.google.com/webstore/detail/etheraddresslookup/pdknmigbbbhmllnmgdfalmedcmcefdfn',

View File

@ -28,9 +28,7 @@ import {
SecureSlideThree,
FinalSlide
} from './components';
const ONBOARD_LOCAL_STORAGE_KEY = 'onboardStatus';
const NUMBER_OF_SLIDES = 10;
import { ONBOARD_LOCAL_STORAGE_KEY, NUMBER_OF_ONBOARD_SLIDES } from 'utils/localStorage';
interface State {
isOpen: boolean;
@ -58,7 +56,6 @@ class OnboardModal extends React.Component<Props, State> {
public componentDidMount() {
const { sessionStarted } = this.props;
const currentSlide = Number(localStorage.getItem(ONBOARD_LOCAL_STORAGE_KEY)) || 0;
if (!sessionStarted) {
@ -68,7 +65,7 @@ class OnboardModal extends React.Component<Props, State> {
isOpen: true
});
}
if (currentSlide > 0 && currentSlide < NUMBER_OF_SLIDES) {
if (currentSlide > 0 && currentSlide < NUMBER_OF_ONBOARD_SLIDES) {
this.props.resumeSlide(currentSlide);
this.setState({
isOpen: true
@ -90,7 +87,7 @@ class OnboardModal extends React.Component<Props, State> {
const firstButtons: IButton[] = [
{
disabled: slideNumber === NUMBER_OF_SLIDES,
disabled: slideNumber === NUMBER_OF_ONBOARD_SLIDES,
text: translate('ACTION_6'),
type: 'primary',
onClick: this.handleNextSlide
@ -115,8 +112,8 @@ class OnboardModal extends React.Component<Props, State> {
}
];
const buttons = slideNumber === NUMBER_OF_SLIDES ? lastButtons : firstButtons;
const steps = new Array(NUMBER_OF_SLIDES).fill({});
const buttons = slideNumber === NUMBER_OF_ONBOARD_SLIDES ? lastButtons : firstButtons;
const steps = new Array(NUMBER_OF_ONBOARD_SLIDES).fill({});
return (
<div className="OnboardModal">
@ -158,8 +155,8 @@ class OnboardModal extends React.Component<Props, State> {
<FinalSlide key={10} closeModal={this.closeModal} />
];
if (slides.length !== NUMBER_OF_SLIDES) {
console.log('Slides length do not match const NUMBER_OF_SLIDES');
if (slides.length !== NUMBER_OF_ONBOARD_SLIDES) {
console.log('Slides length do not match const NUMBER_OF_ONBOARD_SLIDES');
}
const currentSlideIndex = this.props.slideNumber - 1;

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { BetaAgreement, Footer, Header } from 'components';
import { Footer, Header } from 'components';
import { AppState } from 'reducers';
import Notifications from './Notifications';
import OfflineTab from './OfflineTab';
@ -38,7 +38,6 @@ class WebTemplate extends Component<Props, {}> {
<div className="WebTemplate-spacer" />
<Footer latestBlock={latestBlock} />
<Notifications />
<BetaAgreement />
</div>
);
}

View File

@ -87,8 +87,20 @@
&:hover .Tooltip {
opacity: 1;
visibility: visible;
transform: translate(-50%, -100%) translateY(-8px);
transform: translate(-50%, -100%) translateY(-$tooltip-hover-distance);
transition-delay: 400ms, 400ms, 300ms;
&.is-direction-left {
transform: translate(-100%, -50%) translateX(-$tooltip-hover-distance);
}
&.is-direction-right {
transform: translate(100%, -50%) translateX($tooltip-hover-distance);
}
&.is-direction-bottom {
transform: translate(-50%, 100%) translateY($tooltip-hover-distance);
}
}
}

View File

@ -7,6 +7,7 @@
@import './variables/transitions';
@import './variables/links';
@import './variables/tables';
@import './variables/tooltips';
@import './variables/buttons';
@import './variables/forms';
@import './variables/zindex';

View File

@ -0,0 +1,4 @@
$tooltip-start-distance: 5px;
$tooltip-hover-distance: 9px;
$tooltip-arrow-size: 5px;
$tooltip-bg: rgba(#222, 0.95);

View File

@ -390,6 +390,7 @@
"ETHERSCAMDB": "EtherScamDB",
"ETHER_SECURITY_LOOKUP": "EtherSecurityLookup",
"ETHER_ADDRESS_LOOKUP": "EtherAddressLookup",
"OLD_MYCRYPTO": "MyCrypto (Legacy Site)",
"LEDGER_REFERRAL_1": "Buy a Ledger Wallet",
"LEDGER_REFERRAL_2": "Dont have a Ledger? Order one now!",
"LEDGER_TIP": "**Tip:** Make sure you're logged into the $network app on your hardware wallet, and have enabled browser support in the settings",
@ -561,6 +562,16 @@
"APP_UPDATE_TITLE": "New App Version Available",
"APP_UPDATE_BODY": "An updated version of the MyCrypto app has just been released! You can upgrade to the new version by downloading it from our GitHub release page.",
"APP_UPDATE_CONFIRM": "Get the New Version",
"APP_UPDATE_CANCEL": "Maybe Later"
"APP_UPDATE_CANCEL": "Maybe Later",
"WELCOME_MODAL_BETA": "Thank you for testing the beta! People like you made this launch possible",
"WELCOME_MODAL_INTRO": "Welcome to the all new MyCrypto! We've made some cool new changes to the site that we're excited to show you. Beyond the new and improved look and feel of the site, we've also added a ton of new features:",
"WELCOME_MODAL_FEATURE_1": "Token balance scanner",
"WELCOME_MODAL_FEATURE_2": "Combined Send, Info, and Send Offline tabs",
"WELCOME_MODAL_FEATURE_3": "Parity Signer app integration",
"WELCOME_MODAL_FEATURE_4": "Recent transactions history",
"WELCOME_MODAL_FEATURE_5": "A downloadable desktop app",
"WELCOME_MODAL_FEATURE_MORE": "...and much, much more!",
"WELCOME_MODAL_LINKS": "Help out with any issues you find by [reporting bugs on GitHub](https://github.com/MyCryptoHQ/MyCrypto/issues) or [HackerOne](https://hackerone.com/mycrypto). Need something from the old site, or just miss that clunky feel? We've kept it up as [MyCrypto Legacy](https://legacy.mycrypto.com).",
"WELCOME_MODAL_CONTINUE": "Show me the new site!"
}
}

View File

@ -113,7 +113,7 @@ export function bytesToHuman(bytes: number) {
}
export function ensV3Url(name: string) {
return `https://mycrypto.com/?ensname=${name}#ens`;
return `https://legacy.mycrypto.com/?ensname=${name}#ens`;
}
export function hexToNumber(hex: string) {

View File

@ -4,6 +4,8 @@ import { IWallet, WalletConfig } from 'libs/wallet';
import { AppState } from 'reducers';
export const REDUX_STATE = 'REDUX_STATE';
export const ONBOARD_LOCAL_STORAGE_KEY = 'onboardStatus';
export const NUMBER_OF_ONBOARD_SLIDES = 10;
export function loadState<T>(): T | undefined {
try {
@ -61,3 +63,18 @@ function getWalletConfigKey(wallet: IWallet): string {
const address = wallet.getAddressString();
return sha256(`${address}-mycrypto`).toString('hex');
}
export function isLegacyUser() {
// All devs are legacy users!
const oldLSValue = localStorage.getItem('gasPrice') || process.env.NODE_ENV !== 'production';
const onboardProgress = localStorage.getItem(ONBOARD_LOCAL_STORAGE_KEY);
if (oldLSValue && onboardProgress && parseInt(onboardProgress, 10) >= NUMBER_OF_ONBOARD_SLIDES) {
return true;
}
return false;
}
export function isBetaUser() {
return !!localStorage.getItem('acknowledged-beta');
}