From 71b5e13a736aba67cbe29fed77ec9703e20211ac Mon Sep 17 00:00:00 2001 From: Zoey Zheng <zoeyyandi@gmail.com> Date: Sun, 11 Mar 2018 16:56:43 -0400 Subject: [PATCH] added remove product action, created add product form, created filter search bar --- src/App.js | 123 +++++++++++++++++++++++++++++++----------- src/actions/index.js | 24 ++++++++- src/index.js | 15 +++--- src/reducers/index.js | 44 +++++++++------ 4 files changed, 152 insertions(+), 54 deletions(-) diff --git a/src/App.js b/src/App.js index f54312b..b88928a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,63 +1,124 @@ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import './App.css'; -import {connect} from 'react-redux'; -import {addProduct} from './actions/index'; +import { connect } from 'react-redux'; +import { addProduct, deleteProduct, updateSearchString } from './actions/index'; import Chance from 'chance'; export const chance = Chance(); -const Product = (props) => <div>{props.name}</div>; - -const DaBest = ({name}) => <h1>The Best: {name}</h1>; +const Product = ({ product }) => ( + <div> + <p>Name: {product.name}</p> + <p>Department: {product.department}</p> + <p>Price: {product.price}</p> + <p>Stock: {product.stock}</p> + </div> +); + +const DaBest = ({ name }) => <h1>The Best: {name}</h1>; + +const DeleteButton = ({ deleteProduct, id }) => ( + <button onClick={() => deleteProduct(id)}>Delete</button> +); + +const Form = ({ handleSubmit }) => { + return ( + <form onSubmit={handleSubmit}> + <label> + Name:<input name="Name" type="text" autoFocus /> + </label> + + <label> + Department:<input name="Department" type="text" /> + </label> + + <label> + Price:<input name="Price" type="text" /> + </label> + + <label> + Stock:<input name="Stock" type="text" /> + </label> + + <button>Add Product</button> + </form> + ); +}; -const AdderButton = ({add}) => <button onClick={() => add({name: 'Sofa'})}>Add Sofa</button> +const SearchInput = ({ handleOnChange }) => ( + <input + onChange={handleOnChange} + type="text" + autoFocus + placeholder="Search for a product" + /> +); class App extends Component { - - - constructor(props) { - super(props); - } - - componentDidMount() { - this.props.add({ + handleSubmit = event => { + event.preventDefault(); + let product = { id: chance.guid(), - name: 'Table', - department: 'Furniture', - price: '300.00', - stock: 5, - }); - } + name: event.target[0].value, + department: event.target[1].value, + price: event.target[2].value, + stock: event.target[3].value + }; + this.props.add(product); + event.target[0].value = ''; + event.target[1].value = ''; + event.target[2].value = ''; + event.target[3].value = ''; + }; + + handleOnChange = event => { + this.props.updateSearchString(event.target.value); + }; render() { - const {productList, add, whoIsTheBest} = this.props; - debugger; + const { searchString, productList, whoIsTheBest } = this.props; return ( <div> - <DaBest name={whoIsTheBest}/> - {productList.map(product => <Product name={product.name} key={product.id}/>)} - - <AdderButton {...this.props} /> + <DaBest name={whoIsTheBest} /> + <SearchInput handleOnChange={this.handleOnChange} /> + {productList + .filter(product => { + let name = product.name.toLowerCase(); + return name.includes(searchString.toLowerCase()); + }) + .map(product => ( + <div key={product.id}> + <Product product={product} /> + <DeleteButton + deleteProduct={this.props.deleteProduct} + id={product.id} + /> + </div> + ))} + <Form handleSubmit={this.handleSubmit} /> </div> ); } } - // React x REDUX STUFF const mapStateToProps = state => { return { productList: state.products.productList, whoIsTheBest: 'Della', - + searchString: state.products.searchString, // an example of how to derive state in the mapStateToProps function - this is a specific 'subset' of the full list - lowStockProducts: state.products.productList.filter(prod => prod.stock && prod.stock < 4), - } + lowStockProducts: state.products.productList.filter( + prod => prod.stock && prod.stock < 4 + ) + }; }; const mapDispatchToProps = { add: addProduct, + deleteProduct: deleteProduct, + updateSearchString: updateSearchString }; export default connect(mapStateToProps, mapDispatchToProps)(App); diff --git a/src/actions/index.js b/src/actions/index.js index 79e204e..bf3c0f7 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,5 +1,7 @@ export const ACTION_TYPES = { addProduct: 'ADD_PRODUCTS', + deleteProduct: 'DELETE_PRODUCTS', + updateSearchString: 'UPDATE_SEARCH_STRING' }; export function addProduct(product) { @@ -7,7 +9,25 @@ export function addProduct(product) { return { type: ACTION_TYPES.addProduct, payload: { - product, + product } - } + }; +} + +export function deleteProduct(id) { + return { + type: ACTION_TYPES.deleteProduct, + payload: { + id + } + }; +} + +export function updateSearchString(searchInput) { + return { + type: ACTION_TYPES.updateSearchString, + payload: { + searchInput + } + }; } diff --git a/src/index.js b/src/index.js index dfc54fd..ae6190d 100644 --- a/src/index.js +++ b/src/index.js @@ -6,14 +6,17 @@ import { Provider } from 'react-redux'; import App from '../src/App'; import '../src/index.css'; import reducer from './reducers'; -import registerServiceWorker from "../src/registerServiceWorker"; +import registerServiceWorker from '../src/registerServiceWorker'; -const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); +const store = createStore( + reducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() +); ReactDOM.render( - <Provider store={ store }> - <App /> - </Provider>, - document.getElementById('root') + <Provider store={store}> + <App /> + </Provider>, + document.getElementById('root') ); registerServiceWorker(); diff --git a/src/reducers/index.js b/src/reducers/index.js index 5cb12f1..3b1945a 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,27 +1,41 @@ -import {combineReducers} from 'redux'; - -import {generateProducts} from '../utils/data'; -import {ACTION_TYPES} from '../actions'; +import { combineReducers } from 'redux'; +import { generateProducts } from '../utils/data'; +import { ACTION_TYPES } from '../actions'; // you'll notice I set my initial state below on line 13 to equal this object! This is a common pattern const INITIAL_STATE = { - productList: generateProducts(10), - searchString: '' // hint for optional homework + productList: generateProducts(10), + searchString: '' // hint for optional homework }; -export const products = (state = INITIAL_STATE, {type, payload}) => { - switch (type) { - case ACTION_TYPES.addProduct: - // using object spread, I am saying - I want to return the old state, except change the productList property - return {...state, productList: state.productList.concat(payload.product)}; - } - return state; +export const products = (state = INITIAL_STATE, { type, payload }) => { + switch (type) { + case ACTION_TYPES.addProduct: + // using object spread, I am saying - I want to return the old state, except change the productList property + return { + ...state, + productList: [...state.productList, payload.product] + }; + case ACTION_TYPES.deleteProduct: + return { + ...state, + productList: state.productList.filter( + product => product.id !== payload.id + ) + }; + case ACTION_TYPES.updateSearchString: + return { + ...state, + searchString: payload.searchInput + }; + default: + return state; + } }; - // This is how you can combine many reducers into one large reducer: // https://redux.js.org/api-reference/combinereducers export default combineReducers({ - products, + products });