fix(joyent-portal): fix filters on group select

This commit is contained in:
Sara Vieira 2017-09-22 13:15:33 +01:00 committed by Sérgio Ramos
parent b76717d660
commit d315f7faa3
18 changed files with 1840 additions and 1860 deletions

View File

@ -9,7 +9,6 @@ import { register } from './sw';
class App extends Component {
componentWillMount() {
// eslint-disable-next-line no-unused-expressions
injectGlobal`
${global}
`;

View File

@ -233,9 +233,9 @@ exports[`renders <Filters /> without throwing 1`] = `
display: block;
height: 0.875rem;
width: 0.875rem;
-webkit-transform: translateY(-50%) translateX(-1%);
-ms-transform: translateY(-50%) translateX(-1%);
transform: translateY(-50%) translateX(-1%);
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
outline: none;
position: absolute;
top: 0;
@ -252,36 +252,6 @@ exports[`renders <Filters /> without throwing 1`] = `
box-shadow: 0 0 0 5px rgba(63,81,181,0.2);
}
.c17 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: #FFFFFF;
border: 2px solid #bdbdbd;
border-radius: 50%;
cursor: pointer;
display: block;
height: 0.875rem;
width: 0.875rem;
-webkit-transform: translateY(-50%) translateX(-99%);
-ms-transform: translateY(-50%) translateX(-99%);
transform: translateY(-50%) translateX(-99%);
outline: none;
position: absolute;
top: 0;
margin-top: 0.125rem;
}
.c17::active {
-webkit-transform: scale(1.3);
-ms-transform: scale(1.3);
transform: scale(1.3);
}
.c17::focus {
box-shadow: 0 0 0 5px rgba(63,81,181,0.2);
}
.c12 {
background: #D8D8D8;
cursor: pointer;
@ -483,7 +453,7 @@ exports[`renders <Filters /> without throwing 1`] = `
aria-valuemax={50.688}
aria-valuemin={0.256}
aria-valuenow={50.688}
className="c17"
className="c15"
draggable="false"
onKeyDown={[Function]}
onMouseDown={[Function]}
@ -491,7 +461,7 @@ exports[`renders <Filters /> without throwing 1`] = `
role="slider"
style={
Object {
"left": "100%",
"left": "94%",
"position": "absolute",
}
}
@ -573,7 +543,7 @@ exports[`renders <Filters /> without throwing 1`] = `
aria-valuemax={3.25}
aria-valuemin={0.25}
aria-valuenow={3.25}
className="c17"
className="c15"
draggable="false"
onKeyDown={[Function]}
onMouseDown={[Function]}
@ -581,7 +551,7 @@ exports[`renders <Filters /> without throwing 1`] = `
role="slider"
style={
Object {
"left": "100%",
"left": "94%",
"position": "absolute",
}
}
@ -663,7 +633,7 @@ exports[`renders <Filters /> without throwing 1`] = `
aria-valuemax={107.26}
aria-valuemin={0.01}
aria-valuenow={107.26}
className="c17"
className="c15"
draggable="false"
onKeyDown={[Function]}
onMouseDown={[Function]}
@ -671,7 +641,7 @@ exports[`renders <Filters /> without throwing 1`] = `
role="slider"
style={
Object {
"left": "100%",
"left": "94%",
"position": "absolute",
}
}
@ -753,7 +723,7 @@ exports[`renders <Filters /> without throwing 1`] = `
aria-valuemax={0.525}
aria-valuemin={0.016}
aria-valuenow={0.525}
className="c17"
className="c15"
draggable="false"
onKeyDown={[Function]}
onMouseDown={[Function]}
@ -761,7 +731,7 @@ exports[`renders <Filters /> without throwing 1`] = `
role="slider"
style={
Object {
"left": "100%",
"left": "94%",
"position": "absolute",
}
}

View File

@ -6,14 +6,14 @@ import React from 'react';
import renderer from 'react-test-renderer';
import 'jest-styled-components';
import { Router, FiltersMock } from '@mocks/';
import { Router, FiltersMock, PackagesMock } from '@mocks/';
import Filters from '../filters';
it('renders <Filters /> without throwing', () => {
const tree = renderer
.create(
<Router>
<Filters filters={FiltersMock} />
<Filters filters={FiltersMock} packages={PackagesMock} />
</Router>
)
.toJSON();

View File

@ -2,10 +2,20 @@ import React, { Component } from 'react';
import styled from 'styled-components';
import remcalc from 'remcalc';
import isEqual from 'lodash.isequal';
import { Label, Button } from 'joyent-ui-toolkit';
import { Label, Button, Slider } from 'joyent-ui-toolkit';
import { default as defaultState } from '@state/state';
import Sliders from '@components/sliders';
const FilterWrapper = styled.section`
display: flex;
> div {
flex-grow: 1;
&:not(:last-child) {
margin-right: ${remcalc(36)};
}
}
`;
const GroupWrapper = styled.section`
display: flex;
@ -30,24 +40,84 @@ const Subtitle = styled(Label)`
margin-bottom: ${remcalc(8)};
`;
const getFirstAndLast = (arr, key) => {
const sorted = arr.sort(
(a, b) => (a[key] === b[key] ? 0 : a[key] < b[key] ? -1 : 1)
);
if (sorted.length > 0) {
return {
min: parseFloat(sorted[0][key]),
max: parseFloat(sorted[sorted.length - 1][key])
};
}
};
class Filters extends Component {
constructor(props) {
super(props);
const { filters: { cpu, cost, ram, disk } } = this.props;
this.state = {
reset: 0
reset: 0,
ram,
cpu,
disk,
cost,
groupClick: 0,
defaults: this.props.filters
};
this.groupChange = this.groupChange.bind(this);
this.handleResetClick = this.handleResetClick.bind(this);
}
componentWillReceiveProps(nextProps) {
const { packages } = nextProps;
packages.length > 1 &&
this.setState({
ram: getFirstAndLast(packages, 'memory'),
cpu: getFirstAndLast(packages, 'vcpus'),
disk: getFirstAndLast(packages, 'disk'),
cost: getFirstAndLast(packages, 'price')
});
}
groupChange(group) {
this.props.groupChange(group);
this.setState({
groupClick: this.state.groupClick + 1
});
}
shouldComponentUpdate(nextProps, nextState) {
const { groupClick, reset } = this.state;
const { filters } = this.props;
const filtersMap = filter => ({
ram: filter.ram,
cost: filter.cost,
cpu: filter.cpu,
disk: filter.disk
});
return (
(nextState.groupClick !== groupClick &&
isEqual(filtersMap(filters), filtersMap(nextProps.filters))) ||
nextState.reset !== reset
);
}
handleResetClick() {
const { filterReset } = this.props;
const { filterReset, filters: { cpu, cost, ram, disk } } = this.props;
const { reset } = this.state;
filterReset();
this.setState({
reset: reset + 1
reset: reset + 1,
ram,
cpu,
disk,
cost
});
}
@ -58,11 +128,10 @@ class Filters extends Component {
cpuSliderChange,
diskSliderChange,
costSliderChange,
groupChange,
packages
} = this.props;
const { reset } = this.state;
const { reset, cpu, cost, ram, disk, defaults } = this.state;
return (
<Wrapper>
<Title>Choose package</Title>
@ -77,7 +146,7 @@ class Filters extends Component {
tertiary
small
selected={group.selected}
onClick={() => groupChange(group)}
onClick={() => this.groupChange(group)}
>
{group.name}
</Button>
@ -93,15 +162,52 @@ class Filters extends Component {
</Button>
</GroupWrapper>
<Label>Filter by package feature</Label>
<Sliders
greyed={packages === 0}
reset={reset}
filters={filters}
ramSliderChange={ramSliderChange}
cpuSliderChange={cpuSliderChange}
diskSliderChange={diskSliderChange}
costSliderChange={costSliderChange}
/>
<FilterWrapper key={reset}>
<Slider
greyed={packages.length === 0}
minValue={defaults.ram.min}
maxValue={defaults.ram.max}
step={0.256}
value={ram}
key={`${ram.min}-${ram.max}`}
onChangeComplete={value => ramSliderChange(value)}
>
GB RAM
</Slider>
<Slider
greyed={packages.length === 0}
minValue={defaults.cpu.min}
maxValue={defaults.cpu.max}
step={0.25}
value={cpu}
key={`${cpu.min}-${cpu.max}`}
onChangeComplete={value => cpuSliderChange(value)}
>
vCPUs
</Slider>
<Slider
greyed={packages.length === 0}
minValue={defaults.disk.min}
maxValue={defaults.disk.max}
step={0.01}
value={disk}
key={`${disk.min}-${disk.max}`}
onChangeComplete={value => diskSliderChange(value)}
>
TB Disk
</Slider>
<Slider
greyed={packages.length === 0}
minValue={defaults.cost.min}
maxValue={defaults.cost.max}
step={0.02}
value={cost}
key={`${cost.min}-${ram.max}`}
onChangeComplete={value => costSliderChange(value)}
>
$/hr
</Slider>
</FilterWrapper>
</Wrapper>
);
}

View File

@ -175,7 +175,7 @@ exports[`renders <Package /> without throwing 1`] = `
font-size: 0.8125rem;
font-weight: 500;
text-transform: uppercase;
color: #bdbdbd;
color: rgba(73,73,73,0.8);
-webkit-transition: all 300ms ease;
transition: all 300ms ease;
}
@ -253,7 +253,7 @@ exports[`renders <Package /> without throwing 1`] = `
<span
className="c7"
>
2
200
TB disk
</span>
</div>

View File

@ -28,7 +28,7 @@ const Package = ({
<CardSubTitle selected={selected}>{memory} GB RAM</CardSubTitle>
<CardSubTitle selected={selected}>{vcpus} vCPUs</CardSubTitle>
<CardSubTitle selected={selected}>
{disk / 100} TB disk
{disk} TB disk
</CardSubTitle>
<CardSubTitle selected={selected}>SSD</CardSubTitle>

View File

@ -184,7 +184,7 @@ exports[`renders <Packages /> without throwing 1`] = `
font-size: 0.8125rem;
font-weight: 500;
text-transform: uppercase;
color: #bdbdbd;
color: rgba(73,73,73,0.8);
-webkit-transition: all 300ms ease;
transition: all 300ms ease;
}
@ -324,7 +324,7 @@ exports[`renders <Packages /> without throwing 1`] = `
<span
className="c9"
>
0.1
10
TB disk
</span>
</div>
@ -416,7 +416,7 @@ exports[`renders <Packages /> without throwing 1`] = `
<span
className="c9"
>
0.25
25
TB disk
</span>
</div>
@ -508,7 +508,7 @@ exports[`renders <Packages /> without throwing 1`] = `
<span
className="c9"
>
0.5
50
TB disk
</span>
</div>
@ -600,7 +600,7 @@ exports[`renders <Packages /> without throwing 1`] = `
<span
className="c9"
>
1
100
TB disk
</span>
</div>
@ -692,7 +692,7 @@ exports[`renders <Packages /> without throwing 1`] = `
<span
className="c9"
>
2
200
TB disk
</span>
</div>
@ -784,7 +784,7 @@ exports[`renders <Packages /> without throwing 1`] = `
<span
className="c9"
>
4
400
TB disk
</span>
</div>

View File

@ -33,7 +33,7 @@ class Packages extends Component {
selected: id !== this.state.selected ? id : null
});
}
render() {
const { packages } = this.props;
const { selected } = this.state;
@ -41,7 +41,7 @@ class Packages extends Component {
return (
<ListStyled>
{packages.length > 0 ? (
packages.map(pack => (
packages.sort((a, b) => a.price > b.price ? 1 : -1).map(pack => (
<Col xs={12} sm={6} md={4} lg={3} key={pack.id}>
<Package
pack={pack}
@ -50,10 +50,10 @@ class Packages extends Component {
/>
</Col>
))
) : (
) : (
<Col xs={12}>
<Empty />
</Col>
<Empty />
</Col>
)}
</ListStyled>
);

View File

@ -1,71 +0,0 @@
import React from 'react';
import { Slider } from 'joyent-ui-toolkit';
import styled from 'styled-components';
import remcalc from 'remcalc';
const FilterWrapper = styled.section`
display: flex;
> div {
flex-grow: 1;
&:not(:last-child) {
margin-right: ${remcalc(36)};
}
}
`;
const Sliders = ({
filters: { cpu, cost, ram, disk },
ramSliderChange,
cpuSliderChange,
diskSliderChange,
costSliderChange,
reset,
greyed
}) => (
<FilterWrapper key={reset}>
<Slider
greyed={greyed}
minValue={ram.min}
maxValue={ram.max}
step={0.256}
value={ram}
onChangeComplete={value => ramSliderChange(value)}
>
GB RAM
</Slider>
<Slider
greyed={greyed}
minValue={cpu.min}
maxValue={cpu.max}
step={0.25}
value={cpu}
onChangeComplete={value => cpuSliderChange(value)}
>
vCPUs
</Slider>
<Slider
greyed={greyed}
minValue={disk.min}
maxValue={disk.max}
step={0.01}
value={disk}
onChangeComplete={value => diskSliderChange(value)}
>
TB Disk
</Slider>
<Slider
greyed={greyed}
minValue={cost.min}
maxValue={cost.max}
step={0.02}
value={cost}
onChangeComplete={value => costSliderChange(value)}
>
$/hr
</Slider>
</FilterWrapper>
);
export default Sliders;

View File

@ -15,7 +15,7 @@ const HomeHOC = (props) => (
const mapStateToProps = state => {
return {
filters: state.app.filters,
packages: state.app.packages.length
packages: state.app.packages
};
};

View File

@ -4,161 +4,161 @@
"name": "High CPU 0.25",
"vcpus": 0.25,
"memory": 0.256,
"disk": 10,
"disk": 0.010,
"group": "Compute Optimized",
"price": "0.016"
"price": 0.016
},
{
"id": 2,
"name": "High CPU 0.75",
"vcpus": 0.5,
"memory": 0.768,
"disk": 25,
"disk": 0.025,
"group": "Compute Optimized",
"price": "0.033"
"price": 0.033
},
{
"id": 3,
"name": "High CPU 1.75",
"vcpus": 1,
"memory": 1.8,
"disk": 50,
"disk": 0.050,
"group": "Compute Optimized",
"price": "0.066"
"price": 0.066
},
{
"id": 4,
"name": "High CPU 3.75",
"vcpus": 2,
"memory": 3.8,
"disk": 100,
"disk": 0.1,
"group": "Compute Optimized",
"price": "0.131"
"price": 0.131
},
{
"id": 5,
"name": "High CPU 7.75",
"vcpus": 4,
"memory": 7.8,
"disk": 200,
"disk": 0.2,
"group": "Compute Optimized",
"price": "0.263"
"price": 0.263
},
{
"id": 6,
"name": "High CPU 15.75",
"vcpus": 8,
"memory": 15.8,
"disk": 400,
"disk": 0.4,
"group": "Compute Optimized",
"price": "0.525"
"price": 0.525
},
{
"id": 7,
"name": "General 3.75",
"vcpus": 1,
"memory": 3.8,
"disk": 50,
"disk": 0.5,
"group": "General Purpose",
"price": "0.084"
"price": 0.084
},
{
"id": 8,
"name": "General 7.75",
"vcpus": 2,
"memory": 7.8,
"disk": 100,
"disk": 0.1,
"group": "General Purpose",
"price": "0.166"
"price": 0.166
},
{
"id": 9,
"name": "General 15.75",
"vcpus": 4,
"memory": 15.8,
"disk": 200,
"disk": 0.2,
"group": "General Purpose",
"price": "0.333"
"price": 0.333
},
{
"id": 10,
"name": "General 31.75",
"vcpus": 8,
"memory": 31.8,
"disk": 400,
"disk": 0.4,
"group": "General Purpose",
"price": "0.665"
"price": 0.665
},
{
"id": 11,
"name": "High RAM 15.75",
"vcpus": 2,
"memory": 15.8,
"disk": 100,
"disk": 0.1,
"group": "Memory Optimized",
"price": "0.259"
"price": 0.259
},
{
"id": 12,
"name": "High RAM 31.75",
"vcpus": 4,
"memory": 31.8,
"disk": 200,
"disk": 0.1,
"group": "Memory Optimized",
"price": "0.52"
"price": 0.520
},
{
"id": 13,
"name": "High RAM 63.75",
"vcpus": 8,
"memory": 63.8,
"disk": 400,
"disk": 0.4,
"group": "Memory Optimized",
"price": "1.039"
"price": 1.039
},
{
"id": 14,
"name": "Fast Disk 31.75",
"vcpus": 4,
"memory": 31.8,
"disk": 800,
"disk": 0.8,
"group": "Storage Optimized",
"price": "1.066"
"price": 1.066
},
{
"id": 15,
"name": "Fast Disk 63.75",
"vcpus": 8,
"memory": 63.8,
"disk": 1600,
"disk": 1.6,
"group": "Storage Optimized",
"price": "2.31"
},
"price": 2.310
},
{
"id": 16,
"name": "Big Disk 15.75",
"vcpus": 2,
"memory": 15.8,
"disk": 1200,
"disk": 1.2,
"group": "Storage Optimized",
"price": "0.413"
"price": 0.413
},
{
"id": 17,
"name": "Big Disk 31.75",
"vcpus": 4,
"memory": 31.8,
"disk": 2400,
"disk": 2.4,
"group": "Storage Optimized",
"price": "0.825"
"price": 0.825
},
{
"id": 18,
"name": "Big Disk 63.75",
"vcpus": 8,
"memory": 63.8,
"disk": 4900,
"disk": 4.9,
"group": "Storage Optimized",
"price": "1.75"
"price": 1.750
}
]

View File

@ -19,8 +19,8 @@ const filterReducer = (state = defaultState, action) => {
)
.filter(
pack =>
pack.disk / 1000 >= action.filters.disk.min &&
pack.disk / 1000 <= action.filters.disk.max
pack.disk >= action.filters.disk.min &&
pack.disk <= action.filters.disk.max
)
.filter(
pack =>

View File

@ -3,7 +3,7 @@ import packages from '../data/packages';
const state = {
filters: {
cpu: { min: 0.25, max: 8 },
cost: { min: 0.016, max: 2.131 },
cost: { min: 0.016, max: 2.318 },
ram: { min: 0.256, max: 63.8 },
disk: { min: 0.01, max: 4.9 },
groups: [

View File

@ -5,7 +5,7 @@
minValue={0.25}
maxValue={8}
step={0.25}
value={{ min: 0.25, max: 8 }}
value={{ min: 4, max: 4 }}
onChangeComplete={value => console.log(value)}
onChange={value => console.log(value)}
>vCPUs</Slider>

View File

@ -111,6 +111,10 @@ export default class InputRange extends Component {
this.handleKeyUp = this.handleKeyUp.bind(this);
this.handleTouchStart = this.handleTouchStart.bind(this);
this.handleTouchEnd = this.handleTouchEnd.bind(this);
this.state = {
value: this.props.value
}
}
/**
@ -617,7 +621,7 @@ export default class InputRange extends Component {
this.props,
this.isMultiValue()
);
const percentages = valueTransformer.getPercentagesFromValues(
let percentages = valueTransformer.getPercentagesFromValues(
values,
this.props.minValue,
this.props.maxValue

View File

@ -15,10 +15,7 @@ export const SliderStyled = styled.div`
display: block;
height: ${remcalc(14)};
width: ${remcalc(14)};
transform: ${props =>
props.type === 'max'
? 'translateY(-50%) translateX(-99%)'
: 'translateY(-50%) translateX(-1%)'};
transform: translateY(-50%);
outline: none;
position: absolute;
top: 0;
@ -118,10 +115,10 @@ export default class Slider extends Component {
* @return {Object}
*/
getStyle() {
const perc = (this.props.percentage || 0) * 100;
const percentage = (this.props.percentage || 0) * 100;
const style = {
position: 'absolute',
left: `${perc}%`
left: `${percentage > 94 ? 94 : percentage}%`,
};
return style;
@ -289,11 +286,16 @@ export default class Slider extends Component {
this.node = node;
}}
>
<Label greyed={props.greyed} formatLabel={props.formatLabel} type={props.type}>
<Label
greyed={props.greyed}
formatLabel={props.formatLabel}
type={props.type}
>
{props.value}
</Label>
<SliderStyled
type={props.type}
percentage={props.percentage}
style={style}
aria-labelledby={props.ariaLabelledby}
aria-controls={props.ariaControls}