Add Check TX Button to Transaction Notification (#1217)

* Reinstates v3 behavior on transaction send:

* Alert shows Check TX Status button

* Check TX page uses txHash query param

* LogOutPrompt now carries over search params and hash

* Remove console log

* Update test.
This commit is contained in:
William O'Beirne 2018-03-05 13:58:53 -05:00 committed by Daniel Ternyak
parent e3194a649e
commit 3a36818412
8 changed files with 62 additions and 46 deletions

View File

@ -1,26 +1,33 @@
import React from 'react';
import { translateRaw } from 'translations';
import { Link } from 'react-router-dom';
import translate from 'translations';
import { NewTabLink } from 'components/ui';
import { BlockExplorerConfig } from 'types/network';
export interface TransactionSucceededProps {
txHash: string;
blockExplorer: BlockExplorerConfig;
blockExplorer?: BlockExplorerConfig;
}
const TransactionSucceeded = ({ txHash, blockExplorer }: TransactionSucceededProps) => {
const txHashLink = blockExplorer.txUrl(txHash);
let verifyBtn: React.ReactElement<string> | undefined;
if (blockExplorer) {
verifyBtn = (
<NewTabLink className="btn btn-xs" href={blockExplorer.txUrl(txHash)}>
Verify Transaction on {blockExplorer.name}
</NewTabLink>
);
}
return (
<div>
<p>{translateRaw('SUCCESS_3') + txHash}</p>
<a
className="btn btn-xs btn-info string"
href={txHashLink}
target="_blank"
rel="noopener noreferrer"
>
Verify Transaction
</a>
<p>
{translate('SUCCESS_3')} {txHash}
</p>
{verifyBtn}
<Link to={`/tx-status?txHash=${txHash}`} className="btn btn-xs">
{translate('NAV_CheckTxStatus')}
</Link>
</div>
);
};

View File

@ -62,7 +62,7 @@ class LogOutPromptClass extends React.Component<Props, State> {
};
private onConfirm = () => {
const { nextLocation } = this.state;
const { nextLocation: next } = this.state;
this.props.resetWallet();
this.setState(
{
@ -70,8 +70,8 @@ class LogOutPromptClass extends React.Component<Props, State> {
nextLocation: null
},
() => {
if (nextLocation) {
this.props.history.push(nextLocation.pathname);
if (next) {
this.props.history.push(`${next.pathname}${next.search}${next.hash}`);
}
}
);

View File

@ -1,15 +1,17 @@
import React from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps } from 'react-router';
import TabSection from 'containers/TabSection';
import TxHashInput from './components/TxHashInput';
import { TransactionStatus as TransactionStatusComponent } from 'components';
import { NewTabLink } from 'components/ui';
import { getNetworkConfig } from 'selectors/config';
import { getParamFromURL } from 'utils/helpers';
import { AppState } from 'reducers';
import { NetworkConfig } from 'types/network';
import './index.scss';
interface Props {
interface StateProps {
network: NetworkConfig;
}
@ -17,11 +19,20 @@ interface State {
hash: string;
}
type Props = StateProps & RouteComponentProps<{}>;
class CheckTransaction extends React.Component<Props, State> {
public state: State = {
hash: ''
};
public componentDidMount() {
const hash = getParamFromURL(this.props.location.search, 'txHash');
if (hash) {
this.setState({ hash });
}
}
public render() {
const { network } = this.props;
const { hash } = this.state;
@ -43,7 +54,7 @@ class CheckTransaction extends React.Component<Props, State> {
</React.Fragment>
)}
</p>
<TxHashInput onSubmit={this.handleHashSubmit} />
<TxHashInput hash={hash} onSubmit={this.handleHashSubmit} />
</section>
{hash && (
@ -64,6 +75,6 @@ class CheckTransaction extends React.Component<Props, State> {
};
}
export default connect((state: AppState) => ({
export default connect((state: AppState): StateProps => ({
network: getNetworkConfig(state)
}))(CheckTransaction);

View File

@ -20,6 +20,7 @@ import React from 'react';
import { getNetworkConfig } from 'selectors/config';
import TransactionSucceeded from 'components/ExtendedNotifications/TransactionSucceeded';
import { computeIndexingHash } from 'libs/transaction';
import { NetworkConfig } from 'types/network';
export const broadcastTransactionWrapper = (func: (serializedTx: string) => SagaIterator) =>
function* handleBroadcastTransaction(action: BroadcastRequestedAction) {
@ -29,7 +30,7 @@ export const broadcastTransactionWrapper = (func: (serializedTx: string) => Saga
);
try {
const shouldBroadcast = yield call(shouldBroadcastTransaction, indexingHash);
const shouldBroadcast: boolean = yield call(shouldBroadcastTransaction, indexingHash);
if (!shouldBroadcast) {
yield put(
showNotification(
@ -46,16 +47,19 @@ export const broadcastTransactionWrapper = (func: (serializedTx: string) => Saga
});
yield put(queueAction);
const stringTx: string = yield call(bufferToHex, serializedTransaction);
const broadcastedHash = yield call(func, stringTx); // convert to string because node / web3 doesnt support buffers
const broadcastedHash: string = yield call(func, stringTx); // convert to string because node / web3 doesnt support buffers
yield put(broadcastTransactionSucceeded({ indexingHash, broadcastedHash }));
const network = yield select(getNetworkConfig);
//TODO: make this not ugly
const network: NetworkConfig = yield select(getNetworkConfig);
yield put(
showNotification(
'success',
<TransactionSucceeded txHash={broadcastedHash} blockExplorer={network.blockExplorer} />,
0
<TransactionSucceeded
txHash={broadcastedHash}
blockExplorer={network.isCustom ? undefined : network.blockExplorer}
/>,
Infinity
)
);
} catch (error) {

View File

@ -1,7 +1,7 @@
// Extends Bootstrap's `.alert`
@import "common/sass/variables";
@import "common/sass/mixins";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/alerts";
@import 'common/sass/variables';
@import 'common/sass/mixins';
@import '~bootstrap-sass/assets/stylesheets/bootstrap/alerts';
.alert {
margin-bottom: 1rem;
@ -16,6 +16,13 @@
opacity: 0.8;
}
}
// Alerts have their own button style
.btn {
@include button-variant($text-color, #FFF, darken(#FFF, 5%));
text-decoration: none;
margin-right: $space-xs;
}
}
// Alert icons

View File

@ -100,24 +100,6 @@
}
// Contextual color overrides (?)
.alert .btn-info {
background-color: white;
text-decoration: none;
color: $brand-info;
&:hover,
&:focus,
&.focus {
text-decoration: none;
opacity: 1;
}
&.disabled {
background-color: white;
text-decoration: none;
color: $brand-info;
opacity: 0.6;
}
}
.btn-group .btn-default {
border-bottom-width: 1px;
border-color: transparent;

View File

@ -1,3 +1,4 @@
import qs from 'query-string';
import has from 'lodash/has';
export function objectContainsObjectKeys(checkingObject, containingObject) {
@ -19,6 +20,10 @@ export function getParam(query: { [key: string]: string }, key: string) {
return query[keys[index]];
}
export function getParamFromURL(url: string, param: string): string | undefined {
return qs.parse(qs.extract(url))[param];
}
export function isPositiveInteger(n: number) {
return Number.isInteger(n) && n > 0;
}

View File

@ -128,7 +128,7 @@ describe('broadcastTransactionWrapper*', () => {
showNotification(
'success',
<TransactionSucceeded txHash={broadcastedHash} blockExplorer={network.blockExplorer} />,
0
Infinity
)
)
);