diff --git a/client/App.js b/client/App.js index 4edbc82..8acda29 100644 --- a/client/App.js +++ b/client/App.js @@ -1,7 +1,8 @@ import * as React from "react"; import { Platform, StatusBar, View } from "react-native"; import { Provider } from "react-redux"; -import { SplashScreen, Linking } from "expo"; +import * as SplashScreen from 'expo-splash-screen'; +import * as Linking from 'expo-linking'; import { NavigationContainer } from "@react-navigation/native"; import { createStackNavigator } from "@react-navigation/stack"; import { useLinking } from "@react-navigation/native"; diff --git a/client/components/dining/DinQueries.js b/client/components/dining/DinQueries.js index 1b413e8..0a27f45 100644 --- a/client/components/dining/DinQueries.js +++ b/client/components/dining/DinQueries.js @@ -32,7 +32,7 @@ const fetchHours = id => { const fetchMenuDetailed = id => { return axiosPost(` { - menu (id: ${id}) { + menu (id: "${id}") { name dayparts { endtime diff --git a/client/components/dining/DiningCard.js b/client/components/dining/DiningCard.js index ca8cf85..2d3e9d2 100644 --- a/client/components/dining/DiningCard.js +++ b/client/components/dining/DiningCard.js @@ -1,292 +1,301 @@ -import React, { useState, useEffect } from "react"; -import { - View, - StyleSheet, - TouchableOpacity, - Text, - Platform, -} from "react-native"; -import { connect } from "react-redux"; -import { AntDesign } from "@expo/vector-icons"; -import { fetchHours } from "./DinQueries"; -import LottieView from "lottie-react-native"; - -import { getColors } from "../reusable/getColors"; - -const mapStateToProps = (state) => { - return { - darkmode: state.settings.darkmode - }; -}; - -const DiningCard = (props) => { - const Colors = getColors(props.darkmode); - const styles = getStyles(Colors); - const [starred, setStarred] = useState(props.isStarred ? true : false); - const [starName, setStarName] = useState(starred ? "star" : "staro"); - const [starColor, setStarColor] = useState( - starred ? Colors.starYellow : Colors.inactiveIcon - ); - const [hallHours, setHallHours] = useState("Loading..."); - const [loading, setLoading] = useState(true); - const [isClosed, setClosed] = useState(false); - const { navigation } = props; - - // handles changes to star icon if pressed - const starHandler = () => { - if (starred) { - setStarred(false); - setStarName("staro"); - setStarColor(Colors.inactiveIcon); - } else { - setStarred(true); - setStarName("star"); - setStarColor(Colors.starYellow); - } - props.starPressed(); - }; - - // compares the current time w/ the time from the api - const hoursCompare = () => { - let date = new Date(); - let curr = Date.parse( - `11/11/11 ${date.getHours()}:${date.getMinutes()}` - ); - // TODO: hallHours length is sometimes less than 3 (making hallHours[2] = undefined) - console.log("hallHours:", hallHours); - // let open1 = Date.parse(`11/11/11 ${hallHours[0].starttime}`); - // let close1 = Date.parse(`11/11/11 ${hallHours[0].endtime}`); - // let open2 = Date.parse(`11/11/11 ${hallHours[1].starttime}`); - // let close2 = Date.parse(`11/11/11 ${hallHours[1].endtime}`); - // let open3 = Date.parse(`11/11/11 ${hallHours[2].starttime}`); - // let close3 = Date.parse(`11/11/11 ${hallHours[2].endtime}`); - // if (curr > open1 && curr < close1) { - // return 0; - // } else if (curr > open2 && curr < close2) { - // return 1; - // } else if (curr > open3 && curr < close3) { - // return 2; - // } else if (curr > close1 && curr < open2) { - // return 3; - // } else if (curr > close2 && curr < open3) { - // return 4; - // } else { - // return 5; - // } - return 0; - }; - - // formats the time returned from the api - const timeFormatter = time => { - let num = parseInt(time.slice(0, 2)); - if (num < 10) { - return `${time.slice(1)} am`; - } else if (num >= 10 && num <= 12) { - return `${time} am`; - } else { - num -= 12; - time = `${num}${time.slice(2)}`; - return `${time} pm`; - } - }; - - // returns correct open status and hours - const hoursHandler = () => { - let slot = hoursCompare(); - let time; - let text2; - let signStyle = styles.open; - let timeStyle = styles.closed; - let text1 = "Open"; - if (slot <= 2) { - time = hallHours[slot].endtime; - } - if (slot >= 3) { - signStyle = styles.closed; - timeStyle = styles.open; - text1 = "Closed"; - if (slot === 3) { - time = hallHours[1].starttime; - } else if (slot === 4) { - time = hallHours[2].starttime; - } else if (slot === 5) { - time = hallHours[0].starttime; - } - } - time = timeFormatter(time); - if (slot <= 2) { - text2 = `Closes ${time}`; - } else { - text2 = `Opens ${time}`; - } - return ( - - {text1} - {text2} - - ); - }; - - // handles menu summary for card w/ placeholder for menu - const menuHandler = () => { - return ( - - - Turkey bacon, oatmeal, eggs... - - - - ); - }; - - // handles detail return and loading delay - const detailHandler = () => { - if (loading) { - return ( - - - - ); - } else if (isClosed) { - return ( - - - Closed All Day - - - ); - } else { - return ( - - {hoursHandler()} - {menuHandler()} - - ); - } - }; - - useEffect(() => { - let mounted = true; - const effectFunction = async isInitial => { - if (mounted) { - const time = await fetchHours(props.card.queryText); - // const menu = await fetchMenuDetailed(props.queryText); - const hours = time.data.data.cafe.days[0].dayparts; - hours.length === 0 || hours === undefined - ? setClosed(true) - : setHallHours(hours); - // setMenuSummary(menu.data.menu.dayparts[0].stations); - if (isInitial) setLoading(false); - } - }; - effectFunction(true); - - let interval = setInterval(() => effectFunction(false), 60000); - - return () => { - mounted = false; - clearInterval(interval); - }; - }, []); - - return ( - - navigation.navigate("Menu", {name: props.card.name, queryText: props.card.queryText})} - > - - {props.card.name} - - - - - {detailHandler()} - - - ); -}; - -const getStyles = (Colors) => StyleSheet.create({ - card: { - padding: 25, - paddingVertical: 22, - marginBottom: 20, - borderRadius: 8, - shadowColor: "black", - shadowRadius: 3, - shadowOpacity: 0.25, - backgroundColor: "white", - shadowOffset: { width: 1, height: 1 }, - width: "87%", - alignSelf: "center", - elevation: 5, - }, - header: { - flexDirection: "row", - justifyContent: "space-between", - }, - title: { - fontWeight: "600", - fontSize: 28, - }, - info: { - flexDirection: "row", - justifyContent: "space-between", - marginTop: 10, - }, - open: { - color: Colors.success, - borderColor: Colors.success, - }, - closed: { - color: Colors.danger, - borderColor: Colors.danger, - }, - sign: { - textTransform: "uppercase", - fontSize: 20, - borderWidth: 1.5, - borderRadius: 6, - paddingHorizontal: 8, - paddingTop: 2, - paddingBottom: 1, - fontWeight: "600", - }, - menuSummary: { - marginTop: 12, - flexDirection: "row", - justifyContent: "space-between", - }, - menuText: { - marginTop: 6, - }, - text: { - fontSize: 20, - borderColor: "white", - paddingVertical: 3, - fontWeight: "300", - fontStyle: "italic", - }, -}); - -export default connect(mapStateToProps)(DiningCard); +import React, { useState, useEffect } from "react"; +import { + View, + StyleSheet, + TouchableOpacity, + Text, + Platform, +} from "react-native"; +import { connect } from "react-redux"; +import { AntDesign } from "@expo/vector-icons"; +import { fetchHours, fetchMenuDetailed } from "./DinQueries"; +import LottieView from "lottie-react-native"; + +import { getColors } from "../reusable/getColors"; + +const mapStateToProps = (state) => { + return { + darkmode: state.settings.darkmode + }; +}; + +const DiningCard = (props) => { + const Colors = getColors(props.darkmode); + const styles = getStyles(Colors); + const [starred, setStarred] = useState(props.isStarred ? true : false); + const [starName, setStarName] = useState(starred ? "star" : "staro"); + const [starColor, setStarColor] = useState( + starred ? Colors.starYellow : Colors.inactiveIcon + ); + const [hallHours, setHallHours] = useState("Loading..."); + const [loading, setLoading] = useState(true); + const [isClosed, setClosed] = useState(false); + const { navigation } = props; + const [menuSummary, setMenuSummary] = useState('') + + // handles changes to star icon if pressed + const starHandler = () => { + if (starred) { + setStarred(false); + setStarName("staro"); + setStarColor(Colors.inactiveIcon); + } else { + setStarred(true); + setStarName("star"); + setStarColor(Colors.starYellow); + } + props.starPressed(); + }; + + // compares the current time w/ the time from the api + const hoursCompare = () => { + let date = new Date(); + let curr = Date.parse( + `11/11/11 ${date.getHours()}:${date.getMinutes()}` + ); + // TODO: hallHours length is sometimes less than 3 (making hallHours[2] = undefined) + console.log("hallHours:", hallHours); + let open1 = Date.parse(`11/11/11 ${hallHours[0].starttime}`); + let close1 = Date.parse(`11/11/11 ${hallHours[0].endtime}`); + let open2 = Date.parse(`11/11/11 ${hallHours[1].starttime}`); + let close2 = Date.parse(`11/11/11 ${hallHours[1].endtime}`); + let open3 = Date.parse(`11/11/11 ${hallHours[2].starttime}`); + let close3 = Date.parse(`11/11/11 ${hallHours[2].endtime}`); + if (curr > open1 && curr < close1) { + return 0; + } else if (curr > open2 && curr < close2) { + return 1; + } else if (curr > open3 && curr < close3) { + return 2; + } else if (curr > close1 && curr < open2) { + return 3; + } else if (curr > close2 && curr < open3) { + return 4; + } else { + return 5; + } + return 0; + }; + + // formats the time returned from the api + const timeFormatter = time => { + let num = parseInt(time.slice(0, 2)); + if (num < 10) { + return `${time.slice(1)} am`; + } else if (num >= 10 && num <= 12) { + return `${time} am`; + } else { + num -= 12; + time = `${num}${time.slice(2)}`; + return `${time} pm`; + } + }; + + // returns correct open status and hours + const hoursHandler = () => { + let slot = hoursCompare(); + let time; + let text2; + let signStyle = styles.open; + let timeStyle = styles.closed; + let text1 = "Open"; + if (slot <= 2) { + time = hallHours[slot].endtime; + } + if (slot >= 3) { + signStyle = styles.closed; + timeStyle = styles.open; + text1 = "Closed"; + if (slot === 3) { + time = hallHours[1].starttime; + } else if (slot === 4) { + time = hallHours[2].starttime; + } else if (slot === 5) { + time = hallHours[0].starttime; + } + } + time = timeFormatter(time); + if (slot <= 2) { + text2 = `Closes ${time}`; + } else { + text2 = `Opens ${time}`; + } + return ( + + {text1} + {text2} + + ); + }; + + // handles menu summary for card w/ placeholder for menu + const menuHandler = () => { + return ( + + + {menuSummary} + + + + ); + }; + + // handles detail return and loading delay + const detailHandler = () => { + if (loading) { + return ( + + + + ); + } else if (isClosed) { + return ( + + + Closed All Day + + + ); + } else { + return ( + + {hoursHandler()} + {menuHandler()} + + ); + } + }; + + useEffect(() => { + let mounted = true; + const effectFunction = async isInitial => { + if (mounted) { + const time = await fetchHours(props.card.queryText); + const menu = await fetchMenuDetailed(props.card.queryText); + const hours = time.data.data.cafe.days[0].dayparts; + hours.length === 0 || hours === undefined + ? setClosed(true) + : setHallHours(hours); + try { + if (slot <= 2) { + let items = menu.data.data.menu.dayparts[slot].stations[0].items + let summaryString = items.reduce((acc, elt) => acc + ', ' + elt.name, '').substring(2) + setMenuSummary(summaryString); + } + } catch (err) { + console.log(err) + } + if (isInitial) setLoading(false); + } + }; + effectFunction(true); + + let interval = setInterval(() => effectFunction(false), 60000); + + return () => { + mounted = false; + clearInterval(interval); + }; + }, []); + + return ( + + navigation.navigate("Menu", {name: props.card.name, queryText: props.card.queryText})} + > + + {props.card.name} + + + + + {detailHandler()} + + + ); +}; + +const getStyles = (Colors) => StyleSheet.create({ + card: { + padding: 25, + paddingVertical: 22, + marginBottom: 20, + borderRadius: 8, + shadowColor: "black", + shadowRadius: 3, + shadowOpacity: 0.25, + backgroundColor: "white", + shadowOffset: { width: 1, height: 1 }, + width: "87%", + alignSelf: "center", + elevation: 5, + }, + header: { + flexDirection: "row", + justifyContent: "space-between", + }, + title: { + fontWeight: "600", + fontSize: 28, + }, + info: { + flexDirection: "row", + justifyContent: "space-between", + marginTop: 10, + }, + open: { + color: Colors.success, + borderColor: Colors.success, + }, + closed: { + color: Colors.danger, + borderColor: Colors.danger, + }, + sign: { + textTransform: "uppercase", + fontSize: 20, + borderWidth: 1.5, + borderRadius: 6, + paddingHorizontal: 8, + paddingTop: 2, + paddingBottom: 1, + fontWeight: "600", + }, + menuSummary: { + marginTop: 12, + flexDirection: "row", + justifyContent: "space-between", + }, + menuText: { + marginTop: 6, + }, + text: { + fontSize: 20, + borderColor: "white", + paddingVertical: 3, + fontWeight: "300", + fontStyle: "italic", + }, +}); + +export default connect(mapStateToProps)(DiningCard); diff --git a/client/components/dining/DiningMenu.js b/client/components/dining/DiningMenu.js index 616f6d3..15cb174 100644 --- a/client/components/dining/DiningMenu.js +++ b/client/components/dining/DiningMenu.js @@ -20,6 +20,7 @@ const mapStateToProps = (state) => { }; const DiningMenu = (props) => { + console const Colors = getColors(props.darkmode); const styles = getStyles(Colors); const [starred, setStarred] = useState(props.isStarred ? true : false); diff --git a/client/package.json b/client/package.json index 585a9f7..2313759 100644 --- a/client/package.json +++ b/client/package.json @@ -15,18 +15,20 @@ }, "dependencies": { "@expo/vector-icons": "^12.0.0", - "@react-native-community/async-storage": "~1.12.0", + "@react-native-async-storage/async-storage": "^1.13.0", "@react-native-community/masked-view": "0.1.10", "@react-navigation/bottom-tabs": "^5.5.1", "@react-navigation/core": "^5.9.0", "@react-navigation/native": "^5.5.0", "@react-navigation/stack": "^5.4.1", "axios": "^0.19.2", - "expo": "^41.0.0", + "expo": "^41.0.1", "expo-asset": "~8.3.1", "expo-constants": "~10.1.3", "expo-font": "~9.1.0", + "expo-linking": "~2.2.3", "expo-permissions": "~12.0.1", + "expo-splash-screen": "~0.10.2", "expo-web-browser": "~9.1.0", "lottie-react-native": "3.5.0", "prop-types": "^15.7.2", @@ -49,7 +51,8 @@ "redux": "^4.0.5", "redux-logger": "^3.0.6", "redux-persist": "^6.0.0", - "redux-thunk": "^2.3.0" + "redux-thunk": "^2.3.0", + "unimodules-permissions-interface": "^6.1.0" }, "devDependencies": { "@babel/core": "~7.9.0", diff --git a/client/redux/configureStore.js b/client/redux/configureStore.js index dc8682c..636e770 100644 --- a/client/redux/configureStore.js +++ b/client/redux/configureStore.js @@ -2,7 +2,7 @@ import { createStore, applyMiddleware } from "redux"; import { persistStore, persistCombineReducers } from "redux-persist"; import thunk from "redux-thunk"; import logger from "redux-logger"; -import AsyncStorage from "@react-native-community/async-storage"; +import AsyncStorage from '@react-native-async-storage/async-storage'; import { dining } from "./dining"; import { laundry } from "./laundry"; diff --git a/client/tsconfig.json b/client/tsconfig.json index 4482448..2798fce 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,18 +1,27 @@ { - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "lib": ["es6", "dom"], - "jsx": "react", - "sourceMap": true, - "noEmit": true, - "isolatedModules": true, - "strict": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "skipLibCheck": true - }, - "include": ["./", "svgimport.d.ts"], - "exclude": ["node_modules"] + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "lib": [ + "es6", + "dom" + ], + "jsx": "react", + "sourceMap": true, + "noEmit": true, + "isolatedModules": true, + "strict": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": [ + "./", + "svgimport.d.ts" + ], + "exclude": [ + "node_modules" + ], + "extends": "expo/tsconfig.base" } diff --git a/client/yarn.lock b/client/yarn.lock index 0d17f19..a847b4b 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2457,10 +2457,10 @@ "@babel/runtime" "^7.7.2" regenerator-runtime "^0.13.3" -"@react-native-community/async-storage@~1.12.0": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@react-native-community/async-storage/-/async-storage-1.12.1.tgz#25f821b4f6b13abe005ad67e47c6f1cee9f27b24" - integrity sha512-70WGaH3PKYASi4BThuEEKMkyAgE9k7VytBqmgPRx3MzJx9/MkspwqJGmn3QLCgHLIFUgF1pit2mWICbRJ3T3lg== +"@react-native-async-storage/async-storage@^1.13.0": + version "1.15.4" + resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.15.4.tgz#cdba464ca3bb9f10ec538342cbf2520c06f453ab" + integrity sha512-pC0MS6UBuv/YiVAxtzi7CgUed8oCQNYMtGt0yb/I9fI/BWTiJK5cj4YtW2XtL95K5IuvPX/6uGWaouZ8KqXwdg== dependencies: deep-assign "^3.0.0" @@ -4904,11 +4904,28 @@ expo-keep-awake@~9.1.2: resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-9.1.2.tgz#b3e52c7bef0ade975ae88637a2bf980f6b573368" integrity sha512-CCuEOQUNLYtMA0rt0sQ9u5LlIMH7lDJG7dImoorfKMsP95yHXy8dl3oCdtaz2zbsPgggVYeom9gE+gQu+Ki4rQ== +expo-linking@~2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/expo-linking/-/expo-linking-2.2.3.tgz#925584a0ed7a617065fe92a39ba4509f70972664" + integrity sha512-1NqL8sY4EzwRPVnBxbvNKBCfsG/tNZm72tVwzjoLxhO0XA6VTtZcb72Jaku4IlqEyH0lejxV2YAU0rbLv1pAVA== + dependencies: + expo-constants "~10.1.3" + invariant "^2.2.4" + qs "^6.5.0" + url-parse "^1.4.4" + expo-permissions@~12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/expo-permissions/-/expo-permissions-12.0.1.tgz#5163c00d991bf565bf987354611628c298ddd0c4" integrity sha512-TtypNPPLG4SdVEKBlrArLLZIyhlhE+3B4dhz2HaY1Mve2rcvKE0C7z/e1WoUVU8+LgcdKoNGwg/wRVeCkxeEhg== +expo-splash-screen@~0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/expo-splash-screen/-/expo-splash-screen-0.10.2.tgz#3e3d7c24c4ed180a60ce3ec64a77eefd04dd0d97" + integrity sha512-ngelW7g5yFqk3LWbyLDDxi3LYXEfgGFCJddL/Q8S/C1pMUc5foW2j9i/q+akK8i5mjYtSx3+Bk/qbyX92QIF/w== + dependencies: + "@expo/configure-splash-screen" "0.3.4" + expo-web-browser@~9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/expo-web-browser/-/expo-web-browser-9.1.0.tgz#4951213f3b57a206dfc5f3f7b2fd1b73863a33af" @@ -4916,7 +4933,7 @@ expo-web-browser@~9.1.0: dependencies: compare-urls "^2.0.0" -expo@^41.0.0: +expo@^41.0.1: version "41.0.1" resolved "https://registry.yarnpkg.com/expo/-/expo-41.0.1.tgz#2689003212dcc948d010f86dadf055721a6314b4" integrity sha512-Lk4Xdst+OfsLgBNeu89hxk0qFrZnHwwXFmBbJkYLlZkdC3tvNJ8jgGHsKg6jYpsnal/z0uVc+uk2ev91qXQykg== @@ -8242,6 +8259,13 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qs@^6.5.0: + version "6.10.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + dependencies: + side-channel "^1.0.4" + qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -9044,7 +9068,7 @@ side-channel@^1.0.2: es-abstract "^1.17.0-next.1" object-inspect "^1.7.0" -side-channel@^1.0.3: +side-channel@^1.0.3, side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== @@ -9818,6 +9842,11 @@ unicode-property-aliases-ecmascript@^1.0.4: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== +unimodules-permissions-interface@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/unimodules-permissions-interface/-/unimodules-permissions-interface-6.1.0.tgz#fd5589945e3b8fc9d2c80c52521853caea85a9ca" + integrity sha512-jeJx/y+Vn/Cp1/4su5XJ06UBul83MpXkYEqIOAb2jwaikhmj6tNwko7HpKy9OhfGfrhddCzwtedlro8xxZUk9A== + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"