Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
</body>
</html>
 
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import checkActiveStore from '../../functions/utils/checkActiveStore';
import { useAlert } from 'react-alert';
import { isEmpty, capitalize } from 'lodash';
import {
  Heading as HeadingComponent,
  ProductTile as ProductTileComponent,
  MiniCart as MiniCartComponent,
  Button,
} from '@beetsandroots/components';
import { ALERT_TIMEOUT_6000 } from '../../../app/functions/utils/constants';
import HeaderTeaser from '../common/header/HeaderTeaser';
import Menu from '../common/header/Menu';
import {
  PRODUCT_TYPE_INGREDIENT,
  PRODUCT_TYPE_CUSTOM,
  PRODUCT_TYPE_PRECONGIGURED,
  PRODUCT_TYPE_BASIC,
  CATEGORY_TYPE_DISH,
} from './Constants';
import { getCategoriesByParentID } from '../../functions/actions/product/ProductListActions';
import { getProductsByCategoryID } from '../../functions/actions/product/ProductListActions';
import { setCartDisplay } from '../../functions/actions/common/header/HeaderActions';
import {
  setLineItemQuantity,
  checkCartByID,
  getActiveCart,
  getShippingMethodPickup,
  addShippingMethodToCart,
  getShippingMethodDelivery,
} from '../../functions/actions/cart/CartActions';
import { config } from '../../../../../app.config';
import { appURL } from '../../../utils/Url';
import './MenuPage.scss';
import { formatPrice } from '../../../utils/Formatter';
import { isStoreOpenToday } from '../../../utils/StoreUtils';
import { isCartVouchersOnly } from '../../../utils/CartUtils';
import { isProductAvailable } from '../../../utils/ProductPriceCalculation';
import { compareOrderHints } from '../../../utils/Comparer';
import { removeUserDeliveryAddress, setActiveStore } from '../../functions/actions/common/ApplicationActions';
const uuid = require('uuid/v4');
import DirectProductByCategoryID from './DirectProductByCategoryID';
import { getUserCreditsAndReferralCode } from '../../functions/actions/user/UserActions';
import { getLocalStorage } from '../../LocalStorage';
import axios from 'axios';
const MenuPage = (props) => {
  const { t } = useTranslation();
  const dispatch = useDispatch();
  const alert = useAlert();
  useEffect(() => {
    dispatch(getActiveCart());
  }, []);
  // ToDo: Such general things should be done by writing an own provider and should be handled inside
  // App.js between switch and Route
  // toggle mini icon in header
  dispatch(setCartDisplay(props.showMiniCart));
  const contextState = useSelector((state) => state.application.context);
  const currentStoreKey = useSelector((state) => state.application.active.store)?.key;
  const stores = useSelector((state) => state.entities.store.items);
  const user = useSelector((state) => state.application.user);
  const authenticated = useSelector((state) => state.application.authenticated);
  const currentActiveStore = useSelector((state) => state.application.active.store);
  const productTypes = useSelector((state) => state.entities.producttype.items);
  const categories = useSelector((state) => state.entities.category.items);
  const categoryState = useSelector((state) => state.entities.category);
  const shippingMethod = useSelector((state) => state.application.active.shippingMethod);
  const cart = useSelector((state) => state.application.cart);
  const orderType = contextState.app === 'delivery' ? contextState.app : 'pickup';
  const items = useSelector((state) => state.ui.productlist.products);
  const subCategories = useSelector((state) => state.ui.productlist.categories);
  const minimumOrderValue = useSelector((state) => state.application.active.store.minimumOrderValue);
  const category = categories.find((elm) => elm.externalID == config.categories.mainExternalId);
  const deliveryFee = useSelector((state) => state.application.active.shippingMethod?.delivery?.fee);
  const referralVoucher = useSelector((state) => state.application.referral);
  const applicationFailureLS = getLocalStorage()?.getItem('applicationFailure');
  const userDeliveryAddress = useSelector((state) => state.application.active.userDeliveryAddress);
  let formattedDeliveryFee = t('common.header.minicart.text.free');
  if (deliveryFee && deliveryFee.price.centAmount > 0) {
    formattedDeliveryFee = formatPrice(deliveryFee.price.centAmount, null, deliveryFee.price.currencyCode);
  }
  const addToBasketLabel = t('category.productlistpage.addToBasket');
  const customizeLabel = t('category.productlistpage.customize');
  const checkoutURL = contextState.app === 'preorder' ? appURL(`checkout/${currentStoreKey}`) : appURL(`checkout`);
  const storesURL = appURL('stores');
  const [showBasket, setShowBasket] = useState(false);
  const cartStoreKey = cart?.storeKey;
  const restaurantParam = props.match?.params.restaurant;
  useEffect(() => {
    if (contextState.app === 'delivery') {
      dispatch(getShippingMethodDelivery());
    } else {
      dispatch(getShippingMethodPickup());
    }
    if (!isEmpty(cart?.shippingMethod?.name) && cart.shippingMethod?.name !== capitalize(orderType)) {
      dispatch(addShippingMethodToCart());
    }
  }, [contextState.app]);
  checkActiveStore(props.match);
  useEffect(() => {
    // check if active cart is set to restaurant in URL
    if (cartStoreKey) {
      dispatch(checkCartByID(cartStoreKey, restaurantParam, () => props.history.push(storesURL)));
    }
  }, [cartStoreKey]);
  const verifyActiveStoreWithUserDeliveryAddress = async () => {
    const result = await axios.post('/check-sd-address/', userDeliveryAddress);
    if (!result.data.success) {
      await dispatch(removeUserDeliveryAddress());
      return;
    }
    const storeId = result.data?.data?.itemlist[0].store_id;
    const store = stores.find((store) => store.externalId == storeId);
    if (
      currentActiveStore &&
      !isEmpty(currentActiveStore) &&
      store &&
      !isEmpty(store) &&
      currentActiveStore.key === store.key
    )
      return;
    const storeObj = {
      ...store,
      geoLocation: {
        latitude: store.latitude,
        longitude: store.longitude,
      },
    };
    await dispatch(setActiveStore(storeObj));
    await dispatch(getActiveCart());
  };
  useEffect(() => {
    if (contextState.app === 'delivery' && !isEmpty(userDeliveryAddress) && !isEmpty(currentActiveStore)) {
      verifyActiveStoreWithUserDeliveryAddress();
    } else if (
      contextState.app === 'delivery' &&
      isEmpty(userDeliveryAddress) &&
      !isEmpty(currentActiveStore) &&
      currentActiveStore.key.includes('catering') &&
      !isEmpty(stores)
    ) {
      dispatch(setActiveStore(stores.find((store) => store.key === 'berlin-mitte')));
      dispatch(getActiveCart());
    }
  }, [currentActiveStore, stores]);
  useEffect(() => {
    // if cart is null(invalid) get the right one
    if (cart === null) {
      // dispatch(removeCart(storesURL));
      dispatch(getActiveCart());
    }
  }, [cart]);
  if (applicationFailureLS) {
    alert.info(t('common.message.error.connectivityIssue'), {
      timeout: ALERT_TIMEOUT_6000,
    });
    getLocalStorage()?.removeItem('applicationFailure');
  }
  const cartQuantity = () => {
    let quantity = 0;
    cart.lineItems.map((item) => {
      if (!item.parentItemID) {
        quantity += item.quantity;
      }
    });
    return quantity;
  };
  useEffect(() => {
    if (authenticated) dispatch(getUserCreditsAndReferralCode());
  }, [authenticated]);
  const categoryHasProducts = (category, products) => {
    return products?.some((item) => {
      // consider only non ingredient products
      if (PRODUCT_TYPE_INGREDIENT != item.type) {
        // check for directly assigned products
        if (item.categories.find((elm) => elm.id == category.id)) {
          return true;
        }
        // check for products assigned to subcategories
        return category.children?.some((subCat) => {
          return categoryHasProducts(subCat, products);
        });
      }
    });
  };
  const categoryHasSubcategories = (category) => {
    if (category.children && category.children.length > 0) {
      return category.children.find((cat) => cat.type == CATEGORY_TYPE_DISH);
    }
    return false;
  };
  useEffect(() => {
    if (category) {
      // get subcategories for selected header category
      dispatch(getCategoriesByParentID({ ...contextState, store: currentStoreKey }, categoryState, category.id));
      // get all products (not ingredients!) within selected header category
      const productTypesNI = productTypes.filter(
        (elm) =>
          elm.name == PRODUCT_TYPE_CUSTOM || elm.name == PRODUCT_TYPE_PRECONGIGURED || elm.name == PRODUCT_TYPE_BASIC
      );
      dispatch(
        getProductsByCategoryID({ ...contextState, store: currentActiveStore.key }, productTypesNI, category.id)
      );
    }
    if (stores.length > 0 && isEmpty(currentActiveStore) && contextState.app === 'delivery') {
      dispatch(setActiveStore(stores.find((store) => store.key === 'berlin-mitte')));
    }
  }, [category, currentActiveStore]);
  const [disableQuantityBtn, setDisableQuantityBtn] = useState(false);
  const storeOpened = isStoreOpenToday(currentActiveStore, contextState.app);
  const handleSetLineItemQuantity = async (pliID, quantity) => {
    if (!storeOpened) {
      return;
    }
    setDisableQuantityBtn(true);
    await dispatch(setLineItemQuantity(pliID, quantity));
    setDisableQuantityBtn(false);
  };
  const [availableItemsInStore, setAvailableItemsInStore] = useState(items);
  const [filteredSubcategories, setFilteredSubcategories] = useState(subCategories);
  useEffect(() => {
    setAvailableItemsInStore(items.filter((item) => isProductAvailable(item, currentActiveStore)));
    const filteredSubcats = subCategories.filter((subCat) => categoryHasProducts(subCat, availableItemsInStore));
    setFilteredSubcategories(filteredSubcats.sort(compareOrderHints));
  }, [items, subCategories, currentActiveStore]);
  return (
    <>
      <HeaderTeaser />
      <Menu key={'pdp-menu-key'} menuCategories={filteredSubcategories} scrollOffset={-70} anchorOffset={-70} />
      <div className="container-fluid" id="menuPage">
        {category && (
          <div className="row">
            <div className="col-lg-8">
              <DirectProductByCategoryID
                categoryID={category.id}
                products={availableItemsInStore}
                contextState={contextState}
                theProsps={props}
                dispatch={dispatch}
                addToBasketLabel={addToBasketLabel}
                customizeLabel={customizeLabel}
                showFirstCardDeck={true}
              />
              {filteredSubcategories &&
                filteredSubcategories?.length > 0 && // if there are any subcategories with products found
                filteredSubcategories?.map((cat) => {
                  if (categoryHasProducts(cat, availableItemsInStore))
                    return (
                      <div key={cat.id} id={cat.slug} className="dish-type">
                        {!categoryHasSubcategories(cat) && (
                          <>
                            <HeadingComponent style="semi-bold" type="h4" text={cat.name} subtext={cat.description} />
                            <DirectProductByCategoryID
                              categoryID={cat.id}
                              products={availableItemsInStore}
                              contextState={contextState}
                              theProsps={props}
                              dispatch={dispatch}
                              addToBasketLabel={addToBasketLabel}
                              customizeLabel={customizeLabel}
                              showFirstCardDeck={false}
                            />
                          </>
                        )}
                        <div>
                          {cat.children?.map((subCat) => {
                            if (subCat.type == CATEGORY_TYPE_DISH) {
                              if (categoryHasProducts(subCat, availableItemsInStore))
                                return (
                                  <div key={subCat.id}>
                                    <HeadingComponent
                                      style="semi-bold"
                                      type="h4"
                                      text={subCat.name}
                                      subtext={subCat.description}
                                    />
                                    <DirectProductByCategoryID
                                      categoryID={subCat.id}
                                      products={availableItemsInStore}
                                      contextState={contextState}
                                      theProsps={props}
                                      dispatch={dispatch}
                                      addToBasketLabel={addToBasketLabel}
                                      customizeLabel={customizeLabel}
                                      showFirstCardDeck={false}
                                    />
                                  </div>
                                );
                            }
                          })}
                        </div>
                      </div>
                    );
                })}
            </div>
            <div className="goto-basket-btn">
              <Button
                dataDismiss="modal"
                type="primary"
                label={t('menu.button.view_basket')}
                onClick={() => setShowBasket(true)}
              />
              {cart && cart.lineItems && <div className="cart-quantity">{cartQuantity()}</div>}
              {cart && cart.totalPrice && <div className="cart-price">{cart.totalPrice.formattedPrice}</div>}
            </div>
            <div className={`sticky-top cart-box ${showBasket && 'show-basket'}`}>
              {showBasket && (
                <div onClick={() => setShowBasket(false)} className="close-basket">
                  +
                </div>
              )}
              <MiniCartComponent
                getCurrentCart={() => dispatch(getActiveCart())}
                cart={cart}
                labelDeliveryFee={t('common.header.hero.fee')}
                deliverFee={formattedDeliveryFee}
                isVouchersOnly={isCartVouchersOnly(cart)}
                orderType={contextState.app}
                labelMinimumOrderValue={t('common.header.minicart.warning.minimumOrderValue')}
                minimumOrderValue={minimumOrderValue}
                emptyCartIcon={contextState.assetsURL + '/styles/images/empty-cart.svg'}
                title={t('common.header.minicart.title')}
                textEmptyCart={t('common.header.minicart.text.empty')}
                labelTotalPrice={t('common.header.minicart.label.total')}
                labelButton={t('common.header.minicart.button.checkout')}
                referralVoucher={referralVoucher}
                isStoreOpened={storeOpened}
                onClickButton={() => {
                  if (storeOpened) props.history.push(checkoutURL);
                  else {
                    alert.info(t('cart.checkoutpage.cartform.payment.message.error.closedStore'), {
                      timeout: ALERT_TIMEOUT_6000,
                    });
                  }
                }}
                onClickButtonQuantity={handleSetLineItemQuantity}
                disableQuantityBtn={disableQuantityBtn}
                credits={user?.referralCode?.amountToGo}
                labelCredits={t('common.header.hero.credits')}
                store={currentActiveStore}
              />
            </div>
          </div>
        )}
      </div>
    </>
  );
};
export default withRouter(MenuPage);
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
gkatsanospro
0viewers