Procházet zdrojové kódy

add external detail view and make navs smaller

Ramona Plogmann před 4 roky
rodič
revize
93a6694acf

+ 2 - 2
client/.env

@@ -1,6 +1,6 @@
 REACT_APP_SERVER_URL=https://emealay-server.herokuapp.com
-REACT_APP_NAV_BOTTOM_HEIGHT=55
-REACT_APP_NAV_TOP_HEIGHT=55
+REACT_APP_NAV_BOTTOM_HEIGHT=45
+REACT_APP_NAV_TOP_HEIGHT=45
 REACT_APP_GRID_LIST_ROW_HEIGHT=140
 REACT_APP_LOGIN_REDIRECT=http://localhost:3000/plans
 REACT_APP_LOGOUT_REDIRECT=http://localhost:3000/

+ 3 - 1
client/src/App.jsx

@@ -1,5 +1,5 @@
 import React, { useEffect, useState, useMemo } from 'react';
-import { Route, Switch } from 'react-router-dom';
+import { Route, Switch, useRouteMatch } from 'react-router-dom';
 import ContentWrapper from "./components/ContentWrapper";
 import Home from "./components/Home";
 import useMediaQuery from '@material-ui/core/useMediaQuery';
@@ -7,6 +7,7 @@ import CssBaseline from '@material-ui/core/CssBaseline'; // deals with changing
 import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
 import { useAuth0 } from "@auth0/auth0-react";
 import { getSettingsOfUser } from "./components/Settings/settings.util";
+import MealDetailViewExtern from "./components/Meals/MealDetailViewExtern";
 
 /**
  * This is the main App component. It sets the MUI theme as well as the dark mode (if desired). It also deals with Frontend-Routing with the help of React Router.
@@ -63,6 +64,7 @@ const App = () => {
           <Route exact path="/">
             <Home />
           </Route>
+          <Route exact path="/meals/view/:mealId"><MealDetailViewExtern /></Route>
 
           <Route exact path="/meals"><ContentWrapper activeTab="meals" /></Route>
           <Route exact path="/meals/add"><ContentWrapper activeTab="meals/add" /></Route>

+ 8 - 1
client/src/components/ContentWrapper.jsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import { useHistory } from "react-router-dom";
+import { useHistory, useRouteMatch } from "react-router-dom";
 import NavTabs from "./NavTabs";
 import Social from "./Social/Social";
 import Settings from "./Settings/Settings";
@@ -10,6 +10,7 @@ import AddMeal from "./Meals/AddMeal";
 import Home from "./Home";
 import OwnMeals from "./Meals/OwnMeals";
 import OwnPlans from "./Plans/OwnPlans";
+import MealDetailViewExtern from "./Meals/MealDetailViewExtern";
 
 const useStyles = makeStyles(theme => ({
   content: {
@@ -29,6 +30,9 @@ const ContentWrapper = (props) => {
   const { activeTab } = props;
   let history = useHistory();
 
+
+  let { path, url } = useRouteMatch();
+  console.log(path, url);
   const goToPlans = () => {history.push('/plans');};
   const goToMeals = () => {history.push('/meals');};
 
@@ -49,6 +53,9 @@ const ContentWrapper = (props) => {
     case "meals/add":
       contentPage = <AddMeal onDoneAdding={goToMeals} />;
       break;
+    case "meals/view":
+      contentPage = <MealDetailViewExtern />;
+      break;
     case "plans":
       contentPage = <OwnPlans />;
       break;

+ 3 - 4
client/src/components/Meals/EditMeal.jsx

@@ -14,11 +14,10 @@ import { withAuthenticationRequired } from "@auth0/auth0-react";
 import Loading from "../Loading";
 import useSnackbars from "../util/useSnackbars";
 import DoneButton from "../Buttons/DoneButton";
-import FullScreenDialog from "../util/FullScreenDialog";
 
 const useStyles = makeStyles((theme) => ({
   form: {
-    padding: '1em 1.5em',
+    padding: '1em 2.5em',
     backgroundColor: theme.palette.background.default,
   },
   cancelButton: {
@@ -119,7 +118,7 @@ const EditMeal = (props) => {
     <>
 
       {meal ?
-        <FullScreenDialog open={open} onClose={closeDialog}>
+        <Dialog open={open} fullScreen onClose={closeDialog} TransitionComponent={SlidingTransitionLeft}>
           <Navbar pageTitle={t('Edit Meal')}
                   leftSideComponent={<BackButton onClick={closeDialog} />}
                   rightSideComponent={meal.title ? <DoneButton onClick={editAndClose} /> : null}
@@ -138,7 +137,7 @@ const EditMeal = (props) => {
               </Grid>
             </Grid>
           </form>
-        </FullScreenDialog>
+        </Dialog>
         : ''}
 
       {Snackbars}

+ 23 - 27
client/src/components/Meals/MealDetailView.jsx

@@ -1,15 +1,15 @@
 import React, { useEffect, useState } from 'react';
-import { Box, Dialog, Link, Typography } from '@material-ui/core';
+import { Box, Link, Typography } from '@material-ui/core';
 import { makeStyles } from '@material-ui/styles';
-import axios from 'axios';
 import { arrayOf, bool, func, shape, string } from "prop-types";
 import EditMeal from "./EditMeal";
 import Navbar from "../Navbar";
 import BackButton from "../Buttons/BackButton";
 import ImageGrid from "../Images/ImageGrid";
 import { useTranslation } from "react-i18next";
-import { SlidingTransitionLeft } from "../util/SlidingTransition";
 import EditButton from "../Buttons/EditButton";
+import FullScreenDialog from "../util/FullScreenDialog";
+import { fetchAndUpdateMeal } from "./meals.util";
 
 const serverURL = process.env.REACT_APP_SERVER_URL;
 
@@ -27,7 +27,7 @@ const MealDetailView = (props) => {
   const classes = useStyles();
   const { t } = useTranslation();
 
-  const { meal: initialMeal, open, closeDialog, onDoneEditing, allowEditing } = props;
+  const { meal: initialMeal, open, closeDialog, onDoneEditing, allowEditing, extern } = props;
 
   const [meal, setMeal] = useState(initialMeal);
   const [editDialogOpen, setEditDialogOpen] = useState(false);
@@ -39,14 +39,7 @@ const MealDetailView = (props) => {
 
   const fetchMeal = () => {
     if (meal && meal._id) {
-      axios.get(serverURL + '/meals/' + meal._id)
-           .then(res => {
-             setMeal(res.data);
-             console.log('get meal', meal);
-           })
-           .catch(err => {
-             console.log(err.message);
-           });
+      fetchAndUpdateMeal(meal._id, setMeal);
     }
   }
 
@@ -64,32 +57,32 @@ const MealDetailView = (props) => {
   return (
     <>
       {meal ?
-        <Dialog open={open} fullScreen onClose={closeDialog} TransitionComponent={SlidingTransitionLeft}>
+        <FullScreenDialog open={open} onClose={closeDialog}>
           <Navbar pageTitle={t('Meal')}
                   rightSideComponent={allowEditing && <EditButton onClick={() => {openEditItemDialog(meal)}} />}
-                  leftSideComponent={<BackButton onClick={closeDialog} />} />
+                  leftSideComponent={extern ? null : <BackButton onClick={closeDialog} />} />
           <Box className={classes.content}>
-                <Typography variant="h4">{meal.title}</Typography>
-                {meal.recipeLink ?
-                  <>
-                    <Typography><Link href={meal.recipeLink}>{meal.recipeLink}</Link></Typography>
-                  </> : ''}
-                {meal.comment ?
-                  <>
-                    <Typography>{meal.comment}</Typography>
-                  </> : ''}
-                {meal.images && meal.images.length > 0 ? <ImageGrid images={meal.images} allowChoosingMain={false} /> : ''}
+            <Typography variant="h4">{meal.title}</Typography>
+            {meal.recipeLink ?
+              <>
+                <Typography><Link href={meal.recipeLink}>{meal.recipeLink}</Link></Typography>
+              </> : ''}
+            {meal.comment ?
+              <>
+                <Typography>{meal.comment}</Typography>
+              </> : ''}
+            {meal.images && meal.images.length > 0 ? <ImageGrid images={meal.images} allowChoosingMain={false} /> : ''}
           </Box>
-        </Dialog>
+        </FullScreenDialog>
         : ''}
 
-      <EditMeal open={allowEditing && editDialogOpen} meal={mealBeingEdited} closeDialog={() => {
+      {!extern && <EditMeal open={allowEditing && editDialogOpen} meal={mealBeingEdited} closeDialog={() => {
         setMealBeingEdited(null);
         setEditDialogOpen(false);
       }} onDoneEditing={afterEditing} onDoneDelete={() => {
         afterEditing();
         closeDialog();
-      }} />
+      }} />}
     </>
   );
 }
@@ -116,12 +109,15 @@ MealDetailView.propTypes = {
   onDoneEditing: func,
   /** allow opening edit page? (To be false if not one's own meal) */
   allowEditing: bool,
+  /** extern is coming from a link might not be logged in */
+  extern: bool,
 }
 
 MealDetailView.defaultProps = {
   meal: null,
   open: true,
   allowEditing: false,
+  extern: false,
 }
 
 export default MealDetailView;

+ 34 - 0
client/src/components/Meals/MealDetailViewExtern.jsx

@@ -0,0 +1,34 @@
+import React, { useEffect, useState } from 'react';
+import { useHistory, useParams } from "react-router-dom";
+import { useAuth0 } from "@auth0/auth0-react";
+import MealDetailView from "./MealDetailView";
+import { fetchAndUpdateMeal } from "./meals.util";
+
+/** Dialog page that displays Meal Details and optionally opens Edit Dialog */
+const MealDetailViewExtern = (props) => {
+  const { user } = useAuth0();
+  const history = useHistory();
+  const { mealId } = useParams();
+
+  console.log('in view', mealId);
+
+  const [meal, setMeal] = useState(null);
+  const [own, setOwn] = useState(false);
+
+  useEffect(() => {
+    console.log('fetching');
+    fetchAndUpdateMeal(mealId, (meal) => {
+      setMeal(meal);
+      if (user) {
+        setOwn(user.sub === meal.userId);
+      }
+      console.log('get meal', meal);
+    });
+  }, [mealId]);
+
+  console.log(meal, own);
+
+  return (<MealDetailView extern={!user} meal={meal} allowEditing={own} closeDialog={() => {history.push('/meals');}} />);
+}
+
+export default MealDetailViewExtern;

+ 16 - 1
client/src/components/Meals/meals.util.jsx

@@ -3,7 +3,7 @@ import axios from "axios";
 import { useAuth0 } from "@auth0/auth0-react";
 import { useEffect, useState } from "react";
 import { getSettingsOfUser } from "../Settings/settings.util";
-import { lighten, darken } from "@material-ui/core";
+import { darken, lighten } from "@material-ui/core";
 
 const serverURL = process.env.REACT_APP_SERVER_URL;
 
@@ -35,6 +35,21 @@ export const fetchAndUpdateMealsFromUser = (userId, updateMeals) => {
        });
 }
 
+/**
+ * Fetches a single meal by ID from the database and provides it as a parameter to the updateMeal function
+ * @param {string} mealId  ID of meals to be fetched from the database
+ * @param {function} updateMeal  function that receives the meal and will update the state of the calling component
+ */
+export const fetchAndUpdateMeal = (mealId, updateMeal) => {
+  axios.get(serverURL + '/meals/' + mealId)
+       .then(res => {
+         updateMeal(res.data);
+       })
+       .catch(err => {
+         console.log(err.message);
+       });
+}
+
 export const useCategoryIcons = () => {
   const { user } = useAuth0();
 

+ 29 - 20
client/src/components/NavTabs.jsx

@@ -3,19 +3,19 @@ import { BottomNavigation, BottomNavigationAction } from '@material-ui/core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { faClipboardList, faCog, faUserFriends, faUtensils } from '@fortawesome/free-solid-svg-icons';
 import { makeStyles } from '@material-ui/styles';
-import { string } from "prop-types";
 import { Link, useRouteMatch } from 'react-router-dom';
 import { useTranslation } from "react-i18next";
 
 const useStyles = makeStyles({
-  bottomNav: props => ({
-    height: props.height,
+  bottomNav: {
+    height: process.env.REACT_APP_NAV_BOTTOM_HEIGHT + 'px',
     position: 'sticky',
     bottom: 0,
     boxShadow: '0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)',
     width: '100%',
-  }),
+  },
   bottomNavAction: {
+    paddingTop: '8px',
     minWidth: "auto",
   }
 });
@@ -34,24 +34,33 @@ const NavTabs = (props) => {
   return (
     <>
       <BottomNavigation className={classes.bottomNav} value={activeTab} showLabels>
-        <BottomNavigationAction className={classes.bottomNavAction} component={Link} to="/meals" label={t('Meals')} value="meals" icon={<FontAwesomeIcon icon={faUtensils} color="primary" />} />
-        <BottomNavigationAction className={classes.bottomNavAction} component={Link} to="/plans" label={t('Plans')} value="plans" icon={<FontAwesomeIcon icon={faClipboardList} color="primary" />} />
-        <BottomNavigationAction className={classes.bottomNavAction} component={Link} to="/social" label={t('Social')} value="social" icon={<FontAwesomeIcon icon={faUserFriends} color="primary" />} />
-        <BottomNavigationAction className={classes.bottomNavAction} component={Link} to="/settings" label={t('Settings')} value="settings" icon={<FontAwesomeIcon icon={faCog} color="primary" />} />
+        <BottomNavigationAction className={classes.bottomNavAction}
+                                component={Link}
+                                to="/meals"
+                                label={t('Meals')}
+                                value="meals"
+                                icon={<FontAwesomeIcon icon={faUtensils} color="primary" />} />
+        <BottomNavigationAction className={classes.bottomNavAction}
+                                component={Link}
+                                to="/plans"
+                                label={t('Plans')}
+                                value="plans"
+                                icon={<FontAwesomeIcon icon={faClipboardList} color="primary" />} />
+        <BottomNavigationAction className={classes.bottomNavAction}
+                                component={Link}
+                                to="/social"
+                                label={t('Social')}
+                                value="social"
+                                icon={<FontAwesomeIcon icon={faUserFriends} color="primary" />} />
+        <BottomNavigationAction className={classes.bottomNavAction}
+                                component={Link}
+                                to="/settings"
+                                label={t('Settings')}
+                                value="settings"
+                                icon={<FontAwesomeIcon icon={faCog} color="primary" />} />
       </BottomNavigation>
     </>
-  )
-    ;
+  );
 }
-
-NavTabs.propTypes = {
-  /** height of the BottomNav (number + unit) */
-  height: string,
-};
-
-NavTabs.defaultProps = {
-  height: process.env.REACT_APP_NAV_BOTTOM_HEIGHT + 'px',
-};
-
 export default NavTabs;
 

+ 6 - 9
client/src/components/Navbar.jsx

@@ -6,8 +6,8 @@ import { useHistory } from 'react-router-dom';
 
 const useStyles = makeStyles((theme) => ({
   topNav: props => ({
-    height: props.height,
-    minHeight: props.height,
+    height: process.env.REACT_APP_NAVBAR_TOP_HEIGHT,
+    minHeight: process.env.REACT_APP_NAVBAR_TOP_HEIGHT,
     justifyContent: 'space-between',
     backgroundColor: props.secondary ? theme.palette.secondary.main : theme.palette.primary.main,
   }),
@@ -17,7 +17,7 @@ const useStyles = makeStyles((theme) => ({
   },
   headline: {
     fontSize: '25px',
-    lineHeight: '35px',
+    lineHeight: '32px',
     whiteSpace: 'nowrap',
     overflow: "hidden",
     textOverflow: "ellipsis",
@@ -41,13 +41,13 @@ const Navbar = (props) => {
   return (
     <>
       <AppBar position="sticky" style={{ maxWidth: '100%' }}>
-        <Toolbar className={classes.topNav}>
+        <Toolbar className={classes.topNav} variant="dense">
           {leftSideComponent ||
           <img src={palette.type === 'dark' ? '/Emealay_logo_dark.png' : '/Emealay_logo_white.png'}
                className={classes.logo}
                alt="Emealay Logo"
-               height="35px"
-               onClick={() => {history.push('/home');}} />
+               height="32px"
+               onClick={() => {history.push('/');}} />
           }
           <Typography onClick={titleOnClick} variant='h4' className={classes.headline}>{pageTitle}</Typography>
           {rightSideComponent &&
@@ -69,8 +69,6 @@ Navbar.propTypes = {
   rightSideComponent: any,
   /** component to be displayed on the left side (for example Back Button) */
   leftSideComponent: any,
-  /** custom height, may not be of use anymore, but is still working */
-  height: string,
   /** optional onClick function for the title */
   titleOnClick: func,
   /** use secondary color for background? */
@@ -80,7 +78,6 @@ Navbar.propTypes = {
 Navbar.defaultProps = {
   rightSideComponent: null,
   leftSideComponent: null,
-  height: process.env.REACT_APP_NAVBAR_TOP_HEIGHT,
   secondary: false,
 };
 

+ 1 - 2
client/src/components/Plans/EditPlanItem.jsx

@@ -1,5 +1,5 @@
 import React, { useEffect, useState } from 'react';
-import { Button, Dialog, Grid } from '@material-ui/core';
+import { Button, Grid } from '@material-ui/core';
 import { makeStyles } from '@material-ui/styles';
 import axios from 'axios';
 import DeleteButton from "../Buttons/DeleteButton";
@@ -8,7 +8,6 @@ import { any, arrayOf, bool, func, shape, string } from "prop-types";
 import Navbar from "../Navbar";
 import EditPlanItemCore from "./EditPlanItemCore";
 import BackButton from "../Buttons/BackButton";
-import { SlidingTransitionLeft } from "../util/SlidingTransition";
 import { useAuth0, withAuthenticationRequired } from "@auth0/auth0-react";
 import Loading from "../Loading";
 import useSnackbars from "../util/useSnackbars";

+ 0 - 5
client/src/components/Settings/EditMealCategories.jsx

@@ -182,9 +182,4 @@ EditMealCategories.propTypes = {
   onUpdateCategories: func,
 }
 
-EditMealCategories.propTypes = {
-  onUpdateSettings: null,
-  onUpdateCategories: null,
-}
-
 export default EditMealCategories;

+ 0 - 5
client/src/components/Settings/EditMealTags.jsx

@@ -73,9 +73,4 @@ EditMealTags.propTypes = {
   onUpdateTags: func,
 }
 
-EditMealTags.propTypes = {
-  onUpdateSettings: null,
-  onUpdateTags: null,
-}
-
 export default EditMealTags;

+ 1 - 18
client/src/components/Settings/EditProfile.jsx

@@ -1,29 +1,12 @@
 import React, { useEffect, useState } from "react";
 import { withAuthenticationRequired } from "@auth0/auth0-react";
-import {
-  Box,
-  Button,
-  Card,
-  CardContent,
-  CardHeader,
-  Collapse,
-  Dialog,
-  IconButton,
-  InputBase,
-  Table,
-  TableBody,
-  TableCell,
-  TableContainer,
-  TableRow,
-  Typography
-} from "@material-ui/core";
+import { Box, Button, Card, CardContent, CardHeader, Collapse, IconButton, InputBase, Table, TableBody, TableCell, TableContainer, TableRow, Typography } from "@material-ui/core";
 import { ExpandLess, ExpandMore, InfoTwoTone } from "@material-ui/icons";
 import ImageUpload from "../Images/ImageUpload";
 import { updateUser, updateUserMetadata } from "./settings.util";
 import { bool, func, shape } from "prop-types";
 import { makeStyles } from "@material-ui/styles";
 import { useTranslation } from "react-i18next";
-import { SlidingTransitionLeft } from "../util/SlidingTransition";
 import Navbar from "../Navbar";
 import BackButton from "../Buttons/BackButton";
 import { muiTableBorder } from "../util";