From 8160437379300545e230d654b754b214c9f4d92d Mon Sep 17 00:00:00 2001
From: = <=>
Date: Tue, 29 Dec 2020 16:39:17 +0100
Subject: [PATCH] Add redux saga for home apge
---
src/components/AddMealModal/index.js | 91 ---------------
src/components/DailyStats/index.js | 61 ----------
src/components/EditProductDialog/index.js | 71 ++++++++++++
src/components/{Meal => MealCard}/index.js | 6 +-
src/components/{Dish => ProductCard}/index.js | 16 +--
src/components/ScrollableTabs/index.js | 68 ------------
src/components/SliderField/index.js | 24 ----
src/components/TabLabel/index.js | 23 ----
src/components/TabPanel/index.js | 29 -----
src/pages/AddDish/index.js | 72 ++++++++++++
src/pages/AddDish/styles.js | 27 +++++
src/pages/Home/actions.js | 79 +++++++++++++
src/pages/Home/constants.js | 15 +++
src/pages/Home/index.js | 15 ++-
src/pages/Home/reducer.js | 100 +++++++++++++++++
src/pages/Home/saga.js | 105 ++++++++++++++++++
src/pages/Home/selectors.js | 36 ++++++
src/utils/api.js | 2 +
src/utils/routes.js | 7 ++
19 files changed, 532 insertions(+), 315 deletions(-)
delete mode 100644 src/components/AddMealModal/index.js
delete mode 100644 src/components/DailyStats/index.js
create mode 100644 src/components/EditProductDialog/index.js
rename src/components/{Meal => MealCard}/index.js (95%)
rename src/components/{Dish => ProductCard}/index.js (70%)
delete mode 100644 src/components/ScrollableTabs/index.js
delete mode 100644 src/components/SliderField/index.js
delete mode 100644 src/components/TabLabel/index.js
delete mode 100644 src/components/TabPanel/index.js
create mode 100644 src/pages/AddDish/index.js
create mode 100644 src/pages/AddDish/styles.js
create mode 100644 src/pages/Home/actions.js
create mode 100644 src/pages/Home/constants.js
create mode 100644 src/pages/Home/reducer.js
create mode 100644 src/pages/Home/saga.js
create mode 100644 src/pages/Home/selectors.js
diff --git a/src/components/AddMealModal/index.js b/src/components/AddMealModal/index.js
deleted file mode 100644
index 12d9583..0000000
--- a/src/components/AddMealModal/index.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import React from 'react'
-import {
- Grid,
- IconButton,
- Typography,
- TextField,
- List,
- Checkbox,
- Dialog,
- DialogContent,
- ListSubheader,
- ListItemSecondaryAction,
- DialogTitle
-} from '@material-ui/core';
-import { makeStyles } from '@material-ui/core/styles';
-import {Close, CropFree} from '@material-ui/icons';
-import Meal from "components/Dish";
-
-import { MEALS_LIST } from 'utils/mock'
-
-const useStyles = makeStyles((theme) => ({
- closeButton: {
- position: 'absolute',
- right: theme.spacing(1),
- top: theme.spacing(1),
- color: theme.palette.grey[500],
- },
- searchInput: {
- marginRight: theme.spacing(3),
- }
-}))
-
-const AddMealModal = ({ isModalOpen, handleCloseModal }) => {
- const styles = useStyles()
-
- return (
-
- );
-};
-
-export default AddMealModal;
diff --git a/src/components/DailyStats/index.js b/src/components/DailyStats/index.js
deleted file mode 100644
index a926e0d..0000000
--- a/src/components/DailyStats/index.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import React from "react";
-import PropTypes from "prop-types";
-import {Grid, Paper, Typography} from "@material-ui/core";
-import {makeStyles} from "@material-ui/core/styles";
-import grey from '@material-ui/core/colors/grey';
-import MacronutrientsChart from 'components/MacronutrientsChart'
-
-const useStyles = makeStyles((theme) => ({
- root: {
- paddingTop: theme.spacing(2),
- paddingBottom: theme.spacing(2),
- },
- subtitle: {
- color: grey[400]
- }
-}))
-
-const DailyStats = ({ caloriesLeft, macronutrients }) => {
- const classes = useStyles()
-
- return (
-
-
-
-
- Calories left
-
-
- {caloriesLeft} kcal
-
-
-
- {macronutrients.map(({ current, max, label, color }, index) => (
-
- ))}
-
-
-
- )
-}
-
-DailyStats.propTypes = {
- caloriesLeft: PropTypes.number.isRequired,
- macronutrients: PropTypes.arrayOf(PropTypes.shape({
- current: PropTypes.number.isRequired,
- max: PropTypes.number.isRequired,
- label: PropTypes.string.isRequired,
- color: PropTypes.string.isRequired,
- })).isRequired
-}
-
-export default DailyStats
diff --git a/src/components/EditProductDialog/index.js b/src/components/EditProductDialog/index.js
new file mode 100644
index 0000000..d06b200
--- /dev/null
+++ b/src/components/EditProductDialog/index.js
@@ -0,0 +1,71 @@
+import React, { useState } from 'react';
+import {Dialog, DialogTitle, Tooltip, DialogContent, Grid, Typography, TextField, DialogContentText, DialogActions, IconButton, Button} from "@material-ui/core";
+import InputField from "components/InputField";
+import {Edit as EditIcon, VerifiedUserTwoTone as VerifiedUserIcon, EcoTwoTone as EcoIcon} from "@material-ui/icons";
+
+const ProductLabel = ({ label, eco, verified }) => {
+ return (
+
+
+ {label}
+ {verified && (
+
+
+
+ )}
+ {eco && (
+
+
+
+ )}
+
+
+ )
+}
+
+const EditProductDialog = () => {
+ const [isDialogOpen, setIsDialogOpen] = useState(false)
+
+ const handleOpenDialog = () => {
+ setIsDialogOpen(true)
+ }
+
+ const handleCloseDialog = () => {
+ setIsDialogOpen(false)
+ }
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default EditProductDialog;
diff --git a/src/components/Meal/index.js b/src/components/MealCard/index.js
similarity index 95%
rename from src/components/Meal/index.js
rename to src/components/MealCard/index.js
index 8d2bb8b..424d35e 100644
--- a/src/components/Meal/index.js
+++ b/src/components/MealCard/index.js
@@ -11,9 +11,9 @@ import {Add as AddIcon} from "@material-ui/icons";
import React from "react";
import {MACRONUTRIENTS, MEALS_LIST} from "utils/mock";
import MacronutrientsChart from "components/MacronutrientsChart";
-import Dish from "components/Dish";
+import Dish from "components/ProductCard";
-const Meal = ({ label }) => {
+const MealCard = ({ label }) => {
const calcMealMacronutrients = (dishes) => {
const mealMacronutrients = dishes
@@ -73,4 +73,4 @@ const Meal = ({ label }) => {
);
};
-export default Meal;
+export default MealCard;
diff --git a/src/components/Dish/index.js b/src/components/ProductCard/index.js
similarity index 70%
rename from src/components/Dish/index.js
rename to src/components/ProductCard/index.js
index 95f96d5..b10bf35 100644
--- a/src/components/Dish/index.js
+++ b/src/components/ProductCard/index.js
@@ -2,9 +2,11 @@ import {ListItem, ListItemText, ListItemSecondaryAction, IconButton} from "@mate
import PropTypes from 'prop-types'
import React from "react";
import MacronutrientsDetails from "components/MacronutrientsDetails";
-import {Delete as DeleteIcon, Edit as EditIcon} from "@material-ui/icons";
+import EditProductDialog from "components/EditProductDialog";
+import {Delete as DeleteIcon} from "@material-ui/icons";
+
+const ProductCard = ({ label, macronutrients }) => {
-const Dish = ({ label, macronutrients }) => {
return (
{
}
/>
- console.log('elo')}>
-
-
- console.log('elo')}>
+
+ alert('remove')}>
@@ -27,7 +27,7 @@ const Dish = ({ label, macronutrients }) => {
)
}
-Dish.propTypes = {
+ProductCard.propTypes = {
label: PropTypes.string.isRequired,
macronutrients: PropTypes.arrayOf(PropTypes.shape({
value: PropTypes.number.isRequired,
@@ -35,4 +35,4 @@ Dish.propTypes = {
})).isRequired,
}
-export default Dish
+export default ProductCard
diff --git a/src/components/ScrollableTabs/index.js b/src/components/ScrollableTabs/index.js
deleted file mode 100644
index c2d853b..0000000
--- a/src/components/ScrollableTabs/index.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import React, {useState} from "react";
-import PropTypes from "prop-types";
-import { Box, Tab, Tabs } from "@material-ui/core";
-import {makeStyles} from "@material-ui/core/styles";
-
-import TabLabel from 'components/TabLabel';
-import TabPanel from 'components/TabPanel';
-// import MenuList from 'components/MenuList'
-
-import { MENU_LIST } from 'utils/mock'
-
-const a11yProps = (index) => {
- return {
- id: `scrollable-force-tab-${index}`,
- 'aria-controls': `scrollable-force-tabpanel-${index}`,
- };
-}
-
-const useStyles = makeStyles((theme) => ({
- tab: {
- width: `100%`
- }
-}))
-
-const ScrollableTabs = ({ tabs }) => {
- const classes = useStyles()
-
- const [value, setValue] = useState(0);
-
- const handleChangeDay = (event, newDay) => {
- setValue(newDay);
- };
-
- return (
-
-
- {tabs.map((label, index) => (
- }
- {...a11yProps(index)}
- />
- ))}
-
-
- {tabs.map((_, index) => (
-
- {/**/}
- hello from Scrollabel tabs
-
- ))}
-
-
- );
-}
-
-ScrollableTabs.propTypes = {
- tabs: PropTypes.arrayOf(PropTypes.string).isRequired,
-}
-
-export default ScrollableTabs
diff --git a/src/components/SliderField/index.js b/src/components/SliderField/index.js
deleted file mode 100644
index ee71567..0000000
--- a/src/components/SliderField/index.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react';
-import { at } from 'lodash';
-import { useField } from 'formik';
-import {
- Slider,
- FormControl,
- FormControlLabel,
- FormHelperText
-} from '@material-ui/core';
-
-const SliderField = ({ label, ...rest }) => {
- const [field, meta, helper] = useField({ label, ...rest });
- const { setValue } = helper;
-
- const _onChange = (e) => {
- setValue(e.target.checked);
- }
-
- return (
-
- );
-}
-
-export default SliderField
diff --git a/src/components/TabLabel/index.js b/src/components/TabLabel/index.js
deleted file mode 100644
index 734f1aa..0000000
--- a/src/components/TabLabel/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import { Box, Typography } from "@material-ui/core";
-import PropTypes from "prop-types";
-
-const TabLabel = ({ label }) => {
- console.log('TabLabel - todo')
- return (
-
-
- 30 lis
-
-
- poniedziaĆek
-
-
- )
-}
-
-TabLabel.propTypes = {
- label: PropTypes.string.isRequired,
-}
-
-export default TabLabel;
diff --git a/src/components/TabPanel/index.js b/src/components/TabPanel/index.js
deleted file mode 100644
index 0ff834b..0000000
--- a/src/components/TabPanel/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import {Box} from "@material-ui/core";
-import React from "react";
-import PropTypes from "prop-types";
-
-const TabPanel = ({ children, value, index, ...other }) => {
- return (
-
- {value === index && (
-
- {children}
-
- )}
-
- );
-}
-
-TabPanel.propTypes = {
- children: PropTypes.node.isRequired,
- index: PropTypes.any.isRequired,
- value: PropTypes.any.isRequired,
-};
-
-export default TabPanel
diff --git a/src/pages/AddDish/index.js b/src/pages/AddDish/index.js
new file mode 100644
index 0000000..629e299
--- /dev/null
+++ b/src/pages/AddDish/index.js
@@ -0,0 +1,72 @@
+import React from 'react';
+import {Paper, InputBase, FormLabel, ListItemSecondaryAction, ListItem, ListItemText, List, FormControl, FormGroup, FormControlLabel, Divider, Checkbox, Grid, Typography, FilledInput , DialogContentText, DialogActions, IconButton, Button} from "@material-ui/core";
+import { CropFree as CropFreeIcon, Search as SearchIcon } from '@material-ui/icons'
+import EditProductDialog from 'components/EditProductDialog'
+import useStyles from './styles'
+
+function generate(element) {
+ return [0, 1, 2].map((value) =>
+ React.cloneElement(element, {
+ key: value,
+ }),
+ );
+}
+
+const AddProductPage = () => {
+ const classes = useStyles()
+
+ return (
+
+
+
+
+ Filters
+
+ }
+ label="Verified"
+ />
+ }
+ label="Eco"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {generate(
+
+
+
+
+
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default AddProductPage;
diff --git a/src/pages/AddDish/styles.js b/src/pages/AddDish/styles.js
new file mode 100644
index 0000000..4d2a978
--- /dev/null
+++ b/src/pages/AddDish/styles.js
@@ -0,0 +1,27 @@
+import {makeStyles} from "@material-ui/core/styles";
+
+const useStyles = makeStyles((theme) => ({
+ addDishContainer: {
+ padding: theme.spacing(2),
+ minWidth: 750,
+ },
+ root: {
+ padding: '2px 4px',
+ display: 'flex',
+ alignItems: 'center',
+ minWidth: 400,
+ },
+ input: {
+ marginLeft: theme.spacing(1),
+ flex: 1,
+ },
+ iconButton: {
+ padding: 10,
+ },
+ divider: {
+ height: 28,
+ margin: 4,
+ },
+}))
+
+export default useStyles
diff --git a/src/pages/Home/actions.js b/src/pages/Home/actions.js
new file mode 100644
index 0000000..83a9bf1
--- /dev/null
+++ b/src/pages/Home/actions.js
@@ -0,0 +1,79 @@
+import {
+ CREATE_MEAL_REQUEST,
+ CREATE_MEAL_SUCCESS,
+ CREATE_MEAL_ERROR,
+ GET_MEALS_REQUEST,
+ GET_MEALS_SUCCESS,
+ GET_MEALS_ERROR,
+ UPDATE_MEAL_REQUEST,
+ UPDATE_MEAL_SUCCESS,
+ UPDATE_MEAL_ERROR,
+ ADD_PRODUCTS_TO_MEAL_REQUEST,
+ ADD_PRODUCTS_TO_MEAL_SUCCESS,
+ ADD_PRODUCTS_TO_MEAL_ERROR,
+} from './constants';
+
+export const getMealsAction = () => ({
+ type: GET_MEALS_REQUEST,
+})
+
+export const getMealsSuccessAction = ({ meals }) => ({
+ type: GET_MEALS_SUCCESS,
+ meals
+})
+
+export const getMealsErrorAction = ({ error }) => ({
+ type: GET_MEALS_ERROR,
+ error,
+})
+
+export const updateMealAction = () => ({
+ type: UPDATE_MEAL_REQUEST,
+})
+
+export const updateMealSuccessAction = ({ label, products, date }) => ({
+ type: UPDATE_MEAL_SUCCESS,
+ label,
+ products,
+ date,
+})
+
+export const updateMealErrorAction = ({error}) => ({
+ type: UPDATE_MEAL_ERROR,
+ error,
+})
+
+export const createMealAction = ({ label, products, date }) => ({
+ type: CREATE_MEAL_REQUEST,
+ label,
+ products,
+ date,
+})
+
+export const createMealSuccessAction = ({ label, products, date }) => ({
+ type: CREATE_MEAL_SUCCESS,
+ label,
+ products,
+ date,
+})
+
+export const createMealErrorAction = ({error}) => ({
+ type: CREATE_MEAL_ERROR,
+ error,
+})
+
+export const addProductsToMealAction = ({ products }) => ({
+ type: ADD_PRODUCTS_TO_MEAL_REQUEST,
+ products,
+})
+
+export const addProductsToSuccessAction = ({ meal }) => ({
+ type: ADD_PRODUCTS_TO_MEAL_SUCCESS,
+ meal
+})
+
+export const addProductsToMealErrorAction = ({error}) => ({
+ type: ADD_PRODUCTS_TO_MEAL_ERROR,
+ error,
+})
+
diff --git a/src/pages/Home/constants.js b/src/pages/Home/constants.js
new file mode 100644
index 0000000..fe5959a
--- /dev/null
+++ b/src/pages/Home/constants.js
@@ -0,0 +1,15 @@
+export const GET_MEALS_REQUEST = 'app/HomePage/GET_MEALS_REQUEST'
+export const GET_MEALS_SUCCESS = 'app/HomePage/GET_MEALS_SUCCESS';
+export const GET_MEALS_ERROR = 'app/LoginPage/GET_MEALS_ERROR';
+
+export const CREATE_MEAL_REQUEST = 'app/HomePage/CREATE_MEAL_REQUEST'
+export const CREATE_MEAL_SUCCESS = 'app/HomePage/CREATE_MEAL_SUCCESS';
+export const CREATE_MEAL_ERROR = 'app/LoginPage/CREATE_MEAL_ERROR';
+
+export const UPDATE_MEAL_REQUEST = 'app/HomePage/UPDATE_MEAL_REQUEST'
+export const UPDATE_MEAL_SUCCESS = 'app/HomePage/UPDATE_MEAL_SUCCESS';
+export const UPDATE_MEAL_ERROR = 'app/LoginPage/UPDATE_MEAL_ERROR';
+
+export const ADD_PRODUCTS_TO_MEAL_REQUEST = 'app/HomePage/ADD_PRODUCTS_TO_MEAL_REQUEST'
+export const ADD_PRODUCTS_TO_MEAL_SUCCESS = 'app/HomePage/ADD_PRODUCTS_TO_MEAL_SUCCESS';
+export const ADD_PRODUCTS_TO_MEAL_ERROR = 'app/LoginPage/ADD_PRODUCTS_TO_MEAL_ERROR';
diff --git a/src/pages/Home/index.js b/src/pages/Home/index.js
index 668d00a..32897b1 100644
--- a/src/pages/Home/index.js
+++ b/src/pages/Home/index.js
@@ -1,23 +1,22 @@
import React from 'react';
import { Grid, IconButton, Accordion, Container, List, AccordionSummary, Typography, AccordionDetails } from '@material-ui/core';
import {Add as AddIcon} from '@material-ui/icons';
-import ScrollableTabs from 'components/ScrollableTabs';
import MacronutrientsChart from 'components/MacronutrientsChart'
import { TABS, MEALS_LIST, MACRONUTRIENTS } from 'utils/mock'
-import Meal from "components/Meal";
+import Meal from "components/MealCard";
const HomePage = () => {
return (
- {/**/}
- {/**/}
- {/**/}
- {/**/}
- {/**/}
- {/**/}
+
+
+
+
+
+
);
};
diff --git a/src/pages/Home/reducer.js b/src/pages/Home/reducer.js
new file mode 100644
index 0000000..6371deb
--- /dev/null
+++ b/src/pages/Home/reducer.js
@@ -0,0 +1,100 @@
+import { format } from 'date-fns'
+import produce from 'immer';
+import {
+ CREATE_MEAL_REQUEST,
+ CREATE_MEAL_SUCCESS,
+ CREATE_MEAL_ERROR,
+ GET_MEALS_REQUEST,
+ GET_MEALS_SUCCESS,
+ GET_MEALS_ERROR,
+ UPDATE_MEAL_REQUEST,
+ UPDATE_MEAL_SUCCESS,
+ UPDATE_MEAL_ERROR,
+ ADD_PRODUCTS_TO_MEAL_REQUEST,
+ ADD_PRODUCTS_TO_MEAL_SUCCESS,
+ ADD_PRODUCTS_TO_MEAL_ERROR,
+} from './constants';
+
+export const initialState = {
+ isLoading: false,
+ error: {},
+ label: '',
+ products: [],
+ date: format(new Date(), "yyyy-MM-dd"),
+ mealId: '',
+ meals: [
+ {
+ label: 'Breakfast',
+ products: [],
+ },
+ {
+ label: 'Snack I',
+ products: [],
+ },
+ {
+ label: 'Lunch',
+ products: [],
+ },
+ {
+ label: 'Snack II',
+ products: [],
+ },
+ {
+ label: 'Dinner',
+ products: [],
+ },
+ {
+ label: 'Snack III',
+ products: [],
+ },
+ {
+ label: 'Supper',
+ products: [],
+ },
+ ]
+};
+
+const homePageReducer = produce((draft, action) => {
+ switch(action.type) {
+ case GET_MEALS_SUCCESS:
+ draft.meals = action.meals;
+ draft.isLoading = false;
+ break;
+
+ case UPDATE_MEAL_SUCCESS:
+ console.log(UPDATE_MEAL_SUCCESS, 'UPDATE_MEAL_SUCCESS')
+ draft.isLoading = false;
+ break;
+
+ case ADD_PRODUCTS_TO_MEAL_SUCCESS:
+ console.log(ADD_PRODUCTS_TO_MEAL_SUCCESS, 'ADD_PRODUCTS_TO_MEAL_SUCCESS')
+
+ const restMeals = draft.meals.filter(({ id }) => id === action.meal.id)
+
+ draft.meals = [...restMeals, action.meal]
+ draft.isLoading = false;
+ break;
+
+ case CREATE_MEAL_SUCCESS:
+ draft.meals.push(action.meal);
+ draft.isLoading = false;
+ break;
+
+ case GET_MEALS_REQUEST:
+ case CREATE_MEAL_REQUEST:
+ case UPDATE_MEAL_REQUEST:
+ case ADD_PRODUCTS_TO_MEAL_REQUEST:
+ draft.isLoading = true;
+ break;
+
+ case CREATE_MEAL_ERROR:
+ case GET_MEALS_ERROR:
+ case UPDATE_MEAL_ERROR:
+ case ADD_PRODUCTS_TO_MEAL_ERROR:
+ draft.isLoading = false;
+ draft.error = action.error;
+ break;
+ }
+}, initialState);
+
+export default homePageReducer;
diff --git a/src/pages/Home/saga.js b/src/pages/Home/saga.js
new file mode 100644
index 0000000..2fe0a36
--- /dev/null
+++ b/src/pages/Home/saga.js
@@ -0,0 +1,105 @@
+import { takeLatest, call, put, select } from 'redux-saga/effects';
+import {api, request, routes} from 'utils';
+import { GET_MEALS_REQUEST, UPDATE_MEAL_REQUEST, CREATE_MEAL_REQUEST, ADD_PRODUCTS_TO_MEAL_REQUEST } from './constants';
+import {
+
+} from './selectors';
+import { createMealSuccessAction, createMealErrorAction, updateMealErrorAction, updateMealSuccessAction, getMealsSuccessAction, getMealsErrorAction } from './actions';
+import { makeSelectLabel, makeSelectMealId, makeSelectProducts, makeSelectDate, } from './selectors'
+import { makeSelectTokens } from 'containers/App/selectors'
+import {push} from "connected-react-router";
+
+export function* getMeals() {
+ const { access } = yield select(makeSelectTokens());
+
+ const requestURL = api.meals;
+
+ const requestParameters = {
+ method: 'GET',
+ headers: {
+ Authorization: `Bearer ${access.token}`,
+ },
+ };
+
+ try {
+ const { meals } = yield call(request, requestURL, requestParameters);
+ yield put(getMealsSuccessAction({ meals }));
+ } catch (error) {
+ yield put(getMealsErrorAction({ error: error.message }));
+ }
+}
+
+export function* updateMeal() {
+ const { access } = yield select(makeSelectTokens());
+ const label = yield select(makeSelectLabel());
+ const products = yield select(makeSelectProducts());
+ const date = yield select(makeSelectDate());
+ const mealId = yield select(makeSelectMealId());
+
+ const requestURL = `${api.meals}/${mealId}`;
+
+ const requestParameters = {
+ method: 'PUT',
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${access.token}`, },
+ body: JSON.stringify({ label, products, date }),
+ };
+
+ try {
+ const { birthday, gender, height, currentWeight, goalWeight, rateOfChange, activity } = yield call(request, requestURL, requestParameters);
+ yield put(updateMealSuccessAction({birthday, gender, height, currentWeight, goalWeight, rateOfChange, activity}));
+ } catch (error) {
+ yield put(updateMealErrorAction({error: error.message}));
+ }
+}
+
+export function* createMeal() {
+ const { access } = yield select(makeSelectTokens());
+ const label = yield select(makeSelectLabel());
+ const products = yield select(makeSelectProducts());
+ const date = yield select(makeSelectDate());
+
+ const requestURL = api.meals;
+
+ const requestParameters = {
+ method: 'POST',
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${access.token}`, },
+ body: JSON.stringify({ label, products, date }),
+ };
+
+ try {
+ const { id, label, products, date } = yield call(request, requestURL, requestParameters);
+ yield put(createMealSuccessAction({ id, label, products, date }));
+ yield put(push(routes.dashboard.path));
+ } catch (error) {
+ yield put(createMealErrorAction({error: error.message}));
+ }
+}
+
+export function* addProductsToMeal() {
+ const { access } = yield select(makeSelectTokens());
+ const products = yield select(makeSelectProducts());
+ const mealId = yield select(makeSelectMealId());
+
+ const requestURL = `${api.meals}/${mealId}`;
+
+ const requestParameters = {
+ method: 'POST',
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${access.token}`, },
+ body: JSON.stringify({ products }),
+ };
+
+ try {
+ const { meal } = yield call(request, requestURL, requestParameters);
+ yield put(createMealSuccessAction({ meal }));
+ yield put(push(routes.dashboard.path));
+ } catch (error) {
+ yield put(createMealErrorAction({error: error.message}));
+ }
+}
+
+export default function* MealPageSaga() {
+ yield takeLatest(GET_MEALS_REQUEST, getMeals);
+ yield takeLatest(UPDATE_MEAL_REQUEST, updateMeal);
+ yield takeLatest(CREATE_MEAL_REQUEST, createMeal);
+ yield takeLatest(ADD_PRODUCTS_TO_MEAL_REQUEST, addProductsToMeal);
+}
diff --git a/src/pages/Home/selectors.js b/src/pages/Home/selectors.js
new file mode 100644
index 0000000..c313b4f
--- /dev/null
+++ b/src/pages/Home/selectors.js
@@ -0,0 +1,36 @@
+import { createSelector } from 'reselect';
+import { initialState } from './reducer';
+
+const selectHomePageDomain = (state) => state.homePage || initialState;
+
+const makeSelectError = () =>
+ createSelector(selectHomePageDomain, (substate) => substate.error);
+
+const makeSelectIsLoading = () =>
+ createSelector(selectHomePageDomain, (substate) => substate.isLoading);
+
+const makeSelectMeals = () =>
+ createSelector(selectHomePageDomain, (substate) => substate.meals);
+
+const makeSelectMealId = () =>
+ createSelector(selectHomePageDomain, (substate) => substate.mealId);
+
+const makeSelectDate = () =>
+ createSelector(selectHomePageDomain, (substate) => substate.date);
+
+const makeSelectLabel = () =>
+ createSelector(selectHomePageDomain, (substate) => substate.label);
+
+const makeSelectProducts = () =>
+ createSelector(selectHomePageDomain, (substate) => substate.products);
+
+export {
+ selectHomePageDomain,
+ makeSelectMealId,
+ makeSelectDate,
+ makeSelectLabel,
+ makeSelectProducts,
+ makeSelectError,
+ makeSelectIsLoading,
+ makeSelectMeals,
+};
diff --git a/src/utils/api.js b/src/utils/api.js
index e5851dd..dcb653b 100644
--- a/src/utils/api.js
+++ b/src/utils/api.js
@@ -1,6 +1,7 @@
const API_BASE_URL = 'http://localhost:3001/v1'
const AUTH = 'auth';
const PROFILE = 'profiles';
+const MEALS = 'meals';
const urls = {
auth: {
@@ -9,6 +10,7 @@ const urls = {
refreshToken: `${API_BASE_URL}/${AUTH}/refresh-tokens`
},
profile: `${API_BASE_URL}/${PROFILE}`,
+ meals: `${API_BASE_URL}/${MEALS}`,
}
export default urls
diff --git a/src/utils/routes.js b/src/utils/routes.js
index 1246822..11d04c1 100644
--- a/src/utils/routes.js
+++ b/src/utils/routes.js
@@ -3,6 +3,7 @@ import CreateProfilePage from "pages/CreateProfile";
import ProfilePage from "pages/Profile";
import LoginPage from "pages/Login";
import RegisterPage from "pages/Register";
+import AddDishPage from "pages/AddDish";
const routes = {
dashboard: {
@@ -17,6 +18,12 @@ const routes = {
privateRoute: true,
component: CreateProfilePage,
},
+ addDish: {
+ path: '/add-dish',
+ exact: true,
+ privateRoute: true,
+ component: AddDishPage,
+ },
profile: {
path: '/profile',
exact: true,