diff --git a/.gitignore b/.gitignore index 9a407abc..0aaa39fe 100644 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,7 @@ v8-compile-cache-0/ package-lock.json # Favicon cache -.wwp-cache \ No newline at end of file +.wwp-cache + +# MacOSX +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 8b197644..87d45df8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# MyCrypto Beta (VISIT [MyCryptoHQ/mycrypto.com](https://github.com/MyCryptoHQ/mycrypto.com) for the current site)
Just looking to download? Grab our [latest release](https://github.com/MyCryptoHQ/MyCrypto/releases) +# MyCrypto Beta RC (VISIT [MyCryptoHQ/mycrypto.com](https://github.com/MyCryptoHQ/mycrypto.com) for the current site)
Just looking to download? Grab our [latest release](https://github.com/MyCryptoHQ/MyCrypto/releases) [![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) diff --git a/common/Root.tsx b/common/Root.tsx index ca8c5ae2..c9840ab3 100644 --- a/common/Root.tsx +++ b/common/Root.tsx @@ -10,9 +10,11 @@ import Swap from 'containers/Tabs/Swap'; import SignAndVerifyMessage from 'containers/Tabs/SignAndVerifyMessage'; import BroadcastTx from 'containers/Tabs/BroadcastTx'; import CheckTransaction from 'containers/Tabs/CheckTransaction'; +import SupportPage from 'containers/Tabs/SupportPage'; import ErrorScreen from 'components/ErrorScreen'; import PageNotFound from 'components/PageNotFound'; import LogOutPrompt from 'components/LogOutPrompt'; +import QrSignerModal from 'containers/QrSignerModal'; import { TitleBar } from 'components/ui'; import { Store } from 'redux'; import { pollOfflineStatus, TPollOfflineStatus } from 'actions/config'; @@ -50,6 +52,7 @@ class RootClass extends Component { public componentDidMount() { this.props.pollOfflineStatus(); this.props.setUnitMeta(this.props.networkUnit); + this.addBodyClasses(); } public componentDidCatch(error: Error) { @@ -84,6 +87,7 @@ class RootClass extends Component { + @@ -95,18 +99,40 @@ class RootClass extends Component { : BrowserRouter; return ( - - - - {process.env.BUILD_ELECTRON && } - {routes} - - - - - + + + + + {process.env.BUILD_ELECTRON && } + {routes} + + + + + + +
+ ); } + + private addBodyClasses() { + const classes = []; + + if (process.env.BUILD_ELECTRON) { + classes.push('is-electron'); + + if (navigator.appVersion.includes('Win')) { + classes.push('is-windows'); + } else if (navigator.appVersion.includes('Mac')) { + classes.push('is-osx'); + } else { + classes.push('is-linux'); + } + } + + document.body.className += ` ${classes.join(' ')}`; + } } const LegacyRoutes = withRouter(props => { diff --git a/common/actions/config/actionCreators.ts b/common/actions/config/actionCreators.ts index 1a2e770f..5c18d5b9 100644 --- a/common/actions/config/actionCreators.ts +++ b/common/actions/config/actionCreators.ts @@ -1,10 +1,15 @@ import * as interfaces from './actionTypes'; import { TypeKeys } from './constants'; -export type TToggleOffline = typeof toggleOffline; -export function toggleOffline(): interfaces.ToggleOfflineAction { +export function setOnline(): interfaces.SetOnlineAction { return { - type: TypeKeys.CONFIG_TOGGLE_OFFLINE + type: TypeKeys.CONFIG_SET_ONLINE + }; +} + +export function setOffline(): interfaces.SetOfflineAction { + return { + type: TypeKeys.CONFIG_SET_OFFLINE }; } @@ -48,6 +53,14 @@ export function changeNodeIntent(payload: string): interfaces.ChangeNodeIntentAc }; } +export type TChangeNodeIntentOneTime = typeof changeNodeIntentOneTime; +export function changeNodeIntentOneTime(payload: string): interfaces.ChangeNodeIntentOneTimeAction { + return { + type: TypeKeys.CONFIG_NODE_CHANGE_INTENT_ONETIME, + payload + }; +} + export type TChangeNodeForce = typeof changeNodeForce; export function changeNodeForce(payload: string): interfaces.ChangeNodeForceAction { return { diff --git a/common/actions/config/actionTypes.ts b/common/actions/config/actionTypes.ts index be46023a..0b8a57ba 100644 --- a/common/actions/config/actionTypes.ts +++ b/common/actions/config/actionTypes.ts @@ -2,9 +2,12 @@ import { TypeKeys } from './constants'; import { CustomNodeConfig, StaticNodeConfig } from 'types/node'; import { CustomNetworkConfig } from 'types/network'; -/*** Toggle Offline ***/ -export interface ToggleOfflineAction { - type: TypeKeys.CONFIG_TOGGLE_OFFLINE; +export interface SetOnlineAction { + type: TypeKeys.CONFIG_SET_ONLINE; +} + +export interface SetOfflineAction { + type: TypeKeys.CONFIG_SET_OFFLINE; } export interface ToggleAutoGasLimitAction { @@ -36,6 +39,13 @@ export interface ChangeNodeIntentAction { type: TypeKeys.CONFIG_NODE_CHANGE_INTENT; payload: string; } + +/*** Change Node Onetime ***/ +export interface ChangeNodeIntentOneTimeAction { + type: TypeKeys.CONFIG_NODE_CHANGE_INTENT_ONETIME; + payload: string; +} + /*** Force Change Node ***/ export interface ChangeNodeForceAction { type: TypeKeys.CONFIG_NODE_CHANGE_FORCE; @@ -95,7 +105,8 @@ export type NodeAction = export type MetaAction = | ChangeLanguageAction - | ToggleOfflineAction + | SetOnlineAction + | SetOfflineAction | ToggleAutoGasLimitAction | PollOfflineStatus | SetLatestBlockAction; diff --git a/common/actions/config/constants.ts b/common/actions/config/constants.ts index 5c5265d3..b2c2d421 100644 --- a/common/actions/config/constants.ts +++ b/common/actions/config/constants.ts @@ -1,6 +1,9 @@ export enum TypeKeys { CONFIG_LANGUAGE_CHANGE = 'CONFIG_LANGUAGE_CHANGE', + CONFIG_SET_ONLINE = 'CONFIG_SET_ONLINE', + CONFIG_SET_OFFLINE = 'CONFIG_SET_OFFLINE', + CONFIG_TOGGLE_OFFLINE = 'CONFIG_TOGGLE_OFFLINE', CONFIG_TOGGLE_AUTO_GAS_LIMIT = 'CONFIG_TOGGLE_AUTO_GAS_LIMIT', CONFIG_POLL_OFFLINE_STATUS = 'CONFIG_POLL_OFFLINE_STATUS', @@ -10,6 +13,7 @@ export enum TypeKeys { CONFIG_NODE_WEB3_UNSET = 'CONFIG_NODE_WEB3_UNSET', CONFIG_NODE_CHANGE = 'CONFIG_NODE_CHANGE', CONFIG_NODE_CHANGE_INTENT = 'CONFIG_NODE_CHANGE_INTENT', + CONFIG_NODE_CHANGE_INTENT_ONETIME = 'CONFIG_NODE_CHANGE_INTENT_ONETIME', CONFIG_NODE_CHANGE_FORCE = 'CONFIG_NODE_CHANGE_FORCE', CONFIG_ADD_CUSTOM_NODE = 'CONFIG_ADD_CUSTOM_NODE', diff --git a/common/actions/schedule/actionCreators/fields.ts b/common/actions/schedule/actionCreators/fields.ts new file mode 100644 index 00000000..ab1cf3d4 --- /dev/null +++ b/common/actions/schedule/actionCreators/fields.ts @@ -0,0 +1,117 @@ +import { + SetTimeBountyFieldAction, + SetWindowSizeFieldAction, + SetWindowStartFieldAction, + SetScheduleTimestampFieldAction, + SetScheduleTypeAction, + SetSchedulingToggleAction, + SetScheduleTimezoneAction, + SetScheduleGasPriceFieldAction, + SetScheduleGasLimitFieldAction, + SetScheduleDepositFieldAction, + SetScheduleParamsValidityAction +} from '../actionTypes'; +import { TypeKeys } from 'actions/schedule/constants'; + +type TSetTimeBountyField = typeof setTimeBountyField; +const setTimeBountyField = ( + payload: SetTimeBountyFieldAction['payload'] +): SetTimeBountyFieldAction => ({ + type: TypeKeys.TIME_BOUNTY_FIELD_SET, + payload +}); + +type TSetWindowSizeField = typeof setWindowSizeField; +const setWindowSizeField = ( + payload: SetWindowSizeFieldAction['payload'] +): SetWindowSizeFieldAction => ({ + type: TypeKeys.WINDOW_SIZE_FIELD_SET, + payload +}); + +type TSetWindowStartField = typeof setWindowStartField; +const setWindowStartField = ( + payload: SetWindowStartFieldAction['payload'] +): SetWindowStartFieldAction => ({ + type: TypeKeys.WINDOW_START_FIELD_SET, + payload +}); + +type TSetScheduleTimestampField = typeof setScheduleTimestampField; +const setScheduleTimestampField = ( + payload: SetScheduleTimestampFieldAction['payload'] +): SetScheduleTimestampFieldAction => ({ + type: TypeKeys.SCHEDULE_TIMESTAMP_FIELD_SET, + payload +}); + +type TSetScheduleType = typeof setScheduleType; +const setScheduleType = (payload: SetScheduleTypeAction['payload']): SetScheduleTypeAction => ({ + type: TypeKeys.SCHEDULE_TYPE_SET, + payload +}); + +type TSetSchedulingToggle = typeof setSchedulingToggle; +const setSchedulingToggle = ( + payload: SetSchedulingToggleAction['payload'] +): SetSchedulingToggleAction => ({ + type: TypeKeys.SCHEDULING_TOGGLE_SET, + payload +}); + +type TSetScheduleTimezone = typeof setScheduleTimezone; +const setScheduleTimezone = ( + payload: SetScheduleTimezoneAction['payload'] +): SetScheduleTimezoneAction => ({ + type: TypeKeys.SCHEDULE_TIMEZONE_SET, + payload +}); + +type TSetScheduleGasPriceField = typeof setScheduleGasPriceField; +const setScheduleGasPriceField = (payload: SetScheduleGasPriceFieldAction['payload']) => ({ + type: TypeKeys.SCHEDULE_GAS_PRICE_FIELD_SET, + payload +}); + +type TSetScheduleGasLimitField = typeof setScheduleGasLimitField; +const setScheduleGasLimitField = (payload: SetScheduleGasLimitFieldAction['payload']) => ({ + type: TypeKeys.SCHEDULE_GAS_LIMIT_FIELD_SET, + payload +}); + +type TSetScheduleDepositField = typeof setScheduleDepositField; +const setScheduleDepositField = (payload: SetScheduleDepositFieldAction['payload']) => ({ + type: TypeKeys.SCHEDULE_DEPOSIT_FIELD_SET, + payload +}); + +type TSetScheduleParamsValidity = typeof setScheduleParamsValidity; +const setScheduleParamsValidity = (payload: SetScheduleParamsValidityAction['payload']) => ({ + type: TypeKeys.SCHEDULE_PARAMS_VALIDITY_SET, + payload +}); + +export { + TSetWindowSizeField, + TSetWindowStartField, + TSetTimeBountyField, + TSetScheduleTimestampField, + TSetScheduleType, + TSetSchedulingToggle, + TSetScheduleTimezone, + TSetScheduleGasPriceField, + TSetScheduleGasLimitField, + TSetScheduleDepositField, + TSetScheduleParamsValidity, + setTimeBountyField, + setWindowSizeField, + setWindowStartField, + setScheduleTimestampField, + setScheduleType, + setSchedulingToggle, + setScheduleTimezone, + setScheduleGasPriceField, + setScheduleGasLimitField, + setScheduleDepositField, + setScheduleParamsValidity +}; diff --git a/common/actions/schedule/actionCreators/index.ts b/common/actions/schedule/actionCreators/index.ts new file mode 100644 index 00000000..a58fba82 --- /dev/null +++ b/common/actions/schedule/actionCreators/index.ts @@ -0,0 +1,7 @@ +export * from './fields'; +export * from './scheduleTimestamp'; +export * from './scheduleType'; +export * from './schedulingToggle'; +export * from './timeBounty'; +export * from './windowSize'; +export * from './windowStart'; diff --git a/common/actions/schedule/actionCreators/scheduleTimestamp.ts b/common/actions/schedule/actionCreators/scheduleTimestamp.ts new file mode 100644 index 00000000..caa0839c --- /dev/null +++ b/common/actions/schedule/actionCreators/scheduleTimestamp.ts @@ -0,0 +1,21 @@ +import { TypeKeys } from 'actions/schedule'; +import { + SetCurrentScheduleTimestampAction, + SetCurrentScheduleTimezoneAction +} from '../actionTypes/scheduleTimestamp'; + +export type TSetCurrentScheduleTimestamp = typeof setCurrentScheduleTimestamp; +export const setCurrentScheduleTimestamp = ( + payload: SetCurrentScheduleTimestampAction['payload'] +): SetCurrentScheduleTimestampAction => ({ + type: TypeKeys.CURRENT_SCHEDULE_TIMESTAMP_SET, + payload +}); + +export type TSetCurrentScheduleTimezone = typeof setCurrentScheduleTimezone; +export const setCurrentScheduleTimezone = ( + payload: SetCurrentScheduleTimezoneAction['payload'] +): SetCurrentScheduleTimezoneAction => ({ + type: TypeKeys.CURRENT_SCHEDULE_TIMEZONE_SET, + payload +}); diff --git a/common/actions/schedule/actionCreators/scheduleType.ts b/common/actions/schedule/actionCreators/scheduleType.ts new file mode 100644 index 00000000..9e5c78ed --- /dev/null +++ b/common/actions/schedule/actionCreators/scheduleType.ts @@ -0,0 +1,10 @@ +import { TypeKeys } from 'actions/schedule'; +import { SetCurrentScheduleTypeAction } from '../actionTypes/scheduleType'; + +export type TSetCurrentScheduleType = typeof setCurrentScheduleType; +export const setCurrentScheduleType = ( + payload: SetCurrentScheduleTypeAction['payload'] +): SetCurrentScheduleTypeAction => ({ + type: TypeKeys.CURRENT_SCHEDULE_TYPE, + payload +}); diff --git a/common/actions/schedule/actionCreators/schedulingToggle.ts b/common/actions/schedule/actionCreators/schedulingToggle.ts new file mode 100644 index 00000000..10c69a3b --- /dev/null +++ b/common/actions/schedule/actionCreators/schedulingToggle.ts @@ -0,0 +1,12 @@ +import { SetCurrentSchedulingToggleAction } from '../actionTypes/schedulingToggle'; +import { TypeKeys } from 'actions/schedule'; + +type TSetCurrentSchedulingToggle = typeof setCurrentSchedulingToggle; +const setCurrentSchedulingToggle = ( + payload: SetCurrentSchedulingToggleAction['payload'] +): SetCurrentSchedulingToggleAction => ({ + type: TypeKeys.CURRENT_SCHEDULING_TOGGLE, + payload +}); + +export { TSetCurrentSchedulingToggle, setCurrentSchedulingToggle }; diff --git a/common/actions/schedule/actionCreators/timeBounty.ts b/common/actions/schedule/actionCreators/timeBounty.ts new file mode 100644 index 00000000..8d138d81 --- /dev/null +++ b/common/actions/schedule/actionCreators/timeBounty.ts @@ -0,0 +1,12 @@ +import { SetCurrentTimeBountyAction } from '../actionTypes/timeBounty'; +import { TypeKeys } from 'actions/schedule'; + +type TSetCurrentTimeBounty = typeof setCurrentTimeBounty; +const setCurrentTimeBounty = ( + payload: SetCurrentTimeBountyAction['payload'] +): SetCurrentTimeBountyAction => ({ + type: TypeKeys.CURRENT_TIME_BOUNTY_SET, + payload +}); + +export { setCurrentTimeBounty, TSetCurrentTimeBounty }; diff --git a/common/actions/schedule/actionCreators/windowSize.ts b/common/actions/schedule/actionCreators/windowSize.ts new file mode 100644 index 00000000..0c321801 --- /dev/null +++ b/common/actions/schedule/actionCreators/windowSize.ts @@ -0,0 +1,12 @@ +import { SetCurrentWindowSizeAction } from '../actionTypes/windowSize'; +import { TypeKeys } from 'actions/schedule'; + +type TSetCurrentWindowSize = typeof setCurrentWindowSize; +const setCurrentWindowSize = ( + payload: SetCurrentWindowSizeAction['payload'] +): SetCurrentWindowSizeAction => ({ + type: TypeKeys.CURRENT_WINDOW_SIZE_SET, + payload +}); + +export { setCurrentWindowSize, TSetCurrentWindowSize }; diff --git a/common/actions/schedule/actionCreators/windowStart.ts b/common/actions/schedule/actionCreators/windowStart.ts new file mode 100644 index 00000000..c22a6dcb --- /dev/null +++ b/common/actions/schedule/actionCreators/windowStart.ts @@ -0,0 +1,12 @@ +import { SetCurrentWindowStartAction } from '../actionTypes/windowStart'; +import { TypeKeys } from 'actions/schedule'; + +type TSetCurrentWindowStart = typeof setCurrentWindowStart; +const setCurrentWindowStart = ( + payload: SetCurrentWindowStartAction['payload'] +): SetCurrentWindowStartAction => ({ + type: TypeKeys.CURRENT_WINDOW_START_SET, + payload +}); + +export { setCurrentWindowStart, TSetCurrentWindowStart }; diff --git a/common/actions/schedule/actionTypes/actionTypes.ts b/common/actions/schedule/actionTypes/actionTypes.ts new file mode 100644 index 00000000..fd0ead35 --- /dev/null +++ b/common/actions/schedule/actionTypes/actionTypes.ts @@ -0,0 +1,5 @@ +import { ScheduleFieldAction } from './fields'; + +export * from './fields'; + +export type ScheduleAction = ScheduleFieldAction; diff --git a/common/actions/schedule/actionTypes/fields.ts b/common/actions/schedule/actionTypes/fields.ts new file mode 100644 index 00000000..33177bd9 --- /dev/null +++ b/common/actions/schedule/actionTypes/fields.ts @@ -0,0 +1,116 @@ +import { TypeKeys } from 'actions/schedule/constants'; +import { Wei } from 'libs/units'; + +interface SetTimeBountyFieldAction { + type: TypeKeys.TIME_BOUNTY_FIELD_SET; + payload: { + raw: string; + value: Wei | null; + }; +} + +interface SetWindowSizeFieldAction { + type: TypeKeys.WINDOW_SIZE_FIELD_SET; + payload: { + raw: string; + value: Wei | null; + }; +} + +interface SetWindowStartFieldAction { + type: TypeKeys.WINDOW_START_FIELD_SET; + payload: { + raw: string; + value: number | null; + }; +} + +interface SetScheduleTimestampFieldAction { + type: TypeKeys.SCHEDULE_TIMESTAMP_FIELD_SET; + payload: { + raw: string; + value: Date; + }; +} + +interface SetScheduleTypeAction { + type: TypeKeys.SCHEDULE_TYPE_SET; + payload: { + raw: string; + value: string | null; + }; +} + +interface SetSchedulingToggleAction { + type: TypeKeys.SCHEDULING_TOGGLE_SET; + payload: { + value: boolean; + }; +} + +interface SetScheduleTimezoneAction { + type: TypeKeys.SCHEDULE_TIMEZONE_SET; + payload: { + raw: string; + value: string; + }; +} + +interface SetScheduleGasPriceFieldAction { + type: TypeKeys.SCHEDULE_GAS_PRICE_FIELD_SET; + payload: { + raw: string; + value: Wei | null; + }; +} + +interface SetScheduleGasLimitFieldAction { + type: TypeKeys.SCHEDULE_GAS_LIMIT_FIELD_SET; + payload: { + raw: string; + value: Wei | null; + }; +} + +interface SetScheduleDepositFieldAction { + type: TypeKeys.SCHEDULE_DEPOSIT_FIELD_SET; + payload: { + raw: string; + value: Wei | null; + }; +} + +interface SetScheduleParamsValidityAction { + type: TypeKeys.SCHEDULE_PARAMS_VALIDITY_SET; + payload: { + value: boolean; + }; +} + +type ScheduleFieldAction = + | SetTimeBountyFieldAction + | SetWindowSizeFieldAction + | SetWindowStartFieldAction + | SetScheduleTimestampFieldAction + | SetScheduleTypeAction + | SetSchedulingToggleAction + | SetScheduleGasPriceFieldAction + | SetScheduleGasLimitFieldAction + | SetScheduleDepositFieldAction + | SetScheduleTimezoneAction + | SetScheduleParamsValidityAction; + +export { + ScheduleFieldAction, + SetTimeBountyFieldAction, + SetWindowSizeFieldAction, + SetWindowStartFieldAction, + SetScheduleTimestampFieldAction, + SetScheduleTypeAction, + SetSchedulingToggleAction, + SetScheduleGasPriceFieldAction, + SetScheduleGasLimitFieldAction, + SetScheduleDepositFieldAction, + SetScheduleTimezoneAction, + SetScheduleParamsValidityAction +}; diff --git a/common/actions/schedule/actionTypes/index.ts b/common/actions/schedule/actionTypes/index.ts new file mode 100644 index 00000000..3eb256de --- /dev/null +++ b/common/actions/schedule/actionTypes/index.ts @@ -0,0 +1 @@ +export * from './actionTypes'; diff --git a/common/actions/schedule/actionTypes/scheduleTimestamp.ts b/common/actions/schedule/actionTypes/scheduleTimestamp.ts new file mode 100644 index 00000000..118aeffe --- /dev/null +++ b/common/actions/schedule/actionTypes/scheduleTimestamp.ts @@ -0,0 +1,17 @@ +import { TypeKeys } from 'actions/schedule'; + +/* user input */ + +interface SetCurrentScheduleTimestampAction { + type: TypeKeys.CURRENT_SCHEDULE_TIMESTAMP_SET; + payload: string; +} + +type CurrentAction = SetCurrentScheduleTimestampAction; + +interface SetCurrentScheduleTimezoneAction { + type: TypeKeys.CURRENT_SCHEDULE_TIMEZONE_SET; + payload: string; +} + +export { SetCurrentScheduleTimestampAction, CurrentAction, SetCurrentScheduleTimezoneAction }; diff --git a/common/actions/schedule/actionTypes/scheduleType.ts b/common/actions/schedule/actionTypes/scheduleType.ts new file mode 100644 index 00000000..a1cd667f --- /dev/null +++ b/common/actions/schedule/actionTypes/scheduleType.ts @@ -0,0 +1,12 @@ +import { TypeKeys } from 'actions/schedule'; + +/* user input */ + +interface SetCurrentScheduleTypeAction { + type: TypeKeys.CURRENT_SCHEDULE_TYPE; + payload: string; +} + +type CurrentAction = SetCurrentScheduleTypeAction; + +export { SetCurrentScheduleTypeAction, CurrentAction }; diff --git a/common/actions/schedule/actionTypes/schedulingToggle.ts b/common/actions/schedule/actionTypes/schedulingToggle.ts new file mode 100644 index 00000000..64fb3d93 --- /dev/null +++ b/common/actions/schedule/actionTypes/schedulingToggle.ts @@ -0,0 +1,12 @@ +import { TypeKeys } from 'actions/schedule'; + +/* user input */ + +interface SetCurrentSchedulingToggleAction { + type: TypeKeys.CURRENT_SCHEDULING_TOGGLE; + payload: string; +} + +type CurrentAction = SetCurrentSchedulingToggleAction; + +export { SetCurrentSchedulingToggleAction, CurrentAction }; diff --git a/common/actions/schedule/actionTypes/timeBounty.ts b/common/actions/schedule/actionTypes/timeBounty.ts new file mode 100644 index 00000000..ac35eacd --- /dev/null +++ b/common/actions/schedule/actionTypes/timeBounty.ts @@ -0,0 +1,12 @@ +import { TypeKeys } from 'actions/schedule'; + +/* user input */ + +interface SetCurrentTimeBountyAction { + type: TypeKeys.CURRENT_TIME_BOUNTY_SET; + payload: string; +} + +type CurrentAction = SetCurrentTimeBountyAction; + +export { SetCurrentTimeBountyAction, CurrentAction }; diff --git a/common/actions/schedule/actionTypes/windowSize.ts b/common/actions/schedule/actionTypes/windowSize.ts new file mode 100644 index 00000000..fd1465a7 --- /dev/null +++ b/common/actions/schedule/actionTypes/windowSize.ts @@ -0,0 +1,12 @@ +import { TypeKeys } from 'actions/schedule'; + +/* user input */ + +interface SetCurrentWindowSizeAction { + type: TypeKeys.CURRENT_WINDOW_SIZE_SET; + payload: string; +} + +type CurrentAction = SetCurrentWindowSizeAction; + +export { SetCurrentWindowSizeAction, CurrentAction }; diff --git a/common/actions/schedule/actionTypes/windowStart.ts b/common/actions/schedule/actionTypes/windowStart.ts new file mode 100644 index 00000000..cc528316 --- /dev/null +++ b/common/actions/schedule/actionTypes/windowStart.ts @@ -0,0 +1,12 @@ +import { TypeKeys } from 'actions/schedule'; + +/* user input */ + +interface SetCurrentWindowStartAction { + type: TypeKeys.CURRENT_WINDOW_START_SET; + payload: string; +} + +type CurrentAction = SetCurrentWindowStartAction; + +export { SetCurrentWindowStartAction, CurrentAction }; diff --git a/common/actions/schedule/constants.ts b/common/actions/schedule/constants.ts new file mode 100644 index 00000000..c3d4b698 --- /dev/null +++ b/common/actions/schedule/constants.ts @@ -0,0 +1,21 @@ +export enum TypeKeys { + CURRENT_TIME_BOUNTY_SET = 'CURRENT_TIME_BOUNTY_SET', + CURRENT_WINDOW_SIZE_SET = 'CURRENT_WINDOW_SIZE_SET', + CURRENT_WINDOW_START_SET = 'CURRENT_WINDOW_START_SET', + CURRENT_SCHEDULE_TIMESTAMP_SET = 'CURRENT_SCHEDULE_TIMESTAMP_SET', + CURRENT_SCHEDULE_TIMEZONE_SET = 'CURRENT_SCHEDULE_TIMEZONE_SET', + CURRENT_SCHEDULE_TYPE = 'CURRENT_SCHEDULE_TYPE', + CURRENT_SCHEDULING_TOGGLE = 'CURRENT_SCHEDULING_TOGGLE', + + TIME_BOUNTY_FIELD_SET = 'TIME_BOUNTY_FIELD_SET', + WINDOW_SIZE_FIELD_SET = 'WINDOW_SIZE_FIELD_SET', + WINDOW_START_FIELD_SET = 'WINDOW_START_FIELD_SET', + SCHEDULE_GAS_PRICE_FIELD_SET = 'SCHEDULE_GAS_PRICE_SET', + SCHEDULE_GAS_LIMIT_FIELD_SET = 'SCHEDULE_GAS_LIMIT_SET', + SCHEDULE_TIMESTAMP_FIELD_SET = 'SCHEDULE_TIMESTAMP_FIELD_SET', + SCHEDULE_TIMEZONE_SET = 'SCHEDULE_TIMEZONE_SET', + SCHEDULE_TYPE_SET = 'SCHEDULE_TYPE_SET', + SCHEDULING_TOGGLE_SET = 'SCHEDULING_TOGGLE_SET', + SCHEDULE_DEPOSIT_FIELD_SET = 'SCHEDULE_DEPOSIT_FIELD_SET', + SCHEDULE_PARAMS_VALIDITY_SET = 'SCHEDULE_PARAMS_VALIDITY_SET' +} diff --git a/common/actions/schedule/index.ts b/common/actions/schedule/index.ts new file mode 100644 index 00000000..d5122d97 --- /dev/null +++ b/common/actions/schedule/index.ts @@ -0,0 +1,3 @@ +export * from './actionCreators'; +export * from './constants'; +export * from './actionTypes'; diff --git a/common/assets/images/chronologic-logo.svg b/common/assets/images/chronologic-logo.svg new file mode 100644 index 00000000..0a2e3fde --- /dev/null +++ b/common/assets/images/chronologic-logo.svg @@ -0,0 +1,92 @@ + + + + + Layer 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common/assets/images/logo-ethercards.png b/common/assets/images/logo-ethercards.png new file mode 100644 index 00000000..496f934b Binary files /dev/null and b/common/assets/images/logo-ethercards.png differ diff --git a/common/assets/images/logo-mycrypto-transparent.svg b/common/assets/images/logo-mycrypto-transparent.svg new file mode 100644 index 00000000..73a3f86f --- /dev/null +++ b/common/assets/images/logo-mycrypto-transparent.svg @@ -0,0 +1 @@ +logo \ No newline at end of file diff --git a/common/components/BetaAgreement/index.tsx b/common/components/BetaAgreement/index.tsx index fa97718f..b8472e74 100644 --- a/common/components/BetaAgreement/index.tsx +++ b/common/components/BetaAgreement/index.tsx @@ -25,12 +25,13 @@ export default class BetaAgreement extends React.PureComponent<{}, State> { return (
-

Welcome to the New MyCrypto Beta!

+

Welcome to the New MyCrypto Beta Release Candidate!

- You are about to use a version of MyCrypto that hasn't been released yet. While we are - confident that it is close to being production ready, you may want to use the current - production site for larger or more time-sensitive transactions. + 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.

+

We hope to move this version of MyCrypto into production in the near future!

Feedback and bug reports are greatly appreciated. You can file issues on our{' '} @@ -46,7 +47,7 @@ export default class BetaAgreement extends React.PureComponent<{}, State> { className="BetaAgreement-content-buttons-btn is-continue" onClick={this.doContinue} > - Yes, continue to the Beta + Yes, continue to the Beta RC + +

+ +
+ +
+ +
+ +
{panelContent}
+
+
+ ); + } + + private openLanguageSelect = () => { + const panelContent = ; + this.setState({ + panelContent, + isPanelOpen: true + }); + }; + + private openNodeSelect = () => { + const panelContent = ; + this.setState({ + panelContent, + isPanelOpen: true + }); + }; + + private closePanel = () => { + const { panelContent } = this.state; + + // Start closing panel + this.setState({ isPanelOpen: false }); + + // Remove content when out of sight + setTimeout(() => { + if (this.state.panelContent === panelContent) { + this.setState({ panelContent: null }); + } + }, 300); + }; +} diff --git a/common/components/ElectronNav/LanguageSelect.scss b/common/components/ElectronNav/LanguageSelect.scss new file mode 100644 index 00000000..6df85cdf --- /dev/null +++ b/common/components/ElectronNav/LanguageSelect.scss @@ -0,0 +1,25 @@ +@import 'common/sass/variables'; +@import 'common/sass/mixins'; + +.LanguageSelect { + &-language { + @include reset-button; + display: block; + width: 100%; + height: 48px; + line-height: 48px; + padding: 0 10px; + color: $text-color; + border-bottom: 1px solid $gray-lighter; + text-align: left; + + &:hover { + color: $link-hover-color; + } + + &.is-selected { + color: $link-color; + background: $gray-lightest; + } + } +} diff --git a/common/components/ElectronNav/LanguageSelect.tsx b/common/components/ElectronNav/LanguageSelect.tsx new file mode 100644 index 00000000..1d4e336a --- /dev/null +++ b/common/components/ElectronNav/LanguageSelect.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import classnames from 'classnames'; +import { connect } from 'react-redux'; +import { languages } from 'config'; +import { TChangeLanguage, changeLanguage } from 'actions/config'; +import { getLanguageSelection } from 'selectors/config'; +import { AppState } from 'reducers'; +import './LanguageSelect.scss'; + +interface OwnProps { + closePanel(): void; +} + +interface StateProps { + languageSelection: string; +} + +interface DispatchProps { + changeLanguage: TChangeLanguage; +} + +type Props = OwnProps & StateProps & DispatchProps; + +class LanguageSelect extends React.Component { + public render() { + const { languageSelection } = this.props; + return ( +
+ {Object.entries(languages).map(lang => ( + + ))} +
+ ); + } + + private handleLanguageSelect = (lang: string) => { + this.props.changeLanguage(lang); + this.props.closePanel(); + }; +} + +export default connect( + (state: AppState): StateProps => ({ + languageSelection: getLanguageSelection(state) + }), + { + changeLanguage + } +)(LanguageSelect); diff --git a/common/components/ElectronNav/NetworkStatus.scss b/common/components/ElectronNav/NetworkStatus.scss new file mode 100644 index 00000000..3f96fb48 --- /dev/null +++ b/common/components/ElectronNav/NetworkStatus.scss @@ -0,0 +1,30 @@ +@import 'common/sass/variables'; + +.NetworkStatus { + display: flex; + align-items: center; + + &-icon { + width: 10px; + height: 10px; + margin-right: 4px; + border-radius: 100%; + + &.is-online { + background: $brand-success; + } + + &.is-offline { + background: $brand-danger; + } + + &.is-connecting { + background: $brand-warning; + } + } + + &-text { + color: $gray-dark; + font-size: 9px; + } +} diff --git a/common/components/ElectronNav/NetworkStatus.tsx b/common/components/ElectronNav/NetworkStatus.tsx new file mode 100644 index 00000000..367f5d54 --- /dev/null +++ b/common/components/ElectronNav/NetworkStatus.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import translate from 'translations'; +import { getNetworkConfig, getOffline, isNodeChanging } from 'selectors/config'; +import { NetworkConfig } from 'types/network'; +import { AppState } from 'reducers'; +import './NetworkStatus.scss'; + +enum NETWORK_STATUS { + CONNECTING = 'NETWORK_STATUS_CONNECTING', + OFFLINE = 'NETWORK_STATUS_OFFLINE', + ONLINE = 'NETWORK_STATUS_ONLINE' +} + +interface StateProps { + network: NetworkConfig; + isOffline: boolean; + isChangingNode: boolean; +} + +const NetworkStatus: React.SFC = ({ isOffline, isChangingNode, network }) => { + let statusClass: string; + let statusText: string; + const $network = network.isCustom ? network.unit : network.name; + + if (isChangingNode) { + statusClass = 'is-connecting'; + statusText = NETWORK_STATUS.CONNECTING; + } else if (isOffline) { + statusClass = 'is-offline'; + statusText = NETWORK_STATUS.OFFLINE; + } else { + statusClass = 'is-online'; + statusText = NETWORK_STATUS.ONLINE; + } + + return ( +
+
+
{translate(statusText, { $network })}
+
+ ); +}; + +export default connect((state: AppState): StateProps => ({ + network: getNetworkConfig(state), + isOffline: getOffline(state), + isChangingNode: isNodeChanging(state) +}))(NetworkStatus); diff --git a/common/components/ElectronNav/NodeSelect.scss b/common/components/ElectronNav/NodeSelect.scss new file mode 100644 index 00000000..b30e47cd --- /dev/null +++ b/common/components/ElectronNav/NodeSelect.scss @@ -0,0 +1,31 @@ +@import 'common/sass/variables'; +@import 'common/sass/mixins'; + +.NodeSelect { + &-node { + @include reset-button; + display: block; + width: 100%; + height: 48px; + line-height: 48px; + padding: 0 10px; + color: $text-color; + border-bottom: 1px solid $gray-lighter; + border-left: 4px solid; + text-align: left; + @include ellipsis; + + &:hover { + color: $link-hover-color; + } + + &.is-active { + color: $link-color; + background: $gray-lightest; + } + + small { + font-size: 12px; + } + } +} diff --git a/common/components/ElectronNav/NodeSelect.tsx b/common/components/ElectronNav/NodeSelect.tsx new file mode 100644 index 00000000..52f24f73 --- /dev/null +++ b/common/components/ElectronNav/NodeSelect.tsx @@ -0,0 +1,126 @@ +import React from 'react'; +import classnames from 'classnames'; +import { connect } from 'react-redux'; +import translate from 'translations'; +import CustomNodeModal from 'components/CustomNodeModal'; +import { + TChangeNodeIntent, + TAddCustomNode, + TRemoveCustomNode, + changeNodeIntent, + addCustomNode, + removeCustomNode, + AddCustomNodeAction +} from 'actions/config'; +import { + isNodeChanging, + getNodeId, + CustomNodeOption, + NodeOption, + getNodeOptions +} from 'selectors/config'; +import { AppState } from 'reducers'; +import './NodeSelect.scss'; + +interface OwnProps { + closePanel(): void; +} + +interface StateProps { + nodeSelection: AppState['config']['nodes']['selectedNode']['nodeId']; + isChangingNode: AppState['config']['nodes']['selectedNode']['pending']; + nodeOptions: (CustomNodeOption | NodeOption)[]; +} + +interface DispatchProps { + changeNodeIntent: TChangeNodeIntent; + addCustomNode: TAddCustomNode; + removeCustomNode: TRemoveCustomNode; +} + +type Props = OwnProps & StateProps & DispatchProps; + +interface State { + isAddingCustomNode: boolean; +} + +class NodeSelect extends React.Component { + public state: State = { + isAddingCustomNode: false + }; + + public render() { + const { nodeSelection, nodeOptions } = this.props; + const { isAddingCustomNode } = this.state; + + return ( +
+ {nodeOptions.map(node => ( + + ))} + + + +
+ ); + } + + private handleNodeSelect = (node: string) => { + this.props.changeNodeIntent(node); + this.props.closePanel(); + }; + + private renderNodeLabel(node: CustomNodeOption | NodeOption) { + return node.isCustom ? ( + + {node.label.network} - {node.label.nodeName} (custom) + + ) : ( + + {node.label.network} - ({node.label.service}) + + ); + } + + private openCustomNodeModal = () => { + this.setState({ isAddingCustomNode: true }); + }; + + private closeCustomNodeModal = () => { + this.setState({ isAddingCustomNode: false }); + }; + + private addCustomNode = (payload: AddCustomNodeAction['payload']) => { + this.props.addCustomNode(payload); + this.closeCustomNodeModal(); + }; +} + +export default connect( + (state: AppState): StateProps => ({ + isChangingNode: isNodeChanging(state), + nodeSelection: getNodeId(state), + nodeOptions: getNodeOptions(state) + }), + { + changeNodeIntent, + addCustomNode, + removeCustomNode + } +)(NodeSelect); diff --git a/common/components/ElectronNav/index.tsx b/common/components/ElectronNav/index.tsx new file mode 100644 index 00000000..b7fea679 --- /dev/null +++ b/common/components/ElectronNav/index.tsx @@ -0,0 +1,2 @@ +import ElectronNav from './ElectronNav'; +export default ElectronNav; diff --git a/common/components/ExtendedNotifications/TransactionSucceeded.tsx b/common/components/ExtendedNotifications/TransactionSucceeded.tsx index c2e1e51d..c09c4e4f 100644 --- a/common/components/ExtendedNotifications/TransactionSucceeded.tsx +++ b/common/components/ExtendedNotifications/TransactionSucceeded.tsx @@ -3,14 +3,16 @@ import { Link } from 'react-router-dom'; import translate from 'translations'; import { NewTabLink } from 'components/ui'; import { BlockExplorerConfig } from 'types/network'; +import { getTXDetailsCheckURL } from 'libs/scheduling'; import { etherChainExplorerInst } from 'config/data'; export interface TransactionSucceededProps { txHash: string; blockExplorer?: BlockExplorerConfig; + scheduling?: boolean; } -const TransactionSucceeded = ({ txHash, blockExplorer }: TransactionSucceededProps) => { +const TransactionSucceeded = ({ txHash, blockExplorer, scheduling }: TransactionSucceededProps) => { let verifyBtn: React.ReactElement | undefined; let altVerifyBtn: React.ReactElement | undefined; if (blockExplorer) { @@ -30,11 +32,21 @@ const TransactionSucceeded = ({ txHash, blockExplorer }: TransactionSucceededPro ); } + let scheduleDetailsBtn: React.ReactElement | undefined; + if (scheduling) { + scheduleDetailsBtn = ( + + {translate('SCHEDULE_CHECK')} + + ); + } + return (

{translate('SUCCESS_3')} {txHash}

+ {scheduleDetailsBtn} {verifyBtn} {altVerifyBtn} diff --git a/common/components/Footer/index.tsx b/common/components/Footer/index.tsx index a6776173..ecbda241 100644 --- a/common/components/Footer/index.tsx +++ b/common/components/Footer/index.tsx @@ -1,22 +1,22 @@ import logo from 'assets/images/logo-mycrypto.svg'; import { - ledgerReferralURL, - trezorReferralURL, - ethercardReferralURL, donationAddressMap, VERSION, knowledgeBaseURL, - discordURL + socialMediaLinks, + productLinks, + affiliateLinks, + partnerLinks } from 'config'; import React from 'react'; import PreFooter from './PreFooter'; -import DisclaimerModal from './DisclaimerModal'; +import DisclaimerModal from 'components/DisclaimerModal'; import { NewTabLink } from 'components/ui'; import OnboardModal from 'containers/OnboardModal'; import './index.scss'; import { translateRaw } from 'translations'; -const SocialMediaLink = ({ link, text }: Link) => { +const SocialMediaLink = ({ link, text }: { link: string; text: string }) => { return ( @@ -24,101 +24,6 @@ const SocialMediaLink = ({ link, text }: Link) => { ); }; -const SOCIAL_MEDIA: Link[] = [ - { - link: 'https://twitter.com/mycrypto', - text: 'twitter' - }, - { - link: 'https://www.facebook.com/MyCrypto/', - text: 'facebook' - }, - { - link: 'https://medium.com/@mycrypto', - text: 'medium' - }, - { - link: 'https://www.linkedin.com/company/mycrypto', - text: 'linkedin' - }, - { - link: 'https://github.com/MyCryptoHQ', - text: 'github' - }, - { - link: 'https://www.reddit.com/r/mycrypto/', - text: 'reddit' - }, - { - link: discordURL, - text: 'discord' - } -]; - -const PRODUCT_INFO: Link[] = [ - { - link: - 'https://chrome.google.com/webstore/detail/etheraddresslookup/pdknmigbbbhmllnmgdfalmedcmcefdfn', - text: translateRaw('ETHER_ADDRESS_LOOKUP') - }, - { - link: - 'https://chrome.google.com/webstore/detail/ethersecuritylookup/bhhfhgpgmifehjdghlbbijjaimhmcgnf', - text: translateRaw('ETHER_SECURITY_LOOKUP') - }, - { - link: 'https://etherscamdb.info/', - text: translateRaw('ETHERSCAMDB') - }, - { - link: 'https://www.mycrypto.com/helpers.html', - text: translateRaw('FOOTER_HELP_AND_DEBUGGING') - }, - { - link: 'mailto:press@mycrypto.com', - text: translateRaw('FOOTER_PRESS') - } -]; - -const AFFILIATES: Link[] = [ - { - link: ledgerReferralURL, - text: translateRaw('LEDGER_REFERRAL_1') - }, - { - link: trezorReferralURL, - text: translateRaw('TREZOR_REFERAL') - }, - { - link: ethercardReferralURL, - text: translateRaw('ETHERCARD_REFERAL') - } -]; - -const FRIENDS: Link[] = [ - { - link: 'https://metamask.io/', - text: 'MetaMask' - }, - { - link: 'https://infura.io/', - text: 'Infura' - }, - { - link: 'https://etherscan.io/', - text: 'Etherscan' - }, - { - link: 'https://etherchain.org/', - text: 'Etherchain' - } -]; - -interface Link { - link: string; - text: string; -} - interface Props { latestBlock: string; } @@ -139,7 +44,7 @@ export default class Footer extends React.PureComponent {