diff options
| author | Michael Foiani <mfoiani2019@communityschoolnaples.org> | 2018-07-25 19:38:43 -0400 |
|---|---|---|
| committer | Michael Foiani <mfoiani2019@communityschoolnaples.org> | 2018-07-25 19:38:43 -0400 |
| commit | 3c09a0a91488e182f521b0cd39017cb5bc781a83 (patch) | |
| tree | bc26d401b97f13169f3becdfe03bba6fd0f34353 /src/reducers | |
Initial commit. Added pwa starter kit to project for the application.
Diffstat (limited to 'src/reducers')
| -rw-r--r-- | src/reducers/app.js | 51 | ||||
| -rw-r--r-- | src/reducers/counter.js | 30 | ||||
| -rw-r--r-- | src/reducers/shop.js | 199 |
3 files changed, 280 insertions, 0 deletions
diff --git a/src/reducers/app.js b/src/reducers/app.js new file mode 100644 index 0000000..375e214 --- /dev/null +++ b/src/reducers/app.js @@ -0,0 +1,51 @@ +/** +@license +Copyright (c) 2018 The Polymer Project Authors. All rights reserved. +This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt +The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt +The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt +Code distributed by Google as part of the polymer project is also +subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt +*/ + +import { + UPDATE_PAGE, + UPDATE_OFFLINE, + OPEN_SNACKBAR, + CLOSE_SNACKBAR, + UPDATE_DRAWER_STATE +} from '../actions/app.js'; + +const app = (state = {drawerOpened: false}, action) => { + switch (action.type) { + case UPDATE_PAGE: + return { + ...state, + page: action.page + }; + case UPDATE_OFFLINE: + return { + ...state, + offline: action.offline + }; + case UPDATE_DRAWER_STATE: + return { + ...state, + drawerOpened: action.opened + }; + case OPEN_SNACKBAR: + return { + ...state, + snackbarOpened: true + }; + case CLOSE_SNACKBAR: + return { + ...state, + snackbarOpened: false + }; + default: + return state; + } +}; + +export default app; diff --git a/src/reducers/counter.js b/src/reducers/counter.js new file mode 100644 index 0000000..523a0f7 --- /dev/null +++ b/src/reducers/counter.js @@ -0,0 +1,30 @@ +/** +@license +Copyright (c) 2018 The Polymer Project Authors. All rights reserved. +This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt +The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt +The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt +Code distributed by Google as part of the polymer project is also +subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt +*/ + +import { INCREMENT, DECREMENT } from '../actions/counter.js'; + +const counter = (state = {clicks: 0, value: 0}, action) => { + switch (action.type) { + case INCREMENT: + return { + 'clicks': state.clicks + 1, + 'value': state.value + 1 + }; + case DECREMENT: + return { + 'clicks': state.clicks + 1, + 'value': state.value - 1 + }; + default: + return state; + } +}; + +export default counter; diff --git a/src/reducers/shop.js b/src/reducers/shop.js new file mode 100644 index 0000000..1005ca7 --- /dev/null +++ b/src/reducers/shop.js @@ -0,0 +1,199 @@ +/** +@license +Copyright (c) 2018 The Polymer Project Authors. All rights reserved. +This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt +The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt +The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt +Code distributed by Google as part of the polymer project is also +subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt +*/ + +import { + GET_PRODUCTS, + ADD_TO_CART, + REMOVE_FROM_CART, + CHECKOUT_SUCCESS, + CHECKOUT_FAILURE +} from '../actions/shop.js'; +import { createSelector } from 'reselect'; + +const INITIAL_CART = { + addedIds: [], + quantityById: {} +}; + +const UPDATED_CART = { + addedIds: ['1'], + quantityById: {'1': 1} +}; + +const shop = (state = {products: {}, cart: INITIAL_CART}, action) => { + switch (action.type) { + case GET_PRODUCTS: + return { + ...state, + products: action.products + }; + case ADD_TO_CART: + case REMOVE_FROM_CART: + case CHECKOUT_SUCCESS: + return { + ...state, + products: products(state.products, action), + cart: cart(state.cart, action), + error: '' + }; + case CHECKOUT_FAILURE: + return { + ...state, + error: 'Checkout failed. Please try again' + }; + default: + return state; + } +}; + +// Slice reducer: it only reduces the bit of the state it's concerned about. +const products = (state, action) => { + switch (action.type) { + case ADD_TO_CART: + case REMOVE_FROM_CART: + const productId = action.productId; + return { + ...state, + [productId]: product(state[productId], action) + }; + default: + return state; + } +}; + +const product = (state, action) => { + switch (action.type) { + case ADD_TO_CART: + return { + ...state, + inventory: state.inventory - 1 + }; + case REMOVE_FROM_CART: + return { + ...state, + inventory: state.inventory + 1 + }; + default: + return state; + } +}; + +const cart = (state = INITIAL_CART, action) => { + switch (action.type) { + case ADD_TO_CART: + case REMOVE_FROM_CART: + return { + addedIds: addedIds(state.addedIds, state.quantityById, action), + quantityById: quantityById(state.quantityById, action) + }; + case CHECKOUT_SUCCESS: + return INITIAL_CART; + default: + return state; + } +}; + +const addedIds = (state = INITIAL_CART.addedIds, quantityById, action) => { + const productId = action.productId; + switch (action.type) { + case ADD_TO_CART: + if (state.indexOf(productId) !== -1) { + return state; + } + return [ + ...state, + action.productId + ]; + case REMOVE_FROM_CART: + // This is called before the state is updated, so if you have 1 item in the + // cart during the remove action, you'll have 0. + if (quantityById[productId] <= 1) { + // This removes all items in this array equal to productId. + return state.filter(e => e !== productId); + } + return state; + default: + return state; + } +}; + +const quantityById = (state = INITIAL_CART.quantityById, action) => { + const productId = action.productId; + switch (action.type) { + case ADD_TO_CART: + return { + ...state, + [productId]: (state[productId] || 0) + 1 + }; + case REMOVE_FROM_CART: + return { + ...state, + [productId]: (state[productId] || 0) - 1 + }; + default: + return state; + } +}; + +export default shop; + +// Per Redux best practices, the shop data in our store is structured +// for efficiency (small size and fast updates). +// +// The _selectors_ below transform store data into specific forms that +// are tailored for presentation. Putting this logic here keeps the +// layers of our app loosely coupled and easier to maintain, since +// views don't need to know about the store's internal data structures. +// +// We use a tiny library called `reselect` to create efficient +// selectors. More info: https://github.com/reduxjs/reselect. + +const cartSelector = state => state.shop.cart; +const productsSelector = state => state.shop.products; + +// Return a flattened array representation of the items in the cart +export const cartItemsSelector = createSelector( + cartSelector, + productsSelector, + (cart, products) => { + const items = []; + for (let id of cart.addedIds) { + const item = products[id]; + items.push({id: item.id, title: item.title, amount: cart.quantityById[id], price: item.price}); + } + return items; + } +); + +// Return the total cost of the items in the cart +export const cartTotalSelector = createSelector( + cartSelector, + productsSelector, + (cart, products) => { + let total = 0; + for (let id of cart.addedIds) { + const item = products[id]; + total += item.price * cart.quantityById[id]; + } + return parseFloat(Math.round(total * 100) / 100).toFixed(2); + } +); + +// Return the number of items in the cart +export const cartQuantitySelector = createSelector( + cartSelector, + cart => { + let num = 0; + for (let id of cart.addedIds) { + num += cart.quantityById[id]; + } + return num; + } +); |
