app/components/ShoppingCart.js

import React, { useEffect, useState } from "react";
import { Alert, View, StyleSheet, Text, ScrollView } from "react-native";
import { Card, Button } from "react-native-elements";
import colors from "../config/colors";
import PropTypes, { any } from "prop-types";

global.cart = [];
global.orderOpen = false;
global.orders = null;
global.progress = {};

export { cartSum, getDishes, isolateChefs, dishesPerChef, removeChef, addToCart, addQuantity, subTotal, getLongestTime, getLongestTimeForChefinMin, getLongestTimeForChef};

/**
 * Calculate sum of items in shopping cart
 * @memberof ShoppingCart
 * @returns number
 */
function cartSum() {
  let sum = 0;
  global.cart.forEach(item => (sum += item.count));
  return sum;
}


/**
 * Convert array of dishes into string
 * @memberof ShoppingCart
 * @param {Array} dishes 
 * @returns string
 */
function getDishes(dishes) {
  var dishString = "";
  dishes.forEach(item => (dishString += item + " | "));
  return dishString;
}

/**
 * Get all chefs of items in shopping cart
 * @memberof ShoppingCart
 * @returns {Object} pairs {chef, [dish strings]}
 */
function isolateChefs() {
  var pairs = {};
  global.cart.forEach(item => {
    if (!(item.dish["Chef"]["name"] in pairs)) {
      let chefEntry = item.dish["Chef"]["name"];
      pairs[chefEntry] = [];
      let string = item.count + " " + item.dish["name"];
      pairs[chefEntry].push(string);
    } else {
      let chefEntry2 = item.dish["Chef"]["name"];
      let string = item.count + " " + item.dish["name"];
      pairs[chefEntry2].push(string);
    }
  });
  return pairs;
}

/**
 * Get dishes for each chef
 * @memberof ShoppingCart
 * @returns {Object} pairs - {chef, [dishes]}
 */
function dishesPerChef() {
  var pairs = {};
  global.cart.forEach(item => {
    if (!(item.dish["Chef"]["name"] in pairs)) {
      let chefEntry = item.dish["Chef"]["name"];
      pairs[chefEntry] = [];
      pairs[chefEntry].push(item);
    } else {
      let chefEntry2 = item.dish["Chef"]["name"];
      pairs[chefEntry2].push(item);
    }
  });
  return pairs;
}

/**
 * Remove chef from orders
 * @memberof ShoppingCart
 * @param {Chef} chef 
 */
function removeChef(chef){
  global.orders.removeChef(chef);
}

/**
 * Add item to cart
 * @memberof ShoppingCart
 * @param {Dish} item 
 */
function addToCart(item) {
  global.cart.push(item);
}

/**
 * Add quantity to cart (can be positive or negative)
 * @memberof ShoppingCart
 * @param {number} index 
 * @param {number} count 
 */
function addQuantity(index, count) {
  global.cart[index].count += count;
}

/**
 * Calculate subtotal for shopping cart
 * @memberof ShoppingCart
 * @returns number
 */
function subTotal() {
  let tot = 0.0;
  global.cart.forEach(item => (tot += item.dish.price * item.count));
  return tot.toFixed(2);
}

/**
 * Get longest preparation time of items in cart
 * @memberof ShoppingCart
 * @returns number
 */
function getLongestTime() {
  let max = 0;
  global.cart.forEach(item =>
    item.dish.timeMin > max ? (max = item.dish.timeMin) : (max = max)
  );

  if (max < 60) {
    return max + " minutes";
  } else {
    if (max % 60 === 0) {
      return (
        Math.floor(max / 60) + " hour" + (Math.floor(max / 60) == 1 ? "" : "s")
      );
    } else {
      return (
        Math.floor(max / 60) +
        " hour" +
        (Math.floor(max / 60) == 1 ? " " : "s ") +
        (max % 60) +
        " minutes"
      );
    }
  }
}

/**
 * Get longest preparation time for each chef in minutes
 * @memberof ShoppingCart
 * @param {Chef} chef 
 */
function getLongestTimeForChefinMin(chef) {
  let max = 0;
  global.cart.forEach(item =>
    item.dish.Chef.name == chef && item.dish.timeMin > max ? (max = item.dish.timeMin) : (max = max)
  );
  return max;
}

/**
 * Get longest time for each chef
 * @memberof ShoppingCart
 * @param {Chef} chef 
 */
function getLongestTimeForChef(chef) {
  let max = 0;
  global.cart.forEach(item =>
    item.dish.Chef.name == chef && item.dish.timeMin > max ? (max = item.dish.timeMin) : (max = max)
  );

  if (max < 60) {
    return max + " minutes";
  } else {
    if (max % 60 === 0) {
      return (
        Math.floor(max / 60) + " hour" + (Math.floor(max / 60) == 1 ? "" : "s")
      );
    } else {
      return (
        Math.floor(max / 60) +
        " hour" +
        (Math.floor(max / 60) == 1 ? " " : "s ") +
        (max % 60) +
        " minutes"
      );
    }
  }
}

/**
 * 
 * @typedef CartCardProps
 * @memberof ShoppingCart
 * @property {price} price of dish
 * @property {quantity} amount of dish
 * @property {dishid} ID of dish 
 * @property {title} title of dish
 * @property {cart} shopping cart copy
 */
/**
 * Shopping cart card for dish
 * @class CartCard
 * @memberof ShoppingCart
 * @param {CartCardProps} props - Props for CardCard
 */
function CartCard(props) {
  const [total, setTotal] = useState(props.price);
  const [count, setCount] = useState(props.quantity);

  function remove(count, setCount) {
    const found = global.cart.findIndex(
      item => item["dish"]["dishid"] == props.dishid
    );
    if (count > 1) {
      setCount(count - 1);
      global.cart[found].count--;
    } else {
      //remove from array so that the card doesn't show up
      //item count == 0
      setCount(0);
      global.cart[found].count = 0;
    }
  }

  useEffect(() => {
    setTotal(count * props.price);
  }, [count]);

  useEffect(() => {
    const found = global.cart.findIndex(
      item => item["dish"]["dishid"] == props.dishid
    );
    if (found >= 0 && count <= 0) {
      global.cart.splice(found, 1);
    }
    return () => {
      const found = global.cart.findIndex(
        item => item["dish"]["dishid"] == props.dishid
      );
      if (found >= 0 && count <= 0) {
        global.cart.splice(found, 1);
      }
    };
  }, []);

  return count == 0 ? (
    <View style={styles.cartCardContainer}>
      <Text style={styles.empty}>Item Removed</Text>
    </View>
  ) : (
    <View style={styles.cartCardContainer}>
      <Card containerStyle={styles.cardContainer}>
        <Card.Title>
          <Text style={styles.title}>{props.title}</Text>
        </Card.Title>
        <Card.Divider />
        <View style={styles.cardlayout}>
          <View style={styles.horizontal}>
            <View style={styles.checkout}>
              <Button
                type="solid"
                title=" - "
                onPress={() => {
                  remove(count, setCount);
                }}
                titleStyle={styles.buttonText}
                buttonStyle={styles.minusButton}
              />
              <Text style={styles.quantity}>{count}</Text>
              <Button
                type="solid"
                style={styles.plusButtonPadding}
                title=" + "
                onPress={() => {
                  setCount(count + 1);
                  const found = global.cart.findIndex(
                    item => item["dish"]["dishid"] == props.dishid
                  );
                  global.cart[found].count++;
                }}
                titleStyle={styles.buttonText}
                buttonStyle={styles.plusButton}
              />
            </View>
          </View>
          <View style={styles.horizontal}>
            <Text style={styles.text}>
              {count} x ${props.price} each =
            </Text>
            <Text style={styles.price}>${total}</Text>
          </View>
        </View>
      </Card>
    </View>
  );
}

/**
 * 
 * @typedef ShoppingCartProps
 * @memberof ShoppingCart
 * @property {cart} shopping cart copy
 */
/**
 * Shopping Cart object
 * @class ShoppingCart
 * @param {ShoppingCartProps} props 
 */
function ShoppingCart(props) {
  const [cart, setCart] = useState(global.cart);

  useEffect(() => {
    setCart(global.cart);
  }, [props.cart]);

  return (
    <View style={styles.container}>
      <ScrollView style={styles.scrollView}>
        {cart.length == 0 ? (
          <Text style={styles.empty}>No items yet!</Text>
        ) : (
          cart.map(item => (
            <CartCard
              key={item["dish"]["name"]}
              title={item["dish"]["name"]}
              quantity={item["count"]}
              price={item["dish"]["price"]}
              dishid={item["dish"]["dishid"]}
            />
          ))
        )}
        <View style={{height: 150}}/>
      </ScrollView>
    </View>
  );
}

ShoppingCart.propTypes = {
  cart: PropTypes.array,
  navigation: any
};

CartCard.propTypes = {
  title: PropTypes.string,
  quantity: PropTypes.number,
  price: PropTypes.number,
  dishid: PropTypes.number
};

const styles = StyleSheet.create({
  container: {
    width: "100%",
  },
  cartCardContainer: {
    width: "100%",
  },
  cardContainer: {
    alignItems: "flex-end",
    alignContent: "stretch",
    height: 125,
  },
  title: {
    fontWeight: "bold",
    textAlign: "center",
    fontSize: 16
  },
  text: {
    paddingVertical: 4,
    textAlign: "center",
    color: colors.primary
  },
  card: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-evenly"
  },
  price: {
    fontSize: 20,
    alignSelf: "center",
    paddingVertical: 2,
    color: colors.black,
    fontWeight: "bold"
  },
  horizontal: {
    width: "50%",
    justifyContent: "space-around",
    alignItems: "stretch"
  },
  cardlayout: {
    flex: 1,
    flexWrap: "wrap",
    flexDirection: "row"
  },
  quantity: {
    fontWeight: "800",
    fontSize: 20,
    textAlign: "center",
    paddingHorizontal: 8,
    paddingVertical: 0
  },
  buttonText: {
    fontWeight: "bold"
  },
  plusButton: {
    borderBottomRightRadius: 20,
    borderTopRightRadius: 20,
    backgroundColor: colors.secondary
  },

  plusButtonPadding: {
    paddingRight: 10
  },
  checkout: {
    flex: 1,
    alignItems: "center",
    justifyContent: "flex-start",
    flexDirection: "row",
  },
  minusButton: {
    borderBottomLeftRadius: 20,
    borderTopLeftRadius: 20,
    backgroundColor: colors.secondary
  },
  scrollView: {
    width: "100%",
  },
  empty: {
    fontWeight: "bold",
    textAlign: "center",
    fontSize: 16,
    padding: 20
  },
  checkoutTab: {
    flex: 1,
    backgroundColor: colors.primary,
    alignItems: "center",
    justifyContent: "center",
    flexDirection: "row",
    width: "100%",
    height: "7%",
    position: "absolute",
    bottom: 0
  },
  checkoutButton: {
    borderRadius: 20,
    backgroundColor: colors.secondary
  },
  checkoutText: {
    fontWeight: "bold"
  }
});
export default ShoppingCart;