Shapeshift Token Box UI (#1371)
* Convert to box style, fix TRST * Disabled option, better responsive behavior. * Removed unnecessary logic of splitting out origin and destination option arrays.
This commit is contained in:
parent
bdaf40a0ce
commit
02711b390f
|
@ -193,8 +193,7 @@ class ShapeshiftService {
|
||||||
private mapMarketInfo(marketInfo: (IPairData & IAvailablePairData)[]) {
|
private mapMarketInfo(marketInfo: (IPairData & IAvailablePairData)[]) {
|
||||||
const tokenMap: TokenMap = {};
|
const tokenMap: TokenMap = {};
|
||||||
marketInfo.forEach(m => {
|
marketInfo.forEach(m => {
|
||||||
const originKind = m.pair.substring(0, 3);
|
const [originKind, destinationKind] = m.pair.split('_');
|
||||||
const destinationKind = m.pair.substring(4, 7);
|
|
||||||
if (this.isWhitelisted(originKind) && this.isWhitelisted(destinationKind)) {
|
if (this.isWhitelisted(originKind) && this.isWhitelisted(destinationKind)) {
|
||||||
const pairName = originKind + destinationKind;
|
const pairName = originKind + destinationKind;
|
||||||
const { rate, limit, min } = m;
|
const { rate, limit, min } = m;
|
||||||
|
|
|
@ -1,124 +1,139 @@
|
||||||
@import 'common/sass/variables';
|
@import 'common/sass/variables';
|
||||||
|
@import 'common/sass/mixins';
|
||||||
|
|
||||||
|
$menu-max-width: 540px;
|
||||||
|
$menu-padding: 10px;
|
||||||
|
$menu-triangle-size: 14px;
|
||||||
|
$menu-offset: 40px;
|
||||||
|
$option-width: ($menu-max-width - $menu-padding * 2) / 3;
|
||||||
|
$option-width-main: ($menu-max-width - $menu-padding * 2) / 2;
|
||||||
|
$option-width-small: $option-width-main;
|
||||||
|
$option-width-main-small: 100%;
|
||||||
|
|
||||||
.SwapDropdown {
|
.SwapDropdown {
|
||||||
position: relative;
|
position: relative;
|
||||||
button {
|
margin-left: $space-xs;
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
padding: 0.4rem 1rem;
|
|
||||||
border-radius: 2px;
|
|
||||||
height: 2.5rem;
|
|
||||||
&:active,
|
|
||||||
&:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
> li {
|
|
||||||
margin: 0;
|
|
||||||
&:first-child {
|
|
||||||
padding-top: 4px;
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
padding-bottom: 4px;
|
|
||||||
}
|
|
||||||
> a {
|
|
||||||
font-weight: 300;
|
|
||||||
&.active {
|
|
||||||
color: $link-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.SwapDropdown-grid {
|
&-button {
|
||||||
position: absolute;
|
height: 3rem;
|
||||||
display: none;
|
padding-left: $space;
|
||||||
padding: 0;
|
padding-right: $space;
|
||||||
margin-bottom: 0;
|
|
||||||
min-width: 500px;
|
|
||||||
left: 50%;
|
|
||||||
|
|
||||||
top: 50px;
|
&-logo {
|
||||||
transform: translateX(-50%);
|
height: 1.4rem;
|
||||||
list-style: none;
|
margin: -.2rem .3rem 0 -.2rem;
|
||||||
font-size: 0.8rem;
|
width: auto;
|
||||||
text-align: left;
|
}
|
||||||
z-index: 500;
|
|
||||||
background: white;
|
|
||||||
box-shadow: 2px 1px 60px rgba(0, 0, 0, 0.175);
|
|
||||||
|
|
||||||
&::before {
|
&-label {
|
||||||
|
padding-right: .75rem;
|
||||||
|
|
||||||
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -20px;
|
top: 50%;
|
||||||
left: 50%;
|
right: .75rem;
|
||||||
transform: translateX(-50%);
|
// transform: translateY(-50%);
|
||||||
border-right: 10px solid transparent;
|
@include triangle(8px, $text-color, down);
|
||||||
border-left: 10px solid transparent;
|
}
|
||||||
border-top: 10px solid transparent;
|
}
|
||||||
border-bottom: 10px solid #fff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.open {
|
&-menu {
|
||||||
display: block;
|
position: absolute;
|
||||||
}
|
top: 100%;
|
||||||
li {
|
right: -$menu-offset;
|
||||||
display: inline-block;
|
z-index: $zindex-popover;
|
||||||
width: 33.3%;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
li > a {
|
|
||||||
display: block;
|
|
||||||
clear: both;
|
|
||||||
padding: 5px 20px;
|
|
||||||
color: #163151;
|
|
||||||
&:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
background-color: #163151;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.inactive {
|
|
||||||
a {
|
|
||||||
color: grey;
|
|
||||||
&:hover {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #163151;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
filter: grayscale(100%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strong {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
@media screen and (max-width: 800px) {
|
|
||||||
min-width: 300px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.SwapDropdown-desc {
|
&-content {
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SwapDropdown-item {
|
|
||||||
position: relative;
|
|
||||||
img {
|
|
||||||
padding-right: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.swap-option {
|
|
||||||
&-wrapper {
|
|
||||||
font-size: 1rem;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-wrap: wrap;
|
||||||
padding: 0.75rem 1rem;
|
flex-direction: row;
|
||||||
|
width: calc(100vw - 30px);
|
||||||
|
max-width: $menu-max-width;
|
||||||
|
padding: $menu-padding;
|
||||||
|
background: #FFF;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-triangle {
|
||||||
|
position: absolute;
|
||||||
|
top: -($menu-triangle-size / 2);
|
||||||
|
right: $menu-offset + 40px;
|
||||||
|
width: $menu-triangle-size;
|
||||||
|
height: $menu-triangle-size;
|
||||||
|
background: #FFF;
|
||||||
|
box-shadow: -1px -1px 1px rgba(0, 0, 0, 0.1);
|
||||||
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
&-img {
|
}
|
||||||
width: 1rem;
|
}
|
||||||
margin-right: 8px;
|
|
||||||
|
.SwapOption {
|
||||||
|
@include reset-button;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
max-width: $option-width;
|
||||||
|
padding: $space-sm $space-md;
|
||||||
|
text-align: left;
|
||||||
|
background: rgba($brand-info, 0);
|
||||||
|
color: $text-color;
|
||||||
|
transition: $transition;
|
||||||
|
|
||||||
|
@media (max-width: $screen-sm) {
|
||||||
|
width: 50%;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #FFF;
|
||||||
|
background: rgba($brand-info, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-top {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-bottom: $space-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-logo {
|
||||||
|
height: 1.2rem;
|
||||||
|
width: auto;
|
||||||
|
margin-right: $space-xs;
|
||||||
|
|
||||||
|
.is-main > & {
|
||||||
|
height: 2.6rem;
|
||||||
|
margin-right: $space-md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-ticker {
|
||||||
|
}
|
||||||
|
|
||||||
|
&-name {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-main {
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
max-width: $option-width-main;
|
||||||
|
padding: $space $space-md;
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
@media (max-width: $screen-sm) {
|
||||||
|
width: 50%;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-disabled {
|
||||||
|
filter: grayscale(1);
|
||||||
|
opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { Option } from 'react-select';
|
||||||
import './SwapDropdown.scss';
|
import './SwapDropdown.scss';
|
||||||
import { DropDown } from 'components/ui';
|
|
||||||
|
|
||||||
export interface SingleCoin {
|
export interface SingleCoin {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -9,71 +10,178 @@ export interface SingleCoin {
|
||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props<T> {
|
interface Props {
|
||||||
options: SingleCoin[];
|
options: SingleCoin[];
|
||||||
|
disabledOption?: string;
|
||||||
value: string;
|
value: string;
|
||||||
onChange(value: T): void;
|
onChange(value: SingleCoin): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ValueComp: React.SFC = (props: any) => {
|
interface State {
|
||||||
|
isOpen: boolean;
|
||||||
|
mainOptions: SingleCoin[];
|
||||||
|
otherOptions: SingleCoin[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAIN_OPTIONS = ['ETH', 'BTC'];
|
||||||
|
|
||||||
|
class SwapDropdown extends PureComponent<Props, State> {
|
||||||
|
public state: State = {
|
||||||
|
isOpen: false,
|
||||||
|
mainOptions: [],
|
||||||
|
otherOptions: []
|
||||||
|
};
|
||||||
|
|
||||||
|
public dropdown: HTMLDivElement | null;
|
||||||
|
|
||||||
|
public componentWillMount() {
|
||||||
|
this.buildOptions(this.props.options);
|
||||||
|
document.addEventListener('click', this.handleBodyClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
document.removeEventListener('click', this.handleBodyClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillReceiveProps(nextProps: Props) {
|
||||||
|
if (this.props.options !== nextProps.options) {
|
||||||
|
this.buildOptions(nextProps.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const { options, value, disabledOption } = this.props;
|
||||||
|
const { isOpen, mainOptions, otherOptions } = this.state;
|
||||||
|
|
||||||
|
const selectedOption = options.find(opt => opt.name === value);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${props.className} swap-option-wrapper`}>
|
<div className="SwapDropdown" ref={el => (this.dropdown = el)}>
|
||||||
<img src={props.value.img} className="swap-option-img" alt={props.value.label + ' logo'} />
|
<button className="SwapDropdown-button btn btn-default" onClick={this.toggleMenu}>
|
||||||
<span className="swap-option-label">{props.value.label}</span>
|
{selectedOption ? (
|
||||||
|
<React.Fragment>
|
||||||
|
<img src={selectedOption.image} className="SwapDropdown-button-logo" />
|
||||||
|
<span className="SwapDropdown-button-label">{selectedOption.id}</span>
|
||||||
|
</React.Fragment>
|
||||||
|
) : (
|
||||||
|
'Unknown'
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{isOpen && (
|
||||||
|
<div className="SwapDropdown-menu">
|
||||||
|
<i className="SwapDropdown-menu-triangle" />
|
||||||
|
<div className="SwapDropdown-menu-content">
|
||||||
|
{mainOptions.map(opt => (
|
||||||
|
<SwapOption
|
||||||
|
key={opt.name}
|
||||||
|
option={opt}
|
||||||
|
isMain={true}
|
||||||
|
isDisabled={opt.name === disabledOption}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{otherOptions.map(opt => (
|
||||||
|
<SwapOption
|
||||||
|
key={opt.name}
|
||||||
|
option={opt}
|
||||||
|
isMain={false}
|
||||||
|
isDisabled={opt.name === disabledOption}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
const OptionComp: React.SFC = (props: any) => {
|
private toggleMenu = () => {
|
||||||
const handleMouseDown = (event: React.MouseEvent<any>) => {
|
this.setState({ isOpen: !this.state.isOpen });
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
props.onSelect(props.option, event);
|
|
||||||
};
|
};
|
||||||
const handleMouseEnter = (event: React.MouseEvent<any>) => {
|
|
||||||
props.onFocus(props.option, event);
|
private handleChange = (coin: SingleCoin) => {
|
||||||
|
this.props.onChange(coin);
|
||||||
|
if (this.state.isOpen) {
|
||||||
|
this.toggleMenu();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const handleMouseMove = (event: React.MouseEvent<any>) => {
|
|
||||||
if (props.isFocused) {
|
private handleBodyClick = (ev: MouseEvent) => {
|
||||||
|
if (!this.state.isOpen || !this.dropdown) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
props.onFocus(props.option, event);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`${props.className} swap-option-wrapper`}
|
|
||||||
onMouseDown={handleMouseDown}
|
|
||||||
onMouseEnter={handleMouseEnter}
|
|
||||||
onMouseMove={handleMouseMove}
|
|
||||||
>
|
|
||||||
<img src={props.option.img} className="swap-option-img" alt={props.option.label + ' logo'} />
|
|
||||||
<span className="swap-option-label">{props.option.label}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
class SwapDropdown<T> extends PureComponent<Props<T>> {
|
if (
|
||||||
public render() {
|
ev.target !== this.dropdown &&
|
||||||
const { options, value, onChange } = this.props;
|
ev.target instanceof HTMLElement &&
|
||||||
const mappedOptions = options.map(opt => {
|
!this.dropdown.contains(ev.target)
|
||||||
return { label: opt.id, value: opt.name, img: opt.image, status: opt.status };
|
) {
|
||||||
|
this.toggleMenu();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private buildOptions(options: Props['options']) {
|
||||||
|
const mainOptions: SingleCoin[] = [];
|
||||||
|
let otherOptions: SingleCoin[] = [];
|
||||||
|
|
||||||
|
options.forEach(opt => {
|
||||||
|
if (MAIN_OPTIONS.includes(opt.id)) {
|
||||||
|
mainOptions.push(opt);
|
||||||
|
} else {
|
||||||
|
otherOptions.push(opt);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return (
|
|
||||||
<DropDown
|
// Sort non-main coins alphabetically
|
||||||
className="Swap-dropdown"
|
otherOptions = otherOptions.sort(
|
||||||
options={mappedOptions}
|
(opt1, opt2) => (opt1.id.toLowerCase() > opt2.id.toLowerCase() ? 1 : -1)
|
||||||
optionComponent={(props: any) => {
|
|
||||||
return <OptionComp {...props} />;
|
|
||||||
}}
|
|
||||||
value={value}
|
|
||||||
clearable={false}
|
|
||||||
onChange={onChange}
|
|
||||||
valueComponent={(props: any) => {
|
|
||||||
return <ValueComp {...props} />;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.setState({ mainOptions, otherOptions });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SwapOptionProps {
|
||||||
|
option: SingleCoin;
|
||||||
|
isMain?: boolean;
|
||||||
|
isDisabled?: boolean;
|
||||||
|
onChange(opt: Option): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SwapOption: React.SFC<SwapOptionProps> = ({ option, isMain, isDisabled, onChange }) => {
|
||||||
|
const handleChange = (ev: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
onChange({
|
||||||
|
label: option.id,
|
||||||
|
value: option.name
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const classNames = classnames('SwapOption', isMain && 'is-main', isDisabled && 'is-disabled');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button className={classNames} disabled={isDisabled} onClick={handleChange}>
|
||||||
|
{isMain ? (
|
||||||
|
<React.Fragment>
|
||||||
|
<img src={option.image} className="SwapOption-logo" alt={`${option.name} logo`} />
|
||||||
|
<div className="SwapOption-info">
|
||||||
|
<div className="SwapOption-ticker">{option.id}</div>
|
||||||
|
<div className="SwapOption-name">{option.name}</div>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
) : (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className="SwapOption-top">
|
||||||
|
<img src={option.image} className="SwapOption-logo" alt={`${option.name} logo`} />
|
||||||
|
<div className="SwapOption-ticker">{option.id}</div>
|
||||||
|
</div>
|
||||||
|
<div className="SwapOption-name">{option.name}</div>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default SwapDropdown;
|
export default SwapDropdown;
|
||||||
|
|
|
@ -27,10 +27,11 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 0 -8px;
|
margin: 0 -8px;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
> .input-group-wrapper {
|
> .input-group-wrapper {
|
||||||
margin: 0 8px;
|
margin: 0 8px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 400px;
|
max-width: 320px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media (max-width: $screen-sm) {
|
@media (max-width: $screen-sm) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import translate, { translateRaw } from 'translations';
|
||||||
import { combineAndUpper } from 'utils/formatters';
|
import { combineAndUpper } from 'utils/formatters';
|
||||||
import { SwapDropdown, Input } from 'components/ui';
|
import { SwapDropdown, Input } from 'components/ui';
|
||||||
import Spinner from 'components/ui/Spinner';
|
import Spinner from 'components/ui/Spinner';
|
||||||
import { merge, reject, debounce } from 'lodash';
|
import { merge, debounce } from 'lodash';
|
||||||
import './CurrencySwap.scss';
|
import './CurrencySwap.scss';
|
||||||
|
|
||||||
export interface StateProps {
|
export interface StateProps {
|
||||||
|
@ -29,11 +29,10 @@ export interface ActionProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
options: any[];
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
origin: SwapOpt;
|
origin: SwapOpt;
|
||||||
destination: SwapOpt;
|
destination: SwapOpt;
|
||||||
originKindOptions: any[];
|
|
||||||
destinationKindOptions: any[];
|
|
||||||
originErr: string;
|
originErr: string;
|
||||||
destinationErr: string;
|
destinationErr: string;
|
||||||
timeout: boolean;
|
timeout: boolean;
|
||||||
|
@ -50,6 +49,7 @@ interface SwapOpt extends SwapInput {
|
||||||
|
|
||||||
export default class CurrencySwap extends PureComponent<Props, State> {
|
export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
public state: State = {
|
public state: State = {
|
||||||
|
options: [],
|
||||||
disabled: true,
|
disabled: true,
|
||||||
origin: {
|
origin: {
|
||||||
label: 'BTC',
|
label: 'BTC',
|
||||||
|
@ -65,8 +65,6 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
image: 'https://shapeshift.io/images/coins/ether.png',
|
image: 'https://shapeshift.io/images/coins/ether.png',
|
||||||
amount: NaN
|
amount: NaN
|
||||||
},
|
},
|
||||||
originKindOptions: [],
|
|
||||||
destinationKindOptions: [],
|
|
||||||
originErr: '',
|
originErr: '',
|
||||||
destinationErr: '',
|
destinationErr: '',
|
||||||
timeout: false
|
timeout: false
|
||||||
|
@ -110,20 +108,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
});
|
});
|
||||||
}, 10000);
|
}, 10000);
|
||||||
|
|
||||||
const { origin } = this.state;
|
this.setState({ options: Object.values(this.props.options.byId) });
|
||||||
const { options } = this.props;
|
|
||||||
|
|
||||||
if (options.allIds && options.byId) {
|
|
||||||
const originKindOptions: any[] = Object.values(options.byId);
|
|
||||||
const destinationKindOptions: any[] = Object.values(
|
|
||||||
reject<any>(options.byId, o => o.id === origin.label)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
originKindOptions,
|
|
||||||
destinationKindOptions
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
|
@ -132,23 +117,16 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidUpdate(prevProps: Props, prevState: State) {
|
public componentWillReceiveProps(nextProps: Props) {
|
||||||
const { origin, destination } = this.state;
|
if (nextProps.options !== this.props.options) {
|
||||||
const { options } = this.props;
|
this.setState({ options: Object.values(nextProps.options.byId) });
|
||||||
if (origin !== prevState.origin) {
|
}
|
||||||
this.setDisabled(origin, destination);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.allIds !== prevProps.options.allIds && options.byId) {
|
public componentDidUpdate(_: Props, prevState: State) {
|
||||||
const originKindOptions: any[] = Object.values(options.byId);
|
const { origin, destination } = this.state;
|
||||||
const destinationKindOptions: any[] = Object.values(
|
if (origin !== prevState.origin) {
|
||||||
reject<any>(options.byId, o => o.id === origin.label)
|
this.setDisabled(origin, destination);
|
||||||
);
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
originKindOptions,
|
|
||||||
destinationKindOptions
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,8 +258,8 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public onChangeOriginKind = (newOption: any) => {
|
public onChangeOriginKind = (newOption: any) => {
|
||||||
const { origin, destination, destinationKindOptions } = this.state;
|
const { origin, destination } = this.state;
|
||||||
const { options, initSwap } = this.props;
|
const { initSwap } = this.props;
|
||||||
|
|
||||||
const newOrigin = { ...origin, label: newOption.label, value: newOption.value, amount: 0 };
|
const newOrigin = { ...origin, label: newOption.label, value: newOption.value, amount: 0 };
|
||||||
const newDest = {
|
const newDest = {
|
||||||
|
@ -294,11 +272,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
origin: newOrigin,
|
origin: newOrigin,
|
||||||
destination: newDest,
|
destination: newDest
|
||||||
destinationKindOptions: reject(
|
|
||||||
[...destinationKindOptions, options.byId[origin.label]],
|
|
||||||
o => o.id === newOption.label
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
initSwap({ origin: newOrigin, destination: newDest });
|
initSwap({ origin: newOrigin, destination: newDest });
|
||||||
|
@ -324,15 +298,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { bityRates, shapeshiftRates, provider } = this.props;
|
const { bityRates, shapeshiftRates, provider } = this.props;
|
||||||
const {
|
const { options, origin, destination, originErr, destinationErr, timeout } = this.state;
|
||||||
origin,
|
|
||||||
destination,
|
|
||||||
originKindOptions,
|
|
||||||
destinationKindOptions,
|
|
||||||
originErr,
|
|
||||||
destinationErr,
|
|
||||||
timeout
|
|
||||||
} = this.state;
|
|
||||||
const pairName = combineAndUpper(origin.label, destination.label);
|
const pairName = combineAndUpper(origin.label, destination.label);
|
||||||
const bityLoaded = bityRates.byId && bityRates.byId[pairName] ? true : false;
|
const bityLoaded = bityRates.byId && bityRates.byId[pairName] ? true : false;
|
||||||
const shapeshiftLoaded = shapeshiftRates.byId && shapeshiftRates.byId[pairName] ? true : false;
|
const shapeshiftLoaded = shapeshiftRates.byId && shapeshiftRates.byId[pairName] ? true : false;
|
||||||
|
@ -347,7 +313,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
<div className="flex-spacer" />
|
<div className="flex-spacer" />
|
||||||
<div className="input-group-wrapper">
|
<div className="input-group-wrapper">
|
||||||
<div className="input-group-header">{translate('SWAP_DEPOSIT_INPUT_LABEL')}</div>
|
<div className="input-group-header">{translate('SWAP_DEPOSIT_INPUT_LABEL')}</div>
|
||||||
<label className="input-group input-group-inline">
|
<div className="input-group input-group-inline">
|
||||||
<Input
|
<Input
|
||||||
id="origin-swap-input"
|
id="origin-swap-input"
|
||||||
className={`input-group-input ${
|
className={`input-group-input ${
|
||||||
|
@ -362,16 +328,16 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
onChange={this.onChangeAmount}
|
onChange={this.onChangeAmount}
|
||||||
/>
|
/>
|
||||||
<SwapDropdown
|
<SwapDropdown
|
||||||
options={originKindOptions}
|
options={options}
|
||||||
value={origin.value}
|
value={origin.value}
|
||||||
onChange={this.onChangeOriginKind}
|
onChange={this.onChangeOriginKind}
|
||||||
/>
|
/>
|
||||||
</label>
|
</div>
|
||||||
{originErr && <span className="CurrencySwap-error-message">{originErr}</span>}
|
{originErr && <span className="CurrencySwap-error-message">{originErr}</span>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="input-group-wrapper">
|
<div className="input-group-wrapper">
|
||||||
<label className="input-group input-group-inline">
|
<div className="input-group input-group-inline">
|
||||||
<div className="input-group-header">{translate('SWAP_RECIEVE_INPUT_LABEL')}</div>
|
<div className="input-group-header">{translate('SWAP_RECIEVE_INPUT_LABEL')}</div>
|
||||||
<Input
|
<Input
|
||||||
id="destination-swap-input"
|
id="destination-swap-input"
|
||||||
|
@ -387,11 +353,12 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||||
onChange={this.onChangeAmount}
|
onChange={this.onChangeAmount}
|
||||||
/>
|
/>
|
||||||
<SwapDropdown
|
<SwapDropdown
|
||||||
options={destinationKindOptions}
|
options={options}
|
||||||
|
disabledOption={origin.value}
|
||||||
value={destination.value}
|
value={destination.value}
|
||||||
onChange={this.onChangeDestinationKind}
|
onChange={this.onChangeDestinationKind}
|
||||||
/>
|
/>
|
||||||
</label>
|
</div>
|
||||||
{destinationErr && (
|
{destinationErr && (
|
||||||
<span className="CurrencySwap-error-message">{destinationErr}</span>
|
<span className="CurrencySwap-error-message">{destinationErr}</span>
|
||||||
)}
|
)}
|
||||||
|
|
Loading…
Reference in New Issue