Cleanup / Update

This commit is contained in:
2023-03-27 18:45:42 +02:00
parent 5ca5d0d0b9
commit 82e829271c
46 changed files with 7768 additions and 5893 deletions

11623
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,15 +15,15 @@
"@testing-library/user-event": "^7.2.1",
"@types/jest": "^28.1.6",
"@types/node": "^18.0.6",
"@types/react": "^17.0.47",
"@types/react-dom": "^18.0.6",
"@types/react": "^18.0.29",
"@types/react-dom": "^18.0.11",
"axios": "^0.21.1",
"connected-react-router": "^6.8.0",
"dotenv": "^16.0.1",
"node-sass": "^7.0.1",
"node-sass": "^8.0.0",
"notistack": "^1.0.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "^5.0.1",
"redux": "^4.0.5",

View File

@@ -10,13 +10,9 @@ import Footer from "./components/Output/Footer";
import SearchResults from "./components/Output/SearchResults";
import Restaurant from "./components/Output/Restaurant";
import Dialogs from "./components/Dialogs";
import { createMuiTheme, ThemeProvider } from "@material-ui/core/styles";
import LoginDialog from "./components/Dialogs/LoginDialog";
import { ThemeProvider, createTheme } from "@material-ui/core/styles";
import NewRestaurant from "./components/Dialogs/NewRestaurant";
import RegisterDialog from "./components/Dialogs/RegisterDialog";
import ForgotPassword from "./components/Dialogs/ForgotPassword";
import ResetPassword from "./components/Dialogs/ResetPassword";
import Contact from "./components/Output/Contact";
import Settings from "./components/Dialogs/Settings";
import EditRestaurant from "./components/Dialogs/EditRestaurant";
import NewDish from "./components/Dialogs/NewDish";
@@ -24,9 +20,8 @@ import EditDish from "./components/Dialogs/EditDish";
import Dish from "./components/Dialogs/Dish";
import HomeScreen from "./components/Output/HomeScreen";
import Cookies from "./components/Dialogs/Cookies";
import PrivacyPolicy from "./components/Output/PrivacyPolicy"
const theme = createMuiTheme({
const theme = createTheme({
palette: {
primary: {
main: "#d68000",
@@ -61,7 +56,7 @@ function App(props) {
<Route exact path="/">
<HomeScreen/>
</Route>
<Route path="/results">
<Route path="/search/:query">
<SearchResults />
</Route>
<Route path="/restaurant/:id">
@@ -74,18 +69,9 @@ function App(props) {
<Route path="/dish/:id">
<Dish />
</Route>
<Route path="/login">
<LoginDialog />
</Route>
<Route path="/register">
<RegisterDialog />
</Route>
<Route path="/kontakt">
<Contact />
</Route>
<Route path="/privacy">
<PrivacyPolicy />
</Route>
<PrivateRoute
path="/newRestaurant"
component={<NewRestaurant />}
@@ -96,12 +82,6 @@ function App(props) {
component={<EditRestaurant />}
/>
<PrivateRoute path="/editDish/:id" component={<EditDish />} />
<Route path="/forgotpassword">
<ForgotPassword />
</Route>
<Route path="/resetpassword">
<ResetPassword />
</Route>
</Switch>
</div>
<Dialogs />

View File

@@ -1,10 +1,11 @@
import axios from "axios";
import { push } from "connected-react-router";
import { backend } from "../config.js";
import store from "../index.js";
import * as restaurant from "../redux/slices/restaurantSlice";
import * as toggle from "../redux/slices/togglesSlice";
import * as notifications from "../redux/slices/notificationsSlice";
import store from "../redux/store.ts";
import * as restaurant from "../redux/slices/restaurantSlice.ts";
import * as view from "../redux/slices/viewDataSlice.ts";
import * as notifications from "../redux/slices/notificationsSlice.ts";
import * as user from "../redux/slices/userSlice.ts";
axios.defaults.withCredentials = true;
@@ -13,74 +14,10 @@ axios.interceptors.response.use(
return response;
},
(error) => {
return new Promise((resolve) => {
if (
error.response &&
error.response.status === 401 &&
error.config &&
!error.config.__isRetryRequest
) {
const response = axios
.post(backend + "user/refreshtoken", { withCredentials: true })
.then((res) => {
const jwt = res.headers["x-auth-token"];
store.dispatch(setNewToken(jwt));
error.config.__isRetryRequest = true;
error.config.headers["x-auth-token"] = jwt;
return axios(error.config);
});
resolve(response);
} else {
if (error.response && error.response.status === 403) {
store.dispatch(
logout("Podany użytkownik, lub hasło nie istnieje.", "error")
);
} else if (error.response && error.response.status === 400) {
store.dispatch(logout("Dane nieprawidłowe.", "error"));
} else {
store.dispatch(logout("Sesja wygasła", "info"));
}
}
});
store.dispatch(notification("Wystąpił błąd, przepraszamy.", "error"));
}
);
const autocomplete = (input) => {
return {
type: "AUTOCOMPLETE_ADD",
payload: input,
};
};
export const clearAutocomplete = () => {
return {
type: "AUTOCOMPLETE_CLEAR",
};
};
export const setNewToken = (token) => {
return {
type: "SET_NEW_TOKEN",
payload: token,
};
};
export const fetchAutocomplete = (input) => {
return function (dispatch) {
axios
.get(backend + "search/autocomplete?string=" + encodeURI(input))
.then((response) => {
const cities = Array.from(response.data.cities);
const restaurants = Array.from(response.data.restaurants);
const options = cities.concat(restaurants);
dispatch(autocomplete(options));
})
.catch((err) => {
console.log(err);
});
};
};
export const fetchSearch = (input) => {
return function (dispatch) {
axios
@@ -88,7 +25,7 @@ export const fetchSearch = (input) => {
.then((response) => {
const data = response.data;
if (Object.keys(data).length > 0) {
dispatch(setSearchResults(data));
dispatch(view.setSearchResults(data));
dispatch(push("/results"));
}
})
@@ -98,27 +35,12 @@ export const fetchSearch = (input) => {
};
};
const setSearchResults = (input) => {
return {
type: "SEARCH_RESULTS",
payload: input,
};
};
export const setSearchQuery = (input) => {
return {
type: "SEARCH_QUERY_SET",
payload: input,
};
};
export const fetchRestaurant = (id) => {
return function (dispatch) {
axios
.get(backend + "restaurant?restaurantId=" + id)
.then((response) => {
dispatch(restaurant.setRestaurant(response.data));
dispatch(toggle.hideDishes());
dispatch(fetchAllDishes(id));
})
.catch((err) =>
@@ -127,27 +49,12 @@ export const fetchRestaurant = (id) => {
};
};
const setDishes = (data) => {
return {
type: "SET_DISHES",
payload: data,
};
};
const setDish = (data) => {
return {
type: "SET_DISH",
payload: data,
};
};
export const fetchAllDishes = (id) => {
return function (dispatch) {
axios
.get(backend + "restaurant/dishes?restaurantId=" + id)
.then((response) => {
dispatch(setDishes(response.data));
dispatch(toggle.showDishes());
dispatch(view.setDishes(response.data));
});
};
};
@@ -157,43 +64,30 @@ export const fetchDish = (id) => {
axios
.get(backend + "dish/?dishId=" + id)
.then((response) => {
dispatch(setDish(response.data));
//dispatch(setDish(response.data));
})
.catch((err) => {
dispatch(notification("Nie udało się pobrać :(", "error"));
dispatch(push("/"));
});
};
};
export const refreshUserData = () => {
return function (dispatch) {
const state = store.getState();
axios({
url: backend + "user/refresh",
method: "POST",
headers: {
"x-auth-token": state.data.userData.jwt,
"x-auth-token": "",
},
})
.then((response) => {
dispatch(
toggle.setLoggedIn(
response.data.firstname,
response.data.lastname,
state.data.userData.jwt,
response.data.id,
response.data.email,
response.data.NIP,
response.data.adress,
response.data.companyName,
response.data.restaurants
)
);
console.log(response.data);
dispatch(user.setUserData(response.data));
})
.catch((err) => {
if (err.status === 401 || err.status === 500) {
dispatch(logout());
dispatch(notification("Nie udało się pobrać danych.", "error"));
}
console.log(err);
});
@@ -203,7 +97,7 @@ export const refreshUserData = () => {
export const notification = (message, type) => {
return function (dispatch) {
dispatch(
toggle.enqueueSnackbar({
notifications.addNotification({
message: message,
options: {
key: new Date().getTime() + Math.random(),
@@ -213,24 +107,3 @@ export const notification = (message, type) => {
);
};
};
export const updateRestaurant = (restaurant) => {
return {
type: "UPDATE_RESTAURANT",
payload: restaurant,
};
};
export const setTags = (tags) => {
return {
type: "SET_TAGS",
payload: tags,
};
};
export const setTypes = (types) => {
return {
type: "SET_TYPES",
payload: types,
};
};

View File

@@ -1,48 +0,0 @@
export const setLoggedIn = (
firstname,
lastname,
jwt,
userId,
email,
login,
NIP,
adress,
companyName,
restaurants,
isRestaurant
) => {
return {
type: "SET_LOGGEDIN",
payload: {
firstname: firstname,
lastname: lastname,
jwt: jwt,
userId: userId,
email: email,
login: login,
NIP: NIP,
adress: adress,
companyName: companyName,
restaurants: restaurants,
isRestaurant: isRestaurant,
},
};
};
export const setLoggedOut = () => {
return {
type: "SET_LOGGEDOUT",
};
};
export const enqueueSnackbar = (notification) => {
const key = notification.options && notification.options.key;
return {
type: "ENQUEUE_SNACKBAR",
notification: {
...notification,
key: key || new Date().getTime() + Math.random(),
},
};
};

View File

@@ -1,116 +0,0 @@
import React, { useState } 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";
import AddIcon from '@material-ui/icons/Add';
import RemoveIcon from '@material-ui/icons/Remove';
import ButtonPrimary from "../Input/ButtonPrimary";
import ButtonSecondary from "../Input/ButtonSecondary";
export default function AddToSet(props) {
const [quantity, setQuantity] = useState(1);
const [selectedSet, setName] = useState("");
const loginStyles = makeStyles((theme) => ({
root: {
textAlign: "center",
"& .MuiPaper-root": {
backgroundColor: "#262626",
color: "#bbbbbb",
minWidth: "360px",
borderRadius: "24px"
},
zIndex: "5 !important"
},
closeButton: {
color: "#bbbbbb",
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
},
set: {
width: "100%",
"& .Mui-selected": {
backgroundColor: "#b46c00",
},
"& .MuiListItem-root": {
borderRadius: "12px"
}
},
quantity: {
width: "100%",
display: "flex",
justifyContent: "center"
},
h4: {
margin: "12px auto 12px auto"
}
}));
const loginClass = loginStyles();
const Sets = props.lunchMenu.map((lunchSet) => {
return (
<ListItem
button
key={lunchSet.lunchSetName}
onClick={() => setName(lunchSet.lunchSetName)}
selected={selectedSet === lunchSet.lunchSetName}
>
<ListItemText primary={lunchSet.lunchSetName} />
</ListItem>
);
});
const increment = () => {
setQuantity(quantity + 1);
}
const decrement = () => {
if(quantity > 1){
setQuantity(quantity - 1);
}
}
return (
<Dialog
className={loginClass.root}
onClose={props.cancel}
open={props.open}
aria-labelledby="login-title"
>
<DialogTitle id="login-title">Dodaj do zestawu</DialogTitle>
<IconButton
className={loginClass.closeButton}
onClick={props.cancel}
aria-label="close"
>
<CloseIcon />
</IconButton>
<Divider />
<DialogContent>
<h4 className={loginClass.h4}>Ilość</h4>
<div className={loginClass.quantity}>
<IconButton onClick={decrement}>
<RemoveIcon/>
</IconButton>
<h3>{quantity}</h3>
<IconButton onClick={increment}>
<AddIcon/>
</IconButton>
</div>
<h4 className={loginClass.h4}>Zestaw</h4>
<List className={loginClass.set}>{Sets}</List>
<Divider />
<ButtonPrimary text="Anuluj" onClick={() => props.cancel()}/>
<ButtonSecondary disabled={!(selectedSet.length > 0)} text="Dodaj" onClick={() => props.add(selectedSet, quantity)}/>
</DialogContent>
</Dialog>
);
}

View File

@@ -11,7 +11,7 @@ import FitnessCenterIcon from "@material-ui/icons/FitnessCenter";
import LocalHospitalIcon from "@material-ui/icons/LocalHospital";
import FavoriteBorderIcon from "@material-ui/icons/FavoriteBorder";
import { notification, refreshUserData } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
import { showBackdrop, hideBackdrop } from "../../redux/slices/viewDataSlice.ts";
import InputLabel from "@material-ui/core/InputLabel";
import InputAdornment from "@material-ui/core/InputAdornment";
import Checkboxes from "../Input/Checkboxes";

View File

@@ -1,148 +0,0 @@
import React, { useState, useEffect } 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 ButtonSecondary from "../Input/ButtonSecondary";
import IconButton from "@material-ui/core/IconButton";
import TextField from "@material-ui/core/TextField";
import CloseIcon from "@material-ui/icons/Close";
import { useDispatch } from "react-redux";
import Link from "@material-ui/core/Link";
import validator from "validator";
import InputAdornment from "@material-ui/core/InputAdornment";
import AccountCircle from "@material-ui/icons/AccountCircle";
import { remindPassword, notification } from "../../actions";
import { useHistory } from "react-router-dom";
export default function ForgotPassword(props) {
useEffect(() => {
document.title = "Menui - Odzyskiwanie hasła";
});
const initialData = {
email: "",
emailError: false,
};
const [data, setData] = useState(initialData);
const dispatch = useDispatch();
const history = useHistory();
const loginStyles = makeStyles((theme) => ({
root: {
zIndex: "5 !important",
textAlign: "center",
"& .MuiPaper-root": {
backgroundColor: "#262626",
color: "#bbbbbb",
borderRadius: "24px"
},
},
closeButton: {
color: "#bbbbbb",
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
},
textInput: {
marginTop: "20px",
marginBottom: "10px",
width: "90%",
"& .MuiInputBase-root": {
color: "#01c3a9",
borderRadius: "14px"
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
},
},
link: {
fontSize: "0.9rem",
},
}));
const loginClass = loginStyles();
const validateLogin = () => {
var valid;
var validation = {
email: validator.isEmail(data.email),
};
setData({
...data,
emailError: !validation.email,
});
valid = validation.email;
return valid;
};
const handleRemind = () => {
if (validateLogin()) {
dispatch(remindPassword(data.email));
} else {
dispatch(notification("Podaj poprawne dane.", "error"));
}
};
// CODE
return (
<div>
<Dialog
className={loginClass.root}
onClose={() => history.push("/")}
open={true}
aria-labelledby="login-title"
>
<DialogTitle id="login-title">Odzyskiwanie hasła</DialogTitle>
<IconButton
className={loginClass.closeButton}
onClick={() => history.push("/")}
aria-label="close"
>
<CloseIcon />
</IconButton>
<Divider />
<DialogContent>
<p>
Podaj adres email do swojego konta. Link do zmiany hasła powinien
dotrzeć do Ciebie w ciągu maksymalnie 15 minut (sprawdź również
folder SPAM). Jeśli nie pamiętasz również adresu email, skontaktuj
się z obsługą klienta.
</p>
<TextField
className={loginClass.textInput}
required
id="email"
label="Email"
type="email"
variant="outlined"
error={data.emailError}
onChange={(event) => (data.email = event.target.value)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle color="primary" />
</InputAdornment>
),
}}
/>
<div className="login-dialog-buttons">
<ButtonSecondary
onClick={() => handleRemind()}
text="Wyślij email"
/>
</div>
<p>
Nie masz konta?{" "}
<span>
<Link href="#" onClick={() => history.push("/register")}>
Zarejestruj się.
</Link>
</span>
</p>
</DialogContent>
</Dialog>
</div>
);
}

View File

@@ -1,169 +0,0 @@
import React, { useState, useEffect } 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 ButtonSecondary from "../Input/ButtonSecondary";
import IconButton from "@material-ui/core/IconButton";
import TextField from "@material-ui/core/TextField";
import CloseIcon from "@material-ui/icons/Close";
import { useDispatch } from "react-redux";
import Link from "@material-ui/core/Link";
import LockIcon from "@material-ui/icons/Lock";
import validator from "validator";
import InputAdornment from "@material-ui/core/InputAdornment";
import AccountCircle from "@material-ui/icons/AccountCircle";
import { tryLogin, notification } from "../../actions";
import { useHistory } from "react-router-dom";
export default function LoginDialog(props) {
useEffect(() => {
document.title = "Menui - Logowanie";
});
const initialData = {
email: "",
password: "",
emailError: false,
passwordError: false,
};
const [loginData, setLoginData] = useState(initialData);
const dispatch = useDispatch();
const history = useHistory();
const loginStyles = makeStyles((theme) => ({
root: {
textAlign: "center",
"& .MuiPaper-root": {
backgroundColor: "#262626",
color: "#bbbbbb",
borderRadius: "24px"
},
zIndex: "5 !important"
},
closeButton: {
color: "#bbbbbb",
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
},
textInput: {
marginTop: "20px",
marginBottom: "10px",
width: "90%",
"& .MuiInputBase-root": {
color: "#01c3a9",
borderRadius: "14px"
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
},
},
link: {
fontSize: "0.9rem",
},
}));
const loginClass = loginStyles();
const validateLogin = () => {
var valid;
var validation = {
email: validator.isEmail(loginData.email),
password: !validator.isEmpty(loginData.password),
};
setLoginData({
...loginData,
emailError: !validation.email,
passwordError: !validation.password,
});
valid = validation.email && validation.password;
return valid;
};
const handleLogin = () => {
if (validateLogin()) {
dispatch(tryLogin(loginData.email, loginData.password));
} else {
dispatch(notification("Podaj poprawne dane logowania.", "error"));
}
};
// CODE
return (
<div>
<Dialog
className={loginClass.root}
onClose={() => history.push("/")}
open={true}
aria-labelledby="login-title"
>
<DialogTitle id="login-title">Logowanie</DialogTitle>
<IconButton
className={loginClass.closeButton}
onClick={() => history.push("/")}
aria-label="close"
>
<CloseIcon />
</IconButton>
<Divider />
<DialogContent>
<TextField
className={loginClass.textInput}
required
id="email"
label="Email"
type="email"
variant="outlined"
error={loginData.emailError}
onChange={(event) => (loginData.email = event.target.value)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle color="primary" />
</InputAdornment>
),
}}
/>
<TextField
className={loginClass.textInput}
required
id="password"
label="Hasło"
type="password"
variant="outlined"
error={loginData.passwordError}
onChange={(event) => (loginData.password = event.target.value)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<LockIcon color="primary" />
</InputAdornment>
),
}}
/>
<div className="login-dialog-buttons">
<ButtonSecondary onClick={() => handleLogin()} text="Zaloguj" />
</div>
<Link
className={loginClass.link}
href="#"
onClick={() => history.push("/forgotpassword")}
>
Nie pamiętam hasła.
</Link>
<p>
Nie masz konta?{" "}
<span>
<Link href="#" onClick={() => history.push("/register")}>
Zarejestruj się.
</Link>
</span>
</p>
</DialogContent>
</Dialog>
</div>
);
}

View File

@@ -18,7 +18,7 @@ import { useHistory, useParams } from "react-router-dom";
import axios from "axios";
import { useSelector, useDispatch } from "react-redux";
import { notification, refreshUserData } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
import { showBackdrop, hideBackdrop } from "../../redux/slices/viewDataSlice.ts";
import InputLabel from "@material-ui/core/InputLabel";
import InputAdornment from "@material-ui/core/InputAdornment";
import Checkboxes from "../Input/Checkboxes";

View File

@@ -22,9 +22,8 @@ import { prepareTags } from "../../Services.js";
import axios from "axios";
import { useSelector, useDispatch } from "react-redux";
import { notification, refreshUserData } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
import { showBackdrop, hideBackdrop } from "../../redux/slices/viewDataSlice.ts";
import InputWorkingHours from "../Input/InputWorkingHours";
import InputLunchMenuHours from "../Input/InputLunchMenuHours";
import { backend, restaurantTypes } from "../../config";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";

View File

@@ -1,89 +0,0 @@
import React, { useState } 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 ButtonSecondary from "../Input/ButtonSecondary";
import IconButton from "@material-ui/core/IconButton";
import TextField from "@material-ui/core/TextField";
import CloseIcon from "@material-ui/icons/Close";
import LockIcon from "@material-ui/icons/Lock";
import InputAdornment from "@material-ui/core/InputAdornment";
export default function PasswordConfirmation(props) {
const [password, setPassword] = useState("");
const loginStyles = makeStyles((theme) => ({
root: {
zIndex: "5 !important",
textAlign: "center",
"& .MuiPaper-root": {
backgroundColor: "#262626",
color: "#bbbbbb",
},
},
closeButton: {
color: "#bbbbbb",
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
},
textInput: {
marginTop: "20px",
marginBottom: "10px",
width: "90%",
"& .MuiInputBase-root": {
color: "#01c3a9",
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
},
},
}));
const loginClass = loginStyles();
return (
<Dialog
className={loginClass.root}
onClose={props.onCancel}
open={props.open}
aria-labelledby="login-title"
>
<DialogTitle id="login-title">Potwierdź hasłem</DialogTitle>
<IconButton
className={loginClass.closeButton}
onClick={props.onCancel}
aria-label="close"
>
<CloseIcon />
</IconButton>
<Divider />
<DialogContent>
<TextField
className={loginClass.textInput}
id="password"
label="Hasło"
type="password"
value={password}
variant="outlined"
onChange={(event) => setPassword(event.target.value)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<LockIcon color="primary" />
</InputAdornment>
),
}}
/>
<div className="login-dialog-buttons">
<ButtonSecondary
onClick={() => props.onSubmit(password)}
text="Potwierdź"
/>
</div>
</DialogContent>
</Dialog>
);
}

View File

@@ -9,8 +9,6 @@ import IconButton from "@material-ui/core/IconButton";
import TextField from "@material-ui/core/TextField";
import CloseIcon from "@material-ui/icons/Close";
import { useDispatch } from "react-redux";
import { showRegulamin } from "../../actions/toggles";
import { tryRegister, notification } from "../../actions";
import InputAdornment from "@material-ui/core/InputAdornment";
import AccountCircle from "@material-ui/icons/AccountCircle";
import BusinessIcon from "@material-ui/icons/Business";

View File

@@ -9,7 +9,7 @@ import CloseIcon from "@material-ui/icons/Close";
import Paper from "@material-ui/core/Paper";
import Regulamin from "./Regulamin";
import { useSelector, useDispatch } from "react-redux";
import { hideRegulamin } from "../../actions/toggles";
//import { hideRegulamin } from "../../actions/toggles";
export default function RegulaminDialog(props) {
const dispatch = useDispatch();

View File

@@ -1,178 +0,0 @@
import React, { useState, useEffect } 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 ButtonSecondary from "../Input/ButtonSecondary";
import IconButton from "@material-ui/core/IconButton";
import TextField from "@material-ui/core/TextField";
import CloseIcon from "@material-ui/icons/Close";
import { useDispatch } from "react-redux";
import validator from "validator";
import InputAdornment from "@material-ui/core/InputAdornment";
import AccountCircle from "@material-ui/icons/AccountCircle";
import { useHistory, useLocation } from "react-router-dom";
import { changePassword, notification } from "../../actions/index";
function useQuery() {
return new URLSearchParams(useLocation().search);
}
export default function ResetPassword(props) {
useEffect(() => {
document.title = "Menui - Resetowanie hasła";
});
const initialData = {
email: "",
emailError: false,
password: "",
passwordError: false,
passwordRepeat: "",
passwordRepeatError: false,
};
const [data, setData] = useState(initialData);
const dispatch = useDispatch();
const history = useHistory();
const query = useQuery();
const token = query.get("token");
const loginStyles = makeStyles((theme) => ({
root: {
zIndex: "5 !important",
textAlign: "center",
"& .MuiPaper-root": {
backgroundColor: "#262626",
color: "#bbbbbb",
},
},
closeButton: {
color: "#bbbbbb",
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
},
textInput: {
marginTop: "20px",
marginBottom: "10px",
width: "90%",
"& .MuiInputBase-root": {
color: "#01c3a9",
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
},
},
link: {
fontSize: "0.9rem",
},
}));
const loginClass = loginStyles();
const validateLogin = () => {
var valid;
var validation = {
email: validator.isEmail(data.email),
password: validator.isLength(data.password, { min: 6 }),
passwordRepeat: data.passwordRepeat === data.password,
};
setData({
...data,
emailError: !validation.email,
passwordError: !validation.password,
passwordRepeatError: !validation.passwordRepeat,
});
valid =
validation.password && validation.passwordRepeat && validation.email;
return valid;
};
const handleReset = () => {
if (validateLogin()) {
dispatch(changePassword(data.email, data.password, token));
} else {
dispatch(notification("Popraw dane.", "error"));
}
};
// CODE
return (
<div>
<Dialog
className={loginClass.root}
onClose={() => history.push("/")}
open={true}
aria-labelledby="login-title"
>
<DialogTitle id="login-title">Ustaw nowe hasło</DialogTitle>
<IconButton
className={loginClass.closeButton}
onClick={() => history.push("/")}
aria-label="close"
>
<CloseIcon />
</IconButton>
<Divider />
<DialogContent>
<p>Podaj nowe bezpieczne hasło do konta.</p>
<TextField
className={loginClass.textInput}
required
id="email"
label="Email"
type="email"
variant="outlined"
error={data.emailError}
onChange={(event) => (data.email = event.target.value)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle color="primary" />
</InputAdornment>
),
}}
/>
<TextField
className={loginClass.textInput}
required
id="password"
label="Nowe hasło"
type="password"
variant="outlined"
error={data.passwordError}
onChange={(event) => (data.password = event.target.value)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle color="primary" />
</InputAdornment>
),
}}
/>
<TextField
className={loginClass.textInput}
required
id="passwordRepeat"
label="Powtórz nowe hasło"
type="password"
variant="outlined"
error={data.passwordRepeatError}
onChange={(event) => (data.passwordRepeat = event.target.value)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle color="primary" />
</InputAdornment>
),
}}
/>
<div className="login-dialog-buttons">
<ButtonSecondary onClick={() => handleReset()} text="Zmień hasło" />
</div>
</DialogContent>
</Dialog>
</div>
);
}

View File

@@ -17,25 +17,24 @@ import Divider from "@material-ui/core/Divider";
import { decodeTags } from "../../Services";
import validator from "validator";
import { useSelector, useDispatch } from "react-redux";
import { notification, refreshUserData, updateRestaurant } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
import { notification, refreshUserData } from "../../actions";
import { updateRestaurant } from "../../redux/slices/userSlice.ts";
import { showBackdrop, hideBackdrop } from "../../redux/slices/viewDataSlice.ts";
import { prepareTags } from "../../Services.js";
import axios from "axios";
import PasswordConfirmation from "../Dialogs/PasswordConfirmation";
import { backend, restaurantTypes } from "../../config";
import InputLunchMenuHours from "../Input/InputLunchMenuHours";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Select from "@material-ui/core/Select";
import InputLabel from "@material-ui/core/InputLabel";
import Switch from '@material-ui/core/Switch';
import Switch from "@material-ui/core/Switch";
const useStyles = makeStyles((theme) => ({
textInput: {
margin: theme.spacing(2),
"& .MuiInputBase-root": {
color: "#bbbbbb",
borderRadius: "14px"
borderRadius: "14px",
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
@@ -46,7 +45,7 @@ const useStyles = makeStyles((theme) => ({
marginBottom: theme.spacing(2),
"& .MuiInputBase-root": {
color: "#bbbbbb",
borderRadius: "14px"
borderRadius: "14px",
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
@@ -65,7 +64,7 @@ const useStyles = makeStyles((theme) => ({
maxHeight: 400,
"& .MuiInputBase-root": {
color: "#bbbbbb",
borderRadius: "14px"
borderRadius: "14px",
},
"$ .MuiSelect-root": {
color: "#bbbbbb",
@@ -102,7 +101,7 @@ export default function EditRestaurantInfo(props) {
cityError: false,
adressError: false,
descriptionError: false,
typeError: false
typeError: false,
};
const [state, setState] = useState(initialState);
const [passwordDialog, setPasswordDialog] = useState(false);
@@ -113,10 +112,20 @@ export default function EditRestaurantInfo(props) {
const handleDescriptionChange = (event) => {
const stringLength = event.target.value.length;
const charleft = 400 - stringLength;
if(stringLength <= 400){
setState({ ...state, description: event.target.value, charleft: charleft, descriptionError: false });
if (stringLength <= 400) {
setState({
...state,
description: event.target.value,
charleft: charleft,
descriptionError: false,
});
} else {
setState({ ...state, description: event.target.value, charleft: charleft, descriptionError: true });
setState({
...state,
description: event.target.value,
charleft: charleft,
descriptionError: true,
});
}
};
const availableTags = [
@@ -159,7 +168,11 @@ export default function EditRestaurantInfo(props) {
};
const availableTypes = restaurantTypes.map((type) => {
return <MenuItem key={type} value={type}>{type}</MenuItem>
return (
<MenuItem key={type} value={type}>
{type}
</MenuItem>
);
});
const cancelChanges = () => {
@@ -173,7 +186,7 @@ export default function EditRestaurantInfo(props) {
method: "POST",
data: {
restaurantId: props.restaurant._id,
visible: state.hidden
visible: state.hidden,
},
headers: {
"x-auth-token": jwt,
@@ -191,7 +204,7 @@ export default function EditRestaurantInfo(props) {
dispatch(notification("Wystąpił błąd :(", "error"));
throw err;
});
}
};
const handleDelete = (password) => {
dispatch(showBackdrop());
@@ -223,7 +236,7 @@ export default function EditRestaurantInfo(props) {
const setLunchHours = (hours) => {
setState({ ...state, lunchHours: hours });
}
};
const handleSendForm = () => {
if (validateForm()) {
@@ -317,7 +330,9 @@ export default function EditRestaurantInfo(props) {
id="category"
value={state.type}
required
onChange={(event) => setState({ ...state, type: event.target.value })}
onChange={(event) =>
setState({ ...state, type: event.target.value })
}
>
{availableTypes}
</Select>
@@ -491,13 +506,18 @@ export default function EditRestaurantInfo(props) {
<Divider />
<div className="editRestaurant-settings">
<h4>Ukryj restaurację (nie wymaga zatwierdzania)</h4>
<Switch checked={state.hidden} color="primary" onChange={handleSetHidden}/>
<Switch
checked={state.hidden}
color="primary"
onChange={handleSetHidden}
/>
</div>
<div className="editRestaurant-settings">
<h4>
Usuń restaurację (operacja jest nieodwracalna!)
</h4>
<ButtonPrimary text="Usuń" onClick={() => setPasswordDialog(true)} />
<h4>Usuń restaurację (operacja jest nieodwracalna!)</h4>
<ButtonPrimary
text="Usuń"
onClick={() => setPasswordDialog(true)}
/>
</div>
</div>
</div>

View File

@@ -3,7 +3,7 @@ import InputGoogleMaps from "../Input/InputGoogleMaps";
import ButtonSecondary from "../Input/ButtonSecondary";
import { useDispatch, useSelector } from "react-redux";
import { notification } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
import { showBackdrop, hideBackdrop } from "../../redux/slices/viewDataSlice.ts";
import axios from "axios";
import { backend } from "../../config";

View File

@@ -10,11 +10,10 @@ 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 LunchMenu from "./LunchMenu";
import axios from "axios";
import EditCategoriesList from "../Output/EditCategoriesList";
import { notification, refreshUserData } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
//import { notification, refreshUserData } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../redux/slices/viewDataSlice.ts";
import { backend } from "../../config";
const useStyles = makeStyles((theme) => ({
@@ -145,11 +144,6 @@ export default function EditRestaurantMenu(props) {
<ButtonSecondary onClick={addCategory} text="Dodaj" />
</div>
</Accordion>
<div className="editRestaurant-sectiontitle">
<h4>Lunch menu</h4>
<Divider />
</div>
<LunchMenu restaurantId={props.restaurant._id} lunchMenu={lunchMenu} />
</div>
);
}

View File

@@ -3,8 +3,8 @@ import ImageUploadWide from "../Input/ImageUploadWide";
import ButtonSecondary from "../Input/ButtonSecondary";
import ButtonPrimary from "../Input/ButtonPrimary";
import { useDispatch, useSelector } from "react-redux";
import { notification, refreshUserData } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
//import { notification, refreshUserData } from "../../actions";
import { showBackdrop, hideBackdrop } from "../../redux/slices/viewDataSlice.ts";
import axios from "axios";
import { backend } from "../../config";

View File

@@ -1,229 +0,0 @@
import React, { useState } from "react";
import Accordion from "@material-ui/core/Accordion";
import AccordionSummary from "@material-ui/core/AccordionSummary";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete";
import { makeStyles } from "@material-ui/core/styles";
import YesNo from "../Dialogs/YesNo";
import ButtonSecondary from "../Input/ButtonSecondary";
import TextField from "@material-ui/core/TextField";
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";
import LunchSetDishList from "../Output/LunchSetDishList";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#262626",
color: "#bbbbbb",
width: "100%",
maxWidth: "800px",
},
expandIcon: {
color: "#bbbbbb",
},
textInput: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
"& .MuiInputBase-root": {
color: "#bbbbbb",
borderRadius: "14px"
},
"& .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,
"& .MuiInputBase-root": {
color: "#bbbbbb",
borderRadius: "14px"
},
"& .MuiInputLabel-root": {
color: "#bbbbbb",
},
"$ .MuiFormHelperText-root": {
color: "#bbbbbb",
},
},
}));
export default function EditCategoriesList(props) {
const dispatch = useDispatch();
const [open, setOpen] = useState(false);
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 handleDeleteButton = (set) => {
setSelectedSet(set);
setOpen(true);
};
const onCancel = () => {
setOpen(false);
};
const onAccept = () => {
sendForm("delete", selectedSet);
setOpen(false);
};
const SetList = props.lunchMenu.map((set) => {
return (
<Accordion key={set.id} className={classes.root}>
<AccordionSummary
expandIcon={<ExpandMoreIcon className={classes.expandIcon} />}
>
<h4>
{set.lunchSetName} ({set.lunchSetPrice})
</h4>
<div className="editRestaurant-categorySpan">
<Tooltip title="Usuń">
<IconButton
color="primary"
component="span"
onClick={() => handleDeleteButton(set)}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</div>
</AccordionSummary>
<LunchSetDishList lunchSet={set} restaurantId={props.restaurantId} />
</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());
})
.catch((error) => {
dispatch(hideBackdrop());
dispatch(notification("Wystąpił błąd.", "error"));
throw error;
});
} else {
dispatch(notification("Popraw dane.", "error"));
}
};
// COMPONENT
return (
<div style={{ width: "100%", display: "flex", flexFlow: "column", alignItems: "center" }}>
<YesNo open={open} cancel={onCancel} accept={onAccept} />
{props.lunchMenu.length === 0 ? <p>Lunch menu puste</p> : SetList}
<Accordion className={classes.root}>
<AccordionSummary
expandIcon={<AddIcon className={classes.expandIcon} />}
>
<h4>Dodaj zestaw</h4>
</AccordionSummary>
<div className="editRestaurant-addCategory">
<TextField
className={classes.textInputWide}
value={newSet.lunchSetName}
onChange={(event) =>
setNewSet({ ...newSet, lunchSetName: event.target.value })
}
label="Nazwa zestawu"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<TextFieldsIcon color="primary" />
</InputAdornment>
),
}}
></TextField>
<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>
</Accordion>
</div>
);
}

View File

@@ -1,62 +0,0 @@
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",
borderRadius: "14px"
},
"& .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.nieczynne) {
props.changeValue("");
} else {
props.changeValue("12:30 - 13:30");
}
};
const classes = useStyles();
return (
<div className="workingHours-day">
<h5>Lunch hours</h5>
<TextField
value={props.hours}
variant="outlined"
onChange={handleChangeValue}
className={classes.timePicker}
margin="dense"
/>
<FormControlLabel
className={classes.checkbox}
control={
<Checkbox
onClick={handleCheckbox}
checked={props.nieczynne}
name="nieczynne"
/>
}
label="Brak"
/>
</div>
);
}

View File

@@ -5,7 +5,7 @@ import SearchIcon from '@material-ui/icons/Search';
import TextField from "@material-ui/core/TextField";
import Autocomplete from "@material-ui/lab/Autocomplete";
import { useSelector, useDispatch } from "react-redux";
import { fetchAutocomplete, setSearchQuery, fetchSearch } from "../../actions";
import { fetchSearch } from "../../actions";
const useStyles = makeStyles((theme) => ({
root: {

View File

@@ -1,7 +1,7 @@
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { useSnackbar } from "notistack";
import { removeSnackbar } from "../actions/toggles.js";
import { removeNotification } from "../redux/slices/notificationsSlice.ts";
let displayed = [];

View File

@@ -13,8 +13,7 @@ import YesNo from "../Dialogs/YesNo";
import { notification, fetchAllDishes, refreshUserData } 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";
import { showBackdrop, hideBackdrop } from "../../redux/slices/viewDataSlice.ts";
export default function EditDishList(props) {
const [open, setOpen] = useState(false);

View File

@@ -1,33 +0,0 @@
import React from "react";
import { useHistory } from "react-router-dom";
import KeyboardArrowRightIcon from "@material-ui/icons/KeyboardArrowRight";
export default function LunchCardDish(props) {
const history = useHistory();
const {
name,
imgUrl,
_id,
} = props.dish;
return (
<div
className="carddish-container"
onClick={() => history.push(`/dish/${_id}`)}
>
<div className="carddish-left">
<h3>{props.quantity}x</h3>
<div
className="lunch-carddish-img"
style={{ backgroundImage: "url(" + imgUrl + ")" }}
/>
<div className="carddish-left-info">
<h2>{name}</h2>
</div>
</div>
<div className="lunch-carddish-right">
<KeyboardArrowRightIcon color="primary" />
</div>
</div>
);
}

View File

@@ -1,63 +0,0 @@
import React from "react";
import Accordion from "@material-ui/core/Accordion";
import AccordionSummary from "@material-ui/core/AccordionSummary";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import LunchCardDish from "./LunchCardDish";
import { makeStyles } from "@material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#262626",
color: "#bbbbbb",
"& .MuiListItem-gutters": {
padding: "2px"
},
},
expandIcon: {
color: "#bbbbbb",
},
}));
const filterDishes = (dishes, setDishes) => {
const ids = setDishes.map((dish) => {
return dish.dishId
})
let result = [];
dishes.map((dish) => {
if (ids.includes(dish._id)) {
const lunchSetDish = setDishes.filter((thisDish) => thisDish.dishId === dish._id)[0]
result.push({...dish, quantity: lunchSetDish.quantity});
}
return true;
});
return result;
};
export default function LunchDishesCategory(props) {
const classes = useStyles();
const dishes = props.dishes;
const filtered = filterDishes(dishes, props.lunchSetDishes)
const dishCards = filtered.map((dish) => {
return (
<ListItem key={dish._id}>
<LunchCardDish dish={dish} quantity={dish.quantity}></LunchCardDish>
</ListItem>
);
});
return (
<Accordion className={classes.root}>
<AccordionSummary
expandIcon={<ExpandMoreIcon className={classes.expandIcon} />}
>
<h4>
{props.name} <span>{props.price && `(${props.price}zł)`}</span>
</h4>
</AccordionSummary>
<List>{dishCards}</List>
</Accordion>
);
}

View File

@@ -1,27 +0,0 @@
import React from "react";
import LunchDishesCategory from "./LunchDishesCategory";
import { useSelector } from "react-redux";
export default function LunchMenu(props) {
const dishes = useSelector((state) => state.dishes)
const { restaurant } = props;
const lunchMenu = restaurant.lunchMenu;
const sets = lunchMenu.map((set) => {
if(set.lunchSetDishes.length > 0){
return (
<LunchDishesCategory
key={set.lunchSetName}
name={set.lunchSetName}
price={set.lunchSetPrice}
hidePrice={true}
lunchSetDishes={set.lunchSetDishes}
dishes={dishes}
/>
);
} else {
return <div key={set.lunchSetName}></div>;
}
});
return <div className="dishlist-container">{sets && sets}</div>;
}

View File

@@ -1,122 +0,0 @@
import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete";
import axios from "axios";
import { backend } from "../../config";
import YesNo from "../Dialogs/YesNo";
import { notification, refreshUserData } from "../../actions";
import Tooltip from "@material-ui/core/Tooltip";
import { hideBackdrop, showBackdrop } from "../../actions/toggles";
export default function EditDishList(props) {
const [open, setOpen] = useState(false);
const [selectedDish, setDish] = useState("");
const dispatch = useDispatch();
const token = useSelector((state) => state.data.userData.jwt);
const filterDishes = (dishes, setDishes) => {
const ids = setDishes.map((dish) => {
return dish.dishId
})
let result = [];
dishes.map((dish) => {
if (ids.includes(dish._id)) {
result.push(dish);
}
return true;
});
return result;
};
const selectDish = (dishId) => {
setDish(dishId);
setOpen(true);
};
const onCancel = () => {
setOpen(false);
};
const onAccept = () => {
setOpen(false);
removeFromSet();
};
const removeFromSet = () => {
const data = {
setName: props.lunchSet.lunchSetName,
restaurantId: props.restaurantId,
dishId: selectedDish,
action: "delete",
};
dispatch(showBackdrop());
axios({
method: "POST",
url: backend + "restaurant/lunch",
data: data,
headers: {
"x-auth-token": token,
},
})
.then((response) => {
dispatch(hideBackdrop());
dispatch(notification("Zmodyfikowano zestaw.", "success"));
dispatch(refreshUserData());
})
.catch((error) => {
dispatch(hideBackdrop());
dispatch(notification("Wystąpił błąd.", "error"));
});
};
const allDishes = useSelector((state) => state.dishes);
const thisSetDishes = filterDishes(allDishes, props.lunchSet.lunchSetDishes);
const Dishes = thisSetDishes.map((dish) => {
const thisDishInSet = props.lunchSet.lunchSetDishes.filter((dishInSet) => {
return dishInSet.dishId === dish._id;
})[0]
return (
<ListItem key={dish._id}>
<div className="editRestaurant-dish">
<div className="editRestaurant-dishLeft">
<h3 className="editRestaurant-dishLeft-header">{thisDishInSet.quantity}x</h3>
<div
className="editRestaurant-dishImg"
style={
dish.imgUrl !== "empty"
? { backgroundImage: `url(${dish.imgUrl})` }
: { backgroundColor: "#7e7e7e" }
}
></div>
<h3>{dish.name}</h3>
</div>
<div className="editRestaurant-dishRight">
<Tooltip title="Usuń">
<IconButton
color="primary"
component="span"
onClick={() => selectDish(dish._id)}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</div>
</div>
</ListItem>
);
});
return (
<List>
<YesNo open={open} cancel={onCancel} accept={onAccept} />
{thisSetDishes.length === 0 ? (
<ListItem style={{ marginLeft: "14px", fontSize: "12px" }}>
Zestaw jest pusty.
</ListItem>
) : (
Dishes
)}
</List>
);
}

View File

@@ -4,7 +4,7 @@ import DishList from "./DishList";
import CircularProgress from "@material-ui/core/CircularProgress";
import { useParams } from "react-router-dom";
import { extractTags } from "../../Services";
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
import { useAppDispatch, useAppSelector } from "../../redux/hooks.ts";
import { fetchRestaurant } from "../../actions";
import GoogleMapStatic from "./GoogleMapStatic";
import WorkingHours from "./WorkingHours";

View File

@@ -7,7 +7,7 @@ import { IconButton } from "@material-ui/core";
import TuneIcon from '@material-ui/icons/Tune';
import Chip from '@material-ui/core/Chip';
import { restaurantTypes } from '../../config.js';
import { setTags, setTypes } from "../../actions";
//import { setTags, setTypes } from "../../actions";
import { decodeTags, compareArrays } from "../../Services"
const useStyles = makeStyles((theme) => ({

View File

@@ -13,7 +13,6 @@ import ListItemText from "@material-ui/core/ListItemText";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import HomeIcon from "@material-ui/icons/Home";
import MailIcon from "@material-ui/icons/Mail";
import { logout } from "../actions";
import { makeStyles } from "@material-ui/core/styles";
import ButtonSecondary from "./Input/ButtonSecondary";
import ListSubheader from "@material-ui/core/ListSubheader";
@@ -37,10 +36,7 @@ const useStyles = makeStyles((theme) => ({
export default function TopBar() {
const classes = useStyles();
const loggedIn = useSelector((state) => state.data.loggedIn);
const firstname = useSelector((state) => state.data.userData.firstname);
const login = useSelector((state) => state.data.userData.login);
const isRestaurant = useSelector((state) => state.data.userData.isRestaurant)
const loggedIn = false;
const history = useHistory();
const dispatch = useDispatch();
const handleClick = (button) => {
@@ -102,7 +98,7 @@ export default function TopBar() {
{loggedIn && (
<div className="topbar-username">
{" "}
<p>Witaj {isRestaurant ? firstname : login}</p>{" "}
<p>Witaj</p>{" "}
</div>
)}
<IconButton onClick={toggleDrawer(true)} aria-label="menu">

View File

@@ -1,17 +1,18 @@
import React from "react";
import * as dotenv from "dotenv";
dotenv.config();
import ReactDOM from "react-dom";
import { Auth0Provider } from "@auth0/auth0-react";
import "./index.scss";
import { Provider } from "react-redux";
import store from "./redux/store";
import store from "./redux/store.ts";
import App from "./App";
dotenv.config();
ReactDOM.render(
<Auth0Provider
domain={process.env.AUTH0_DOMAIN as string}
clientId={process.env.AUTH0_CLIENTID as string}
domain={process.env.AUTH0_DOMAIN}
clientId={process.env.AUTH0_CLIENTID}
redirectUri={window.location.origin}
>
<Provider store={store}>

View File

@@ -1,81 +0,0 @@
const data = (state = initialState, action) => {
switch (action.type) {
case "SET_LOGGEDIN":
return (state = {
...state,
loggedIn: true,
userData: {
jwt: action.payload.jwt,
firstname: action.payload.firstname,
lastname: action.payload.lastname,
userId: action.payload.userId,
userEmail: action.payload.email,
login: action.payload.login,
billing: {
NIP: action.payload.NIP,
adress: action.payload.adress,
companyName: action.payload.companyName,
},
restaurants: action.payload.restaurants,
isRestaurant: action.payload.isRestaurant,
},
});
case "SET_LOGGEDOUT":
return (state = {
...state,
loggedIn: false,
userData: {
jwt: "",
firstname: "",
lastname: "",
userId: "",
userEmail: "",
billing: {
NIP: "",
adress: "",
companyName: "",
},
restaurants: [],
isRestaurant: false,
},
});
case "SET_TEMP_DATA":
return (state = { ...state, tempData: action.payload });
case "CLEAR_TEMP_DATA":
return (state = { ...state, tempData: {} });
case "UPDATE_RESTAURANT":
const index = state.userData.restaurants.findIndex(
(restaurant) => restaurant._id === action.payload._id
);
return (state = {
...state,
userData: {
...state.userData,
restaurants: [
...state.userData.restaurants.slice(0, index),
action.payload,
...state.userData.restaurants.slice(index + 1),
],
},
});
case "SET_NEW_TOKEN":
return (state = {
...state,
userData: { ...state.userData, jwt: action.payload },
});
case "SET_TYPES":
return (state = {
...state,
filters: { ...state.filters, types: action.payload },
});
case "SET_TAGS":
return (state = {
...state,
filters: { ...state.filters, tags: action.payload },
});
default:
return state;
}
};
export default data;

View File

@@ -1,16 +0,0 @@
const dishes = (state = [], action) => {
switch (action.type) {
case "SET_DISHES":
return (state = action.payload);
case "SET_DISH":
return [action.payload];
case "ADD_DISH":
return [...state, action.payload];
case "CLEAR_DISHES":
return (state = []);
default:
return state;
}
};
export default dishes;

View File

@@ -1,23 +0,0 @@
import { combineReducers } from "redux";
import { connectRouter } from "connected-react-router";
import autoCompleteReducer from "./autoComplete";
import searchResults from "./searchResults";
import searchQuery from "./searchQuery";
import restaurant from "./restaurant";
import dishes from "./dishes";
import data from "./data";
import notifications from "./notifications";
const rootReducer = (history) =>
combineReducers({
router: connectRouter(history),
autocomplete: autoCompleteReducer,
searchResults: searchResults,
searchQuery: searchQuery,
restaurant: restaurant,
dishes: dishes,
data: data,
notifications: notifications,
});
export default rootReducer;

View File

@@ -1,12 +0,0 @@
const notifications = (state = [], action) => {
switch (action.type) {
case "ENQUEUE_SNACKBAR":
return [...state, { key: action.key, ...action.notification }];
case "REMOVE_SNACKBAR":
return state.filter((notification) => notification.key !== action.key);
default:
return state;
}
};
export default notifications;

View File

@@ -1,12 +0,0 @@
const restaurant = (state = {}, action) => {
switch (action.type) {
case "SET_RESTAURANT":
return (state = action.payload);
case "CLEAR_RESTAURANT":
return (state = {});
default:
return state;
}
};
export default restaurant;

View File

@@ -1,12 +0,0 @@
const searchQuery = (state = {}, action) => {
switch (action.type) {
case "SEARCH_QUERY_SET":
return (state = action.payload);
case "SEARCH_QUERY_CLEAR":
return (state = "");
default:
return state;
}
};
export default searchQuery;

View File

@@ -1,12 +0,0 @@
const searchResults = (state = {}, action) => {
switch (action.type) {
case "SEARCH_RESULTS":
return action.payload;
case "SEARCH_CLEAR":
return (state = {});
default:
return state;
}
};
export default searchResults;

View File

@@ -1,6 +1,5 @@
import { createSlice } from "@reduxjs/toolkit";
import { Restaurant } from "../../typescript/interfaces";
import axios from "axios";
import { Restaurant } from "../../typescript";
const initialState: Restaurant = {} as Restaurant;

View File

@@ -1,42 +0,0 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
backdrop: false,
showDishList: false,
regulamin: false,
};
export const togglesSlice = createSlice({
name: "toggles",
initialState: initialState,
reducers: {
showBackdrop: (state) => {
state = { ...state, backdrop: true };
},
hideBackdrop: (state) => {
state = { ...state, backdrop: false };
},
showDishes: (state) => {
state = { ...state, showDishList: true };
},
hideDishes: (state) => {
state = { ...state, showDishList: false };
},
showRegulamin: (state) => {
state = { ...state, showDishList: true };
},
hideRegulamin: (state) => {
state = { ...state, showDishList: false };
},
},
});
export const {
showBackdrop,
hideBackdrop,
showDishes,
hideDishes,
showRegulamin,
hideRegulamin,
} = togglesSlice.actions;
export default togglesSlice.reducer;

View File

@@ -1,11 +1,11 @@
import { Restaurant, User } from "../../typescript/interfaces";
import { Restaurant, User } from "../../typescript";
import { createSlice } from "@reduxjs/toolkit";
const initialState: User = {
id: "",
username: "",
email: "",
isRestaurant: true,
isBusiness: true,
trialUsed: false,
billing: {
NIP: "",
@@ -22,6 +22,9 @@ export const userSlice = createSlice({
clearUserData: (state) => {
state = initialState;
},
setUserData: (state, action) => {
state = action.payload as User;
},
updateRestaurant: (state, action) => {
const index = state.restaurants?.findIndex(
(restaurant) => restaurant.id === action.payload.id
@@ -43,5 +46,6 @@ export const userSlice = createSlice({
},
});
export const { clearUserData, updateRestaurant } = userSlice.actions;
export const { clearUserData, updateRestaurant, setUserData } =
userSlice.actions;
export default userSlice.reducer;

View File

@@ -0,0 +1,105 @@
import { createSlice } from "@reduxjs/toolkit";
import { RestaurantTag, Dish } from "../../typescript";
interface initState {
backdrop: boolean;
showDishList: boolean;
regulamin: boolean;
types: string[];
tags: RestaurantTag[];
searchResults: {};
dishes: Dish[];
}
const initialState: initState = {
backdrop: false,
showDishList: false,
regulamin: false,
types: [],
tags: [],
searchResults: {},
dishes: [],
};
export const togglesSlice = createSlice({
name: "toggles",
initialState: initialState,
reducers: {
showBackdrop: (state) => {
state = { ...state, backdrop: true };
},
hideBackdrop: (state) => {
state = { ...state, backdrop: false };
},
showDishes: (state) => {
state = { ...state, showDishList: true };
},
hideDishes: (state) => {
state = { ...state, showDishList: false };
},
showRegulamin: (state) => {
state = { ...state, showDishList: true };
},
hideRegulamin: (state) => {
state = { ...state, showDishList: false };
},
addTypeFilter: (state, action) => {
let tempTypes = state.types;
tempTypes.push(action.payload as string);
state = { ...state, types: tempTypes };
},
removeTypeFilter: (state, action) => {
let tempTypes = state.types;
state = {
...state,
types: tempTypes.filter((temp) => temp != action.payload),
};
},
clearTypeFilter: (state) => {
state = { ...state, types: initialState.types };
},
addTagFilter: (state, action) => {
let tempTags = state.tags;
tempTags.push(action.payload as RestaurantTag);
state = { ...state, tags: tempTags };
},
removeTagFilter: (state, action) => {
let tempTags = state.tags;
state = {
...state,
tags: tempTags.filter((tag) => tag != action.payload),
};
},
clearTagFilter: (state) => {
state = { ...state, tags: initialState.tags };
},
setSearchResults: (state, action) => {
state = { ...state, searchResults: action.payload };
},
clearSearchResults: (state) => {
state = { ...state, searchResults: initialState.searchResults };
},
setDishes: (state, action) => {
state = { ...state, dishes: action.payload };
},
},
});
export const {
showBackdrop,
hideBackdrop,
showDishes,
hideDishes,
showRegulamin,
hideRegulamin,
addTypeFilter,
removeTypeFilter,
clearTypeFilter,
addTagFilter,
removeTagFilter,
clearTagFilter,
setSearchResults,
clearSearchResults,
setDishes,
} = togglesSlice.actions;
export default togglesSlice.reducer;

View File

@@ -1,14 +1,18 @@
import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./slices/userSlice";
import restaurantReducer from "./slices/restaurantSlice";
import togglesReducer from "./slices/togglesSlice";
import notificationsReducer from "./slices/notificationsSlice";
// @ts-ignore
import userReducer from "./slices/userSlice.ts";
// @ts-ignore
import restaurantReducer from "./slices/restaurantSlice.ts";
// @ts-ignore
import viewDataReducer from "./slices/viewDataSlice.ts";
// @ts-ignore
import notificationsReducer from "./slices/notificationsSlice.ts";
const store = configureStore({
reducer: {
user: userReducer,
restaurant: restaurantReducer,
toggles: togglesReducer,
viewData: viewDataReducer,
notifications: notificationsReducer,
},
});

View File

@@ -3,7 +3,7 @@ export interface User {
username: string;
email: string;
billing: BillingData;
isRestaurant: boolean;
isBusiness: boolean;
restaurants?: Restaurant[];
trialUsed: boolean;
}
@@ -21,16 +21,28 @@ export interface Restaurant {
type: string;
city: string;
adress: string;
location: number[];
location: {
lon: number,
lat: number
};
placesId: string;
imgURL: string;
phone: string;
social: Social;
tags: RestaurantTags;
tags: RestaurantTag[];
hours: WorkingHours;
hidden: boolean;
categories: string[];
dishes: Dish[];
reviews: Review[];
subscriptionActive: boolean;
subscriptionDue: Date;
}
export interface Review {
author: string,
score: number,
note: string
}
export interface Social {
@@ -39,14 +51,14 @@ export interface Social {
www: string;
}
export interface RestaurantTags {
cardPayments: boolean;
petFriendly: boolean;
glutenFree: boolean;
vegan: boolean;
vegetarian: boolean;
alcohol: boolean;
delivery: boolean;
export enum RestaurantTag {
cardPayments,
petFriendly,
glutenFree,
vegan,
vegetarian,
alcohol,
delivery,
}
export interface WorkingHours {
@@ -69,7 +81,7 @@ export interface Dish {
notes: string;
hidden: boolean;
weight: string;
allergens: Allergens;
allergens: Allergen[];
ingredients: string;
glicemicIndex: string;
kcal: string;
@@ -77,14 +89,14 @@ export interface Dish {
vegetarian: boolean;
}
export interface Allergens {
gluten: boolean;
lactose: boolean;
soy: boolean;
eggs: boolean;
seaFood: boolean;
peanuts: boolean;
sesame: boolean;
export enum Allergen {
gluten,
lactose,
soy,
eggs,
seaFood,
peanuts,
sesame,
}
export interface DishPrices {