diff --git a/.gitignore b/.gitignore index 4d29575..8692cf6 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ # misc .DS_Store +.env .env.local .env.development.local .env.test.local diff --git a/package-lock.json b/package-lock.json index 681953e..4fcbc75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "web_client", - "version": "0.1.0", + "version": "0.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -13624,6 +13624,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "validator": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.1.1.tgz", + "integrity": "sha512-8GfPiwzzRoWTg7OV1zva1KvrSemuMkv07MA9TTl91hfhe+wKrsrgVN4H2QSFd/U/FhiU3iWPYVgvbsOGwhyFWw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 9d23972..c1c8c08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "web_client", - "version": "0.1.0", + "version": "0.3.0", "private": true, "dependencies": { "@material-ui/core": "^4.11.0", @@ -16,7 +16,8 @@ "react-redux": "^7.2.0", "react-scripts": "3.4.1", "redux": "^4.0.5", - "redux-thunk": "^2.3.0" + "redux-thunk": "^2.3.0", + "validator": "^13.1.1" }, "scripts": { "start": "react-scripts start", diff --git a/src/App.js b/src/App.js index 1e1d2d4..5d3ff54 100644 --- a/src/App.js +++ b/src/App.js @@ -13,7 +13,7 @@ import { useSelector } from "react-redux"; const theme = createMuiTheme({ palette: { primary: { - main: "#0e8496", + main: "#d68000", }, secondary: { light: "#ffffff", diff --git a/src/actions/index.js b/src/actions/index.js index cf4d133..236c4e9 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,5 +1,6 @@ import axios from "axios"; import * as toggles from "./toggles"; +const backend = "http://localhost:4000/"; const autocomplete = (input) => { return { @@ -17,9 +18,7 @@ export const clearAutocomplete = () => { export const fetchAutocomplete = (input) => { return function (dispatch) { axios - .get( - "http://localhost:4000/search/autocomplete?string=" + encodeURI(input) - ) + .get(backend + "search/autocomplete?string=" + encodeURI(input)) .then((response) => { const cities = Array.from(response.data.cities); const restaurants = Array.from(response.data.restaurants); @@ -36,7 +35,7 @@ export const fetchAutocomplete = (input) => { export const fetchSearch = (input) => { return function (dispatch) { axios - .get("http://localhost:4000/search?string=" + encodeURI(input)) + .get(backend + "search?string=" + encodeURI(input)) .then((response) => { const data = response.data; if (Object.keys(data).length > 0) { @@ -80,7 +79,7 @@ export const setRestaurant = (restaurant) => { export const fetchRestaurant = (id) => { return function (dispatch) { axios - .get("http://localhost:4000/restaurant?restaurantId=" + id) + .get(backend + "restaurant?restaurantId=" + id) .then((response) => { dispatch(setRestaurant(response.data)); dispatch(toggles.hideDishes()); @@ -101,7 +100,7 @@ const setDishes = (data) => { export const fetchAllDishes = (id) => { return function (dispatch) { axios - .get("http://localhost:4000/restaurant/dishes?restaurantId=" + id) + .get(backend + "restaurant/dishes?restaurantId=" + id) .then((response) => { dispatch(setDishes(response.data)); dispatch(toggles.showDishes()); @@ -109,10 +108,38 @@ export const fetchAllDishes = (id) => { }; }; -export const tryLogin = (username) => { +export const tryLogin = (username, password) => { + const data = { email: username, password: password }; + return function (dispatch) { - dispatch(toggles.setLoggedIn(username)); - dispatch(toggles.hideLoginDialog()); + axios + .post(backend + "user/login", data) + .then((response) => { + const jwt = response.headers["x-auth-token"]; + console.log(response.headers); + dispatch( + toggles.setLoggedIn( + response.data.firstname, + jwt, + response.data.id, + response.data.email + ) + ); + dispatch(toggles.hideLoginDialog()); + }) + .catch((err) => { + if (err.response.status === 404) { + dispatch( + toggles.setLoginResult( + "Użytkownik o podanym adresie email nie istnieje." + ) + ); + } else if (err.response.status === 401) { + dispatch(toggles.setLoginResult("Podane hasło jest nieprawidłowe")); + } else { + dispatch(toggles.setLoginResult("Błąd serwera...")); + } + }); }; }; @@ -121,3 +148,39 @@ export const logout = () => { dispatch(toggles.setLoggedOut()); }; }; + +export const tryRegister = (data) => { + return function (dispatch) { + dispatch(toggles.showRegisterCircle()); + 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." + ) + ); + dispatch(toggles.hideRegisterCircle()); + dispatch(toggles.hideRegisterForm()); + } + }) + .catch((err) => { + if (err.response.status === 500) { + dispatch( + toggles.setRegisterResult( + "Wystąpił nieoczekiwany błąd serwera, przepraszamy..." + ) + ); + dispatch(toggles.hideRegisterCircle()); + } else if (err.response.status === 409) { + dispatch( + toggles.setRegisterResult( + "Adres email jest już zajęty, proszę użyć innego." + ) + ); + dispatch(toggles.hideRegisterCircle()); + } + }); + }; +}; diff --git a/src/actions/toggles.js b/src/actions/toggles.js index c035003..9abcc9d 100644 --- a/src/actions/toggles.js +++ b/src/actions/toggles.js @@ -22,10 +22,10 @@ export const hideLoginDialog = () => { }; }; -export const setLoggedIn = (username) => { +export const setLoggedIn = (username, jwt, id, email) => { return { type: "SET_LOGGEDIN", - payload: username, + payload: { username: username, jwt: jwt, id: id, email: email }, }; }; @@ -34,3 +34,59 @@ export const setLoggedOut = () => { type: "SET_LOGGEDOUT", }; }; + +export const showRegisterDialog = () => { + return { + type: "DIALOG_REGISTER_VISIBLE", + }; +}; + +export const hideRegisterDialog = () => { + return { + type: "DIALOG_REGISTER_HIDDEN", + }; +}; + +export const showRegulaminDialog = () => { + return { + type: "DIALOG_REGULAMIN_VISIBLE", + }; +}; + +export const hideRegulaminDialog = () => { + return { + type: "DIALOG_REGULAMIN_HIDDEN", + }; +}; + +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, + }; +}; diff --git a/src/components/ButtonSecondary.js b/src/components/ButtonSecondary.js index 91d29be..2dd8cdc 100644 --- a/src/components/ButtonSecondary.js +++ b/src/components/ButtonSecondary.js @@ -4,13 +4,13 @@ import Button from "@material-ui/core/Button"; const StylizedButton = withStyles({ root: { - background: "#01c3a9", + background: "#d68000", color: "#262626", margin: "16px 16px 16px 16px", padding: "8px 16px 8px 16px", borderColor: "white", "&:hover": { - backgroundColor: "#00af98", + backgroundColor: "#b46c00", }, }, label: { diff --git a/src/components/CardDish.js b/src/components/CardDish.js index 616bcab..f8c35ab 100644 --- a/src/components/CardDish.js +++ b/src/components/CardDish.js @@ -7,10 +7,10 @@ export default function CardDish(props) { name, price, imgUrl, - notes, + //notes, weight, - vegan, - vegetarian, + //vegan, + //vegetarian, allergens, } = props.dish; diff --git a/src/components/Dialogs.js b/src/components/Dialogs.js index ad851bb..f4fea98 100644 --- a/src/components/Dialogs.js +++ b/src/components/Dialogs.js @@ -1,98 +1,14 @@ import React from "react"; -import { makeStyles } from "@material-ui/core/styles"; -import DialogTitle from "@material-ui/core/DialogTitle"; -import DialogContent from "@material-ui/core/DialogContent"; -import Dialog from "@material-ui/core/Dialog"; -import Divider from "@material-ui/core/Divider"; -import ButtonSecondary from "./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 { hideLoginDialog } from "../actions/toggles"; -import { tryLogin } from "../actions"; +import LoginDialog from "./Dialogs/LoginDialog"; +import RegisterDialog from "./Dialogs/RegisterDialog"; +import RegulaminDialog from "./Dialogs/RegulaminDialog"; export default function (props) { - var loginDialog = useSelector((state) => state.data.dialogs.logIn); - const dispatch = useDispatch(); - - 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 (
- dispatch(hideLoginDialog())} - open={loginDialog} - aria-labelledby="login-title" - > - Logowanie - dispatch(hideLoginDialog())} - aria-label="close" - > - - - - - - -
- dispatch(tryLogin("jonasz@bankai.pl"))} - text="Zaloguj" - /> -
-

- Nie masz konta? - -

Zarejestruj się.

- -

-
-
+ + +
); } diff --git a/src/components/Dialogs/LoginDialog.js b/src/components/Dialogs/LoginDialog.js new file mode 100644 index 0000000..166fa53 --- /dev/null +++ b/src/components/Dialogs/LoginDialog.js @@ -0,0 +1,174 @@ +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 ".././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 { + hideLoginDialog, + showRegisterDialog, + setLoginResult, +} from "../../actions/toggles"; +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"; + +export default function LoginDialog(props) { + const initialData = { + email: "", + password: "", + emailError: false, + passwordError: false, + }; + const [loginData, setLoginData] = useState(initialData); + const loginDialog = useSelector((state) => state.data.dialogs.logIn); + const loginResult = useSelector((state) => state.data.dialogs.loginResult); + const dispatch = useDispatch(); + + 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", + }, + }, + link: { + fontSize: "0.9rem", + }, + })); + + const handleRegisterClick = () => { + dispatch(hideLoginDialog()); + dispatch(showRegisterDialog()); + }; + + 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(setLoginResult("Podaj poprawne dane logowania.")); + } + }; + + // CODE + + return ( +
+ dispatch(hideLoginDialog())} + open={loginDialog} + aria-labelledby="login-title" + > + Logowanie + dispatch(hideLoginDialog())} + aria-label="close" + > + + + + + (loginData.email = event.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + }} + /> + (loginData.password = event.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + }} + /> +

{loginResult}

+
+ handleLogin()} text="Zaloguj" /> +
+ handleRegisterClick()} + > + Nie pamiętam hasła. + +

+ Nie masz konta?{" "} + + handleRegisterClick()}> + Zarejestruj się. + + +

+
+
+
+ ); +} diff --git a/src/components/Dialogs/RegisterDialog.js b/src/components/Dialogs/RegisterDialog.js new file mode 100644 index 0000000..eb1c6ac --- /dev/null +++ b/src/components/Dialogs/RegisterDialog.js @@ -0,0 +1,281 @@ +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 ".././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 { + hideRegisterDialog, + showRegulaminDialog, + setRegisterResult, + showLoginDialog, +} from "../../actions/toggles"; +import { tryRegister } from "../../actions"; +import InputAdornment from "@material-ui/core/InputAdornment"; +import AccountCircle from "@material-ui/icons/AccountCircle"; +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"; + +export default function RegisterDialog(props) { + // SETUP + + const initialFormData = { + firstname: "", + lastname: "", + email: "", + password: "", + repeatPassword: "", + firstnameError: false, + lastnameError: false, + emailError: false, + passwordError: false, + repeatPasswordError: false, + }; + const [formData, setFormData] = useState(initialFormData); + var registerDialog = useSelector((state) => state.data.dialogs.register); + 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(); + + // STYLES + + const loginStyles = makeStyles((theme) => ({ + root: { + textAlign: "center", + "& .MuiPaper-root": { + backgroundColor: "#262626", + color: "#bbbbbb", + }, + "& .MuiFormHelperText-root": { + color: "#606060", + textAlign: "center", + }, + }, + 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(); + + // HANDLERS + + const handleRegulaminClick = (event) => { + event.preventDefault(); + dispatch(showRegulaminDialog()); + }; + + const validateForm = () => { + var valid; + const validations = { + firstname: !validator.isEmpty(formData.firstname), + lastname: !validator.isEmpty(formData.lastname), + email: validator.isEmail(formData.email), + password: validator.isLength(formData.password, { + min: 8, + max: 128, + }), + repeatPassword: formData.password === formData.repeatPassword, + }; + + setFormData({ + ...formData, + firstnameError: !validations.firstname, + lastnameError: !validations.lastname, + emailError: !validations.email, + passwordError: !validations.password, + repeatPasswordError: !validations.repeatPassword, + }); + valid = + validations.firstname && + validations.lastname && + validations.email && + validations.password && + validations.repeatPassword; + + return valid; + }; + + const sendForm = (form) => { + if (validateForm()) { + dispatch(tryRegister(form)); + } else { + dispatch(setRegisterResult("Proszę poprawić poprawić formularz.")); + } + }; + + const openLogin = () => { + dispatch(hideRegisterDialog()); + dispatch(showLoginDialog()); + }; + + // CODE + + return ( +
+ dispatch(hideRegisterDialog())} + open={registerDialog} + aria-labelledby="login-title" + > + Rejestracja + dispatch(hideRegisterDialog())} + aria-label="close" + > + + + + + {registerForm && ( +
+ + + + ), + }} + error={formData.firstnameError} + onChange={(event) => (formData.firstname = event.target.value)} + /> + + + + ), + }} + error={formData.lastnameError} + onChange={(event) => (formData.lastname = event.target.value)} + /> + + + + ), + }} + error={formData.emailError} + onChange={(event) => (formData.email = event.target.value)} + /> + + + + ), + }} + error={formData.passwordError} + onChange={(event) => (formData.password = event.target.value)} + /> + + + + ), + }} + error={formData.repeatPasswordError} + onChange={(event) => + (formData.repeatPassword = event.target.value) + } + /> +
+ )} +

{registerResult}

+ +
+ {circularProgress && } + {registerForm && ( +

+ Rejestracja oznacza akceptację{" "} + + handleRegulaminClick(event)} + > + regulaminu + + +

+ )} +
+ {registerForm ? ( + sendForm(formData)} + text="Zarejestruj" + /> + ) : ( + openLogin()} text="Logowanie" /> + )} +
+
+
+
+
+ ); +} diff --git a/src/components/Dialogs/Regulamin.js b/src/components/Dialogs/Regulamin.js new file mode 100644 index 0000000..e24c2e5 --- /dev/null +++ b/src/components/Dialogs/Regulamin.js @@ -0,0 +1,53 @@ +import React from "react"; + +export default function Regulamin() { + return ( +
+

1. Postanowienia ogólne

+

+ Sklep Internetowy "Nazwa Sklepu" działający pod adresem + www.twoja-domena.pl, prowadzony jest przez "nazwa -Firmy" Sp. z o.o. z + siedzibą w Bielsku-Białej, ul. Cieszyńska 367, wpisaną przez Sąd + Rejonowy w Bielsku-Białej, VIII Wydział Gospodarczy Krajowego Rejestru + Sądowego pod numerem KRS: 00000000001. NIP: numer 547-000-00-00. Regon + numer: 000000001. +

+

2. Zwroty i reklamacje

+

+ Zwrot towaru. Zgodnie z Ustawą z 2 marca 2000 roku „o ochronie + niektórych praw konsumentów oraz o odpowiedzialności za szkodę + wyrządzoną przez produkt niebezpieczny”, klient może zrezygnować z + towaru kupionego w naszym sklepie bez podania przyczyny w ciągu 10 dni + od dnia odebrania przesyłki. Wzór oświadczenia o odstąpieniu stanowi + załącznik do niniejszego regulaminu. Jest to możliwe tylko wówczas, gdy + towar nie nosi śladów użytkowania, jest kompletny i nie został w żaden + sposób zniszczony. Zwracany towar należy odesłać razem z otrzymaną wraz + z nim fakturą. Sklep gwarantuje zwrot kwoty równej cenie towaru. + Pieniądze zostaną zwrócone w ciągu 5 dni roboczych przelewem bankowym na + konto wskazane przez klienta lub przekazem pocztowym na adres wskazany w + zamówieniu. Koszt odesłania towaru nie podlega zwrotowi. +

+

3. Dane osobowe

+

+ Informujemy, że dane osobowe podane na formularzu zamówienia w sklepie + internetowym „Nazwa Sklepu”, są gromadzone i przetwarzane zgodnie z + Ustawą z dn. 29 sierpnia 1997r. o ochronie danych osobowych (Dz.U. z + 2002 roku nr 101 poz. 926 z późniejszymi zmianami). Zgromadzone dane + osobowe są wykorzystywane tylko i wyłącznie do celów realizacji + złożonych zamówień oraz informowania o promocjach i w żadnym wypadku nie + będą udostępniane osobom trzecim. Każdy klient naszego sklepu ma prawo + do wglądu, modyfikacji oraz usunięcia swoich danych osobowych z naszej + bazy danych. +

+

4. Postanowienia końcowe

+

+ Wszystkie ceny podawane są w złotych polskich i zawierają podatek VAT. + Cena podana przy każdym towarze jest wiążąca w chwili złożenia + zamówienia przez klienta. Sklep zastrzega sobie prawo do zmiany cen + towarów znajdujących się w ofercie, wprowadzania nowych towarów do + oferty sklepu internetowego, przeprowadzania i odwoływania akcji + promocyjnych na stronach sklepu bądź wprowadzania w nich zmian. +

+
+ ); +} diff --git a/src/components/Dialogs/RegulaminDialog.js b/src/components/Dialogs/RegulaminDialog.js new file mode 100644 index 0000000..5f98828 --- /dev/null +++ b/src/components/Dialogs/RegulaminDialog.js @@ -0,0 +1,69 @@ +import React from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import DialogTitle from "@material-ui/core/DialogTitle"; +import DialogContent from "@material-ui/core/DialogContent"; +import Dialog from "@material-ui/core/Dialog"; +import Divider from "@material-ui/core/Divider"; +import IconButton from "@material-ui/core/IconButton"; +import CloseIcon from "@material-ui/icons/Close"; +import Paper from "@material-ui/core/Paper"; +import { useSelector, useDispatch } from "react-redux"; +import { hideRegulaminDialog } from "../../actions/toggles"; +import Regulamin from "./Regulamin"; + +export default function RegulaminDialog(props) { + var regulaminDialog = useSelector((state) => state.data.dialogs.regulamin); + const dispatch = useDispatch(); + + const loginStyles = makeStyles((theme) => ({ + root: { + textAlign: "center", + "& .MuiPaper-root": { + backgroundColor: "#262626", + color: "#bbbbbb", + }, + "& .MuiFormHelperText-root": { + color: "#606060", + textAlign: "center", + }, + }, + closeButton: { + color: "#bbbbbb", + position: "absolute", + right: theme.spacing(1), + top: theme.spacing(1), + }, + paper: { + textAlign: "left", + padding: "18px", + maxHeight: "50vh", + overflow: "auto", + }, + })); + + const styles = loginStyles(); + + return ( +
+ dispatch(hideRegulaminDialog())} + aria-labelledby="regulamin-title" + > + Regulamin + dispatch(hideRegulaminDialog())} + aria-label="close" + > + + + + + {} + + +
+ ); +} diff --git a/src/components/Social.js b/src/components/Social.js new file mode 100644 index 0000000..8bcbdd1 --- /dev/null +++ b/src/components/Social.js @@ -0,0 +1,21 @@ +import React from "react"; +import FacebookIcon from "@material-ui/icons/Facebook"; +import TwitterIcon from "@material-ui/icons/Twitter"; +import InstagramIcon from "@material-ui/icons/Instagram"; +import IconButton from "@material-ui/core/IconButton"; + +export default function Social(props) { + return ( +
+ + + + + + + + + +
+ ); +} diff --git a/src/components/TopBar.js b/src/components/TopBar.js index 0494655..cdbf970 100644 --- a/src/components/TopBar.js +++ b/src/components/TopBar.js @@ -1,4 +1,6 @@ import React from "react"; +import UserMenu from "./UserMenu"; +import Social from "./Social"; import logo from "../public/logo_white.svg"; import IconButton from "@material-ui/core/IconButton"; import MenuIcon from "@material-ui/icons/Menu"; @@ -13,24 +15,25 @@ import ListItemIcon from "@material-ui/core/ListItemIcon"; import HomeIcon from "@material-ui/icons/Home"; import MailIcon from "@material-ui/icons/Mail"; import PaymentIcon from "@material-ui/icons/Payment"; -import FastfoodIcon from "@material-ui/icons/Fastfood"; -import AddCircleIcon from "@material-ui/icons/AddCircle"; -import FacebookIcon from "@material-ui/icons/Facebook"; -import TwitterIcon from "@material-ui/icons/Twitter"; -import InstagramIcon from "@material-ui/icons/Instagram"; -import { showLoginDialog } from "../actions/toggles"; +import { showLoginDialog, showRegisterDialog } from "../actions/toggles"; import { logout } from "../actions"; import { makeStyles } from "@material-ui/core/styles"; import ButtonSecondary from "./ButtonSecondary"; +import ListSubheader from "@material-ui/core/ListSubheader"; const useStyles = makeStyles((theme) => ({ paper: { backgroundColor: "#262626", color: "#bbbbbb", "& .MuiListItemIcon-root": { - color: "#01c3a9", + color: "#d68000", }, }, + subheader: { + color: "#767676", + fontSize: "0.8rem", + fontWeight: "400", + }, })); export default function TopBar() { @@ -50,6 +53,9 @@ export default function TopBar() { case "logIn": dispatch(showLoginDialog()); break; + case "register": + dispatch(showRegisterDialog()); + break; case "logOut": dispatch(logout()); break; @@ -108,7 +114,14 @@ export default function TopBar() { onClose={toggleDrawer(false)} PaperProps={{ className: classes.paper }} > - + + Nawigacja + + } + > handleClick("menui")}> @@ -119,7 +132,7 @@ export default function TopBar() { - + handleClick("pricing")}> @@ -128,47 +141,30 @@ export default function TopBar() { - {loggedIn && ( - handleClick("myRestaurant")}> - - - - - - )} - {loggedIn && ( - handleClick("addDish")}> - - - - - - )} + {loggedIn && } -
- {!loggedIn && ( - handleClick("logIn")} - text="Zaloguj się" - /> - )} - {loggedIn && ( - handleClick("logOut")} - text="Wyloguj" - /> - )} -
- - - - - - - - - +
+ {!loggedIn && ( + handleClick("logIn")} + text="Logowanie" + /> + )} + {!loggedIn && ( + handleClick("register")} + text="Rejestracja" + /> + )} + {loggedIn && ( + handleClick("logOut")} + text="Wyloguj" + /> + )} +
+
diff --git a/src/components/UserMenu.js b/src/components/UserMenu.js new file mode 100644 index 0000000..743ed6f --- /dev/null +++ b/src/components/UserMenu.js @@ -0,0 +1,71 @@ +import React, { useState } from "react"; +import Collapse from "@material-ui/core/Collapse"; +import { makeStyles } from "@material-ui/core/styles"; +import List from "@material-ui/core/List"; +import ListItem from "@material-ui/core/ListItem"; +import ListSubheader from "@material-ui/core/ListSubheader"; +import ListItemIcon from "@material-ui/core/ListItemIcon"; +import ListItemText from "@material-ui/core/ListItemText"; +import ExpandLess from "@material-ui/icons/ExpandLess"; +import ExpandMore from "@material-ui/icons/ExpandMore"; +import FastfoodIcon from "@material-ui/icons/Fastfood"; +import AddIcon from "@material-ui/icons/Add"; +import SettingsIcon from "@material-ui/icons/Settings"; + +const useStyles = makeStyles((theme) => ({ + root: { + width: "100%", + }, + nested: { + paddingLeft: theme.spacing(4), + }, + subheader: { + color: "#767676", + fontSize: "0.8rem", + fontWeight: "400", + paddingLeft: 0, + }, +})); + +export default function UserMenu(props) { + const [open, setOpen] = useState(false); + const classes = useStyles(); + const handleClick = () => { + setOpen(!open); + }; + + return ( + + Menu użytkownika + + } + > + + + + + + + + + + + + {open ? : } + + + + + + + + + + + + + ); +} diff --git a/src/reducers/data.js b/src/reducers/data.js index 8e3ff29..09c699d 100644 --- a/src/reducers/data.js +++ b/src/reducers/data.js @@ -3,11 +3,18 @@ const initialState = { loggedIn: false, jwt: "", username: "", + userId: "", + userEmail: "", dialogs: { logIn: false, register: false, contact: false, pricing: false, + regulamin: false, + registerCircularProgress: false, + registerForm: true, + registerResult: "", + loginResult: "", }, }; @@ -20,14 +27,73 @@ const data = (state = initialState, action) => { case "DIALOG_LOGIN_VISIBLE": return (state = { ...state, dialogs: { ...state.dialogs, logIn: true } }); case "SET_LOGGEDIN": - return (state = { ...state, loggedIn: true, username: action.payload }); + return (state = { + ...state, + loggedIn: true, + username: action.payload.username, + jwt: action.payload.jwt, + userEmail: action.payload.email, + userId: action.payload.id, + }); case "SET_LOGGEDOUT": - return (state = { ...state, loggedIn: false, username: "" }); + return (state = { + ...state, + loggedIn: false, + username: "", + jwt: "", + userEmail: "", + userId: "", + }); case "DIALOG_LOGIN_HIDDEN": return (state = { ...state, dialogs: { ...state.dialogs, logIn: false }, }); + case "DIALOG_REGISTER_VISIBLE": + return (state = { + ...state, + dialogs: { ...state.dialogs, register: true }, + }); + case "DIALOG_REGISTER_HIDDEN": + return (state = { + ...state, + dialogs: { ...state.dialogs, register: false }, + }); + case "DIALOG_REGULAMIN_VISIBLE": + return (state = { + ...state, + dialogs: { ...state.dialogs, regulamin: true }, + }); + case "DIALOG_REGULAMIN_HIDDEN": + return (state = { + ...state, + dialogs: { ...state.dialogs, regulamin: false }, + }); + case "DIALOG_REGISTER_CIRCLE_SHOW": + return (state = { + ...state, + dialogs: { ...state.dialogs, registerCircularProgress: true }, + }); + 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_LOGIN_SET_RESULT": + return (state = { + ...state, + dialogs: { ...state.dialogs, loginResult: action.payload }, + }); default: return state; } diff --git a/src/styles/Dialogs.scss b/src/styles/Dialogs.scss index 8c9abf0..0d4284c 100644 --- a/src/styles/Dialogs.scss +++ b/src/styles/Dialogs.scss @@ -4,4 +4,22 @@ .login-dialog-buttons { display: flex; justify-content: center; + align-items: center; + flex-direction: column; + p { + font-size: 0.8rem; + } +} + +.register-dialog-actions { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + p { + font-size: 0.8rem; + } +} + +.regulamin { } diff --git a/src/styles/TopBar.scss b/src/styles/TopBar.scss index 6e9c272..a92e53d 100644 --- a/src/styles/TopBar.scss +++ b/src/styles/TopBar.scss @@ -50,6 +50,7 @@ margin-bottom: 20px; display: flex; justify-content: center; + flex-direction: column; position: absolute; bottom: 0; } @@ -58,3 +59,11 @@ margin-left: auto; margin-right: auto; } + +.social-container { + width: 100%; + margin-bottom: 20px; + margin-top: 20px; + display: flex; + justify-content: center; +}