Add basic meals list
This commit is contained in:
parent
7d01db8018
commit
c4c23916cf
18
package.json
18
package.json
@ -5,20 +5,28 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4.11.1",
|
"@material-ui/core": "^4.11.1",
|
||||||
"@material-ui/icons": "^4.9.1",
|
"@material-ui/icons": "^4.9.1",
|
||||||
|
"@tailwindcss/forms": "^0.2.1",
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
"@zxing/library": "^0.18.3",
|
"@zxing/library": "^0.18.3",
|
||||||
"add": "^2.0.6",
|
"add": "^2.0.6",
|
||||||
|
"autoprefixer": "^10.0.4",
|
||||||
|
"lodash": "^4.17.20",
|
||||||
|
"postcss": "^8.1.10",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-barcode-reader": "^0.0.2",
|
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
|
"react-redux": "^7.2.2",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.0",
|
"react-scripts": "4.0.0",
|
||||||
"react-webcam": "^5.2.2",
|
"react-webcam": "^5.2.2",
|
||||||
"react-webcam-barcode-scanner": "^0.0.2-rc2",
|
"recharts": "^1.8.5",
|
||||||
"styled-components": "^5.2.1",
|
"redux": "^4.0.5",
|
||||||
|
"redux-saga": "^1.1.3",
|
||||||
|
"reselect": "^4.0.0",
|
||||||
|
"tailwindcss": "^2.0.1",
|
||||||
"web-vitals": "^0.2.4",
|
"web-vitals": "^0.2.4",
|
||||||
"yarn": "^1.22.10"
|
"yarn": "^1.22.10"
|
||||||
},
|
},
|
||||||
@ -46,7 +54,5 @@
|
|||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {}
|
||||||
"prop-types": "^15.7.2"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
10
src/components/AuthHeader/index.js
Normal file
10
src/components/AuthHeader/index.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const AuthHeader = () => (
|
||||||
|
<header className="flex md:h-screen md:w-7/12 flex-col justify-center items-center text-center mt-10 mb-20">
|
||||||
|
<h1 className="text-6xl font-bold uppercase text-primary-base">Fitwave</h1>
|
||||||
|
<p className="mt-1 text-base text-xl">Your best calorie calculator</p>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default AuthHeader;
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useRef, useCallback, useEffect } from 'react'
|
import React, { useRef, useCallback, useEffect } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
import { BrowserMultiFormatReader } from '@zxing/library'
|
import { BrowserMultiFormatReader } from '@zxing/library'
|
||||||
import Webcam from 'react-webcam'
|
import Webcam from 'react-webcam'
|
||||||
|
|
||||||
@ -44,4 +45,11 @@ const BarcodeScanner = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BarcodeScanner.propTypes = {
|
||||||
|
width: PropTypes.number.isRequired,
|
||||||
|
height: PropTypes.number.isRequired,
|
||||||
|
onUpdate: PropTypes.func.isRequired,
|
||||||
|
onError: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
export default BarcodeScanner
|
export default BarcodeScanner
|
||||||
|
90
src/components/MenuList/index.js
Normal file
90
src/components/MenuList/index.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
import {List, ListItem, ListItemSecondaryAction, ListItemText, IconButton, Box, Typography} from '@material-ui/core';
|
||||||
|
import { Add as AddIcon } from '@material-ui/icons';
|
||||||
|
|
||||||
|
const ITEMS = [
|
||||||
|
{
|
||||||
|
calories: 0,
|
||||||
|
proteins: 0,
|
||||||
|
fats: 0,
|
||||||
|
carbohydrates: 0,
|
||||||
|
mealName: 'breakfast',
|
||||||
|
meals: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
calories: 0,
|
||||||
|
proteins: 0,
|
||||||
|
fats: 0,
|
||||||
|
carbohydrates: 0,
|
||||||
|
mealName: 'lunch',
|
||||||
|
meals: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
calories: 0,
|
||||||
|
proteins: 0,
|
||||||
|
fats: 0,
|
||||||
|
carbohydrates: 0,
|
||||||
|
mealName: 'dinner',
|
||||||
|
meals: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
calories: 0,
|
||||||
|
proteins: 0,
|
||||||
|
fats: 0,
|
||||||
|
carbohydrates: 0,
|
||||||
|
mealName: 'supper',
|
||||||
|
meals: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
root: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingRight: theme.spacing(2)
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Macronutrients = ({ calories, proteins, fats, carbohydrates }) => {
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const macronutrients = [
|
||||||
|
calories, proteins, fats, carbohydrates
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box className={classes.root}>
|
||||||
|
{macronutrients.map((value, index) => (
|
||||||
|
<Typography paragraph key={index}>
|
||||||
|
{value}{' '}{index === 0 ? 'kcal' : 'g'}
|
||||||
|
</Typography>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const MenuList = ({ items }) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List dense>
|
||||||
|
{ITEMS.map(({calories, proteins, fats, carbohydrates, mealName, meals}, index) => (
|
||||||
|
<ListItem key={index}>
|
||||||
|
<ListItemText
|
||||||
|
primary={mealName.toUpperCase()}
|
||||||
|
secondary={<Macronutrients calories={calories} proteins={proteins} fats={fats} carbohydrates={carbohydrates} />}
|
||||||
|
/>
|
||||||
|
<ListItemSecondaryAction>
|
||||||
|
<IconButton edge="end" aria-label="add meal" color="secondary">
|
||||||
|
<AddIcon />
|
||||||
|
</IconButton>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MenuList
|
37
src/components/Navbar/index.js
Normal file
37
src/components/Navbar/index.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {makeStyles} from "@material-ui/core/styles";
|
||||||
|
import {AppBar, Button, IconButton, Toolbar, Typography} from "@material-ui/core";
|
||||||
|
import MenuIcon from "@material-ui/icons/Menu";
|
||||||
|
import Waves from "@material-ui/icons/Waves";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
root: {
|
||||||
|
flexGrow: 1,
|
||||||
|
},
|
||||||
|
menuButton: {
|
||||||
|
marginRight: theme.spacing(2),
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
flexGrow: 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Navbar = () => {
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppBar position="static">
|
||||||
|
<Toolbar>
|
||||||
|
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
|
||||||
|
<MenuIcon />
|
||||||
|
</IconButton>
|
||||||
|
<Typography variant="h6" className={classes.title}>
|
||||||
|
<Waves />
|
||||||
|
</Typography>
|
||||||
|
<Button color="inherit">Login</Button>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Navbar;
|
55
src/components/ScrollableTabs/index.js
Normal file
55
src/components/ScrollableTabs/index.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import React, {useState} from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { Box, Tab, Tabs } from "@material-ui/core";
|
||||||
|
|
||||||
|
import TabLabel from 'components/TabLabel';
|
||||||
|
import TabPanel from 'components/TabPanel';
|
||||||
|
|
||||||
|
const a11yProps = (index) => {
|
||||||
|
return {
|
||||||
|
id: `scrollable-force-tab-${index}`,
|
||||||
|
'aria-controls': `scrollable-force-tabpanel-${index}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const ScrollableTabs = ({ tabs, panels }) => {
|
||||||
|
const [value, setValue] = useState(0);
|
||||||
|
|
||||||
|
const handleChange = (event, newValue) => {
|
||||||
|
setValue(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Tabs
|
||||||
|
value={value}
|
||||||
|
onChange={handleChange}
|
||||||
|
variant="scrollable"
|
||||||
|
scrollButtons="desktop"
|
||||||
|
indicatorColor="primary"
|
||||||
|
>
|
||||||
|
{tabs.map((label, index) => (
|
||||||
|
<Tab
|
||||||
|
style={{ minWidth: '33%' }}
|
||||||
|
label={<TabLabel label={label} />}
|
||||||
|
{...a11yProps(index)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
<Box>
|
||||||
|
{panels.map((Component, index) => (
|
||||||
|
<TabPanel value={value} index={index}>
|
||||||
|
<Component />
|
||||||
|
</TabPanel>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollableTabs.propTypes = {
|
||||||
|
tabs: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||||
|
panels: PropTypes.arrayOf(PropTypes.node).isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ScrollableTabs
|
23
src/components/TabLabel/index.js
Normal file
23
src/components/TabLabel/index.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Box, Typography } from "@material-ui/core";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
const TabLabel = ({ label }) => {
|
||||||
|
console.log('TabLabel - todo')
|
||||||
|
return (
|
||||||
|
<Box display="flex" flexDirection="column">
|
||||||
|
<Typography component="span" variant="caption">
|
||||||
|
30 lis
|
||||||
|
</Typography>
|
||||||
|
<Typography component="span" variant="caption">
|
||||||
|
poniedziałek
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TabLabel.propTypes = {
|
||||||
|
label: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TabLabel;
|
29
src/components/TabPanel/index.js
Normal file
29
src/components/TabPanel/index.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {Box} from "@material-ui/core";
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
const TabPanel = ({ children, value, index, ...other }) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
role="tabpanel"
|
||||||
|
hidden={value !== index}
|
||||||
|
id={`scrollable-force-tabpanel-${index}`}
|
||||||
|
aria-labelledby={`scrollable-force-tab-${index}`}
|
||||||
|
{...other}
|
||||||
|
>
|
||||||
|
{value === index && (
|
||||||
|
<Box p={3}>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TabPanel.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
index: PropTypes.any.isRequired,
|
||||||
|
value: PropTypes.any.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TabPanel
|
@ -1,20 +1,30 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
|
||||||
import { Switch } from 'react-router-dom';
|
import { Switch } from 'react-router-dom';
|
||||||
import { ROUTES } from 'utils/routes';
|
|
||||||
import RouteWithSubRoutes from 'containers/RouteWithSubRoutes'
|
import RouteWithSubRoutes from 'containers/RouteWithSubRoutes'
|
||||||
|
import { ThemeProvider } from '@material-ui/core/styles'
|
||||||
|
import CssBaseline from '@material-ui/core/CssBaseline'
|
||||||
|
import { ROUTES } from 'utils/routes';
|
||||||
|
import { theme } from 'utils/theme'
|
||||||
|
|
||||||
const AppWrapper = styled.div``
|
import Navbar from 'components/Navbar'
|
||||||
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
<AppWrapper>
|
<ThemeProvider theme={theme}>
|
||||||
|
<CssBaseline />
|
||||||
|
<Navbar />
|
||||||
<Switch>
|
<Switch>
|
||||||
{ROUTES.map(({ key, ...props }) => <RouteWithSubRoutes key={key} {...props} />)}
|
{ROUTES.map(({ key, component, path, exact, routes }) => (
|
||||||
|
<RouteWithSubRoutes
|
||||||
|
key={key}
|
||||||
|
component={component}
|
||||||
|
path={path}
|
||||||
|
exact={exact}
|
||||||
|
routes={routes}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</Switch>
|
</Switch>
|
||||||
</AppWrapper>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { Route } from 'react-router-dom'
|
import { Route } from 'react-router-dom'
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const RouteWithSubRoutes = ({ component: Component, path, exact, routes }) => (
|
const RouteWithSubRoutes = ({ component: Component, path, exact, routes = [] }) => (
|
||||||
<Route
|
<Route
|
||||||
path={path}
|
path={path}
|
||||||
exact={exact}
|
exact={exact}
|
||||||
@ -11,10 +11,10 @@ const RouteWithSubRoutes = ({ component: Component, path, exact, routes }) => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
RouteWithSubRoutes.propTypes = {
|
RouteWithSubRoutes.propTypes = {
|
||||||
component: PropTypes.node.isRequired,
|
routes: PropTypes.array,
|
||||||
|
component: PropTypes.elementType.isRequired,
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
exact: PropTypes.bool.isRequired,
|
exact: PropTypes.bool.isRequired,
|
||||||
routes: PropTypes.array.isRequired,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RouteWithSubRoutes;
|
export default RouteWithSubRoutes;
|
||||||
|
@ -1,10 +1,46 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {makeStyles} from "@material-ui/core/styles";
|
||||||
|
import { Container, Grid, Paper } from '@material-ui/core';
|
||||||
|
|
||||||
|
import ScrollableTabs from 'components/ScrollableTabs';
|
||||||
|
import MenuList from 'components/MenuList'
|
||||||
|
|
||||||
|
let i = 1
|
||||||
|
const TABS = Array.from({ length: 30 }, () => i++)
|
||||||
|
const PANELS = Array.from({ length: 30 }, () => MenuList)
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
root: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
const HomePage = () => {
|
const HomePage = () => {
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Container className={classes.root}>
|
||||||
Home page hello world
|
<Grid xs="12" container spacing={2} justify="center">
|
||||||
</div>
|
<Grid item xs="12" md="6">
|
||||||
|
<Paper>
|
||||||
|
<ScrollableTabs tabs={TABS} panels={PANELS} />
|
||||||
|
</Paper >
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs="12" md="6">
|
||||||
|
<Paper>
|
||||||
|
<span>Hello world</span>
|
||||||
|
</Paper >
|
||||||
|
|
||||||
|
<Paper>
|
||||||
|
<span>Hello world</span>
|
||||||
|
</Paper >
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
const LoginPage = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Login page
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LoginPage;
|
|
@ -1,5 +1,4 @@
|
|||||||
import HomePage from 'pages/Home'
|
import HomePage from 'pages/Home'
|
||||||
import LoginPage from 'pages/Login'
|
|
||||||
|
|
||||||
export const ROUTES = [
|
export const ROUTES = [
|
||||||
{
|
{
|
||||||
@ -8,10 +7,4 @@ export const ROUTES = [
|
|||||||
exact: true,
|
exact: true,
|
||||||
component: HomePage
|
component: HomePage
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/login',
|
|
||||||
key: 'LOGIN',
|
|
||||||
exact: true,
|
|
||||||
component: LoginPage
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
13
src/utils/theme.js
Normal file
13
src/utils/theme.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { createMuiTheme } from '@material-ui/core/styles';
|
||||||
|
|
||||||
|
export const theme = createMuiTheme({
|
||||||
|
palette: {
|
||||||
|
type: 'dark',
|
||||||
|
primary: {
|
||||||
|
main: '#512da8',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#40c4ff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user