feat: redirigir usuarios registrados a Home en login y register

This commit is contained in:
Sofía Maturana 2026-05-08 20:24:47 -04:00
parent 7c2c8e7470
commit 69deb9c18d
27 changed files with 449 additions and 394 deletions

2
.tokeignore Normal file
View file

@ -0,0 +1,2 @@
pnpm-lock.yaml
backend/package-lock.json

View file

@ -1,50 +1,50 @@
[
{
"desc": "La pizza napolitana, de masa tierna y delgada pero bordes altos, es la versión propia de la cocina napolitana de la pizza redonda. El término pizza napoletana, por su importancia histórica o regional, se emplea en algunas zonas como sinónimo de pizza tonda.",
"id": "p001",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-1239077_640_cl.jpg?alt=media&token=6a9a33da-5c00-49d4-9080-784dcc87ec2c",
"ingredients": ["mozzarella", "tomates", "jamón", "orégano"],
"name": "napolitana",
"price": 5950
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p002",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fcheese-164872_640_com.jpg?alt=media&token=18b2b821-4d0d-43f2-a1c6-8c57bc388fab",
"ingredients": ["mozzarella", "tomates", "jamón", "choricillo"],
"name": "española",
"price": 7250
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p003",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-1239077_640_com.jpg?alt=media&token=e7cde87a-08d5-4040-ac54-90f6c31eb3e3",
"ingredients": ["mozzarella", "tomates", "salame", "orégano"],
"name": "salame",
"price": 5990
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p004",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-2000595_640_c.jpg?alt=media&token=61325b6e-a1e0-441e-b3b5-7335ba13e8be",
"ingredients": ["mozzarella", "salame", "aceitunas", "champiñones"],
"name": "cuatro estaciones",
"price": 9590
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p005",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-salame.jpg?alt=media&token=ab3d4bf8-01f2-4810-982b-bd7fb6b517b2",
"ingredients": ["mozzarella", "tomates cherry", "bacon", "orégano"],
"name": "bacon",
"price": 6450
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p006",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-2000595_640_c.jpg?alt=media&token=61325b6e-a1e0-441e-b3b5-7335ba13e8be",
"ingredients": ["mozzarella", "pimientos", "pollo grillé", "orégano"],
"name": "pollo picante",
"price": 8500
}
{
"desc": "La pizza napolitana, de masa tierna y delgada pero bordes altos, es la versión propia de la cocina napolitana de la pizza redonda. El término pizza napoletana, por su importancia histórica o regional, se emplea en algunas zonas como sinónimo de pizza tonda.",
"id": "p001",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-1239077_640_cl.jpg?alt=media&token=6a9a33da-5c00-49d4-9080-784dcc87ec2c",
"ingredients": ["mozzarella", "tomates", "jamón", "orégano"],
"name": "napolitana",
"price": 5950
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p002",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fcheese-164872_640_com.jpg?alt=media&token=18b2b821-4d0d-43f2-a1c6-8c57bc388fab",
"ingredients": ["mozzarella", "tomates", "jamón", "choricillo"],
"name": "española",
"price": 7250
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p003",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-1239077_640_com.jpg?alt=media&token=e7cde87a-08d5-4040-ac54-90f6c31eb3e3",
"ingredients": ["mozzarella", "tomates", "salame", "orégano"],
"name": "salame",
"price": 5990
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p004",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-2000595_640_c.jpg?alt=media&token=61325b6e-a1e0-441e-b3b5-7335ba13e8be",
"ingredients": ["mozzarella", "salame", "aceitunas", "champiñones"],
"name": "cuatro estaciones",
"price": 9590
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p005",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-salame.jpg?alt=media&token=ab3d4bf8-01f2-4810-982b-bd7fb6b517b2",
"ingredients": ["mozzarella", "tomates cherry", "bacon", "orégano"],
"name": "bacon",
"price": 6450
},
{
"desc": "La pizza es una preparación culinaria que consiste en un pan plano, habitualmente de forma circular, elaborado con harina de trigo, levadura, agua y sal (a veces aceite de oliva) que comúnmente se cubre con salsa de tomate, queso y otros muchos ingredientes, y que se hornea a alta temperatura, tradicionalmente en un horno de leña.",
"id": "p006",
"img": "https://firebasestorage.googleapis.com/v0/b/apis-varias-mias.appspot.com/o/pizzeria%2Fpizza-2000595_640_c.jpg?alt=media&token=61325b6e-a1e0-441e-b3b5-7335ba13e8be",
"ingredients": ["mozzarella", "pimientos", "pollo grillé", "orégano"],
"name": "pollo picante",
"price": 8500
}
]

View file

@ -1,7 +1,7 @@
[
{
"email": "test@test.com",
"password": "123123",
"id": "UYz_2Vy9rNw7uELQ7AZ8D"
}
{
"email": "test@test.com",
"password": "123123",
"id": "UYz_2Vy9rNw7uELQ7AZ8D"
}
]

View file

@ -1,24 +1,24 @@
{
"name": "simple-api-jwt",
"type": "module",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [],
"author": "bluuweb",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"jsonwebtoken": "^9.0.2",
"nanoid": "^5.0.6"
},
"devDependencies": {
"nodemon": "^3.1.0"
}
"name": "simple-api-jwt",
"type": "module",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [],
"author": "bluuweb",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"jsonwebtoken": "^9.0.2",
"nanoid": "^5.0.6"
},
"devDependencies": {
"nodemon": "^3.1.0"
}
}

View file

@ -1,33 +1,33 @@
{
"name": "desafio",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "biome check",
"preview": "vite preview"
},
"dependencies": {
"radashi": "^12.7.2",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-router-dom": "^7.14.2"
},
"devDependencies": {
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"@eslint/js": "^9.39.4",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@unocss/reset": "^66.6.7",
"@vitejs/plugin-react": "^6.0.1",
"eslint": "^9.39.4",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.4.0",
"unocss": "^66.6.7",
"vite": "^8.0.1"
}
"name": "desafio",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "biome check",
"preview": "vite preview"
},
"dependencies": {
"radashi": "^12.7.2",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-router-dom": "^7.14.2"
},
"devDependencies": {
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"@eslint/js": "^9.39.4",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@unocss/reset": "^66.6.7",
"@vitejs/plugin-react": "^6.0.1",
"eslint": "^9.39.4",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.4.0",
"unocss": "^66.6.7",
"vite": "^8.0.1"
}
}

View file

@ -1,28 +1,40 @@
import { Route, Routes } from "react-router-dom";
import { useContext } from "react";
import { Navigate, Route, Routes } from "react-router-dom";
import "./App.css";
import CartProvider from "./context/CartContext.jsx";
import { UserContext } from "./context/UserContext.jsx";
import Footer from "./Footer";
import Navbar from "./Navbar";
import Cart from "./pages/Cart";
import Home from "./pages/Home";
import Login from "./pages/Login";
import Register from "./pages/Register";
import "./App.css";
import NotFound from "./pages/NotFound";
import Pizza from "./pages/Pizza";
import Profile from "./pages/Profile.jsx";
import CartProvider from "./context/CartContext.jsx";
import Register from "./pages/Register";
function App() {
const { token } = useContext(UserContext);
return (
<CartProvider>
<Navbar />
<main className="pb-4">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/pizza/p001" element={<Pizza />} />
<Route
path="/login"
element={!token ? <Navigate to="/" /> : <Login />}
/>
<Route
path="/register"
element={!token ? <Navigate to="/" /> : <Register />}
/>
<Route path="/pizza/:id" element={<Pizza />} />
<Route path="/cart" element={<Cart />} />
<Route path="/profile" element={<Profile />} />
<Route
path="/profile"
element={token ? <Profile /> : <Navigate to="/login" />}
/>
<Route path="*" element={<NotFound />} />
</Routes>
</main>

View file

@ -1,12 +1,13 @@
import { CartContext } from "./context/CartContext";
import { UserContext } from "./context/UserContext";
import "./Navbar.css";
import { useContext } from "react";
import { Link } from "react-router-dom";
const Navbar = () => {
const { cart } = useContext(CartContext);
const token = false;
const total = cart.reduce((acc, it) => acc + it.price * it.count, 0);
const { getTotal } = useContext(CartContext);
const { logout, token } = useContext(UserContext);
const total = getTotal();
return (
<nav className="bg-green-700 text-white flex items-center justify-between gap-4">
@ -17,7 +18,7 @@ const Navbar = () => {
{token ? (
<>
<Link to="/profile">Profile</Link>
<button>Logout</button>
<button onClick={logout}>Logout</button>
</>
) : (
<>

View file

@ -1,8 +1,8 @@
import { useContext } from "react";
import "./CardPizza.css";
import * as R from "radashi";
import { Link } from "react-router-dom";
import { CartContext } from "../context/CartContext";
import * as R from "radashi";
/**
*
@ -10,7 +10,7 @@ import * as R from "radashi";
* @returns
*/
const CardPizza = (props) => {
const { cart, setCart } = useContext(CartContext);
const { addToCart } = useContext(CartContext);
return (
<article className="card-pizza">
<img src={props.img} />
@ -35,18 +35,7 @@ const CardPizza = (props) => {
Ver más
</Link>
<button
onClick={() =>
setCart((cart) => {
const pizza = cart.find((p) => p.id === props.id);
if (pizza) {
return cart.map((p) =>
p.id === props.id ? { ...p, count: p.count + 1 } : p,
);
} else {
return [...cart, { ...R.omit(props, ["key"]), count: 1 }];
}
})
}
onClick={() => addToCart(props)}
className="bg-black text-white rounded-md px-4"
>
Añadir

View file

@ -1,11 +1,27 @@
import { createContext, useState } from "react";
import * as R from "radashi";
export const CartContext = createContext();
const CartProvider = ({ children }) => {
const [cart, setCart] = useState([]);
const getTotal = () => {
return cart.reduce((acc, it) => acc + it.price * it.count, 0);
};
const addToCart = (pizzaToAdd) => {
setCart((cart) => {
const pizza = cart.find((p) => p.id === pizzaToAdd.id);
if (pizza) {
return cart.map((p) =>
p.id === pizzaToAdd.id ? { ...p, count: p.count + 1 } : p,
);
} else {
return [...cart, { ...R.omit(pizzaToAdd, ["key"]), count: 1 }];
}
});
};
return (
<CartContext.Provider value={{ cart, setCart }}>
<CartContext.Provider value={{ cart, setCart, addToCart, getTotal }}>
{children}
</CartContext.Provider>
);

View file

@ -0,0 +1,17 @@
import { createContext, useState } from "react";
export const UserContext = createContext();
const UserProvider = ({ children }) => {
const [token, setToken] = useState(true);
const logout = () => {
setToken(false);
};
return (
<UserContext.Provider value={{ token, setToken, logout }}>
{children}
</UserContext.Provider>
);
};
export default UserProvider;

View file

@ -5,11 +5,14 @@ import App from "./App.jsx";
import "@unocss/reset/tailwind.css";
import "virtual:uno.css";
import { BrowserRouter } from "react-router-dom";
import UserProvider from "./context/UserContext.jsx";
createRoot(document.getElementById("root")).render(
<StrictMode>
<BrowserRouter>
<App />
<UserProvider>
<App />
</UserProvider>
</BrowserRouter>
</StrictMode>,
);

View file

@ -1,9 +1,10 @@
import { useState } from "react";
import { pizzaCart } from "../pizzas";
import { useContext } from "react";
import { useContext, useState } from "react";
import { CartContext } from "../context/CartContext";
import { pizzaCart } from "../pizzas";
import { UserContext } from "../context/UserContext";
const Cart = () => {
const { token } = useContext(UserContext);
const { cart, setCart } = useContext(CartContext);
return (
<>
@ -58,7 +59,8 @@ const Cart = () => {
</div>
<button
type="submit"
className="bg-black text-white rounded-md p-2 text-lg hover:bg-gray-500"
disabled={!token}
className="bg-black text-white rounded-md p-2 text-lg hover:bg-gray-500 disabled:bg-gray-200"
>
Pagar
</button>

View file

@ -1,10 +1,9 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import española from "../assets/española.jpg";
import napolitana from "../assets/napolitana.jpg";
import pepperoni from "../assets/pepperoni.jpg";
import CardPizza from "../components/CardPizza";
import Header from "../Header";
import { useEffect } from "react";
const Home = () => {
const [pizzas, setPizzas] = useState([]);

View file

@ -1,10 +1,14 @@
import { useEffect, useState } from "react";
import { useContext, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { CartContext } from "../context/CartContext";
const Pizza = () => {
const { id } = useParams();
const [pizza, setPizza] = useState(null);
const [error, setError] = useState(null);
const { addToCart } = useContext(CartContext);
const fetchPizza = async () => {
const url = "http://localhost:5000/api/pizzas/p001";
const url = `http://localhost:5000/api/pizzas/${id}`;
const res = await fetch(url);
const data = await res.json();
setPizza(data);
@ -26,7 +30,10 @@ const Pizza = () => {
<li key={index}>- {i}</li>
))}
</ul>
<button className="text-white bg-black p-2 rounded-md">
<button
onClick={() => addToCart(pizza)}
className="text-white bg-black p-2 rounded-md"
>
Añadir al carrito
</button>
</section>

View file

@ -1,12 +1,19 @@
import { useContext } from "react";
import { UserContext } from "../context/UserContext";
const Profile = () => {
const email = "test@example.com";
const { logout } = useContext(UserContext);
return (
<div>
<p>
<strong>Mail: </strong>
{email}
</p>
<button className="bg-green-700 hover:bg-green-300 text-white hover:text-black">
<button
onClick={logout}
className="bg-green-700 hover:bg-green-300 text-white hover:text-black"
>
Cerrar sesión
</button>
</div>

View file

@ -1,8 +1,8 @@
import imgNapolitana from "./assets/napolitana.jpg";
import imgEspanola from "./assets/española.jpg";
import imgSalame from "./assets/pepperoni.jpg";
import imgCuatroEstaciones from "./assets/cuatro-estaciones.jpg";
import imgBacon from "./assets/bacon.jpg";
import imgCuatroEstaciones from "./assets/cuatro-estaciones.jpg";
import imgEspanola from "./assets/española.jpg";
import imgNapolitana from "./assets/napolitana.jpg";
import imgSalame from "./assets/pepperoni.jpg";
import imgPolloPicante from "./assets/pollo-picante.jpg";
export const pizzas = [