Sfoglia il codice sorgente

Use List instead of ShoppingList component. Add basic Shopping cart item functionality (selection, merge and clear selection)

Tatiana Inama 6 anni fa
parent
commit
7767935264

+ 136 - 42
recipes/src/containers/ShoppingCart/View/index.tsx

@@ -2,31 +2,47 @@ import React from 'react';
 import { connect } from 'react-redux';
 import { ThunkDispatch } from 'redux-thunk';
 import { bindActionCreators } from 'redux';
+import { update, includes, remove } from 'ramda';
 
-import ShoppingList from 'components/ShoppingList';
 import Button from 'components/Button';
 import Dialog from 'components/Dialog';
+import List from 'components/List';
 
 import shoppingCartActions, { fetchCartActionCreator, saveCartActionCreator } from 'containers/ShoppingCart/actions';
 
 import { ShoppingItem, ShoppingCartState } from 'types/shopping-cart';
 import { AppState } from 'store/configureStore';
 
+import { combineItems, combineMultipleItems } from '../services';
+import { GetMeasure } from 'services/measurements';
 import './styles.scss';
 
 type shoppingCartActionTypes = typeof shoppingCartActions;
+interface SelectedItems extends ShoppingItem {
+  index: number
+};
 
 interface ShoppingCartViewProps extends ShoppingCartState, shoppingCartActionTypes {
   fetch: typeof fetchCartActionCreator,
   save: typeof saveCartActionCreator,
 }
 
-class ShoppingCartView extends React.Component<ShoppingCartViewProps, { dialogOpen: boolean }> {
+interface ShoppingCartViewState {
+  dialogOpen: boolean,
+  selected: SelectedItems[],
+  selectedMeasure?: {
+    name: string, values: string[]
+  },
+}
+
+class ShoppingCartView extends React.Component<ShoppingCartViewProps, ShoppingCartViewState> {
 
   constructor (props: ShoppingCartViewProps) {
     super(props);
     this.state = {
-      dialogOpen: false
+      dialogOpen: false,
+      selected: [],
+      selectedMeasure: undefined,
     }
   }
   
@@ -57,48 +73,126 @@ class ShoppingCartView extends React.Component<ShoppingCartViewProps, { dialogOp
     })
   }
 
+  selectItem = (item: ShoppingItem, index: number) => {
+    const duplicated = this.state.selected.findIndex(selected => selected._original === item._original);
+    if (duplicated !== -1) {
+      const newSelection = remove(duplicated, 1, this.state.selected);
+      this.setState({
+        selected: newSelection,
+        selectedMeasure: newSelection.length ? GetMeasure(newSelection[0].unit) : undefined
+      })
+    } else {
+      this.setState({
+        selected: [
+          ...this.state.selected,
+          { ...item, index }
+        ],
+        selectedMeasure: !this.state.selectedMeasure ? GetMeasure(item.unit) : undefined
+      });
+    }
+  }
+
+  mergeItems = () => {
+    const { selected, selectedMeasure } = this.state;
+    if (selectedMeasure && selected.every(item => selectedMeasure.values.includes(item.unit))) {
+      try {
+        this.props.mergeItemsCart(this.state.selected.map(selected => selected._original), combineMultipleItems(this.state.selected));
+        this.clearSelection();
+      } catch(error) {
+        console.log(error)
+      }
+    } else {
+      console.log('one or more items do not match one of the selected measurements')
+    }
+  }
+
+  clearSelection = () => {
+    this.setState({
+      selected: [],
+      selectedMeasure: undefined,
+    })
+  }
+
   render () {
     return (
-          <section className='cbk-shopping-cart-view'>
-              {
-                this.props.items.length ? (
-                  <>
-                    <div className='cbk-shopping-cart-view__items'>
-                      <ShoppingList
-                        items={this.props.items}
-                      />
-                    </div>
-                    <div className='cbk-shopping-cart-view__actions'>
-                      <Button
-                        outlined
-                        onClick={() => this.openDialog(true) }
-                      > Delete
-                      </Button>
-                      <Button
-                        raised
-                        onClick={() => this.props.save(this.props.items)}
-                      > Save
-                      </Button>
-                    </div>
-                  </>
-                ) : (
-                  <div className='cbk-shopping-cart-view--empty'>
-                    Shopping cart is empty
+      <section className='cbk-shopping-cart-view'>
+          {
+            this.props.items.length ? (
+              <>
+                <div className='cbk-shopping-cart-view__actions'>
+                  {
+                    this.state.selected.length >= 2 ? (
+                      <>
+                        <Button
+                          outlined
+                          onClick={this.mergeItems}
+                        >
+                          Merge
+                        </Button>
+                        <Button
+                          outlined
+                          onClick={this.clearSelection}
+                        >
+                          Clear
+                        </Button>
+                      </>
+                    ) : null
+                  }
+                  <Button
+                    outlined
+                    onClick={() => this.openDialog(true) }
+                  > Delete
+                  </Button>
+                  <Button
+                    raised
+                    onClick={() => this.props.save(this.props.items)}
+                  > Save
+                  </Button>
+                </div>
+                <div className='cbk-shopping-cart-view__items'>
+                  <div className='cbk-shopping-list'>
+                    <List
+                      dense
+                      focusMultiple={this.state.selected.map(item => item.index)}
+                      items={this.props.items}
+                      render={ item => (
+                        <div className='cbk-shopping-list__item'>
+                          <div className='cbk-shopping-list__item__name'>
+                            {item.name}
+                            <div className='cbk-shopping-list__item__name__recipes'>
+                              {
+                                item.recipeName && item.recipeName.join(', ')
+                              }
+                            </div>
+                          </div>
+                          <div className='cbk-shopping-list__item__quantity'>
+                            {item.quantity} {item.unit}
+                          </div>
+                        </div>
+                      )}
+                      onClick={(item, index) => { this.selectItem(item, index) }}
+                    />
                   </div>
-                )
-              }
-              {
-                this.state.dialogOpen ? (
-                  <Dialog
-                    isOpen={this.state.dialogOpen}
-                    actions={this.actions}
-                  >
-                    <span>Are you sure you want to delete the shopping cart?</span>
-                  </Dialog>
-                ) : null
-              }
-          </section>
-        )
+                </div>
+              </>
+            ) : (
+              <div className='cbk-shopping-cart-view--empty'>
+                Shopping cart is empty
+              </div>
+            )
+          }
+          {
+            this.state.dialogOpen ? (
+              <Dialog
+                isOpen={this.state.dialogOpen}
+                actions={this.actions}
+              >
+                <span>Are you sure you want to delete the shopping cart?</span>
+              </Dialog>
+            ) : null
+          }
+      </section>
+    )
   }
 }
 

+ 35 - 0
recipes/src/containers/ShoppingCart/View/styles.scss

@@ -3,6 +3,41 @@
 .cbk-shopping-cart-view {
   margin: $spacing-small;
   @include box();
+  &__items {
+    .cbk-shopping-list {
+      column-count: 2;
+      column-gap: $spacing-regular;
+      li {
+        -webkit-column-break-inside: avoid;
+        page-break-inside: avoid;
+        break-inside: avoid;
+      }
+    
+      &__item {
+        display: flex;
+        flex: 1;
+        padding: 4px 0;
+    
+        &__name {
+          flex: 2;
+          font-weight: $font-weight-bold;
+          &__recipes {
+            font-size: 0.75rem;
+            font-style: italic;
+            color: $grey-600;
+            font-weight: initial;
+            span {
+              margin-right: $spacing-small/2;
+            }
+          }
+        }
+        &__quantity {
+          flex: 1;
+          text-align: right;
+        }
+      }
+    }
+  }
   &__actions {
     display: flex;
     justify-content: flex-end;