web client v0.8

This commit is contained in:
2020-10-03 18:54:34 +02:00
parent 62702521ee
commit 21ea3f821e
7 changed files with 382 additions and 41 deletions

View File

@@ -0,0 +1,69 @@
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import DialogTitle from "@material-ui/core/DialogTitle";
import DialogContent from "@material-ui/core/DialogContent";
import Dialog from "@material-ui/core/Dialog";
import Divider from "@material-ui/core/Divider";
import IconButton from "@material-ui/core/IconButton";
import CloseIcon from "@material-ui/icons/Close";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
export default function AddToSet(props) {
const loginStyles = makeStyles((theme) => ({
root: {
textAlign: "center",
"& .MuiPaper-root": {
backgroundColor: "#262626",
color: "#bbbbbb",
minWidth: "360px",
},
},
closeButton: {
color: "#bbbbbb",
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
},
set: {
width: "100%",
},
}));
const loginClass = loginStyles();
const Sets = props.lunchMenu.map((lunchSet) => {
return (
<ListItem
button
key={lunchSet.lunchSetName}
onClick={() => props.add(lunchSet.lunchSetName)}
>
<ListItemText primary={lunchSet.lunchSetName} />
</ListItem>
);
});
return (
<Dialog
className={loginClass.root}
onClose={props.cancel}
open={props.open}
aria-labelledby="login-title"
>
<DialogTitle id="login-title">Wybierz zestaw</DialogTitle>
<IconButton
className={loginClass.closeButton}
onClick={props.cancel}
aria-label="close"
>
<CloseIcon />
</IconButton>
<Divider />
<DialogContent>
<List className={loginClass.set}>{Sets}</List>
</DialogContent>
</Dialog>
);
}

View File

@@ -24,6 +24,7 @@ import { prepareTags } from "../../Services.js";
import axios from "axios"; import axios from "axios";
import PasswordConfirmation from "../Dialogs/PasswordConfirmation"; import PasswordConfirmation from "../Dialogs/PasswordConfirmation";
import { backend } from "../../config"; import { backend } from "../../config";
import InputLunchMenuHours from "../Input/InputLunchMenuHours";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
textInput: { textInput: {
@@ -69,6 +70,7 @@ export default function EditRestaurantInfo(props) {
links: props.restaurant.links, links: props.restaurant.links,
tags: decodeTags(props.restaurant.tags), tags: decodeTags(props.restaurant.tags),
workingHours: props.restaurant.workingHours, workingHours: props.restaurant.workingHours,
lunchHours: props.lunchHours,
charleft: calculateCharLeft(props.restaurant.description), charleft: calculateCharLeft(props.restaurant.description),
nameError: false, nameError: false,
cityError: false, cityError: false,
@@ -167,6 +169,7 @@ export default function EditRestaurantInfo(props) {
placesId: props.restaurant.placesId, placesId: props.restaurant.placesId,
imgUrl: props.restaurant.imgUrl, imgUrl: props.restaurant.imgUrl,
workingHours: state.workingHours, workingHours: state.workingHours,
lunchHours: state.lunchHours,
description: state.description, description: state.description,
tags: formattedTags, tags: formattedTags,
links: state.links, links: state.links,
@@ -383,6 +386,15 @@ export default function EditRestaurantInfo(props) {
), ),
}} }}
/> />
<div className="editRestaurant-sectiontitle">
<h4>Lunch menu</h4>
<Divider />
<InputLunchMenuHours
off={!state.lunchHours}
hours={state.lunchHours}
changeValue={(value) => setState({ ...state, lunchHours: value })}
/>
</div>
<div className="editRestaurant-sectiontitle"> <div className="editRestaurant-sectiontitle">
<h4>Zaawansowane</h4> <h4>Zaawansowane</h4>
<Divider /> <Divider />

View File

@@ -7,6 +7,8 @@ import ButtonSecondary from "../Input/ButtonSecondary";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import AddIcon from "@material-ui/icons/Add"; import AddIcon from "@material-ui/icons/Add";
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import InputAdornment from "@material-ui/core/InputAdornment";
import TextFieldsIcon from "@material-ui/icons/TextFields";
import validator from "validator"; import validator from "validator";
import LunchMenu from "./LunchMenu"; import LunchMenu from "./LunchMenu";
import axios from "axios"; import axios from "axios";
@@ -27,6 +29,7 @@ const useStyles = makeStyles((theme) => ({
textInputFullWidth: { textInputFullWidth: {
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
marginBottom: theme.spacing(2), marginBottom: theme.spacing(2),
marginLeft: theme.spacing(2),
flexGrow: 5, flexGrow: 5,
"& .MuiInputBase-root": { "& .MuiInputBase-root": {
color: "#bbbbbb", color: "#bbbbbb",
@@ -109,6 +112,7 @@ export default function EditRestaurantMenu(props) {
</div> </div>
<EditCategoriesList <EditCategoriesList
restaurantId={props.restaurant._id} restaurantId={props.restaurant._id}
lunchMenu={props.restaurant.lunchMenu}
categories={categories} categories={categories}
deleteCategory={removeCategory} deleteCategory={removeCategory}
/> />
@@ -125,6 +129,13 @@ export default function EditRestaurantMenu(props) {
onChange={(event) => setNewCategory(event.target.value)} onChange={(event) => setNewCategory(event.target.value)}
label="Nazwa kategorii" label="Nazwa kategorii"
variant="outlined" variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<TextFieldsIcon color="primary" />
</InputAdornment>
),
}}
></TextField> ></TextField>
<ButtonSecondary onClick={addCategory} text="Dodaj" /> <ButtonSecondary onClick={addCategory} text="Dodaj" />
</div> </div>
@@ -133,7 +144,7 @@ export default function EditRestaurantMenu(props) {
<h4>Lunch menu</h4> <h4>Lunch menu</h4>
<Divider /> <Divider />
</div> </div>
<LunchMenu lunchMenu={lunchMenu} /> <LunchMenu restaurantId={props.restaurant._id} lunchMenu={lunchMenu} />
</div> </div>
); );
} }

View File

@@ -9,6 +9,16 @@ import YesNo from "../Dialogs/YesNo";
import ButtonSecondary from "../Input/ButtonSecondary"; import ButtonSecondary from "../Input/ButtonSecondary";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import AddIcon from "@material-ui/icons/Add"; import AddIcon from "@material-ui/icons/Add";
import InputAdornment from "@material-ui/core/InputAdornment";
import AttachMoneyIcon from "@material-ui/icons/AttachMoney";
import TextFieldsIcon from "@material-ui/icons/TextFields";
import axios from "axios";
import validator from "validator";
import { useDispatch, useSelector } from "react-redux";
import { notification, refreshUserData } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
import { backend } from "../../config";
import Tooltip from "@material-ui/core/Tooltip";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
root: { root: {
@@ -20,9 +30,24 @@ const useStyles = makeStyles((theme) => ({
expandIcon: { expandIcon: {
color: "#bbbbbb", color: "#bbbbbb",
}, },
textInputFullWidth: { textInput: {
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
marginBottom: theme.spacing(2), marginBottom: theme.spacing(2),
"& .MuiInputBase-root": {
color: "#bbbbbb",
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
},
"$ .MuiFormHelperText-root": {
color: "#bbbbbb",
},
},
textInputWide: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
marginRight: theme.spacing(1),
marginLeft: theme.spacing(2),
flexGrow: 5, flexGrow: 5,
"& .MuiInputBase-root": { "& .MuiInputBase-root": {
color: "#bbbbbb", color: "#bbbbbb",
@@ -37,16 +62,28 @@ const useStyles = makeStyles((theme) => ({
})); }));
export default function EditCategoriesList(props) { export default function EditCategoriesList(props) {
const dispatch = useDispatch();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [newSet, setNewSet] = useState(""); const initialSet = {
lunchSetName: "",
lunchSetPrice: "",
lunchSetDishes: [],
nameError: false,
priceError: false,
};
const [newSet, setNewSet] = useState(initialSet);
const [selectedSet, setSelectedSet] = useState(initialSet);
const token = useSelector((state) => state.data.userData.jwt);
const classes = useStyles(); const classes = useStyles();
const handleDeleteButton = (set) => { const handleDeleteButton = (set) => {
setSelectedSet(set);
setOpen(true); setOpen(true);
}; };
const onCancel = () => { const onCancel = () => {
setOpen(false); setOpen(false);
}; };
const onAccept = () => { const onAccept = () => {
sendForm("delete", selectedSet);
setOpen(false); setOpen(false);
}; };
const SetList = props.lunchMenu.map((set) => { const SetList = props.lunchMenu.map((set) => {
@@ -55,8 +92,11 @@ export default function EditCategoriesList(props) {
<AccordionSummary <AccordionSummary
expandIcon={<ExpandMoreIcon className={classes.expandIcon} />} expandIcon={<ExpandMoreIcon className={classes.expandIcon} />}
> >
<h4>{set.name}</h4> <h4>
{set.lunchSetName} ({set.lunchSetPrice})
</h4>
<div className="editRestaurant-categorySpan"> <div className="editRestaurant-categorySpan">
<Tooltip title="Usuń">
<IconButton <IconButton
color="primary" color="primary"
component="span" component="span"
@@ -64,12 +104,71 @@ export default function EditCategoriesList(props) {
> >
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
</Tooltip>
</div> </div>
</AccordionSummary> </AccordionSummary>
</Accordion> </Accordion>
); );
}); });
// HANDLERS
const validateForm = () => {
const validation = {
nameValid: validator.isLength(newSet.lunchSetName, { min: 1, max: 30 }),
priceValid: validator.isLength(newSet.lunchSetPrice, { min: 1, max: 12 }),
};
setNewSet({
...newSet,
nameError: !validation.nameValid,
priceError: !validation.priceValid,
});
return validation.nameValid && validation.priceValid;
};
const sendForm = (action, set) => {
let valid = false;
if (action === "add") {
valid = validateForm();
} else {
valid = true;
}
if (valid) {
const data = {
restaurantId: props.restaurantId,
action: action,
set: {
lunchSetName: set.lunchSetName,
lunchSetPrice: set.lunchSetPrice,
lunchSetDishes: set.lunchSetDishes,
},
};
dispatch(showBackdrop());
axios({
method: "POST",
url: backend + "/restaurant/lunchSet",
data: data,
headers: {
"x-auth-token": token,
},
})
.then((response) => {
dispatch(hideBackdrop());
dispatch(notification("Zmieniono zestaw.", "success"));
dispatch(refreshUserData(token));
})
.catch((error) => {
dispatch(hideBackdrop());
dispatch(notification("Wystąpił błąd.", "error"));
});
} else {
dispatch(notification("Popraw dane.", "error"));
}
};
// COMPONENT
return ( return (
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<YesNo open={open} cancel={onCancel} accept={onAccept} /> <YesNo open={open} cancel={onCancel} accept={onAccept} />
@@ -82,13 +181,41 @@ export default function EditCategoriesList(props) {
</AccordionSummary> </AccordionSummary>
<div className="editRestaurant-addCategory"> <div className="editRestaurant-addCategory">
<TextField <TextField
className={classes.textInputFullWidth} className={classes.textInputWide}
value={newSet} value={newSet.lunchSetName}
onChange={(event) => setNewSet(event.target.value)} onChange={(event) =>
setNewSet({ ...newSet, lunchSetName: event.target.value })
}
label="Nazwa zestawu" label="Nazwa zestawu"
variant="outlined" variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<TextFieldsIcon color="primary" />
</InputAdornment>
),
}}
></TextField> ></TextField>
<ButtonSecondary onClick={() => {}} text="Dodaj" /> <TextField
className={classes.textInput}
value={newSet.lunchSetPrice}
onChange={(event) =>
setNewSet({ ...newSet, lunchSetPrice: event.target.value })
}
label="Cena"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AttachMoneyIcon color="primary" />
</InputAdornment>
),
}}
></TextField>
<ButtonSecondary
onClick={() => sendForm("add", newSet)}
text="Dodaj"
/>
</div> </div>
</Accordion> </Accordion>
</div> </div>

View File

@@ -0,0 +1,57 @@
import React from "react";
import TextField from "@material-ui/core/TextField";
import Checkbox from "@material-ui/core/Checkbox";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import { makeStyles } from "@material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
timePicker: {
"& .MuiInputBase-root": {
color: "#bbbbbb",
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
},
},
checkbox: {
marginLeft: theme.spacing(1),
"& .MuiFormControlLabel-label": {
color: "#979797",
fontSize: "14px",
},
},
}));
export default function InputWorkingHoursSingle(props) {
const handleChangeValue = (event) => {
props.changeValue(event.target.value);
};
const handleCheckbox = () => {
if (!props.off) {
props.changeValue("");
} else {
props.changeValue("13:00 - 15:00");
}
};
const classes = useStyles();
return (
<div className="workingHours-day">
<h5>Lunch menu</h5>
<TextField
value={props.hours}
variant="outlined"
onChange={handleChangeValue}
className={classes.timePicker}
margin="dense"
/>
<FormControlLabel
className={classes.checkbox}
control={
<Checkbox onClick={handleCheckbox} checked={props.off} name="brak" />
}
label="Wyłącz"
/>
</div>
);
}

View File

@@ -9,6 +9,7 @@ import EditDishList from "./EditDishList";
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import YesNo from "../Dialogs/YesNo"; import YesNo from "../Dialogs/YesNo";
import { notification } from "../../actions"; import { notification } from "../../actions";
import Tooltip from "@material-ui/core/Tooltip";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
root: { root: {
@@ -75,6 +76,7 @@ export default function EditCategoriesList(props) {
> >
<h4>{category}</h4> <h4>{category}</h4>
<div className="editRestaurant-categorySpan"> <div className="editRestaurant-categorySpan">
<Tooltip title="Usuń">
<IconButton <IconButton
color="primary" color="primary"
component="span" component="span"
@@ -82,9 +84,14 @@ export default function EditCategoriesList(props) {
> >
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
</Tooltip>
</div> </div>
</AccordionSummary> </AccordionSummary>
<EditDishList restaurantId={props.restaurantId} category={category} /> <EditDishList
restaurantId={props.restaurantId}
lunchMenu={props.lunchMenu}
category={category}
/>
</Accordion> </Accordion>
); );
}); });

View File

@@ -11,9 +11,14 @@ import axios from "axios";
import { backend } from "../../config"; import { backend } from "../../config";
import YesNo from "../Dialogs/YesNo"; import YesNo from "../Dialogs/YesNo";
import { notification, fetchAllDishes } from "../../actions"; import { notification, fetchAllDishes } from "../../actions";
import Tooltip from "@material-ui/core/Tooltip";
import FastfoodIcon from "@material-ui/icons/Fastfood";
import AddToSet from "../Dialogs/AddToSet";
import { hideBackdrop, showBackdrop } from "../../actions/toggles";
export default function EditDishList(props) { export default function EditDishList(props) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [setListOpen, setSetListOpen] = useState(false);
const [selectedDish, setDish] = useState(""); const [selectedDish, setDish] = useState("");
const history = useHistory(); const history = useHistory();
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -80,6 +85,38 @@ export default function EditDishList(props) {
}); });
}; };
const handleAddToSet = (dishId) => {
setDish(dishId);
setSetListOpen(true);
};
const addToSet = (setName) => {
setSetListOpen(false);
const data = {
setName: setName,
restaurantId: props.restaurantId,
dishId: selectedDish,
action: "add",
};
dispatch(showBackdrop());
axios({
method: "POST",
url: backend + "/restaurant/lunch",
data: data,
headers: {
"x-auth-token": token,
},
})
.then((response) => {
dispatch(hideBackdrop());
dispatch(notification("Dodano do zestawu.", "success"));
})
.catch((error) => {
dispatch(hideBackdrop());
dispatch(notification("Wystąpił błąd.", "error"));
});
};
const allDishes = useSelector((state) => state.dishes); const allDishes = useSelector((state) => state.dishes);
const thisCategoryDishes = filterDishes(allDishes, props.category); const thisCategoryDishes = filterDishes(allDishes, props.category);
const Dishes = thisCategoryDishes.map((dish) => { const Dishes = thisCategoryDishes.map((dish) => {
@@ -98,10 +135,13 @@ export default function EditDishList(props) {
<h3>{dish.name}</h3> <h3>{dish.name}</h3>
</div> </div>
<div className="editRestaurant-dishRight"> <div className="editRestaurant-dishRight">
<Tooltip title="Widoczność">
<Switch <Switch
checked={!dish.hidden} checked={!dish.hidden}
onClick={() => handleSetDishVisibility(dish._id, dish.hidden)} onClick={() => handleSetDishVisibility(dish._id, dish.hidden)}
/> />
</Tooltip>
<Tooltip title="Usuń">
<IconButton <IconButton
color="primary" color="primary"
component="span" component="span"
@@ -109,6 +149,8 @@ export default function EditDishList(props) {
> >
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
</Tooltip>
<Tooltip title="Edytuj">
<IconButton <IconButton
color="primary" color="primary"
component="span" component="span"
@@ -116,6 +158,16 @@ export default function EditDishList(props) {
> >
<EditIcon /> <EditIcon />
</IconButton> </IconButton>
</Tooltip>
<Tooltip title="Dodaj do zestawu">
<IconButton
color="primary"
component="span"
onClick={() => handleAddToSet(dish._id)}
>
<FastfoodIcon />
</IconButton>
</Tooltip>
</div> </div>
</div> </div>
</ListItem> </ListItem>
@@ -125,6 +177,12 @@ export default function EditDishList(props) {
return ( return (
<List> <List>
<YesNo open={open} cancel={onCancel} accept={onAccept} /> <YesNo open={open} cancel={onCancel} accept={onAccept} />
<AddToSet
lunchMenu={props.lunchMenu}
open={setListOpen}
cancel={() => setSetListOpen(false)}
add={(setName) => addToSet(setName)}
/>
{thisCategoryDishes.length === 0 ? ( {thisCategoryDishes.length === 0 ? (
<ListItem style={{ marginLeft: "14px", fontSize: "12px" }}> <ListItem style={{ marginLeft: "14px", fontSize: "12px" }}>
Kategoria pusta Kategoria pusta