Преглед на файлове

Group items with the same name

Tatiana Inama преди 7 години
родител
ревизия
f5aa8267e4

+ 5 - 5
recipes/src/containers/Recipes/List/index.tsx

@@ -5,7 +5,7 @@ import {
   selectRecipe as select,
 } from "containers/Recipes/List/actions";
 import {
-  addToCart,
+  addRecipeToCart,
   removeFromCart
 } from 'containers/ShoppingCart/actions';
 import { connect } from "react-redux";
@@ -29,7 +29,7 @@ interface RecipeListProps extends RouteComponentProps {
   receiveRecipes: (recipes: DBRecipe[]) => undefined,
   selectRecipe: (recipe?: DBRecipe) => undefined,
   removeFromCart: (recipe: DBRecipe) => undefined,
-  addToCart: (recipe: DBRecipe) => undefined,
+  addRecipeToCart: (recipe: DBRecipe) => undefined,
 };
 
 class RecipeList extends Component<RecipeListProps, {phoneDisplay: boolean, search: string}> {
@@ -87,7 +87,7 @@ class RecipeList extends Component<RecipeListProps, {phoneDisplay: boolean, sear
   }
 
   handleAddToShopping = (recipe: DBRecipe) => (event: React.MouseEvent) => {
-    this.props.addToCart(recipe)
+    this.props.addRecipeToCart(recipe)
   }
 
   handler = (event: React.MouseEvent) => {
@@ -182,8 +182,8 @@ const mapDispatchToProps = (dispatch: any) => {
     selectRecipe: (recipe: DBRecipe) => {
       dispatch(select(recipe))
     },
-    addToCart: (recipe: DBRecipe) => {
-      dispatch(addToCart(recipe))
+    addRecipeToCart: (recipe: DBRecipe) => {
+      dispatch(addRecipeToCart(recipe))
     },
     removeFromCart: (recipe: DBRecipe) => {
       dispatch(removeFromCart(recipe))

+ 3 - 3
recipes/src/containers/ShoppingCart/List/index.tsx

@@ -6,13 +6,13 @@ import Navbar from 'components/Navbar';
 import { Grid, Row, Cell } from '@material/react-layout-grid';
 import List from 'components/List';
 import ShoppingItem from 'src/types/shopping-cart';
-import { addToCart, removeItemFromCart, removeAll } from './../actions';
+import { addRecipeToCart, removeItemFromCart, removeAll } from './../actions';
 import Dialog from 'components/Dialog';
 import Button from 'components/Button';
 import { DBRecipe } from 'src/types/recipes';
 
 type ActionsType = {
-  addToCart: typeof addToCart,
+  addToCart: typeof addRecipeToCart,
   removeItemFromCart: typeof removeItemFromCart
 }
 
@@ -87,5 +87,5 @@ const mapStateToProps = (state: AppState) => {
 
 export default connect(
   mapStateToProps,
-  {addToCart, removeItemFromCart, removeAll}
+  {addToCart: addRecipeToCart, removeItemFromCart, removeAll}
 )(ShoppingList);

+ 6 - 6
recipes/src/containers/ShoppingCart/actions.ts

@@ -2,13 +2,13 @@ import { DBRecipe } from 'types/recipes';
 import ShoppingItem from 'types/shopping-cart';
 import { bindActionCreators } from 'redux';
 
-export const ADD_TO_CART = 'ADD_TO_CART';
+export const ADD_RECIPE_TO_CART = 'ADD_ RECIPE_TO_CART';
 export const REMOVE_RECIPE_FROM_CART = 'REMOVE_RECIPE_FROM_CART';
 export const REMOVE_ITEM_FROM_CART = 'REMOVE_ITEM_FROM_CART';
 export const REMOVE_ALL = 'REMOVE_ALL';
 
-export const addToCart = (recipe: DBRecipe): AddToCart => ({
-  type: ADD_TO_CART,
+export const addRecipeToCart = (recipe: DBRecipe): AddRecipeToCart => ({
+  type: ADD_RECIPE_TO_CART,
   payload: recipe
 })
 
@@ -26,8 +26,8 @@ export const removeAll = (): RemoveAll => ({
   type: REMOVE_ALL
 });
 
-export type AddToCart = {
-  type: typeof ADD_TO_CART,
+export type AddRecipeToCart = {
+  type: typeof ADD_RECIPE_TO_CART,
   payload: DBRecipe
 }
 
@@ -45,4 +45,4 @@ export type RemoveAll = {
   type: typeof REMOVE_ALL
 }
 
-export type ActionTypes = AddToCart | RemoveRecipeFromCart | RemoveItemFromCart | RemoveAll;
+export type ActionTypes = AddRecipeToCart | RemoveRecipeFromCart | RemoveItemFromCart | RemoveAll;

+ 67 - 19
recipes/src/containers/ShoppingCart/reducers.ts

@@ -1,6 +1,8 @@
 import ShoppingItem from 'types/shopping-cart';
-import { ActionTypes, ADD_TO_CART, REMOVE_RECIPE_FROM_CART, REMOVE_ITEM_FROM_CART, REMOVE_ALL } from './actions';
-import { DBRecipe } from 'src/types/recipes';
+import { ActionTypes, ADD_RECIPE_TO_CART, REMOVE_RECIPE_FROM_CART, REMOVE_ITEM_FROM_CART, REMOVE_ALL } from './actions';
+import { DBRecipe, Ingredient } from 'src/types/recipes';
+import { update } from 'ramda';
+import { Convert, GetMeasure, Measure } from 'services/measurements';
 
 export type ShoppingCartState = {
   items: ShoppingItem[],
@@ -16,7 +18,7 @@ const initialState: ShoppingCartState = {
         _original: '4 6oz Chicken Breast',
         suggestions: [],
         recipeId: '5d37045aef8ef87af296cba7',
-        recipeName: ['Sunday Night Chicken Parm', 'Fried Chicken']
+        recipeName: ['Chicken', 'Fried Chicken']
       },
       {
         name: 'eggs',
@@ -25,7 +27,7 @@ const initialState: ShoppingCartState = {
         _original: '2 Eggs',
         suggestions: [],
         recipeId: '5d37045aef8ef87af296cba7',
-        recipeName: ['Sunday Night Chicken Parm']
+        recipeName: ['Chicken']
       },
       {
         name: 'freshly grated parm',
@@ -34,7 +36,7 @@ const initialState: ShoppingCartState = {
         _original: 'Freshly Grated Parm',
         suggestions: [],
         recipeId: '5d37045aef8ef87af296cba7',
-        recipeName: ['Sunday Night Chicken Parm']
+        recipeName: ['Chicken']
       },
       {
         name: 'bread crumbs',
@@ -58,7 +60,7 @@ const initialState: ShoppingCartState = {
           }
         ],
         recipeId: '5d37045aef8ef87af296cba7',
-        recipeName: ['Sunday Night Chicken Parm']
+        recipeName: ['Chicken']
       },
       {
         name: 'salt and pepper, to taste',
@@ -67,7 +69,7 @@ const initialState: ShoppingCartState = {
         _original: 'Salt and Pepper, to taste',
         suggestions: [],
         recipeId: '5d37045aef8ef87af296cba7',
-        recipeName: ['Sunday Night Chicken Parm']
+        recipeName: ['Chicken']
       },
       {
         name: 'light olive oil for shallow frying',
@@ -75,7 +77,7 @@ const initialState: ShoppingCartState = {
         unit: '',
         _original: 'Light Olive Oil for shallow Frying',
         recipeId: '5d37045aef8ef87af296cba7',
-        recipeName: ['Sunday Night Chicken Parm']
+        recipeName: ['Chicken']
       },
       {
         name: 'olive oil',
@@ -90,30 +92,76 @@ const initialState: ShoppingCartState = {
     ]
 };
 
-const getIngredients = (recipe: DBRecipe): ShoppingItem[] => {
+const getItemsFromRecipe = (recipe: DBRecipe): ShoppingItem[] => {
   return recipe.ingredients.reduce((ingredients, subRecipe) => {
     return [
       ...ingredients,
-      ...subRecipe.ingredients.map(ingredient => ({
-        ...ingredient,
-        recipeId: recipe._id,
-        recipeName: [recipe.name]
-      })),
+      ...subRecipe.ingredients.map(createShoppingItem(recipe._id, recipe.name)),
     ]
   }, [] as ShoppingItem[])
 } 
 
+const combineItems = (a: ShoppingItem, b: ShoppingItem): ShoppingItem => {
+  if (a.unit && b.unit) {
+    const m = GetMeasure(b.unit);
+    return {
+      ...a,
+      quantity: a.quantity + Convert(b.quantity, b.unit, a.unit, m.name as Measure)
+    }
+  } else {
+    if (a.unit !== b.unit) {
+      throw Error(`cannot sum this units: ${b.unit, a.unit}`)
+    } else {
+      return {
+        ...a,
+        quantity: a.quantity + b.quantity
+      }
+    }
+  }
+}
+
+const createShoppingList = (initial: ShoppingItem[], newItems: ShoppingItem[]): ShoppingItem[] => {
+  return newItems.reduce((shoppingCart, newItem) => {
+    const existentItemIdx = shoppingCart.findIndex(item => item.name === newItem.name);
+    if ( existentItemIdx > -1 ) {
+      try {
+        const sum = combineItems(initial[existentItemIdx], newItem).quantity
+        return update(existentItemIdx, {
+          ...initial[existentItemIdx],
+          recipeName: (initial[existentItemIdx].recipeName||[]).concat(newItem.recipeName||[]),
+          quantity: sum
+        }, shoppingCart)
+      } catch {
+        return [
+          ...shoppingCart,
+          newItem
+        ]
+      }
+    } else {
+      return [
+        ...shoppingCart,
+        newItem
+      ]
+    }
+  }, initial);
+}
+
+const createShoppingItem = (recipeId: string, recipeName: string) => (ingredient: Ingredient): ShoppingItem => {
+  return {
+    ...ingredient,
+    recipeId,
+    recipeName: [recipeName]
+  };
+}
+
 const shoppingCartReducer = (
   state = initialState,
   action: ActionTypes
 ): ShoppingCartState => {
   switch (action.type) {
-    case ADD_TO_CART:
+    case ADD_RECIPE_TO_CART:
       return {
-        items: [
-          ...state.items,
-          ...getIngredients(action.payload)
-        ],
+        items: createShoppingList(state.items, getItemsFromRecipe(action.payload)),
         recipesId: state.recipesId.concat([action.payload._id])
       }
     case REMOVE_RECIPE_FROM_CART: 

+ 1 - 1
recipes/src/types/shopping-cart.ts

@@ -1,7 +1,7 @@
 import Recipe, { Ingredient } from './recipes';
 
 interface ShoppingItem extends Ingredient {
-  recipeId: string,
+  recipeId?: string,
   recipeName?: string[]
 }