diff --git a/package-lock.json b/package-lock.json
index f0346e2..0960083 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2,7 +2,6 @@
"name": "bridge-redux-starter-homework",
"version": "0.1.0",
"lockfileVersion": 1,
- "requires": true,
"dependencies": {
"abab": {
"version": "1.0.4",
@@ -8916,6 +8915,14 @@
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
},
+ "string_decoder": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
+ },
"string-length": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz",
@@ -8948,14 +8955,6 @@
}
}
},
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "requires": {
- "safe-buffer": "5.1.1"
- }
- },
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
diff --git a/src/App.js b/src/App.js
index f54312b..df65cbf 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,20 +1,42 @@
import React, {Component} from 'react';
import './App.css';
import {connect} from 'react-redux';
-import {addProduct} from './actions/index';
+import {addProduct, removeProduct, submitForm, updateProduct, updateSearchTerm} from './actions/index';
import Chance from 'chance';
+import { Form } from './components/Form';
+import { Product } from './components/Product';
+
export const chance = Chance();
-const Product = (props) =>
{props.name}
;
+const SearchBar = ({searchTerm, updateSearchTerm}) => {
+ return (
+ {
+ updateSearchTerm(e.target.value);
+ }
+ }
+ />
+ );
+};
+
+const EnhancedProductList = ({searchTerm, filteredProducts, productList, remove}) => {
+ const products = searchTerm.length > 0 ? filteredProducts : productList;
+ return (
+
+ {
+ products.map(product =>
)
+ }
+
+ );
+};
const DaBest = ({name}) => The Best: {name}
;
-const AdderButton = ({add}) =>
+const AdderButton = ({add}) => ;
class App extends Component {
-
-
constructor(props) {
super(props);
}
@@ -30,14 +52,16 @@ class App extends Component {
}
render() {
- const {productList, add, whoIsTheBest} = this.props;
+ const {whoIsTheBest, productList, searchTerm, filteredProducts, add, remove, updateSearchTerm} = this.props;
debugger;
return (
+
- {productList.map(product => )}
-
+
+
+
);
}
@@ -49,15 +73,21 @@ class App extends Component {
const mapStateToProps = state => {
return {
productList: state.products.productList,
+ searchTerm: state.products.searchTerm,
whoIsTheBest: 'Della',
// 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),
+ filteredProducts: state.products.productList.filter(prod => prod.name.toLowerCase().includes(state.products.searchTerm.toLowerCase())),
}
};
const mapDispatchToProps = {
add: addProduct,
+ remove: removeProduct,
+ submitForm,
+ updateProduct,
+ updateSearchTerm
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
diff --git a/src/actions/index.js b/src/actions/index.js
index 79e204e..b1f8c36 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -1,9 +1,12 @@
export const ACTION_TYPES = {
addProduct: 'ADD_PRODUCTS',
+ removeProduct: 'REMOVE_PRODUCTS',
+ submitForm: 'SUBMIT_FORM',
+ updateProduct: 'UPDATE_PRODUCT',
+ updateSearchTerm: 'UPDATE_SEARCHTERM',
};
export function addProduct(product) {
- debugger;
return {
type: ACTION_TYPES.addProduct,
payload: {
@@ -11,3 +14,31 @@ export function addProduct(product) {
}
}
}
+
+export function removeProduct(productId) {
+ return {
+ type: ACTION_TYPES.removeProduct,
+ payload: productId
+ }
+}
+
+export function submitForm() {
+ return {
+ type: ACTION_TYPES.submitForm
+ }
+}
+
+export function updateProduct(label, val) {
+ return {
+ type: ACTION_TYPES.updateProduct,
+ label,
+ val
+ }
+}
+
+export function updateSearchTerm(term) {
+ return {
+ type: ACTION_TYPES.updateSearchTerm,
+ payload: term
+ }
+}
diff --git a/src/components/Form.js b/src/components/Form.js
new file mode 100644
index 0000000..9382577
--- /dev/null
+++ b/src/components/Form.js
@@ -0,0 +1,14 @@
+import React from 'react';
+
+export const Form = ({submitForm, updateProduct}) => {
+ return (
+
+ )
+};
diff --git a/src/components/Product.js b/src/components/Product.js
new file mode 100644
index 0000000..5d63df0
--- /dev/null
+++ b/src/components/Product.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+export const Product = ({id, name, department, price, stock, type, remove}) => {
+ debugger;
+ return (
+
+
{name}
+
Department: {department}
+
Price: {price}
+
Stock: {stock}
+
Type: {type}
+
+
+ );
+};
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 5cb12f1..7e9f7a1 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -1,20 +1,35 @@
import {combineReducers} from 'redux';
-import {generateProducts} from '../utils/data';
+import {generateProducts, chance} 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),
+ searchTerm: '',
+ product: {
+ id: chance.guid(),
+ name: '',
+ department: '',
+ price: 0,
+ stock: 0,
+ type: '',
+ }
};
-export const products = (state = INITIAL_STATE, {type, payload}) => {
+export const products = (state = INITIAL_STATE, {type, payload, label, val}) => {
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)};
+ case ACTION_TYPES.removeProduct:
+ return {...state, productList: state.productList.filter(prod => prod.id !== payload)};
+ case ACTION_TYPES.submitForm:
+ return {...state, productList: state.productList.concat(state.product)};
+ case ACTION_TYPES.updateProduct:
+ return {...state, product: {...state.product, [label]: val}};
+ case ACTION_TYPES.updateSearchTerm:
+ return {...state, searchTerm: payload};
}
return state;
};
diff --git a/src/reducers/index.test.js b/src/reducers/index.test.js
index dd671fd..0ce0476 100644
--- a/src/reducers/index.test.js
+++ b/src/reducers/index.test.js
@@ -2,6 +2,9 @@ import { ACTION_TYPES } from '../actions';
import { products } from './index';
it('adds a product on ADD_PRODUCT', () => {
+ const intialState = {
+ productList: []
+ };
const action = {
type: ACTION_TYPES.addProduct,
payload: {
@@ -10,7 +13,54 @@ import { products } from './index';
}
}
};
- expect(products([], action)).toEqual([{
- name: 'Sofa',
- }]);
+ expect(products(intialState, action).productList).toEqual([{name: 'Sofa'}]);
+ });
+
+ it('remove a product on REMOVE_PRODUCT', () => {
+ const intialState = {
+ productList: [{
+ id: '123',
+ name: 'table',
+ }]
+ };
+ const action = {
+ type: ACTION_TYPES.removeProduct,
+ payload: '123'
+ };
+ expect(products(intialState, action).productList).toEqual([]);
+ });
+
+ it('add a product through Form on SUBMIT_FORM', () => {
+ const intialState = {
+ productList: [],
+ product: {
+ name: 'table'
+ }
+ }
+ const action = {
+ type: ACTION_TYPES.submitForm
+ };
+ expect(products(intialState, action).productList).toEqual([{name: 'table'}]);
+ });
+
+ it('update product info on UPDATE_PRODUCT', () => {
+ const initialState = {
+ product: {
+ name: ''
+ }
+ };
+ const action = {
+ type: ACTION_TYPES.updateProduct,
+ label: 'name',
+ val: 'table'
+ };
+ expect(products(initialState, action).product.name).toEqual('table');
+ });
+
+ it('update search term on UPDATE_SEARCHTERM', () => {
+ const action = {
+ type: ACTION_TYPES.updateSearchTerm,
+ payload: 'chair'
+ };
+ expect(products({searchTerm: ''}, action).searchTerm).toEqual('chair');
});