ソースを参照

Save and Delete actions for shopping cart view

Tatiana Inama 7 年 前
コミット
051438514d

+ 1 - 1
ktchn/src/shopping/controller.ts

@@ -9,7 +9,7 @@ const getShoppingList: Controller<void, IDBDocument<ShoppingList>|null> = db =>
 }
 
 const validShoppingList = (mbShoppingList: any): mbShoppingList is IDBDocument<ShoppingList> => {
-  return mbShoppingList._id && mbShoppingList.items;
+  return mbShoppingList.items && Array.isArray(mbShoppingList.items);
 }
 
 const validateShoppingList: Controller<void, IDBDocument<ShoppingList>> = () => req => () => {

+ 84 - 17
recipes/src/containers/ShoppingCart/View/index.tsx

@@ -4,8 +4,10 @@ import { ThunkDispatch } from 'redux-thunk';
 import { bindActionCreators } from 'redux';
 
 import ShoppingList from 'components/ShoppingList';
+import Button from 'components/Button';
+import Dialog from 'components/Dialog';
 
-import shoppingCartActions, { fetchCartActionCreator } from 'containers/ShoppingCart/actions';
+import shoppingCartActions, { fetchCartActionCreator, saveCartActionCreator } from 'containers/ShoppingCart/actions';
 
 import { ShoppingItem, ShoppingCartState } from 'types/shopping-cart';
 import { AppState } from 'store/configureStore';
@@ -16,25 +18,89 @@ type shoppingCartActionTypes = typeof shoppingCartActions;
 
 interface ShoppingCartViewProps extends ShoppingCartState, shoppingCartActionTypes {
   fetch: typeof fetchCartActionCreator,
+  save: typeof saveCartActionCreator,
 }
 
-const ShoppingCartView: React.FunctionComponent<ShoppingCartViewProps> = ( props ) => {
-  return (
-    <section className='cbk-shopping-cart-view'>
-      {
-        props.items.length ? (
-          <ShoppingList
-            items={props.items}
-          />
-        ) : (
-          <div className='cbk-shopping-cart-view--empty'>
-            Shopping cart is empty
-          </div>
+class ShoppingCartView extends React.Component<ShoppingCartViewProps, { dialogOpen: boolean }> {
+
+  constructor (props: ShoppingCartViewProps) {
+    super(props);
+    this.state = {
+      dialogOpen: false
+    }
+  }
+  
+  private actions = {
+    cancel: {
+      label: 'cancel',
+      onSelect: () => { this.openDialog(false) }
+    },
+    delete: {
+      label: 'delete',
+      onSelect: () => { this.deleteCart(); this.openDialog(false); }
+    }
+  };
+
+  componentDidMount() {
+    if(!this.props.items.length) {
+      this.props.fetch();
+    }
+  }
+
+  deleteCart = () => {
+    this.props.save([], true);
+  }
+
+  openDialog = (state: boolean) => {
+    this.setState({
+      dialogOpen: state
+    })
+  }
+
+  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
+                  </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>
         )
-      }
-    </section>
-  )
-};
+  }
+}
 
 const mapStateToProps = (state: AppState) => {
   return {
@@ -44,6 +110,7 @@ const mapStateToProps = (state: AppState) => {
 
 const mapDispatchToProps = (dispatch: ThunkDispatch<AppState, any, any>) => ({
   fetch: () => dispatch(fetchCartActionCreator()),
+  save: (cart: ShoppingItem[], deleted?: boolean) => dispatch(saveCartActionCreator(cart, deleted)),
   ...bindActionCreators(shoppingCartActions, dispatch)
 })
 

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

@@ -3,4 +3,9 @@
 .cbk-shopping-cart-view {
   margin: $spacing-small;
   @include box();
+  &__actions {
+    display: flex;
+    justify-content: flex-end;
+    padding: $spacing-small;
+  }
 }

+ 4 - 1
recipes/src/containers/ShoppingCart/actions.ts

@@ -89,11 +89,14 @@ export const saveCartActionCreator: ActionCreator<
     any,
     ConfirmSaveCartAction|RejectSaveCartAction
   >
-> = (cart: ShoppingItem[]) => {
+> = (cart: ShoppingItem[], deleted?: boolean) => {
   return async (dispatch: Dispatch) => {
     dispatch(pendingSaveCart(cart));
     try {
       const result = await saveShoppingCart(cart);
+      if (deleted) {
+        dispatch(removeAll());
+      }
       return dispatch(confirmSaveCart(result));
     } catch (error) {
       return dispatch(rejectSaveCart(error))

+ 3 - 1
recipes/src/containers/ShoppingCart/reducers.ts

@@ -78,7 +78,8 @@ const shoppingCartReducer = (
       };
     case DELETE_CART:
       return {
-        ...state
+        ...state,
+        items: [],
       };
     case REQUEST_CART:
       return {
@@ -89,6 +90,7 @@ const shoppingCartReducer = (
       return {
         ...state,
         isFetching: false,
+        items: action.payload.items
       }
     default:
       return state