diff --git a/index.html b/index.html
index e0d1c84..f5f1d40 100644
--- a/index.html
+++ b/index.html
@@ -4,7 +4,7 @@
-
Vite + React + TS
+ Buenavida
diff --git a/src/components/navbar/Navbar.tsx b/src/components/navbar/Navbar.tsx
index 2a6734c..6ae64df 100644
--- a/src/components/navbar/Navbar.tsx
+++ b/src/components/navbar/Navbar.tsx
@@ -48,7 +48,7 @@ export function Navbar() {
-
+
Mis favoritos
@@ -131,7 +131,7 @@ export function Navbar() {
-
-
+
Favorites
diff --git a/src/context/SessionContext.tsx b/src/context/SessionContext.tsx
index 4f2cb07..cf0f8b9 100644
--- a/src/context/SessionContext.tsx
+++ b/src/context/SessionContext.tsx
@@ -48,7 +48,7 @@ interface ISessionCTX {
export const SessionContext = createContext({
user: UserTemplate,
isLoggedIn: false,
- isSessionLoading: true,
+ isSessionLoading: false,
cart: [],
favorites: [],
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-empty-function
@@ -85,21 +85,28 @@ export const SessionContextProvider = ({ children }: Props) => {
const [user, setUser] = useState(UserTemplate);
const [cart, setCart] = useState(Array);
const [favorites, setFavorites] = useState(Array);
- const [isSessionLoading, setIsSessionLoading] = useState(true);
+ const [isSessionLoading, setIsSessionLoading] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState(false);
// Try to get the user information on reload
// or new start
useEffect(() => {
const recover = async () => {
+ setIsSessionLoading(true);
+
const reply = await WhoamiService(1); // First iteration
- if (!reply) return;
+
+ if (!reply) {
+ setIsSessionLoading(false);
+ return;
+ }
if (reply.status === 200) {
setUser(reply.data.user);
- setIsSessionLoading(false);
setIsLoggedIn(true);
}
+
+ setIsSessionLoading(false);
};
recover();
@@ -137,6 +144,7 @@ export const SessionContextProvider = ({ children }: Props) => {
// Actual value for login function
const login = async (response: AxiosResponse) => {
+ setIsSessionLoading(true);
setUser(response.data.user);
setIsLoggedIn(true);
setIsSessionLoading(false);
diff --git a/src/main.tsx b/src/main.tsx
index b144ce2..a4b2713 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -15,6 +15,7 @@ import { SessionContextProvider } from './context/SessionContext';
// Components
import { Navbar } from './components/navbar/Navbar';
import { ProductsGrid } from './pages/productsGrid/ProductsGrid';
+import { Favorites } from './pages/Favorites/Favorites';
import { Login } from './pages/login/Login';
import { Signup } from './pages/signup/Signup';
import { ShopCart } from './pages/shopcart/ShopCart';
@@ -34,6 +35,7 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
}>
}>
}>
+ }>
diff --git a/src/pages/Favorites/Favorites.module.css b/src/pages/Favorites/Favorites.module.css
new file mode 100644
index 0000000..a4d7eab
--- /dev/null
+++ b/src/pages/Favorites/Favorites.module.css
@@ -0,0 +1,11 @@
+/*Cards container*/
+.products {
+ padding-block-start: 16px;
+ padding-block-end: 70px;
+ height: max-content;
+ display: flex;
+ justify-content: center;
+ align-items: stretch;
+ flex-wrap: wrap;
+ gap: 24px;
+}
diff --git a/src/pages/Favorites/Favorites.tsx b/src/pages/Favorites/Favorites.tsx
new file mode 100644
index 0000000..b935613
--- /dev/null
+++ b/src/pages/Favorites/Favorites.tsx
@@ -0,0 +1,91 @@
+import Styles from './Favorites.module.css';
+import { useEffect, useState, useContext } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { SessionContext } from '../../context/SessionContext';
+import { GetDetailedFavoritesService } from '../../services/user.services';
+import { GetProductImageFromEndpointService } from '../../services/products.service';
+import { Iproduct } from '../../interfaces/interfaces';
+import { ProductCard } from '../../components/productCard/ProductCard';
+import { ModalProduct } from '../../components/modalproducts/ModalProducts';
+
+import { toast } from 'react-toastify';
+
+export function Favorites() {
+ const { isSessionLoading, isLoggedIn } = useContext(SessionContext);
+ const [favorites, setFavorites] = useState(Array);
+ const [viewModal, setViewModal] = useState(false);
+ const navigate = useNavigate();
+
+ // Redirect to home if is not logged in
+ useEffect(() => {
+ console.log(isSessionLoading, isLoggedIn);
+ if (!isSessionLoading && !isLoggedIn) {
+ // Show an information alert
+ toast.warn('Please, log in to see your favorites', {
+ position: 'top-right',
+ autoClose: 2500,
+ pauseOnHover: true,
+ theme: 'light',
+ });
+
+ // Redirect to heme because there is an active session
+ navigate('/login');
+ }
+ }, [isSessionLoading, isLoggedIn]);
+
+ // Datos del producto actual que es mostrado en el modal
+ const [modalData, setModalData] = useState({
+ id: '',
+ serial: 0,
+ name: '',
+ image: '',
+ units: '',
+ annotations: '',
+ discount: 0,
+ price: 0,
+ description: '',
+ });
+
+ useEffect(() => {
+ const getCurrentFavorites = async () => {
+ const response = await GetDetailedFavoritesService(1);
+ const items = response.data.favorites;
+ const products: Array = [];
+
+ if (response.status === 200) {
+ for (let i = 0; i < items.length; i++) {
+ const ireply = await GetProductImageFromEndpointService(items[i].image);
+ products.push({ ...items[i], image: ireply.image });
+ }
+
+ setFavorites(products);
+ }
+ };
+
+ getCurrentFavorites();
+ }, []);
+
+ // Funcion para abrir el modal
+ const handleAbrir = (data: Iproduct) => {
+ // Se cambian los datos del modal con los datos del producto
+ setModalData({ ...data });
+ // Se cambia la vista del modal a true
+ setViewModal(true);
+ };
+
+ // Funcion para cerrar el modal
+ const handleCerrar = () => {
+ setViewModal(false);
+ };
+
+ return (
+ <>
+
+ {favorites.map((product, index) => {
+ return ;
+ })}
+
+ {viewModal ? : ''}
+ >
+ );
+}
diff --git a/src/pages/login/Login.tsx b/src/pages/login/Login.tsx
index 7d2df94..1a1106f 100644
--- a/src/pages/login/Login.tsx
+++ b/src/pages/login/Login.tsx
@@ -26,7 +26,7 @@ export function Login() {
// Redirect to heme because there is an active session
navigate('/');
}
- }, [isLoggedIn]);
+ }, [isSessionLoading, isLoggedIn]);
// Prepare callback
const HandleLoginSubmit = async (payload: ILoginPayload) => {
diff --git a/src/pages/shopcart/ShopCart.tsx b/src/pages/shopcart/ShopCart.tsx
index 07f39ed..fb5e539 100644
--- a/src/pages/shopcart/ShopCart.tsx
+++ b/src/pages/shopcart/ShopCart.tsx
@@ -24,7 +24,7 @@ export function ShopCart() {
// Redirect to heme because there is an active session
navigate('/');
}
- }, [isLoggedIn]);
+ }, [isSessionLoading, isLoggedIn]);
const GetCartTotal = () => {
const price = cart.reduce((acc, curr) => {
diff --git a/src/pages/signup/Signup.tsx b/src/pages/signup/Signup.tsx
index 41d7324..d52762e 100644
--- a/src/pages/signup/Signup.tsx
+++ b/src/pages/signup/Signup.tsx
@@ -23,7 +23,7 @@ export function Signup() {
theme: 'light',
});
}
- }, [isLoggedIn]);
+ }, [isSessionLoading, isLoggedIn]);
const HandleSignupSubmit = async (payload: ISignupPayload) => {
// Get response from back-end
diff --git a/src/services/user.services.ts b/src/services/user.services.ts
index 432a32d..1052686 100644
--- a/src/services/user.services.ts
+++ b/src/services/user.services.ts
@@ -1,6 +1,7 @@
import axios from 'axios';
import { GLOBALS } from '../config/config';
import { ISignupPayload } from '../interfaces/interfaces.services';
+import { RefreshTokenService } from './session.services';
// Create a new user on database
export const SignupService = async (payload: ISignupPayload) => {
@@ -13,3 +14,28 @@ export const SignupService = async (payload: ISignupPayload) => {
return new axios.AxiosError().response;
}
};
+
+// Get detailed favorites (For /favorites route)
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export const GetDetailedFavoritesService = async (it: number): Promise => {
+ if (it > 2) return new axios.AxiosError().response;
+
+ try {
+ const response = await axios.get(`${GLOBALS.API_HOST}/api/user/favorites/detailed`, {
+ withCredentials: true,
+ });
+
+ return response;
+ } catch (err) {
+ if (axios.isAxiosError(err)) {
+ // Error caused because of no access-token provided
+ if (err.response?.status === 403) {
+ await RefreshTokenService();
+ return await GetDetailedFavoritesService(++it); // Try one more time
+ }
+
+ return err.response;
+ }
+ return new axios.AxiosError().response;
+ }
+};