Logout Prompt Modal on Navigation from Send (#275)
* Add disclaimer modal to footer * Remove duplicate code & unnecessary styles * Fix formatting noise * remove un-used css style * Fix tslint error & add media query for modals * Nest Media Query * Add NavigationPrompt component * Fix types * Fix types * Extend History Types * break out logic into setupUnblock method
This commit is contained in:
parent
2e472e5c5a
commit
4858f96520
|
@ -99,3 +99,10 @@ export function broadCastTxFailed(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TResetWallet = typeof resetWallet;
|
||||||
|
export function resetWallet() {
|
||||||
|
return {
|
||||||
|
type: constants.WALLET_RESET
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@ export interface SetWalletAction {
|
||||||
payload: IWallet;
|
payload: IWallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** Reset Wallet ***/
|
||||||
|
export interface ResetWalletAction {
|
||||||
|
type: 'WALLET_RESET';
|
||||||
|
}
|
||||||
|
|
||||||
/*** Set Balance ***/
|
/*** Set Balance ***/
|
||||||
export interface SetBalanceAction {
|
export interface SetBalanceAction {
|
||||||
type: 'WALLET_SET_BALANCE';
|
type: 'WALLET_SET_BALANCE';
|
||||||
|
@ -84,6 +89,7 @@ export interface BroadcastTxFailedAction {
|
||||||
export type WalletAction =
|
export type WalletAction =
|
||||||
| UnlockPrivateKeyAction
|
| UnlockPrivateKeyAction
|
||||||
| SetWalletAction
|
| SetWalletAction
|
||||||
|
| ResetWalletAction
|
||||||
| SetBalanceAction
|
| SetBalanceAction
|
||||||
| SetTokenBalancesAction
|
| SetTokenBalancesAction
|
||||||
| BroadcastTxRequestedAction
|
| BroadcastTxRequestedAction
|
||||||
|
|
|
@ -7,3 +7,4 @@ export const WALLET_SET_TOKEN_BALANCES = 'WALLET_SET_TOKEN_BALANCES';
|
||||||
export const WALLET_BROADCAST_TX_REQUESTED = 'WALLET_BROADCAST_TX_REQUESTED';
|
export const WALLET_BROADCAST_TX_REQUESTED = 'WALLET_BROADCAST_TX_REQUESTED';
|
||||||
export const WALLET_BROADCAST_TX_FAILED = 'WALLET_BROADCAST_TX_FAILED';
|
export const WALLET_BROADCAST_TX_FAILED = 'WALLET_BROADCAST_TX_FAILED';
|
||||||
export const WALLET_BROADCAST_TX_SUCCEEDED = 'WALLET_BROADCAST_TX_SUCCEEDED';
|
export const WALLET_BROADCAST_TX_SUCCEEDED = 'WALLET_BROADCAST_TX_SUCCEEDED';
|
||||||
|
export const WALLET_RESET = 'WALLET_RESET';
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
import Modal, { IButton } from 'components/ui/Modal';
|
||||||
|
import { Location, History as H } from 'history';
|
||||||
|
|
||||||
|
type UnregisterCallback = () => void;
|
||||||
|
type BooleanCallback = (arg?: any) => boolean;
|
||||||
|
interface History extends H {
|
||||||
|
block(prompt?: boolean | BooleanCallback): UnregisterCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
when: boolean;
|
||||||
|
onConfirm?: any;
|
||||||
|
onCancel?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InjectedProps extends Props {
|
||||||
|
location: Location;
|
||||||
|
history: History;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
nextLocation: Location | null;
|
||||||
|
openModal: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class NavigationPrompt extends React.Component<Props, State> {
|
||||||
|
public unblock;
|
||||||
|
get injected() {
|
||||||
|
return this.props as InjectedProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
nextLocation: null,
|
||||||
|
openModal: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public setupUnblock() {
|
||||||
|
this.unblock = this.injected.history.block(nextLocation => {
|
||||||
|
if (
|
||||||
|
this.props.when &&
|
||||||
|
nextLocation.pathname !== this.injected.location.pathname
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
openModal: true,
|
||||||
|
nextLocation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return !this.props.when;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
this.setupUnblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
this.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onCancel = () => {
|
||||||
|
if (this.props.onCancel) {
|
||||||
|
this.props.onCancel();
|
||||||
|
}
|
||||||
|
this.setState({ nextLocation: null, openModal: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
public onConfirm = () => {
|
||||||
|
if (this.props.onConfirm) {
|
||||||
|
this.props.onConfirm();
|
||||||
|
}
|
||||||
|
// Lock Wallet
|
||||||
|
this.navigateToNextLocation();
|
||||||
|
};
|
||||||
|
|
||||||
|
public navigateToNextLocation() {
|
||||||
|
this.unblock();
|
||||||
|
if (this.state.nextLocation) {
|
||||||
|
this.injected.history.push(this.state.nextLocation.pathname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const buttons: IButton[] = [
|
||||||
|
{ text: 'Log Out', type: 'primary', onClick: this.onConfirm },
|
||||||
|
{ text: 'Cancel', type: 'default', onClick: this.onCancel }
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="You are about to log out"
|
||||||
|
isOpen={this.state.openModal}
|
||||||
|
handleClose={this.onCancel}
|
||||||
|
buttons={buttons}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
Leaving this page will log you out. Are you sure you want to continue?
|
||||||
|
</p>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(NavigationPrompt);
|
|
@ -1,11 +1,17 @@
|
||||||
import { showNotification, TShowNotification } from 'actions/notifications';
|
import { showNotification, TShowNotification } from 'actions/notifications';
|
||||||
import { broadcastTx, TBroadcastTx } from 'actions/wallet';
|
import {
|
||||||
|
broadcastTx,
|
||||||
|
TBroadcastTx,
|
||||||
|
resetWallet,
|
||||||
|
TResetWallet
|
||||||
|
} from 'actions/wallet';
|
||||||
import Big from 'bignumber.js';
|
import Big from 'bignumber.js';
|
||||||
import { BalanceSidebar } from 'components';
|
import { BalanceSidebar } from 'components';
|
||||||
// COMPONENTS
|
// COMPONENTS
|
||||||
import { UnlockHeader } from 'components/ui';
|
import { UnlockHeader } from 'components/ui';
|
||||||
import { donationAddressMap, NetworkConfig, NodeConfig } from 'config/data';
|
import { donationAddressMap, NetworkConfig, NodeConfig } from 'config/data';
|
||||||
import TabSection from 'containers/TabSection';
|
import TabSection from 'containers/TabSection';
|
||||||
|
import NavigationPrompt from './components/NavigationPrompt';
|
||||||
// CONFIG
|
// CONFIG
|
||||||
import { TransactionWithoutGas } from 'libs/messages';
|
import { TransactionWithoutGas } from 'libs/messages';
|
||||||
import { RPCNode } from 'libs/nodes';
|
import { RPCNode } from 'libs/nodes';
|
||||||
|
@ -92,6 +98,7 @@ interface Props {
|
||||||
transactions: BroadcastTransactionStatus[];
|
transactions: BroadcastTransactionStatus[];
|
||||||
showNotification: TShowNotification;
|
showNotification: TShowNotification;
|
||||||
broadcastTx: TBroadcastTx;
|
broadcastTx: TBroadcastTx;
|
||||||
|
resetWallet: TResetWallet;
|
||||||
location: { search: string };
|
location: { search: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,12 +179,14 @@ export class SendTransaction extends React.Component<Props, State> {
|
||||||
transaction
|
transaction
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const customMessage = customMessages.find(m => m.to === to);
|
const customMessage = customMessages.find(m => m.to === to);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabSection>
|
<TabSection>
|
||||||
<section className="Tab-content">
|
<section className="Tab-content">
|
||||||
<UnlockHeader title={'NAV_SendEther'} />
|
<UnlockHeader title={'NAV_SendEther'} />
|
||||||
|
<NavigationPrompt
|
||||||
|
when={unlocked}
|
||||||
|
onConfirm={this.props.resetWallet}
|
||||||
|
/>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{/* Send Form */}
|
{/* Send Form */}
|
||||||
{unlocked && (
|
{unlocked && (
|
||||||
|
@ -272,7 +281,6 @@ export class SendTransaction extends React.Component<Props, State> {
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{transaction &&
|
{transaction &&
|
||||||
showTxConfirm && (
|
showTxConfirm && (
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
|
@ -489,6 +497,8 @@ function mapStateToProps(state: AppState) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, { showNotification, broadcastTx })(
|
export default connect(mapStateToProps, {
|
||||||
SendTransaction
|
showNotification,
|
||||||
);
|
broadcastTx,
|
||||||
|
resetWallet
|
||||||
|
})(SendTransaction);
|
||||||
|
|
|
@ -109,6 +109,8 @@ export function wallet(
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'WALLET_SET':
|
case 'WALLET_SET':
|
||||||
return setWallet(state, action);
|
return setWallet(state, action);
|
||||||
|
case 'WALLET_RESET':
|
||||||
|
return INITIAL_STATE;
|
||||||
case 'WALLET_SET_BALANCE':
|
case 'WALLET_SET_BALANCE':
|
||||||
return setBalance(state, action);
|
return setBalance(state, action);
|
||||||
case 'WALLET_SET_TOKEN_BALANCES':
|
case 'WALLET_SET_TOKEN_BALANCES':
|
||||||
|
|
Loading…
Reference in New Issue