Skip to content

Instantly share code, notes, and snippets.

@Y-Taras
Last active July 3, 2017 08:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Y-Taras/be0777006e925a9d80e367221a481caf to your computer and use it in GitHub Desktop.
Save Y-Taras/be0777006e925a9d80e367221a481caf to your computer and use it in GitHub Desktop.
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
});
};
}
/* 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,
};
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