Merge pull request 'Add basic meals list' (#1) from login-page into master

Reviewed-on: #1
This commit is contained in:
Dawid Wesołowski 2020-11-30 20:34:43 +01:00
commit e6a3254147
15 changed files with 891 additions and 246 deletions

View File

@ -5,20 +5,28 @@
"dependencies": {
"@material-ui/core": "^4.11.1",
"@material-ui/icons": "^4.9.1",
"@tailwindcss/forms": "^0.2.1",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@zxing/library": "^0.18.3",
"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-barcode-reader": "^0.0.2",
"react-dom": "^17.0.1",
"react-helmet": "^6.1.0",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.0",
"react-webcam": "^5.2.2",
"react-webcam-barcode-scanner": "^0.0.2-rc2",
"styled-components": "^5.2.1",
"recharts": "^1.8.5",
"redux": "^4.0.5",
"redux-saga": "^1.1.3",
"reselect": "^4.0.0",
"tailwindcss": "^2.0.1",
"web-vitals": "^0.2.4",
"yarn": "^1.22.10"
},
@ -46,7 +54,5 @@
"last 1 safari version"
]
},
"devDependencies": {
"prop-types": "^15.7.2"
}
"devDependencies": {}
}

View 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;

View File

@ -1,4 +1,5 @@
import React, { useRef, useCallback, useEffect } from 'react'
import PropTypes from 'prop-types'
import { BrowserMultiFormatReader } from '@zxing/library'
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

View 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

View 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;

View 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

View 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;

View 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

View File

@ -1,20 +1,30 @@
import React from 'react';
import styled from 'styled-components';
import { Switch } from 'react-router-dom';
import { ROUTES } from 'utils/routes';
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 = () => {
return (
<AppWrapper>
<ThemeProvider theme={theme}>
<CssBaseline />
<Navbar />
<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>
</AppWrapper>
</ThemeProvider>
);
};

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Route } from 'react-router-dom'
import PropTypes from 'prop-types';
const RouteWithSubRoutes = ({ component: Component, path, exact, routes }) => (
const RouteWithSubRoutes = ({ component: Component, path, exact, routes = [] }) => (
<Route
path={path}
exact={exact}
@ -11,10 +11,10 @@ const RouteWithSubRoutes = ({ component: Component, path, exact, routes }) => (
)
RouteWithSubRoutes.propTypes = {
component: PropTypes.node.isRequired,
routes: PropTypes.array,
component: PropTypes.elementType.isRequired,
path: PropTypes.string.isRequired,
exact: PropTypes.bool.isRequired,
routes: PropTypes.array.isRequired,
}
export default RouteWithSubRoutes;

View File

@ -1,10 +1,46 @@
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 classes = useStyles()
return (
<div>
Home page hello world
</div>
<Container className={classes.root}>
<Grid xs="12" container spacing={2} justify="center">
<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>
);
};

View File

@ -1,11 +0,0 @@
import React from 'react';
const LoginPage = () => {
return (
<div>
Login page
</div>
);
};
export default LoginPage;

View File

@ -1,5 +1,4 @@
import HomePage from 'pages/Home'
import LoginPage from 'pages/Login'
export const ROUTES = [
{
@ -8,10 +7,4 @@ export const ROUTES = [
exact: true,
component: HomePage
},
{
path: '/login',
key: 'LOGIN',
exact: true,
component: LoginPage
}
]

13
src/utils/theme.js Normal file
View 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',
},
},
})

762
yarn.lock

File diff suppressed because it is too large Load Diff