Last active
July 3, 2017 08:27
-
-
Save Y-Taras/be0777006e925a9d80e367221a481caf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import axios from 'axios'; | |
import {SET_FILTER_TERM, SET_FILTER_PRICE, SORT_BY_PRICE, ADD_API_DATA, ADD_TO_CART, REMOVE_FROM_CART} from './actions'; | |
export function setFilterTerm(filterTerm) { | |
return {type: SET_FILTER_TERM, payload: filterTerm}; | |
} | |
export function setFilterPrice(filterPrice) { | |
return {type: SET_FILTER_PRICE, payload: filterPrice}; | |
} | |
export function changeSortKey(sortKey) { | |
return {type: SORT_BY_PRICE, payload: sortKey}; | |
} | |
export function addToCart(productId) { | |
return {type: ADD_TO_CART, payload: productId}; | |
} | |
export function removeFromCart(productId) { | |
return {type: REMOVE_FROM_CART, payload: productId}; | |
} | |
export function addAPIData(apiData) { | |
return {type: ADD_API_DATA, payload: apiData}; | |
} | |
export function getAPIDetails() { | |
return (dispatch) => { | |
axios | |
.get("http://localhost:3000/productsList") | |
.then(response => { | |
dispatch(addAPIData(response.data)); | |
}) | |
.catch(error => { | |
console.error('axios error', error); // eslint-disable-line no-console | |
}); | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint no-console: 0 */ | |
import React, {Component} from "react"; | |
import PropTypes from 'prop-types' | |
import {connect} from 'react-redux'; | |
import { | |
Card, Button, CardImg, CardTitle, CardText, | |
CardBlock, Row, Col, Input, InputGroup, InputGroupAddon | |
} from 'reactstrap'; | |
import InputRange from 'react-input-range'; | |
import { | |
setFilterTerm, | |
setFilterPrice, | |
changeSortKey, | |
getAPIDetails, | |
addToCart, | |
removeFromCart | |
} from '../redux/actionCreators'; | |
class ProductsList extends Component { | |
componentDidMount() { | |
if (!this.props.products[0]) { | |
this.props.getAPIData(); | |
} | |
} | |
renderProductsList() { | |
function mapProductCards(elem) { | |
console.log(this); | |
return ( | |
<Card className="m-1" style={{width: '18rem'}} key={elem.id}> | |
<CardImg top width="100%" src={`/public/img/${elem.image}`} alt="Card image cap"/> | |
<CardBlock> | |
<CardTitle>{elem.name}</CardTitle> | |
<CardText>{elem.price}</CardText> | |
<CardText>isAvailable</CardText> | |
<Button onClick={() => this.props.addItemToCart(elem.id)}>Add to Cart</Button> | |
</CardBlock> | |
</Card> | |
) | |
} | |
if (this.props.sortListKey) | |
return ( | |
this.props.products | |
.slice() | |
.sort((a, b) => a.price - b.price) | |
.filter((elem) => ((elem.category === this.props.match.params.category) && | |
(elem.manufacturer.toUpperCase().indexOf(this.props.filterVal.toUpperCase()) >= 0) && | |
(elem.price >= this.props.filterRange.min && elem.price <= this.props.filterRange.max)) | |
) | |
.map(mapProductCards, this) | |
); | |
return ( | |
this.props.products | |
.filter((elem) => ((elem.category === this.props.match.params.category) && | |
(elem.manufacturer.toUpperCase().indexOf(this.props.filterVal.toUpperCase()) >= 0) && | |
(elem.price >= this.props.filterRange.min && elem.price <= this.props.filterRange.max)) | |
) | |
.map(mapProductCards, this) | |
) | |
} | |
render() { | |
return ( | |
<div className="landing"> | |
<Row> | |
<Col> | |
<div className="d-flex flex-row flex-wrap">{this.renderProductsList()}</div> | |
</Col> | |
<Col xs="4" sm="2"> | |
<InputGroup> | |
<InputGroupAddon>@</InputGroupAddon> | |
<input type="text" className="form-control" | |
name="filter1" | |
value={this.props.filterVal} | |
onChange={this.props.handleFilterTermChange} | |
placeholder="Grown in:" | |
aria-describedby="basic-addon1"/> | |
</InputGroup> | |
<br/> | |
<InputGroup> | |
<InputRange | |
formatLabel={value => `${value}$`} | |
maxValue={20} | |
minValue={0} | |
value={this.props.filterRange} | |
onChange={value => this.props.handleFilterRangeChange(value)}/> | |
</InputGroup> | |
<br/> | |
<InputGroup> | |
<InputGroupAddon> | |
<Input addon type="checkbox" aria-label="Checkbox for following text input" | |
placeholder="Sort by price" | |
defaultChecked={this.props.sortListKey} | |
onChange={this.props.handleInputChange}/> | |
</InputGroupAddon> | |
<InputGroupAddon>Sort by price</InputGroupAddon> | |
</InputGroup> | |
</Col> | |
</Row> | |
</div> | |
); | |
} | |
} | |
const mapStateToProps = (state) => { | |
const filterTerm = state.filterTerm ? state.filterTerm : ""; | |
const filterPrice = state.filterPrice; | |
const apiData = state.apiData ? state.apiData : []; | |
const sortKey = state.sortKey; | |
return { | |
products: apiData, | |
filterVal: filterTerm, | |
filterRange: filterPrice, | |
sortListKey: sortKey | |
}; | |
}; | |
const mapDispatchToProps = (dispatch) => ({ | |
getAPIData() { | |
dispatch(getAPIDetails()); | |
}, | |
handleFilterTermChange(evt) { | |
dispatch(setFilterTerm(evt.target.value)); | |
}, | |
handleFilterRangeChange(value) { | |
dispatch(setFilterPrice(value)); | |
}, | |
handleInputChange(evt) { | |
dispatch(changeSortKey(evt.target.checked)) | |
}, | |
addItemToCart(value) { | |
dispatch(addToCart(value)); | |
}, | |
removeItemFromCart(value) { | |
dispatch(removeFromCart(value)); | |
} | |
}); | |
export default connect(mapStateToProps, mapDispatchToProps)(ProductsList); | |
ProductsList.defaultProps = { | |
getAPIData: null, | |
products: [], | |
filterVal: "", | |
filterRange: {min: 1, max: 10}, | |
sortListKey: false | |
}; | |
ProductsList.propTypes = { | |
products: PropTypes.arrayOf(PropTypes.object), | |
getAPIData: PropTypes.func, | |
match: PropTypes.shape({ | |
params: PropTypes.shape({ | |
category: PropTypes.string | |
}) | |
}).isRequired, | |
handleFilterTermChange: PropTypes.func.isRequired, | |
handleFilterRangeChange: PropTypes.func.isRequired, | |
handleInputChange: PropTypes.func.isRequired, | |
filterVal: PropTypes.string, | |
filterRange: PropTypes.shape({ | |
min: PropTypes.number, | |
max: PropTypes.number, | |
}), | |
sortListKey: PropTypes.bool, | |
addItemToCart: PropTypes.func.isRequired, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {combineReducers} from 'redux'; | |
import {SET_FILTER_TERM, SET_FILTER_PRICE, SORT_BY_PRICE, ADD_API_DATA, ADD_TO_CART, REMOVE_FROM_CART} from './actions'; | |
const initialState = { | |
addedIds: [], | |
quantityById: {} | |
}; | |
const filterTerm = (state = '', action) => { | |
if (action.type === SET_FILTER_TERM) { | |
return action.payload; | |
} | |
return state; | |
}; | |
const filterPrice = (state = {min: 1, max: 20}, action) => { | |
if (action.type === SET_FILTER_PRICE) { | |
return action.payload; | |
} | |
return state; | |
}; | |
const sortKey = (state = false, action) => { | |
if (action.type === SORT_BY_PRICE) { | |
return action.payload; | |
} | |
return state; | |
}; | |
const handleCart = (state = initialState.addedIds, action) => { | |
switch (action.type) { | |
case ADD_TO_CART: | |
if (state.indexOf(action.productId) !== -1) { | |
return state | |
} | |
return [...state, action.productId]; | |
case REMOVE_FROM_CART: | |
return state.filter(productId => action.productId !== productId); | |
default: | |
return state | |
} | |
}; | |
const apiData = (state = [], action) => { | |
if (action.type === ADD_API_DATA) { | |
return action.payload; | |
} | |
return state; | |
}; | |
const rootReducer = combineReducers({filterTerm, filterPrice, handleCart, apiData, sortKey }); | |
export default rootReducer; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment