Commit 370d9e10 authored by Kenny Tran's avatar Kenny Tran Committed by Chi Kei Chan

Pending transactions modal (#67)

* Create pending transactions modal

* Add pending icon
parent 9db88515
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.1603 6C10.7795 8.39146 7.72159 9.21084 5.33013 7.83013C2.93866 6.44942 2.11929 3.39146 3.5 1" stroke="#2F80ED" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
import React from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { drizzleConnect } from 'drizzle-react'
import classnames from 'classnames';
import Web3 from 'web3';
import Jazzicon from 'jazzicon';
import { CSSTransitionGroup } from "react-transition-group";
import './web3-status.scss';
import Pending from '../../assets/images/pending.svg';
import Modal from '../Modal';
function Web3Status(props) {
const { address } = props;
function getEtherscanLink(tx) {
return `https://etherscan.io/tx/${tx}`;
}
return (
<div
className={classnames("web3-status", {
'web3-status__connected': props.isConnected,
})}
>
class Web3Status extends Component {
state = {
isShowingModal: false,
};
handleClick = () => {
if (this.props.hasPendingTransactions && !this.state.isShowingModal) {
this.setState({isShowingModal: true});
}
}
renderPendingTransactions() {
return this.props.pendingTransactions.map((transaction) => {
return (
<div
key={transaction}
className={classnames('pending-modal__transaction-row')}
onClick={() => window.open(getEtherscanLink(transaction), '_blank')}
>
<div className="pending-modal__transaction-label">
{transaction}
</div>
<div className="pending-modal__pending-indicator">
<img src={Pending} />
Pending
</div>
</div>
);
});
}
renderModal() {
if (!this.state.isShowingModal) {
return null;
}
return (
<Modal onClose={() => this.setState({ isShowingModal: false })}>
<CSSTransitionGroup
transitionName="token-modal"
transitionAppear={true}
transitionLeave={true}
transitionAppearTimeout={200}
transitionLeaveTimeout={200}
transitionEnterTimeout={200}
>
<div className="pending-modal">
<div className="pending-modal__transaction-list">
<div className="pending-modal__header">Transactions</div>
{this.renderPendingTransactions()}
</div>
</div>
</CSSTransitionGroup>
</Modal>
);
}
render() {
const { address, transactions, pendingTransactions, hasPendingTransactions } = this.props;
console.count('hi');
let text = getText(address);
if (hasPendingTransactions) {
text = getPendingText(pendingTransactions);
}
return (
<div
className="web3-status__identicon"
ref={el => {
if (!el) {
return;
}
className={classnames("web3-status", {
'web3-status__connected': this.props.isConnected,
})}
onClick={this.handleClick}
>
<div
className="web3-status__identicon"
ref={el => {
if (!el) {
return;
}
if (!address|| address.length < 42 || !Web3.utils.isHexStrict(address)) {
return;
}
if (!address|| address.length < 42 || !Web3.utils.isHexStrict(address)) {
return;
}
el.innerHTML = '';
el.appendChild(Jazzicon(18, parseInt(address.slice(2), 16)));
}}
/>
<div className="web3-status__text">
{ getText(props.address) }
el.innerHTML = '';
el.appendChild(Jazzicon(18, parseInt(address.slice(2), 16)));
}}
/>
<div className="web3-status__text">
{
hasPendingTransactions ?
getPendingText(pendingTransactions) :
getText(address)
}
</div>
{this.renderModal()}
</div>
);
}
}
function getPendingText(pendingTransactions) {
return (
<div className="web3-status__pending-container">
<img key="icon" src={Pending} />
<span key="text">{pendingTransactions.length} Pending</span>
</div>
)
);
}
function getText(text) {
......@@ -43,7 +130,6 @@ function getText(text) {
}
const address = Web3.utils.toChecksumAddress(text);
return `${address.substring(0, 6)}...${address.substring(38)}`;
}
......@@ -59,8 +145,19 @@ Web3Status.defaultProps = {
export default drizzleConnect(
Web3Status,
state => ({
address: state.accounts[0],
isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
})
state => {
const pendingTransactions = [];
Object.keys(state.transactions).forEach((transaction) => {
if (state.transactions[transaction] && state.transactions[transaction].status === 'pending') {
pendingTransactions.push(transaction);
}
});
return {
address: state.accounts[0],
isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
pendingTransactions,
hasPendingTransactions: pendingTransactions.length > 0,
};
}
);
......@@ -28,4 +28,74 @@
margin-left: 1rem;
font-size: .85rem;
}
}
\ No newline at end of file
&__pending-container {
display: flex;
justify-content: space-around;
}
}
.pending-modal {
background-color: $white;
position: relative;
bottom: 12rem;
height: 12rem;
width: 100%;
z-index: 2000;
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
transition: 250ms ease-in-out;
&__transaction-list {
height: 12rem;
overflow-y: auto;
}
&__transaction-row {
@extend %row-nowrap;
box-sizing: border-box;
align-items: center;
padding: 0.25rem 1.5rem;
justify-content: space-between;
cursor: pointer;
width: 100%;
user-select: none;
}
&__transaction-label {
color: $royal-blue;
width: 60%;
overflow: hidden;
text-overflow: ellipsis;
font-weight: 200;
}
&__pending-indicator {
color: $royal-blue;
border: 1px solid $zumthor-blue;
padding: 10px;
border-radius: 100px;
& > img {
margin-right: 10px;
}
}
&__header {
font-size: 1rem;
color: $dove-gray;
padding: 1rem 1.5rem 0.25rem 1.5rem;
}
}
.pending-modal-appear {
bottom: 0;
}
.pending-modal-appear.modal-container-appear-active {
bottom: 0;
}
......@@ -28,5 +28,6 @@ html, body {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 200;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment