-
-
-
Method of Payment *
+
-
-
-
+ ref={methodOfPaymentRef}
+ >
+
+
+
+
+
+ {!formInputsValidity.methodOfPayment && (
+
Please Choose a Method of Payment
+ )}
+
);
};
diff --git a/src/components/FoodOrder/FoodOrder.js b/src/components/FoodOrder/FoodOrder.js
index 568797b..67fb894 100644
--- a/src/components/FoodOrder/FoodOrder.js
+++ b/src/components/FoodOrder/FoodOrder.js
@@ -1,31 +1,71 @@
-import React, { useState } from 'react';
-import Header from './Layout/Header';
-import Meals from './Meals/Meals';
-import Cart from './Cart/Cart';
-import CartProvider from './store/CartProvider';
-
+import React, { useState } from "react";
+import Header from "./Layout/Header";
+import Meals from "./Meals/Meals";
+import Cart from "./Cart/Cart";
+import Login from "./Login/Login";
+import Signup from "./Login/Signup";
+import CartProvider from "./store/CartProvider";
const FoodOrder = () => {
- const [cartIsShown, setCartIsShown] = useState(false);
-
- const showCartHandler = () => {
- setCartIsShown(true);
- }
-
- const hideCartHandler = () => {
- setCartIsShown(false);
- }
-
- return(
-
- {cartIsShown && }
-
-
-
-
-
-
- );
-}
-
-export default FoodOrder;
\ No newline at end of file
+ const [cartIsShown, setCartIsShown] = useState(false);
+ const [loginIsShown, setLoginIsShown] = useState(false);
+ const [SignupIsShown, setSignupIsShown] = useState(false);
+
+ const showCartHandler = () => {
+ setCartIsShown(true);
+ };
+
+ const hideCartHandler = () => {
+ setCartIsShown(false);
+ };
+
+ const showLoginHandler = () => {
+ setLoginIsShown(true);
+ };
+
+ const hideLoginHandler = () => {
+ setLoginIsShown(false);
+ };
+
+ const showSignupHandler = () => {
+ setSignupIsShown(true);
+ };
+
+ const hideSignupHandler = () => {
+ setSignupIsShown(false);
+ };
+
+ const requestLogoutHandler = () => {
+ /*
+ steps to consider:
+ 1. products in the cart
+ 2. orders not place them
+ */
+
+ /*
+ source code example:
+ const authCtx = useContext(AuthContext);
+
+ */
+ }
+
+
+ return (
+
+ {cartIsShown && }
+ {loginIsShown && }
+ {SignupIsShown && }
+
+
+
+
+
+ );
+};
+
+export default FoodOrder;
diff --git a/src/components/FoodOrder/Layout/Header.js b/src/components/FoodOrder/Layout/Header.js
index 6b2f6c3..e11c0e4 100644
--- a/src/components/FoodOrder/Layout/Header.js
+++ b/src/components/FoodOrder/Layout/Header.js
@@ -1,20 +1,33 @@
-import React, { Fragment }from 'react';
-import HeaderCartButton from './HeaderCartButton';
-import mealsImage from '../assets/banner.jpg';
-import classes from './Header.module.css';
+import React, { useContext, Fragment } from "react";
+import AuthContext from "../store/auth-context";
+import HeaderCartButton from "../UI/Buttons/HeaderCartButton";
+import HeaderActionButton from "../UI/Buttons/HeaderActionButton";
+import mealsImage from "../assets/banner.jpg";
+import classes from "./Header.module.css";
-const Header = props => {
- return (
-
-
-
-

-
-
- );
+const Header = (props) => {
+ const authCtx = useContext(AuthContext);
+ return (
+
+
+ Lets Order!!!
+ {authCtx.isLoggedIn ? (
+
+
+
+
+ ) : (
+
+
+
+
+ )}
+
+
+

+
+
+ );
};
-export default Header;
\ No newline at end of file
+export default Header;
diff --git a/src/components/FoodOrder/Layout/Header.module.css b/src/components/FoodOrder/Layout/Header.module.css
index 8549499..bf00b1d 100644
--- a/src/components/FoodOrder/Layout/Header.module.css
+++ b/src/components/FoodOrder/Layout/Header.module.css
@@ -26,4 +26,9 @@
height: 100%;
object-fit: cover;
transform: rotateZ(-5deg) translateY(-4rem) translateX(-1rem);
+ }
+
+ .btncontainer {
+ display: flex;
+
}
\ No newline at end of file
diff --git a/src/components/FoodOrder/Layout/Navigation.js b/src/components/FoodOrder/Layout/Navigation.js
new file mode 100644
index 0000000..f110e0a
--- /dev/null
+++ b/src/components/FoodOrder/Layout/Navigation.js
@@ -0,0 +1,32 @@
+import React, { useContext } from 'react';
+
+import AuthContext from '../store/auth-context';
+import classes from './Navigation.module.css';
+
+const Navigation = () => {
+ const ctx = useContext(AuthContext);
+
+ return (
+
+ );
+};
+
+export default Navigation;
diff --git a/src/components/FoodOrder/Layout/Navigation.module.css b/src/components/FoodOrder/Layout/Navigation.module.css
new file mode 100644
index 0000000..b09826f
--- /dev/null
+++ b/src/components/FoodOrder/Layout/Navigation.module.css
@@ -0,0 +1,43 @@
+.nav ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ align-items: center;
+}
+
+.nav li {
+ margin: 0;
+ margin-left: 2rem;
+}
+
+.nav a {
+ text-decoration: none;
+ color: white;
+}
+
+.nav a:hover,
+.nav a:active {
+ color: #f3cafb;
+}
+
+.nav button {
+ font: inherit;
+ background: #dd0db0;
+ border: 1px solid #dd0db0;
+ padding: 0.5rem 1.5rem;
+ color: white;
+ cursor: pointer;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.26);
+ border-radius: 20px;
+}
+
+.nav button:focus {
+ outline: none;
+}
+
+.nav button:hover,
+.nav button:active {
+ color: #f3cafb;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.26);
+}
diff --git a/src/components/FoodOrder/Login/Login.js b/src/components/FoodOrder/Login/Login.js
new file mode 100644
index 0000000..0c85b41
--- /dev/null
+++ b/src/components/FoodOrder/Login/Login.js
@@ -0,0 +1,135 @@
+import React, { useContext, useState } from "react";
+import Modal from "../UI/Modal/Modal";
+import classes from "./Login.module.css";
+import Input from "../UI/Input/Input";
+import AuthContext from "../store/auth-context";
+
+const Login = (props) => {
+ const [emailValue, setEmailValue] = useState('');
+ const [passwordValue, setPasswordValue] = useState('');
+
+ const [isCanceling, setIsCanceling] = useState(false);
+ const [isValidating, setIsValidating] = useState(false);
+ const [didValidate, setDidValidate] = useState(false);
+ const [isErrorOnValidate, setIsErrorOnValidate] = useState(false);
+ const authCtx = useContext(AuthContext);
+
+ const emailValueHandler = (event) => {
+ setEmailValue(event.target.value);
+ }
+
+ const passwordValueHandler = (event) => {
+ setPasswordValue(event.target.value);
+ }
+
+ const errorOnValidateHandler = () => {
+ setIsErrorOnValidate(true);
+ };
+
+ const validateCredentialsHandler = async () => {
+ setIsValidating(true);
+ const enteredEmail = emailValue;
+ const enteredPassword = passwordValue;
+
+ const userCredentialsEntered = {
+ email: enteredEmail,
+ password: enteredPassword,
+ }
+
+ const response = await fetch("http://localhost:3000/auth/login", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(userCredentialsEntered),
+ });
+ if (!response.ok) {
+ errorOnValidateHandler();
+ } else {
+ setIsValidating(false);
+ setIsCanceling(false);
+ setDidValidate(true);
+ authCtx.onValidSession();
+ //cartCtx.clearCart();
+ }
+ };
+
+ const isValidatingModalContent =
Validating Credentials...
;
+ /* incluir transaccion para verificar si es exitoso o hubo algun error */
+
+ const errorOnValidateModalContent = (
+
+ User or Password incorrect, please verify
+
+
+
+
+ );
+
+ const didValidateModalContent = (
+
+ Creditials verified, welcome!
+
+
+
+
+ );
+
+ const loginButtons = (
+
+
+
+
+ );
+
+ const modalActions = (
+
{!isCanceling ? loginButtons : ""}
+ );
+
+ const LoginModalContent = (
+
+
+
+ {modalActions}
+
+ );
+
+ return (
+
+ {!isCanceling && !isValidating && !isErrorOnValidate && !didValidate && LoginModalContent}
+ {isValidating && isValidatingModalContent}
+ {isErrorOnValidate && errorOnValidateModalContent}
+ {!isValidating && didValidate && didValidateModalContent}
+
+ );
+};
+
+export default Login;
diff --git a/src/components/FoodOrder/Login/Login.module.css b/src/components/FoodOrder/Login/Login.module.css
new file mode 100644
index 0000000..c6ec895
--- /dev/null
+++ b/src/components/FoodOrder/Login/Login.module.css
@@ -0,0 +1,36 @@
+.login {
+ width: 90%;
+ max-width: 40rem;
+ margin: 2rem auto;
+ padding: 2rem;
+}
+
+.actions {
+ text-align: center;
+}
+
+.actions button {
+ font: inherit;
+ cursor: pointer;
+ background-color: transparent;
+ border: 1px solid #8a2b06;
+ padding: 0.5rem 2rem;
+ border-radius: 25px;
+ margin-left: 1rem;
+}
+
+.actions button:hover,
+.actions button:active {
+ background-color: #5a1a01;
+ border-color: #5a1a01;
+ color: white;
+}
+
+.actions .button--alt {
+ color: #8a2b06;
+}
+
+.actions .button {
+ background-color: #8a2b06;
+ color: white;
+}
diff --git a/src/components/FoodOrder/Login/Signup.js b/src/components/FoodOrder/Login/Signup.js
new file mode 100644
index 0000000..080b50d
--- /dev/null
+++ b/src/components/FoodOrder/Login/Signup.js
@@ -0,0 +1,183 @@
+import React, { useState, useRef } from "react";
+import Modal from "../UI/Modal/Modal";
+import classes from "./Login.module.css";
+import Input from "../UI/Input/Input";
+
+const Signup = (props) => {
+ const [firstNameValue, setFirstNameValue] = useState('');
+ const [lastNameValue, setLastNameValue] = useState('');
+ const [emailClientValue, setEmailClientValue] = useState('');
+ const [passwordClientValue, setPasswordClientValue] = useState('');
+
+ const [isCanceling, setIsCanceling] = useState(false);
+ const [isSaving, setIsSaving] = useState(false);
+ const [didSave, setDidSave] = useState(false);
+ const [isErrorOnSave, setIsErrorOnSave] = useState(false);
+ //const cartCtx = useContext(CartContext);
+
+ const firstNameValueHandler = (event) => {
+ setFirstNameValue(event.target.value);
+ }
+
+ const lastNameValueHandler = (event) => {
+ setLastNameValue(event.target.value);
+ }
+
+ const emailClientValueHandler = (event) => {
+ setEmailClientValue(event.target.value);
+ }
+
+ const passwordClientValueHandler = (event) => {
+ setPasswordClientValue(event.target.value);
+ }
+
+ const errorOnSignupHandler = () => {
+ setIsErrorOnSave(true);
+ };
+
+ const signupHandler = async () => {
+ setIsSaving(true);
+ const enteredFirstname = firstNameValue;
+ const enteredLastname = lastNameValue;
+ const enteredEmail = emailClientValue;
+ const enteredPassword = passwordClientValue;
+
+ const newClientData = {
+ firstname: enteredFirstname,
+ lastname: enteredLastname,
+ email: enteredEmail,
+ password: enteredPassword,
+ };
+
+ const response = await fetch("http://localhost:3000/clients", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(newClientData),
+ });
+
+ if (!response.ok) {
+ errorOnSignupHandler();
+ } else {
+ setIsSaving(false);
+ setIsCanceling(false);
+ setDidSave(true);
+ //cartCtx.clearCart();
+ }
+ };
+
+ const isSavingModalContent =
Saving new user...
;
+ /* incluir transaccion para verificar si es exitoso o hubo algun error */
+
+ const errorOnSavingModalContent = (
+
+ The user account could not be created. Please try again later
+
+
+
+
+ );
+
+ const didSaveModalContent = (
+
+ User account created, welcome!
+
+
+
+
+ );
+
+ const SignupButtons = (
+
+
+
+
+ );
+
+ const modalActions = (
+
{!isCanceling ? SignupButtons : ""}
+ );
+
+ const SignupModalContent = (
+
+
+
+
+
+
+ {modalActions}
+
+ );
+
+ return (
+
+ {!isCanceling && !isSaving && !isErrorOnSave && !didSave && SignupModalContent}
+ {isSaving && isSavingModalContent}
+ {isErrorOnSave && errorOnSavingModalContent}
+ {!isSaving && didSave && didSaveModalContent}
+
+ );
+};
+
+export default Signup;
diff --git a/src/components/FoodOrder/LoginUsers.js b/src/components/FoodOrder/LoginUsers.js
new file mode 100644
index 0000000..ef5afec
--- /dev/null
+++ b/src/components/FoodOrder/LoginUsers.js
@@ -0,0 +1,21 @@
+import React, { useContext } from "react";
+
+import Login from "./Login/Login";
+import Home from "./Home/Home";
+import MainHeader from "./MainHeader/MainHeader";
+import AuthContext from "./store/auth-context";
+
+function LoginUsers() {
+ const ctx = useContext(AuthContext);
+ return (
+
+
+
+ {!ctx.isLoggedIn && }
+ {ctx.isLoggedIn && }
+
+
+ );
+}
+
+export default LoginUsers;
diff --git a/src/components/FoodOrder/Meals/AvailableMeals.js b/src/components/FoodOrder/Meals/AvailableMeals.js
index eaab1c1..313cf07 100644
--- a/src/components/FoodOrder/Meals/AvailableMeals.js
+++ b/src/components/FoodOrder/Meals/AvailableMeals.js
@@ -1,10 +1,9 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useState } from "react";
-import Card from "../UI/Card";
+import Card from "../UI/Card/Card";
import MealItem from "./MealItem/MealItem";
import classes from "./AvailableMeals.module.css";
-
const AvailableMeals = () => {
const [meals, setMeals] = useState([]);
const [isLoading, setIsLoading] = useState(true);
@@ -12,18 +11,20 @@ const AvailableMeals = () => {
useEffect(() => {
const fetchMeals = async () => {
- const response = await fetch('https://movieserp-default-rtdb.firebaseio.com/meals.json');
- //const response = await fetch('http://localhost:8080/api/products');
+ const response = await fetch("http://localhost:3000/meals", {
+ method: "GET",
+ });
- if(!response.ok){
- throw new Error('something went wrong');
+ if (!response.ok) {
+ throw new Error("The data could not be shown");
}
- const responseData = await response.json(); //este es un objeto
+ const responseData = await response.json();
+
//el objeto se traduce a un array
const loadedMeals = [];
- for(const key in responseData){
+ for (const key in responseData) {
loadedMeals.push({
id: key,
name: responseData[key].name,
@@ -32,32 +33,41 @@ const AvailableMeals = () => {
});
}
- setMeals(loadedMeals);
- setIsLoading(false);
+ //checking if the array is not null
+ if (!loadedMeals.length) {
+ throw new Error("No products found to display");
+ } else {
+ setMeals(loadedMeals);
+ setIsLoading(false);
+ }
};
- fetchMeals().catch(error => {
+ fetchMeals().catch((error) => {
setIsLoading(false);
setHttpError(error.message);
});
}, []);
- if(isLoading){
- return
+ if (isLoading) {
+ return (
+
+ );
}
- if(httpError){
- return
+ if (httpError) {
+ return (
+
+ );
}
const mealsList = meals.map((meal) => (
{
const cartCtx = useContext(CartContext);
- const price = `$${props.price.toFixed(2)}`; //content literal formatting
+ const authCtx = useContext(AuthContext);
+ //const price = `$${props.price.toFixed(2)}`; //content literal formatting
+ const price = `$ ${parseFloat(props.price).toFixed(2)}`;
const addToCartHandler = amount => {
cartCtx.addItem({
@@ -25,7 +28,7 @@ const MealItem = (props) => {
{price}