William O'Beirne bf4171dfbd Transaction confirmation modal (#108)
* Add a little arrow icon.

* Replaced toEther function with toUnit to reduce the number of conversion functions wed need. Add tests for conversion functions.

* First pass at a styled confirm transaction modal.

* More data about data

* Hook up generated transaction with modal

* Fix modal position

* Add from address. Restyle a bit.

* Only show textareas and button if transaction has been generated.

* Remove need for param.

* Copy.

* Use non-relative path.

* Initial crack at transaction token support.

* Fix flow type

* Unit tests for contracts and erc20

* Convert contract class to ethereumjs-abi, caught a bug

* Add decodeArgs for contracts, decodeTransfer for erc20

* Show token value in modal

* Show value from transaction data in confirmation.

* Show address of receiver, not token contract

* Flow type

* Only accept bigs

* Unlog

* Use ethereumjs-abis method ID function

* Get transaction stuff out of state. Leave todo notes.

* Intuit token from transaction to address.

* Move generate transaction out of node and into libs/transaction.

* timeout -> interval

* Promise.reject -> throw

* Get default currency from network.

* Add more unit tests for decoding. Adopt the $ prefix for decoding calls.

* Use signed transaction in confirmation modal.
2017-08-23 08:57:18 +02:00

118 lines
2.7 KiB
JavaScript

// @flow
import React, { Component } from 'react';
import closeIcon from 'assets/images/icon-x.svg';
import './Modal.scss';
type Props = {
isOpen?: boolean,
title: string,
buttons: {
text: string,
type?:
| 'default'
| 'primary'
| 'success'
| 'info'
| 'warning'
| 'danger'
| 'link',
disabled?: boolean,
// $FlowFixMe - Why the fuck doesn't this like onClick?
onClick: () => void
}[],
handleClose: () => void,
children: any
};
export default class Modal extends Component {
props: Props;
componentDidMount() {
this.updateBodyClass();
document.addEventListener('keydown', this._escapeListner);
}
componentDidUpdate() {
this.updateBodyClass();
}
updateBodyClass() {
// $FlowFixMe
document.body.classList.toggle('no-scroll', !!this.props.isOpen);
}
componentWillUnmount() {
document.removeEventListener('keydown', this._escapeListner);
// $FlowFixMe
document.body.classList.remove('no-scroll');
}
_escapeListner = (ev: KeyboardEvent) => {
// Don't trigger if they hit escape while on an input
if (ev.target) {
if (
ev.target.tagName === 'INPUT' ||
ev.target.tagName === 'SELECT' ||
ev.target.tagName === 'TEXTAREA' ||
ev.target.isContentEditable
) {
return;
}
}
if (ev.key === 'Escape' || ev.keyCode === 27) {
this.props.handleClose();
}
};
_renderButtons() {
return this.props.buttons.map((btn, idx) => {
let btnClass = 'Modal-footer-btn btn';
if (btn.type) {
btnClass += ` btn-${btn.type}`;
}
return (
<button
className={btnClass}
onClick={btn.onClick}
key={idx}
disabled={btn.disabled}
>
{btn.text}
</button>
);
});
}
render() {
const { isOpen, title, children, buttons, handleClose } = this.props;
const hasButtons = buttons && buttons.length;
return (
<div>
<div className={`Modalshade ${isOpen ? 'is-open' : ''}`} />
<div className={`Modal ${isOpen ? 'is-open' : ''}`}>
<div className="Modal-header">
<h2 className="Modal-header-title">
{title}
</h2>
<button className="Modal-header-close" onClick={handleClose}>
<img className="Modal-header-close-icon" src={closeIcon} />
</button>
</div>
<div className="Modal-content">
{isOpen && children}
</div>
{hasButtons &&
<div className="Modal-footer">
{this._renderButtons()}
</div>}
</div>
</div>
);
}
}