web client v0.5
//notifications //delete restaurant //change picture //redesigned data store
This commit is contained in:
113
src/App.js
113
src/App.js
@@ -1,8 +1,11 @@
|
||||
import React from "react";
|
||||
import { Router, Switch, Route } from "react-router-dom";
|
||||
import { SnackbarProvider } from "notistack";
|
||||
import PrivateRoute from "./components/PrivateRoute";
|
||||
import "./App.scss";
|
||||
import TopBar from "./components/TopBar";
|
||||
import Notifier from "./components/Notifier";
|
||||
import AppBackdrop from "./components/Output/AppBackdrop";
|
||||
import LogoMain from "./components/Output/logoMain";
|
||||
import Footer from "./components/Output/Footer";
|
||||
import SearchPanel from "./components/Input/SearchPanel";
|
||||
@@ -37,57 +40,67 @@ function App(props) {
|
||||
return (
|
||||
<Router history={props.history}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<div className="App">
|
||||
<TopBar />
|
||||
<div className="main-container">
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<LogoMain />
|
||||
<SearchPanel />
|
||||
<p className="darkParagraph">
|
||||
Sprawdź co serwuje Twoja ulubiona restauracja.
|
||||
</p>
|
||||
</Route>
|
||||
<Route path="/results">
|
||||
<LogoMain />
|
||||
<SearchPanel />
|
||||
<SearchResults />
|
||||
</Route>
|
||||
<Route path="/restaurant">
|
||||
<Restaurant />
|
||||
</Route>
|
||||
<Route path="/dish">
|
||||
<LogoMain />
|
||||
</Route>
|
||||
<Route path="/login">
|
||||
<LoginDialog />
|
||||
</Route>
|
||||
<Route path="/register">
|
||||
<RegisterDialog />
|
||||
</Route>
|
||||
<Route path="/kontakt">
|
||||
<Contact />
|
||||
</Route>
|
||||
<PrivateRoute
|
||||
path="/newRestaurant"
|
||||
component={<NewRestaurant />}
|
||||
/>
|
||||
<PrivateRoute path="/settings" component={<Settings />} />
|
||||
<PrivateRoute
|
||||
path="/editRestaurant/:id"
|
||||
component={<EditRestaurant />}
|
||||
/>
|
||||
<Route path="/forgotpassword">
|
||||
<ForgotPassword />
|
||||
</Route>
|
||||
<Route path="/resetpassword">
|
||||
<ResetPassword />
|
||||
</Route>
|
||||
</Switch>
|
||||
<SnackbarProvider
|
||||
maxSnack={3}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "center",
|
||||
}}
|
||||
>
|
||||
<div className="App">
|
||||
<AppBackdrop />
|
||||
<Notifier />
|
||||
<TopBar />
|
||||
<div className="main-container">
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<LogoMain />
|
||||
<SearchPanel />
|
||||
<p className="darkParagraph">
|
||||
Sprawdź co serwuje Twoja ulubiona restauracja.
|
||||
</p>
|
||||
</Route>
|
||||
<Route path="/results">
|
||||
<LogoMain />
|
||||
<SearchPanel />
|
||||
<SearchResults />
|
||||
</Route>
|
||||
<Route path="/restaurant/:id">
|
||||
<Restaurant />
|
||||
</Route>
|
||||
<Route path="/dish">
|
||||
<LogoMain />
|
||||
</Route>
|
||||
<Route path="/login">
|
||||
<LoginDialog />
|
||||
</Route>
|
||||
<Route path="/register">
|
||||
<RegisterDialog />
|
||||
</Route>
|
||||
<Route path="/kontakt">
|
||||
<Contact />
|
||||
</Route>
|
||||
<PrivateRoute
|
||||
path="/newRestaurant"
|
||||
component={<NewRestaurant />}
|
||||
/>
|
||||
<PrivateRoute path="/settings" component={<Settings />} />
|
||||
<PrivateRoute
|
||||
path="/editRestaurant/:id"
|
||||
component={<EditRestaurant />}
|
||||
/>
|
||||
<Route path="/forgotpassword">
|
||||
<ForgotPassword />
|
||||
</Route>
|
||||
<Route path="/resetpassword">
|
||||
<ResetPassword />
|
||||
</Route>
|
||||
</Switch>
|
||||
</div>
|
||||
<Dialogs />
|
||||
<Footer />
|
||||
</div>
|
||||
<Dialogs />
|
||||
<Footer />
|
||||
</div>
|
||||
</SnackbarProvider>
|
||||
</ThemeProvider>
|
||||
</Router>
|
||||
);
|
||||
|
||||
@@ -81,7 +81,9 @@ export const fetchRestaurant = (id) => {
|
||||
dispatch(push("/restaurant"));
|
||||
dispatch(fetchAllDishes(id));
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
.catch((err) =>
|
||||
dispatch(notification("Nie udało się pobrać restauracji.", "error"))
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -103,11 +105,41 @@ export const fetchAllDishes = (id) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const refreshUserData = (token) => {
|
||||
return function (dispatch) {
|
||||
axios({
|
||||
url: backend + "user/refresh",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"x-auth-token": token,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
dispatch(
|
||||
toggles.setLoggedIn(
|
||||
response.data.firstname,
|
||||
response.data.lastname,
|
||||
token,
|
||||
response.data.id,
|
||||
response.data.email,
|
||||
response.data.NIP,
|
||||
response.data.adress,
|
||||
response.data.companyName,
|
||||
response.data.restaurants
|
||||
)
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const tryLogin = (username, password) => {
|
||||
const data = { email: username, password: password };
|
||||
|
||||
return function (dispatch) {
|
||||
dispatch(toggles.setLoginResult(""));
|
||||
dispatch(toggles.showBackdrop());
|
||||
axios
|
||||
.post(backend + "user/login", data)
|
||||
.then((response) => {
|
||||
@@ -125,21 +157,22 @@ export const tryLogin = (username, password) => {
|
||||
response.data.restaurants
|
||||
)
|
||||
);
|
||||
dispatch(toggles.hideBackdrop());
|
||||
dispatch(notification(`Witaj ${response.data.firstname}!`, "success"));
|
||||
dispatch(push("/"));
|
||||
})
|
||||
.catch((err) => {
|
||||
if (!err.response) {
|
||||
console.log(err);
|
||||
} else if (err.response.status === 404) {
|
||||
dispatch(
|
||||
toggles.setLoginResult(
|
||||
"Użytkownik o podanym adresie email nie istnieje."
|
||||
)
|
||||
);
|
||||
dispatch(toggles.hideBackdrop());
|
||||
dispatch(notification("Użytkownik nie istnieje :(", "error"));
|
||||
} else if (err.response.status === 401) {
|
||||
dispatch(toggles.setLoginResult("Podane hasło jest nieprawidłowe"));
|
||||
dispatch(toggles.hideBackdrop());
|
||||
dispatch(notification("Błędne dane logowania :(", "error"));
|
||||
} else {
|
||||
dispatch(toggles.setLoginResult("Błąd serwera..."));
|
||||
dispatch(toggles.hideBackdrop());
|
||||
dispatch(notification("Błąd serwera :(", "error"));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -148,17 +181,16 @@ export const tryLogin = (username, password) => {
|
||||
export const remindPassword = (email) => {
|
||||
return function (dispatch) {
|
||||
const data = { email: email };
|
||||
dispatch(toggles.setReminderResult(""));
|
||||
dispatch(toggles.showReminderCircle());
|
||||
dispatch(toggles.showBackdrop());
|
||||
axios
|
||||
.post(backend + "user/forgotpassword", data)
|
||||
.then((response) => {
|
||||
dispatch(toggles.hideReminderCircle());
|
||||
dispatch(toggles.setReminderResult(response.data));
|
||||
dispatch(toggles.hideBackdrop());
|
||||
dispatch(notification(response.data, "info"));
|
||||
})
|
||||
.catch((e) => {
|
||||
dispatch(toggles.hideReminderCircle());
|
||||
dispatch(toggles.setReminderResult(e.response.data));
|
||||
dispatch(toggles.hideBackdrop());
|
||||
dispatch(notification(e.response.data, "error"));
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -170,59 +202,60 @@ export const changePassword = (email, password, token) => {
|
||||
email: email,
|
||||
newPass: password,
|
||||
};
|
||||
dispatch(toggles.setResetResult(""));
|
||||
dispatch(toggles.showResetCircle());
|
||||
dispatch(toggles.showBackdrop());
|
||||
axios
|
||||
.post(backend + "user/resetpass", data)
|
||||
.then((response) => {
|
||||
dispatch(toggles.hideResetCircle());
|
||||
dispatch(toggles.setResetResult(response.data));
|
||||
dispatch(toggles.hideBackdrop());
|
||||
dispatch(notification(response.data, "info"));
|
||||
})
|
||||
.catch((e) => {
|
||||
dispatch(toggles.hideResetCircle());
|
||||
dispatch(toggles.setResetResult(e.response.data));
|
||||
dispatch(toggles.hideBackdrop());
|
||||
dispatch(notification(e.response.data, "error"));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const logout = () => {
|
||||
return function (dispatch) {
|
||||
dispatch(notification("Poprawnie wylogowano.", "success"));
|
||||
dispatch(toggles.setLoggedOut());
|
||||
};
|
||||
};
|
||||
|
||||
export const tryRegister = (data) => {
|
||||
return function (dispatch) {
|
||||
dispatch(toggles.setRegisterResult(""));
|
||||
dispatch(toggles.showRegisterCircle());
|
||||
dispatch(toggles.showBackdrop());
|
||||
axios
|
||||
.post(backend + "user/register", data)
|
||||
.then((response) => {
|
||||
if (response.status === 201) {
|
||||
dispatch(
|
||||
toggles.setRegisterResult(
|
||||
"Dziękujemy za rejestrację. Teraz możesz zalogować się do swojego konta."
|
||||
notification(
|
||||
"Rejestracja przebiegła pomyślnie, możesz teraz zalogować się do swojego konta.",
|
||||
"success"
|
||||
)
|
||||
);
|
||||
dispatch(toggles.hideRegisterCircle());
|
||||
dispatch(toggles.hideRegisterForm());
|
||||
dispatch(toggles.hideBackdrop());
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response.status === 500) {
|
||||
dispatch(
|
||||
toggles.setRegisterResult(
|
||||
"Wystąpił nieoczekiwany błąd serwera, przepraszamy..."
|
||||
notification(
|
||||
"Wystąpił nieoczekiwany błąd serwera, przepraszamy...",
|
||||
"error"
|
||||
)
|
||||
);
|
||||
dispatch(toggles.hideRegisterCircle());
|
||||
dispatch(toggles.hideBackdrop());
|
||||
} else if (err.response.status === 409) {
|
||||
dispatch(
|
||||
toggles.setRegisterResult(
|
||||
"Adres email jest już zajęty, proszę użyć innego."
|
||||
notification(
|
||||
"Adres email jest już zajęty, proszę użyć innego.",
|
||||
"error"
|
||||
)
|
||||
);
|
||||
dispatch(toggles.hideRegisterCircle());
|
||||
dispatch(toggles.hideBackdrop());
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -240,3 +273,24 @@ export const clearTempData = () => {
|
||||
type: "CLEAR_TEMP_DATA",
|
||||
};
|
||||
};
|
||||
|
||||
export const notification = (message, type) => {
|
||||
return function (dispatch) {
|
||||
dispatch(
|
||||
toggles.enqueueSnackbar({
|
||||
message: message,
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: type,
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
export const updateRestaurant = (restaurant) => {
|
||||
return {
|
||||
type: "UPDATE_RESTAURANT",
|
||||
payload: restaurant,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -43,52 +43,6 @@ export const setLoggedOut = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const showRegisterCircle = () => {
|
||||
return {
|
||||
type: "DIALOG_REGISTER_CIRCLE_SHOW",
|
||||
};
|
||||
};
|
||||
|
||||
export const hideRegisterCircle = () => {
|
||||
return {
|
||||
type: "DIALOG_REGISTER_CIRCLE_HIDE",
|
||||
};
|
||||
};
|
||||
|
||||
export const hideRegisterForm = () => {
|
||||
return {
|
||||
type: "DIALOG_REGISTER_FORM_HIDE",
|
||||
};
|
||||
};
|
||||
|
||||
export const setRegisterResult = (text) => {
|
||||
return {
|
||||
type: "DIALOG_REGISTER_SET_RESULT",
|
||||
payload: text,
|
||||
};
|
||||
};
|
||||
|
||||
export const setLoginResult = (text) => {
|
||||
return {
|
||||
type: "DIALOG_LOGIN_SET_RESULT",
|
||||
payload: text,
|
||||
};
|
||||
};
|
||||
|
||||
export const setReminderResult = (text) => {
|
||||
return {
|
||||
type: "DIALOG_REMINDER_SET_RESULT",
|
||||
payload: text,
|
||||
};
|
||||
};
|
||||
|
||||
export const setResetResult = (text) => {
|
||||
return {
|
||||
type: "DIALOG_RESET_SET_RESULT",
|
||||
payload: text,
|
||||
};
|
||||
};
|
||||
|
||||
export const hideRegulamin = () => {
|
||||
return {
|
||||
type: "DIALOG_REGULAMIN_HIDE",
|
||||
@@ -101,26 +55,31 @@ export const showRegulamin = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const showReminderCircle = () => {
|
||||
export const enqueueSnackbar = (notification) => {
|
||||
const key = notification.options && notification.options.key;
|
||||
|
||||
return {
|
||||
type: "DIALOG_REMINDER_CIRCLE_SHOW",
|
||||
type: "ENQUEUE_SNACKBAR",
|
||||
notification: {
|
||||
...notification,
|
||||
key: key || new Date().getTime() + Math.random(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const hideReminderCircle = () => {
|
||||
export const removeSnackbar = (key) => ({
|
||||
type: "REMOVE_SNACKBAR",
|
||||
key,
|
||||
});
|
||||
|
||||
export const showBackdrop = () => {
|
||||
return {
|
||||
type: "DIALOG_REMINDER_CIRCLE_HIDE",
|
||||
type: "SHOW_BACKDROP",
|
||||
};
|
||||
};
|
||||
|
||||
export const showResetCircle = () => {
|
||||
export const hideBackdrop = () => {
|
||||
return {
|
||||
type: "DIALOG_RESET_CIRCLE_SHOW",
|
||||
};
|
||||
};
|
||||
|
||||
export const hideResetCircle = () => {
|
||||
return {
|
||||
type: "DIALOG_RESET_CIRCLE_HIDE",
|
||||
type: "HIDE_BACKDROP",
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ import RestaurantMenuIcon from "@material-ui/icons/RestaurantMenu";
|
||||
import FastfoodIcon from "@material-ui/icons/Fastfood";
|
||||
import AddIcon from "@material-ui/icons/Add";
|
||||
import Badge from "@material-ui/core/Badge";
|
||||
import SearchIcon from "@material-ui/icons/Search";
|
||||
//--------------
|
||||
import EditRestaurantInfo from "../EditRestaurant/EditRestaurantInfo";
|
||||
import EditRestaurantLocation from "../EditRestaurant/EditRestaurantLocation";
|
||||
@@ -84,6 +85,15 @@ export default function EditRestaurant(props) {
|
||||
<h3 className="editRestaurant-title">{restaurant.name}</h3>
|
||||
<Divider />
|
||||
<List className={classes.main} component="nav">
|
||||
<ListItem
|
||||
button
|
||||
onClick={() => history.push(`/restaurant/${restaurant._id}`)}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<SearchIcon color="primary" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Podgląd" />
|
||||
</ListItem>
|
||||
<ListItem
|
||||
button
|
||||
selected={tab === 0}
|
||||
|
||||
@@ -8,15 +8,13 @@ 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 { useSelector, useDispatch } from "react-redux";
|
||||
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 CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import { remindPassword } from "../../actions";
|
||||
import { remindPassword, notification } from "../../actions";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { setReminderResult } from "../../actions/toggles";
|
||||
|
||||
export default function ForgotPassword(props) {
|
||||
const initialData = {
|
||||
@@ -24,12 +22,6 @@ export default function ForgotPassword(props) {
|
||||
emailError: false,
|
||||
};
|
||||
const [data, setData] = useState(initialData);
|
||||
const reminderResult = useSelector(
|
||||
(state) => state.data.dialogs.reminderResult
|
||||
);
|
||||
const reminderCircle = useSelector(
|
||||
(state) => state.data.dialogs.reminderCircularProgress
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
|
||||
@@ -82,7 +74,7 @@ export default function ForgotPassword(props) {
|
||||
if (validateLogin()) {
|
||||
dispatch(remindPassword(data.email));
|
||||
} else {
|
||||
dispatch(setReminderResult("Podaj poprawne dane."));
|
||||
dispatch(notification("Podaj poprawne dane.", "error"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -129,10 +121,6 @@ export default function ForgotPassword(props) {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<p>
|
||||
{reminderResult}
|
||||
<span>{reminderCircle && <CircularProgress />}</span>
|
||||
</p>
|
||||
<div className="login-dialog-buttons">
|
||||
<ButtonSecondary
|
||||
onClick={() => handleRemind()}
|
||||
|
||||
@@ -8,14 +8,13 @@ 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 { useSelector, useDispatch } from "react-redux";
|
||||
import { setLoginResult } from "../../actions/toggles";
|
||||
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 } from "../../actions";
|
||||
import { tryLogin, notification } from "../../actions";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
export default function LoginDialog(props) {
|
||||
@@ -26,7 +25,6 @@ export default function LoginDialog(props) {
|
||||
passwordError: false,
|
||||
};
|
||||
const [loginData, setLoginData] = useState(initialData);
|
||||
const loginResult = useSelector((state) => state.data.dialogs.loginResult);
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
|
||||
@@ -82,7 +80,7 @@ export default function LoginDialog(props) {
|
||||
if (validateLogin()) {
|
||||
dispatch(tryLogin(loginData.email, loginData.password));
|
||||
} else {
|
||||
dispatch(setLoginResult("Podaj poprawne dane logowania."));
|
||||
dispatch(notification("Podaj poprawne dane logowania.", "error"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -140,7 +138,6 @@ export default function LoginDialog(props) {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<p>{loginResult}</p>
|
||||
<div className="login-dialog-buttons">
|
||||
<ButtonSecondary onClick={() => handleLogin()} text="Zaloguj" />
|
||||
</div>
|
||||
|
||||
@@ -18,10 +18,11 @@ import ImageUpload from "../Input/ImageUpload";
|
||||
import validator from "validator";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import InputGoogleMaps from "../Input/InputGoogleMaps";
|
||||
import InfoDialog from "../Output/InfoDialog";
|
||||
import { prepareTags } from "../../Services.js";
|
||||
import axios from "axios";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { notification, refreshUserData } from "../../actions";
|
||||
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
|
||||
import InputWorkingHours from "../Input/InputWorkingHours";
|
||||
// ICONS
|
||||
import FastfoodIcon from "@material-ui/icons/Fastfood";
|
||||
@@ -84,13 +85,14 @@ const useStyles = makeStyles((theme) => ({
|
||||
}));
|
||||
|
||||
export default function NewRestaurant() {
|
||||
const dispatch = useDispatch();
|
||||
const initialState = {
|
||||
name: "",
|
||||
city: "",
|
||||
adress: "",
|
||||
coordinates: [52.354293, 19.42377],
|
||||
placesId: "",
|
||||
imgURL: "",
|
||||
imgUrl: "",
|
||||
workingHours: {
|
||||
pn: "8:00 - 22:00",
|
||||
wt: "8:00 - 22:00",
|
||||
@@ -113,12 +115,9 @@ export default function NewRestaurant() {
|
||||
adressError: false,
|
||||
descriptionError: false,
|
||||
charLeft: 400,
|
||||
response: "Dodawanie lokalu, prosimy o chwilę cierpliwości...",
|
||||
};
|
||||
const steps = ["Informacje", "Zdjęcie", "Lokalizacja"];
|
||||
const [state, setState] = useState(initialState);
|
||||
const [open, setOpen] = useState(true);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [activeStep, setActiveStep] = React.useState(0);
|
||||
const styles = useStyles();
|
||||
const availableTags = [
|
||||
@@ -131,7 +130,7 @@ export default function NewRestaurant() {
|
||||
"Dowozimy",
|
||||
];
|
||||
const history = useHistory();
|
||||
const token = useSelector((state) => state.data.jwt);
|
||||
const token = useSelector((state) => state.data.userData.jwt);
|
||||
|
||||
// HANDLERS
|
||||
|
||||
@@ -143,7 +142,7 @@ export default function NewRestaurant() {
|
||||
adress: state.adress,
|
||||
coordinates: state.coordinates,
|
||||
placesId: state.placesId,
|
||||
imgURL: state.imgURL,
|
||||
imgUrl: state.imgUrl,
|
||||
workingHours: state.workingHours,
|
||||
description: state.description,
|
||||
tags: formattedTags,
|
||||
@@ -151,7 +150,7 @@ export default function NewRestaurant() {
|
||||
phone: state.phone,
|
||||
hidden: false,
|
||||
};
|
||||
setOpen(false);
|
||||
dispatch(showBackdrop());
|
||||
axios({
|
||||
url: "http://localhost:4000/restaurant",
|
||||
method: "POST",
|
||||
@@ -161,26 +160,26 @@ export default function NewRestaurant() {
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
setLoading(false);
|
||||
setState({
|
||||
...state,
|
||||
response:
|
||||
dispatch(hideBackdrop());
|
||||
dispatch(
|
||||
notification(
|
||||
"Lokal został dodany, aktywuj subskrypcję, aby był widoczny w wynikach wyszukiwania.",
|
||||
});
|
||||
setTimeout(() => {
|
||||
history.push("/");
|
||||
}, 5000);
|
||||
"success"
|
||||
)
|
||||
);
|
||||
dispatch(refreshUserData(token));
|
||||
history.push("/");
|
||||
})
|
||||
.catch((error) => {
|
||||
setLoading(false);
|
||||
setState({
|
||||
...state,
|
||||
response:
|
||||
dispatch(hideBackdrop());
|
||||
console.log(error);
|
||||
dispatch(
|
||||
notification(
|
||||
"Wystąpił nieoczekiwany błąd, przepraszamy za utrudnienia. Spróbuj ponownie za chwilę.",
|
||||
});
|
||||
setTimeout(() => {
|
||||
history.push("/");
|
||||
}, 5000);
|
||||
"error"
|
||||
)
|
||||
);
|
||||
history.push("/");
|
||||
});
|
||||
};
|
||||
|
||||
@@ -200,7 +199,7 @@ export default function NewRestaurant() {
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!validator.isEmpty(state.imgURL)) {
|
||||
if (!validator.isEmpty(state.imgUrl)) {
|
||||
setActiveStep(2);
|
||||
}
|
||||
break;
|
||||
@@ -213,7 +212,7 @@ export default function NewRestaurant() {
|
||||
};
|
||||
|
||||
const handleImageUploaded = (link) => {
|
||||
setState({ ...state, imgURL: link });
|
||||
setState({ ...state, imgUrl: link });
|
||||
};
|
||||
|
||||
const handleDescriptionChange = (event) => {
|
||||
@@ -256,16 +255,9 @@ export default function NewRestaurant() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!open && (
|
||||
<InfoDialog
|
||||
title={"Dodawanie lokalu"}
|
||||
text={state.response}
|
||||
loading={loading}
|
||||
/>
|
||||
)}
|
||||
<Dialog
|
||||
className={styles.root}
|
||||
open={open}
|
||||
open={true}
|
||||
aria-labelledby="newRestaurant-title"
|
||||
>
|
||||
<DialogTitle id="newRestaurant-title">Dodaj Lokal</DialogTitle>
|
||||
@@ -469,7 +461,7 @@ export default function NewRestaurant() {
|
||||
<Paper>
|
||||
<h4>Dodaj zdjęcie lokalu.</h4>
|
||||
<ImageUpload
|
||||
img={state.imgURL}
|
||||
img={state.imgUrl}
|
||||
onUpload={(link) => handleImageUploaded(link)}
|
||||
/>
|
||||
</Paper>
|
||||
|
||||
88
src/components/Dialogs/PasswordConfirmation.js
Normal file
88
src/components/Dialogs/PasswordConfirmation.js
Normal file
@@ -0,0 +1,88 @@
|
||||
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: {
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -8,9 +8,9 @@ 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 { useSelector, useDispatch } from "react-redux";
|
||||
import { setRegisterResult, showRegulamin } from "../../actions/toggles";
|
||||
import { tryRegister } from "../../actions";
|
||||
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";
|
||||
@@ -18,12 +18,9 @@ import EmailIcon from "@material-ui/icons/Email";
|
||||
import LockIcon from "@material-ui/icons/Lock";
|
||||
import Link from "@material-ui/core/Link";
|
||||
import validator from "validator";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
export default function RegisterDialog(props) {
|
||||
// SETUP
|
||||
|
||||
const initialFormData = {
|
||||
firstname: "",
|
||||
lastname: "",
|
||||
@@ -43,13 +40,6 @@ export default function RegisterDialog(props) {
|
||||
repeatPasswordError: false,
|
||||
};
|
||||
const [formData, setFormData] = useState(initialFormData);
|
||||
var circularProgress = useSelector(
|
||||
(state) => state.data.dialogs.registerCircularProgress
|
||||
);
|
||||
var registerForm = useSelector((state) => state.data.dialogs.registerForm);
|
||||
var registerResult = useSelector(
|
||||
(state) => state.data.dialogs.registerResult
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
|
||||
@@ -138,7 +128,7 @@ export default function RegisterDialog(props) {
|
||||
if (validateForm()) {
|
||||
dispatch(tryRegister(form));
|
||||
} else {
|
||||
dispatch(setRegisterResult("Proszę poprawić formularz."));
|
||||
dispatch(notification("Proszę poprawić formularz.", "error"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -162,179 +152,161 @@ export default function RegisterDialog(props) {
|
||||
</IconButton>
|
||||
<Divider />
|
||||
<DialogContent>
|
||||
{registerForm && (
|
||||
<div>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="firstname"
|
||||
label="Imię"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<AccountCircle color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.firstnameError}
|
||||
onChange={(event) => (formData.firstname = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="lastname"
|
||||
label="Nazwisko"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<AccountCircle color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.lastnameError}
|
||||
onChange={(event) => (formData.lastname = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="companyName"
|
||||
label="Nazwa firmy"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<BusinessIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.companyNameError}
|
||||
onChange={(event) =>
|
||||
(formData.companyName = event.target.value)
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="adress"
|
||||
label="Adres firmy"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<BusinessIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.adressError}
|
||||
onChange={(event) => (formData.adress = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="NIP"
|
||||
label="NIP"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<BusinessIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.NIPError}
|
||||
onChange={(event) => (formData.NIP = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="email"
|
||||
label="Email"
|
||||
type="email"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<EmailIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.emailError}
|
||||
onChange={(event) => (formData.email = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="password"
|
||||
label="Hasło (min. 8 znaków)"
|
||||
type="password"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<LockIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.passwordError}
|
||||
onChange={(event) => (formData.password = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="repeat-password"
|
||||
label="Powtórz hasło"
|
||||
type="password"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<LockIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.repeatPasswordError}
|
||||
onChange={(event) =>
|
||||
(formData.repeatPassword = event.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<p>{registerResult}</p>
|
||||
<div>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="firstname"
|
||||
label="Imię"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<AccountCircle color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.firstnameError}
|
||||
onChange={(event) => (formData.firstname = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="lastname"
|
||||
label="Nazwisko"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<AccountCircle color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.lastnameError}
|
||||
onChange={(event) => (formData.lastname = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="companyName"
|
||||
label="Nazwa firmy"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<BusinessIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.companyNameError}
|
||||
onChange={(event) => (formData.companyName = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="adress"
|
||||
label="Adres firmy"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<BusinessIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.adressError}
|
||||
onChange={(event) => (formData.adress = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="NIP"
|
||||
label="NIP"
|
||||
type="name"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<BusinessIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.NIPError}
|
||||
onChange={(event) => (formData.NIP = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="email"
|
||||
label="Email"
|
||||
type="email"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<EmailIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.emailError}
|
||||
onChange={(event) => (formData.email = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="password"
|
||||
label="Hasło (min. 8 znaków)"
|
||||
type="password"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<LockIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.passwordError}
|
||||
onChange={(event) => (formData.password = event.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
className={loginClass.textInput}
|
||||
required
|
||||
id="repeat-password"
|
||||
label="Powtórz hasło"
|
||||
type="password"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<LockIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
error={formData.repeatPasswordError}
|
||||
onChange={(event) =>
|
||||
(formData.repeatPassword = event.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
<div className="register-dialog-actions">
|
||||
{circularProgress && <CircularProgress />}
|
||||
{registerForm && (
|
||||
<p>
|
||||
Rejestracja oznacza akceptację{" "}
|
||||
<span>
|
||||
<Link
|
||||
href="#"
|
||||
onClick={(event) => handleRegulaminClick(event)}
|
||||
>
|
||||
regulaminu
|
||||
</Link>
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
Rejestracja oznacza akceptację{" "}
|
||||
<span>
|
||||
<Link href="#" onClick={(event) => handleRegulaminClick(event)}>
|
||||
regulaminu
|
||||
</Link>
|
||||
</span>
|
||||
</p>
|
||||
<div className="register-dialog-button">
|
||||
{registerForm ? (
|
||||
<ButtonSecondary
|
||||
onClick={() => sendForm(formData)}
|
||||
text="Zarejestruj"
|
||||
/>
|
||||
) : (
|
||||
<ButtonSecondary
|
||||
onClick={() => history.push("/login")}
|
||||
text="Logowanie"
|
||||
/>
|
||||
)}
|
||||
<ButtonSecondary
|
||||
onClick={() => sendForm(formData)}
|
||||
text="Zarejestruj"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
@@ -8,14 +8,12 @@ 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 { useSelector, useDispatch } from "react-redux";
|
||||
import { useDispatch } from "react-redux";
|
||||
import validator from "validator";
|
||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||
import AccountCircle from "@material-ui/icons/AccountCircle";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
import { changePassword } from "../../actions/index";
|
||||
import { setResetResult } from "../../actions/toggles";
|
||||
import { changePassword, notification } from "../../actions/index";
|
||||
|
||||
function useQuery() {
|
||||
return new URLSearchParams(useLocation().search);
|
||||
@@ -31,10 +29,6 @@ export default function ResetPassword(props) {
|
||||
passwordRepeatError: false,
|
||||
};
|
||||
const [data, setData] = useState(initialData);
|
||||
const resetResult = useSelector((state) => state.data.dialogs.resetResult);
|
||||
const resetCircle = useSelector(
|
||||
(state) => state.data.dialogs.resetCircularProgress
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
const query = useQuery();
|
||||
@@ -94,7 +88,7 @@ export default function ResetPassword(props) {
|
||||
if (validateLogin()) {
|
||||
dispatch(changePassword(data.email, data.password, token));
|
||||
} else {
|
||||
dispatch(setResetResult("Popraw dane."));
|
||||
dispatch(notification("Popraw dane.", "error"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -170,10 +164,6 @@ export default function ResetPassword(props) {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
{resetCircle && <CircularProgress />}
|
||||
<p>{resetResult}</p>
|
||||
</div>
|
||||
<div className="login-dialog-buttons">
|
||||
<ButtonSecondary onClick={() => handleReset()} text="Zmień hasło" />
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import ButtonPrimary from "../Input/ButtonPrimary";
|
||||
import ButtonSecondary from "../Input/ButtonSecondary";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
@@ -10,8 +11,18 @@ import PhoneIcon from "@material-ui/icons/Phone";
|
||||
import FacebookIcon from "@material-ui/icons/Facebook";
|
||||
import InstagramIcon from "@material-ui/icons/Instagram";
|
||||
import LanguageIcon from "@material-ui/icons/Language";
|
||||
import FastfoodIcon from "@material-ui/icons/Fastfood";
|
||||
import LocationCityIcon from "@material-ui/icons/LocationCity";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import Link from "@material-ui/core/Link";
|
||||
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 { prepareTags } from "../../Services.js";
|
||||
import axios from "axios";
|
||||
import PasswordConfirmation from "../Dialogs/PasswordConfirmation";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
textInput: {
|
||||
@@ -36,6 +47,9 @@ const useStyles = makeStyles((theme) => ({
|
||||
color: "#bbbbbb",
|
||||
},
|
||||
},
|
||||
link: {
|
||||
cursor: "pointer",
|
||||
},
|
||||
}));
|
||||
|
||||
const calculateCharLeft = (from) => {
|
||||
@@ -43,6 +57,7 @@ const calculateCharLeft = (from) => {
|
||||
};
|
||||
|
||||
export default function EditRestaurantInfo(props) {
|
||||
const history = useHistory();
|
||||
const initialState = {
|
||||
name: props.restaurant.name,
|
||||
city: props.restaurant.city,
|
||||
@@ -54,9 +69,17 @@ export default function EditRestaurantInfo(props) {
|
||||
tags: decodeTags(props.restaurant.tags),
|
||||
workingHours: props.restaurant.workingHours,
|
||||
charleft: calculateCharLeft(props.restaurant.description),
|
||||
nameError: false,
|
||||
cityError: false,
|
||||
adressError: false,
|
||||
descriptionError: false,
|
||||
};
|
||||
const [state, setState] = useState(initialState);
|
||||
const [passwordDialog, setPasswordDialog] = useState(false);
|
||||
const styles = useStyles();
|
||||
const dispatch = useDispatch();
|
||||
const jwt = useSelector((state) => state.data.userData.jwt);
|
||||
const email = useSelector((state) => state.data.userData.userEmail);
|
||||
const handleDescriptionChange = (event) => {
|
||||
let stringLength = event.target.value.length;
|
||||
let charleft = 400 - stringLength;
|
||||
@@ -72,8 +95,112 @@ export default function EditRestaurantInfo(props) {
|
||||
"Dowozimy",
|
||||
];
|
||||
|
||||
const validateForm = () => {
|
||||
const validation = {
|
||||
nameValid: validator.isLength(state.name, { min: 1, max: 40 }),
|
||||
cityValid: validator.isLength(state.city, { min: 1, max: 40 }),
|
||||
adressValid: validator.isLength(state.name, { min: 1, max: 40 }),
|
||||
descriptionValid: validator.isLength(state.description, {
|
||||
min: 1,
|
||||
max: 400,
|
||||
}),
|
||||
};
|
||||
setState({
|
||||
...state,
|
||||
nameError: !validation.nameValid,
|
||||
cityError: !validation.cityValid,
|
||||
adressError: !validation.adressValid,
|
||||
descriptionError: !validation.descriptionValid,
|
||||
});
|
||||
|
||||
return (
|
||||
validation.nameValid &&
|
||||
validation.cityValid &&
|
||||
validation.adressValid &&
|
||||
validation.descriptionValid
|
||||
);
|
||||
};
|
||||
|
||||
const cancelChanges = () => {
|
||||
setState(initialState);
|
||||
};
|
||||
|
||||
const handleDelete = (password) => {
|
||||
axios({
|
||||
url: "http://localhost:4000/restaurant/delete",
|
||||
method: "POST",
|
||||
data: {
|
||||
restaurantId: props.restaurant._id,
|
||||
password: password,
|
||||
email: email,
|
||||
},
|
||||
headers: {
|
||||
"x-auth-token": jwt,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
dispatch(refreshUserData(jwt));
|
||||
dispatch(hideBackdrop());
|
||||
dispatch(notification("Restauracja została usunięta", "success"));
|
||||
history.push("/");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
dispatch(hideBackdrop());
|
||||
dispatch(notification("Wystąpił nieoczekiwany błąd :(", "error"));
|
||||
});
|
||||
};
|
||||
|
||||
const handleSendForm = () => {
|
||||
if (validateForm()) {
|
||||
const formattedTags = prepareTags(state.tags);
|
||||
const data = {
|
||||
restaurantId: props.restaurant._id,
|
||||
dishes: props.restaurant.dishes,
|
||||
categories: props.restaurant.categories,
|
||||
lunchMenu: props.restaurant.lunchMenu,
|
||||
name: state.name,
|
||||
city: state.city,
|
||||
adress: state.adress,
|
||||
coordinates: props.restaurant.location.coordinates,
|
||||
placesId: props.restaurant.placesId,
|
||||
imgUrl: props.restaurant.imgUrl,
|
||||
workingHours: state.workingHours,
|
||||
description: state.description,
|
||||
tags: formattedTags,
|
||||
links: state.links,
|
||||
phone: state.phone,
|
||||
hidden: props.restaurant.hidden,
|
||||
};
|
||||
dispatch(showBackdrop());
|
||||
axios({
|
||||
url: "http://localhost:4000/restaurant",
|
||||
method: "PUT",
|
||||
data: data,
|
||||
headers: {
|
||||
"x-auth-token": jwt,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
dispatch(hideBackdrop());
|
||||
dispatch(notification("Dane zostały zapisane.", "success"));
|
||||
dispatch(updateRestaurant(response));
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
dispatch(hideBackdrop());
|
||||
dispatch(notification("Wystąpił nieoczekiwany błąd :(", "error"));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="editRestaurant-tab">
|
||||
<PasswordConfirmation
|
||||
open={passwordDialog}
|
||||
onCancel={() => setPasswordDialog(false)}
|
||||
onSubmit={handleDelete}
|
||||
/>
|
||||
<div className="editRestaurant-doubleColumn">
|
||||
<div className="editRestaurant-sectiontitle">
|
||||
<h4>Podstawowe dane</h4>
|
||||
@@ -84,10 +211,18 @@ export default function EditRestaurantInfo(props) {
|
||||
className={styles.textInputFullWidth}
|
||||
fullWidth
|
||||
value={state.name}
|
||||
error={state.nameError}
|
||||
onChange={(event) =>
|
||||
setState({ ...state, name: event.target.value })
|
||||
}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<FastfoodIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
label="Nazwa lokalu"
|
||||
variant="outlined"
|
||||
/>
|
||||
@@ -96,18 +231,34 @@ export default function EditRestaurantInfo(props) {
|
||||
<TextField
|
||||
className={styles.textInput}
|
||||
value={state.city}
|
||||
error={state.cityError}
|
||||
onChange={(event) => setState({ ...state, city: event.target.value })}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<LocationCityIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
label="Miasto"
|
||||
variant="outlined"
|
||||
/>
|
||||
<TextField
|
||||
className={styles.textInput}
|
||||
value={state.adress}
|
||||
error={state.adressError}
|
||||
onChange={(event) =>
|
||||
setState({ ...state, adress: event.target.value })
|
||||
}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<LocationCityIcon color="primary" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
label="Adres"
|
||||
variant="outlined"
|
||||
/>
|
||||
@@ -117,6 +268,7 @@ export default function EditRestaurantInfo(props) {
|
||||
fullWidth
|
||||
label="Opis"
|
||||
value={state.description}
|
||||
error={state.descriptionError}
|
||||
onChange={handleDescriptionChange}
|
||||
multiline
|
||||
rows={3}
|
||||
@@ -230,10 +382,17 @@ export default function EditRestaurantInfo(props) {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<div className="editRestaurant-sectiontitle">
|
||||
<h4>Zaawansowane</h4>
|
||||
<Divider />
|
||||
</div>
|
||||
<Link className={styles.link} onClick={() => setPasswordDialog(true)}>
|
||||
Usuń restaurację
|
||||
</Link>
|
||||
</div>
|
||||
<div className="editRestaurant-bottom">
|
||||
<ButtonPrimary text="Anuluj" />
|
||||
<ButtonSecondary text="Zapisz" />
|
||||
<ButtonPrimary text="Anuluj" onClick={cancelChanges} />
|
||||
<ButtonSecondary onClick={handleSendForm} text="Zapisz" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,77 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import ImageUpload from "../Input/ImageUpload";
|
||||
import ButtonSecondary from "../Input/ButtonSecondary";
|
||||
import ButtonPrimary from "../Input/ButtonPrimary";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { notification } from "../../actions";
|
||||
import { showBackdrop, hideBackdrop } from "../../actions/toggles.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default function EditRestaurantPhoto(props) {
|
||||
const {
|
||||
imgUrl,
|
||||
dishes,
|
||||
categories,
|
||||
lunchMenu,
|
||||
name,
|
||||
city,
|
||||
adress,
|
||||
placesId,
|
||||
location,
|
||||
workingHours,
|
||||
description,
|
||||
tags,
|
||||
links,
|
||||
phone,
|
||||
hidden,
|
||||
} = props.restaurant;
|
||||
const [url, setUrl] = useState(imgUrl);
|
||||
const token = useSelector((state) => state.data.userData.jwt);
|
||||
const dispatch = useDispatch();
|
||||
const handleSave = () => {
|
||||
dispatch(showBackdrop());
|
||||
const data = {
|
||||
restaurantId: props.restaurant._id,
|
||||
dishes: dishes,
|
||||
categories: categories,
|
||||
lunchMenu: lunchMenu,
|
||||
name: name,
|
||||
city: city,
|
||||
adress: adress,
|
||||
coordinates: location.coordinates,
|
||||
placesId: placesId,
|
||||
imgUrl: url,
|
||||
workingHours: workingHours,
|
||||
description: description,
|
||||
tags: tags,
|
||||
links: links,
|
||||
phone: phone,
|
||||
hidden: hidden,
|
||||
};
|
||||
axios({
|
||||
url: "http://localhost:4000/restaurant",
|
||||
method: "PUT",
|
||||
data: data,
|
||||
headers: {
|
||||
"x-auth-token": token,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
dispatch(hideBackdrop());
|
||||
dispatch(notification("Zmieniono zdjęcie.", "success"));
|
||||
})
|
||||
.catch((e) => {
|
||||
dispatch(hideBackdrop());
|
||||
dispatch(notification("Nie udało się zmienić zdjęcia :(", "error"));
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="editRestaurant-tab">
|
||||
<p>Phottttto</p>
|
||||
<ImageUpload img={url} onUpload={(newUrl) => setUrl(newUrl)} />
|
||||
<div className="editRestaurant-bottom">
|
||||
<ButtonPrimary text="Anuluj" onClick={() => setUrl(imgUrl)} />
|
||||
<ButtonSecondary onClick={handleSave} text="Zapisz" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import { useSelector } from "react-redux";
|
||||
import axios from "axios";
|
||||
|
||||
export default function ImageUpload(props) {
|
||||
const [imagePreviewURL, setPreviewURL] = useState(props.img);
|
||||
let showCircle = false;
|
||||
const { img } = props;
|
||||
const [loading, setLoading] = useState(false);
|
||||
const token = useSelector((state) => state.data.userData.jwt);
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
let data = new FormData();
|
||||
data.append("menuiImage", event.target.files[0]);
|
||||
|
||||
setLoading(true);
|
||||
axios({
|
||||
url: "http://localhost:4000/img",
|
||||
method: "POST",
|
||||
@@ -23,24 +23,25 @@ export default function ImageUpload(props) {
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
setPreviewURL(response.data.imgURL);
|
||||
props.onUpload(response.data.imgURL);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Wystąpił błąd podczas wgrywania pliku.");
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
let imagePreview = (
|
||||
<div className="image-preview">
|
||||
{showCircle ? <CircularProgress /> : "Proszę wybrać obraz. (max. 2MB)"}
|
||||
{loading ? <CircularProgress /> : "Proszę wybrać obraz. (max. 2MB)"}
|
||||
</div>
|
||||
);
|
||||
if (imagePreviewURL) {
|
||||
if (img) {
|
||||
imagePreview = (
|
||||
<div
|
||||
className="image-preview"
|
||||
style={{ backgroundImage: `url(${imagePreviewURL})` }}
|
||||
style={{ backgroundImage: `url(${img})` }}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
45
src/components/Notifier.js
Normal file
45
src/components/Notifier.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import React from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useSnackbar } from "notistack";
|
||||
import { removeSnackbar } from "../actions/toggles.js";
|
||||
|
||||
let displayed = [];
|
||||
|
||||
const Notifier = () => {
|
||||
const dispatch = useDispatch();
|
||||
const notifications = useSelector((store) => store.notifications || []);
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const storeDisplayed = (id) => {
|
||||
displayed = [...displayed, id];
|
||||
};
|
||||
|
||||
const removeDisplayed = (id) => {
|
||||
displayed = [...displayed.filter((key) => id !== key)];
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
notifications.forEach(({ key, message, options = {} }) => {
|
||||
// do nothing if snackbar is already displayed
|
||||
if (displayed.includes(key)) return;
|
||||
|
||||
// display snackbar using notistack
|
||||
enqueueSnackbar(message, {
|
||||
key,
|
||||
...options,
|
||||
onExited: (event, myKey) => {
|
||||
// remove this snackbar from redux store
|
||||
dispatch(removeSnackbar(myKey));
|
||||
removeDisplayed(myKey);
|
||||
},
|
||||
});
|
||||
|
||||
// keep track of snackbars that we've displayed
|
||||
storeDisplayed(key);
|
||||
});
|
||||
}, [notifications, enqueueSnackbar, dispatch]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default Notifier;
|
||||
22
src/components/Output/AppBackdrop.js
Normal file
22
src/components/Output/AppBackdrop.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from "react";
|
||||
import Backdrop from "@material-ui/core/Backdrop";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import { useSelector } from "react-redux";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
backdrop: {
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
color: "#fff",
|
||||
},
|
||||
}));
|
||||
|
||||
export default function AppBackdrop() {
|
||||
const open = useSelector((state) => state.data.backdrop);
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<Backdrop className={classes.backdrop} open={open}>
|
||||
<CircularProgress color="inherit" />
|
||||
</Backdrop>
|
||||
);
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import ListItem from "@material-ui/core/ListItem";
|
||||
import FastfoodIcon from "@material-ui/icons/Fastfood";
|
||||
import Badge from "@material-ui/core/Badge";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
@@ -25,7 +24,6 @@ const useStyles = makeStyles((theme) => ({
|
||||
}));
|
||||
|
||||
export default function ListItemRestaurant(props) {
|
||||
const history = useHistory();
|
||||
const styles = useStyles();
|
||||
const badgeData = {
|
||||
color: "",
|
||||
@@ -45,7 +43,7 @@ export default function ListItemRestaurant(props) {
|
||||
return (
|
||||
<ListItem
|
||||
button
|
||||
onClick={() => history.push(`/editRestaurant/${props.id}`)}
|
||||
onClick={() => props.onClick(`/editRestaurant/${props.id}`)}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Badge
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import logo from "../../public/logo_mint.svg";
|
||||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
export default function LogoMain() {
|
||||
let appMode = useSelector((store) => store.appMode);
|
||||
|
||||
if (appMode === "init") {
|
||||
return <img src={logo} alt="Menui logo" className="logo" />;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
return <img src={logo} alt="Menui logo" className="logo" />;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ export default function UserMenu(props) {
|
||||
key={restaurant._id}
|
||||
subscriptionActive={restaurant.subscriptionActive}
|
||||
id={restaurant._id}
|
||||
onClick={(link) => handleButtonClick(link)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
const appModeReducer = (state = "init", action) => {
|
||||
switch (action.type) {
|
||||
case "APP_INIT":
|
||||
return (state = "init");
|
||||
case "APP_EMPTY":
|
||||
return (state = "empty");
|
||||
case "APP_SEARCH_RESULTS":
|
||||
return (state = "search results");
|
||||
case "APP_RESTAURANT":
|
||||
return (state = "restaurant");
|
||||
case "APP_DISH":
|
||||
return (state = "dish");
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default appModeReducer;
|
||||
@@ -1,7 +1,6 @@
|
||||
const initialState = {
|
||||
showDishList: false,
|
||||
loggedIn: false,
|
||||
jwt: "",
|
||||
username: "",
|
||||
userId: "",
|
||||
userEmail: "",
|
||||
@@ -19,16 +18,9 @@ const initialState = {
|
||||
restaurants: [],
|
||||
},
|
||||
dialogs: {
|
||||
registerCircularProgress: false,
|
||||
registerForm: true,
|
||||
registerResult: "",
|
||||
loginResult: "",
|
||||
regulamin: false,
|
||||
reminderResult: "",
|
||||
reminderCircularProgress: false,
|
||||
resetResult: "",
|
||||
resetCircularProgress: false,
|
||||
},
|
||||
backdrop: false,
|
||||
tempData: {},
|
||||
};
|
||||
|
||||
@@ -74,11 +66,6 @@ const data = (state = initialState, action) => {
|
||||
restaurants: [],
|
||||
},
|
||||
});
|
||||
case "DIALOG_REGISTER_CIRCLE_SHOW":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, registerCircularProgress: true },
|
||||
});
|
||||
case "DIALOG_REGULAMIN_SHOW":
|
||||
return (state = {
|
||||
...state,
|
||||
@@ -89,60 +76,28 @@ const data = (state = initialState, action) => {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, regulamin: false },
|
||||
});
|
||||
case "DIALOG_REGISTER_CIRCLE_HIDE":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, registerCircularProgress: false },
|
||||
});
|
||||
case "DIALOG_REGISTER_FORM_HIDE":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, registerForm: false },
|
||||
});
|
||||
case "DIALOG_REGISTER_SET_RESULT":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, registerResult: action.payload },
|
||||
});
|
||||
case "DIALOG_REMINDER_SET_RESULT":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, reminderResult: action.payload },
|
||||
});
|
||||
case "DIALOG_REMINDER_CIRCLE_SHOW":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, reminderCircularProgress: true },
|
||||
});
|
||||
case "DIALOG_REMINDER_CIRCLE_HIDE":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, reminderCircularProgress: false },
|
||||
});
|
||||
case "DIALOG_RESET_CIRCLE_SHOW":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, resetCircularProgress: true },
|
||||
});
|
||||
case "DIALOG_RESET_CIRCLE_HIDE":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, resetCircularProgress: false },
|
||||
});
|
||||
case "DIALOG_LOGIN_SET_RESULT":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, loginResult: action.payload },
|
||||
});
|
||||
case "DIALOG_RESET_SET_RESULT":
|
||||
return (state = {
|
||||
...state,
|
||||
dialogs: { ...state.dialogs, resetResult: action.payload },
|
||||
});
|
||||
case "SET_TEMP_DATA":
|
||||
return (state = { ...state, tempData: action.payload });
|
||||
case "CLEAR_TEMP_DATA":
|
||||
return (state = { ...state, tempData: {} });
|
||||
case "SHOW_BACKDROP":
|
||||
return (state = { ...state, backdrop: true });
|
||||
case "HIDE_BACKDROP":
|
||||
return (state = { ...state, backdrop: false });
|
||||
case "UPDATE_RESTAURANT":
|
||||
return (state = {
|
||||
...state,
|
||||
userData: {
|
||||
...state.userData,
|
||||
restaurants: state.userData.restaurants.map((restaurant) => {
|
||||
if (restaurant._id === action.payload._id) {
|
||||
return action.payload;
|
||||
} else {
|
||||
return restaurant;
|
||||
}
|
||||
}),
|
||||
},
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -2,22 +2,22 @@ import { combineReducers } from "redux";
|
||||
import { connectRouter } from "connected-react-router";
|
||||
import autoCompleteReducer from "./autoComplete";
|
||||
import searchResults from "./searchResults";
|
||||
import appMode from "./appMode";
|
||||
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,
|
||||
appMode: appMode,
|
||||
searchResults: searchResults,
|
||||
searchQuery: searchQuery,
|
||||
restaurant: restaurant,
|
||||
dishes: dishes,
|
||||
data: data,
|
||||
notifications: notifications,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
|
||||
12
src/reducers/notifications.js
Normal file
12
src/reducers/notifications.js
Normal file
@@ -0,0 +1,12 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user