Skip to content

Commit

Permalink
Add filters to trade history (#544)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevva authored and sindresorhus committed Nov 9, 2018
1 parent be63d25 commit 6074f21
Show file tree
Hide file tree
Showing 17 changed files with 674 additions and 8 deletions.
9 changes: 9 additions & 0 deletions app/locales/en-US/swap.json
Expand Up @@ -54,5 +54,14 @@
"toggleAdvancedButton": {
"more": "More",
"less": "Less"
},
"filter": {
"buy": "Buy",
"date": "Date",
"dateFrom": "From",
"dateTo": "To",
"pair": "Pair",
"sell": "Sell",
"type": "Type"
}
}
104 changes: 104 additions & 0 deletions app/renderer/components/DateInput.js
@@ -0,0 +1,104 @@
import React from 'react';
import PropTypes from 'prop-types';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import moment from 'moment';
import MomentLocaleUtils, {formatDate, parseDate} from 'react-day-picker/moment';
import 'react-day-picker/lib/style.css';
import Input from 'components/Input';
import {instance} from '../translate';
import {setInputValue} from '../util';
import './DateInput.scss';

const WrappedInput = React.forwardRef((props, ref) => {
const onChange = (value, event) => props.onChange(event);
const validateInput = value => moment(value).isValid();

return <Input {...props} ref={ref} pattern={validateInput} onChange={onChange}/>;
});

class DateInput extends React.Component {
static propTypes = {
autoCorrect: PropTypes.bool,
forwardedRef: PropTypes.oneOfType([
PropTypes.func,
PropTypes.object,
]),
onDayChange: PropTypes.func,
}

constructor(props) {
super(props);
this.inputRef = this.props.forwardedRef || React.createRef();
this.state = {
hasError: false,
isInvalid: false,
value: this.props.value,
};
}

handleBlur = event => {
const {autoCorrect, onBlur} = this.props;
const {value} = this.state;

if (autoCorrect && this.state.isInvalid) {
this.setState({hasError: true});

setTimeout(() => {
const {dayPickerProps, format, formatDate} = this.inputRef.current.props;
setInputValue(event.target, formatDate(value, format, dayPickerProps.locale));
}, 600);
}

if (typeof onBlur === 'function') {
onBlur(event);
}
}

handleDayChange = (day, modifiers, input) => {
const {onDayChange} = this.props;
const inputValue = input.getInput().value;
const isInvalid = modifiers.disabled || (!day && inputValue);

this.setState(state => ({
hasError: false,
isInvalid,
value: isInvalid ? state.value : day,
}), () => {
onDayChange(day, modifiers, input);
});
};

render() {
const {hasError} = this.state;

return (
<DayPickerInput
{...this.props}
ref={this.inputRef}
component={WrappedInput}
format="YYYY-MM-DD"
formatDate={formatDate}
onDayChange={this.handleDayChange}
parseDate={parseDate}
dayPickerProps={{
...this.props.dayPickerProps,
locale: instance.language,
localeUtils: MomentLocaleUtils,
}}
inputProps={{
...this.props.inputProps,
className: hasError ? 'shake-animation' : '',
onBlur: this.handleBlur,
}}
/>
);
}
}

export default React.forwardRef((props, ref) => (
<DateInput {...props} forwardedRef={ref}/>
));

export {
WrappedInput,
};
49 changes: 49 additions & 0 deletions app/renderer/components/DateInput.scss
@@ -0,0 +1,49 @@
/* stylelint-disable selector-class-pattern */
.DayPickerInput-Overlay {
margin-top: 4px;
text-align: center;
color: var(--text-color);
background-color: var(--input-background-color);
border: 1px solid var(--input-border-color);
border-radius: 4px;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
}

.DayPicker-Months {
flex-wrap: unset;
}

.DayPicker-NavButton,
.DayPicker-Day {
cursor: default;
}

.DayPicker:not(.DayPicker--interactionDisabled) .DayPicker-Day:not(.DayPicker-Day--disabled):not(.DayPicker-Day--selected):not(.DayPicker-Day--outside):hover {
color: var(--text-color2);
background-color: var(--primary-color);
border-radius: 2px;
}

.DayPicker-Day--today {
color: var(--secondary-color);
font-weight: normal;

&:hover:not(.DayPicker-Day--disabled):not(.DayPicker-Day--outside) {
color: var(--text-color2);
}
}

.DayPicker-Day--selected:not(.DayPicker-Day--disabled):not(.DayPicker-Day--outside) {
color: var(--text-color2);
background-color: var(--primary-color);

&:hover {
background-color: var(--primary-color);
}
}

.DayPicker-Day--disabled:not(.DayPicker-Day--today),
.DayPicker-Day--outside:not(.DayPicker-Day--today) {
color: var(--text-color);
opacity: 0.5;
}
39 changes: 35 additions & 4 deletions app/renderer/components/Input.js
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import {classNames} from 'react-extras';
import propTypesRange from 'prop-types-range';
import _ from 'lodash';
import './Input.scss';

const stripLeadingZeros = string => string.replace(/^0+(?=\d)/, '');
Expand Down Expand Up @@ -46,13 +47,27 @@ class Input extends React.Component {
}

static getDerivedStateFromProps(props, state) {
return props.value === state.prevValue ? null : {
value: props.value,
prevValue: props.value,
const isValueChanged = props.value !== state.prevValue;
const isLevelChanged = props.level !== state.prevLevel;

if (!isValueChanged && !isLevelChanged) {
return null;
}

return {
...isValueChanged && {
value: props.value,
prevValue: props.value,
},
...isLevelChanged && {
level: props.level,
prevLevel: props.level,
},
};
}

state = {
level: this.props.level,
value: this.props.value || '',
};

Expand All @@ -76,13 +91,23 @@ class Input extends React.Component {
event.persist();
}

this._checkValidity(event);

this.setState({value}, () => {
if (onChange) {
onChange(value, event);
}
});
};

_checkValidity = _.debounce(event => {
const {pattern} = this.props;
const {value} = event.target;
const isValid = typeof pattern === 'function' ? (!value || pattern(value)) : event.target.checkValidity();

this.setState({level: isValid ? null : 'error'});
}, 500);

_shouldTruncateFractions(value) {
const {fractionalDigits} = this.props;

Expand Down Expand Up @@ -113,7 +138,6 @@ class Input extends React.Component {
let {
forwardedRef,
className,
level,
message,
errorMessage,
disabled,
Expand All @@ -125,10 +149,12 @@ class Input extends React.Component {
icon,
iconSize,
iconName,
pattern,
view: View,
button: Button,
...props
} = this.props;
let {level} = this.state;

if (errorMessage) {
level = 'error';
Expand All @@ -143,6 +169,10 @@ class Input extends React.Component {
icon = `/assets/${iconName}-icon.svg`;
}

if (typeof pattern === 'function') {
pattern = null;
}

const containerClassName = classNames(
'Input',
{
Expand Down Expand Up @@ -182,6 +212,7 @@ class Input extends React.Component {
value={value}
type={type}
disabled={disabled}
pattern={pattern}
readOnly={readOnly}
onChange={this.handleChange}
/>
Expand Down
2 changes: 1 addition & 1 deletion app/renderer/components/Select.scss
Expand Up @@ -198,7 +198,7 @@
height: 5px;
position: absolute;
top: 50%;
margin: -3px 0 0 -3px;
margin: -4px 0 0 -3px;
transform: rotate(45deg);
border-left: none;
border-top: none;
Expand Down

0 comments on commit 6074f21

Please sign in to comment.