Skip to content

Commit

Permalink
Merge pull request #27 from MiguelMRojas/_Favorites
Browse files Browse the repository at this point in the history
Favorites
  • Loading branch information
SilviaPabon committed Nov 9, 2022
2 parents 1ab67d9 + 31151cd commit 3863b7c
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 10 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<title>Buenavida</title>
</head>
<body>
<div id="root"></div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function Navbar() {
</Link>
</li>
<li>
<Link className={Styles.navigation__floatItem} to='#'>
<Link className={Styles.navigation__floatItem} to='/favorites'>
<FiHeart color={'#2f2f2f'} />
<span>Mis favoritos</span>
</Link>
Expand Down Expand Up @@ -131,7 +131,7 @@ export function Navbar() {
</div>
<ul className={Styles.navigation}>
<li>
<NavLink to='/' className={Styles.navigation__item}>
<NavLink to='/favorites' className={Styles.navigation__item}>
<FiHeart color={'#21a764'} />
<span>Favorites</span>
</NavLink>
Expand Down
16 changes: 12 additions & 4 deletions src/context/SessionContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ interface ISessionCTX {
export const SessionContext = createContext<ISessionCTX>({
user: UserTemplate,
isLoggedIn: false,
isSessionLoading: true,
isSessionLoading: false,
cart: [],
favorites: [],
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-empty-function
Expand Down Expand Up @@ -85,21 +85,28 @@ export const SessionContextProvider = ({ children }: Props) => {
const [user, setUser] = useState(UserTemplate);
const [cart, setCart] = useState(Array<ICartItem>);
const [favorites, setFavorites] = useState(Array<string>);
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();
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -34,6 +35,7 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<Route path='/login' element={<Login />}></Route>
<Route path='/signup' element={<Signup />}></Route>
<Route path='/cart' element={<ShopCart />}></Route>
<Route path='/favorites' element={<Favorites />}></Route>
</Routes>
</SessionContextProvider>
</BrowserRouter>
Expand Down
11 changes: 11 additions & 0 deletions src/pages/Favorites/Favorites.module.css
Original file line number Diff line number Diff line change
@@ -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;
}
91 changes: 91 additions & 0 deletions src/pages/Favorites/Favorites.tsx
Original file line number Diff line number Diff line change
@@ -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<Iproduct>);
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<Iproduct> = [];

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 (
<>
<main className={Styles.products}>
{favorites.map((product, index) => {
return <ProductCard CallBack={handleAbrir} product={product} key={index} />;
})}
</main>
{viewModal ? <ModalProduct CerrarCallBack={handleCerrar} product={modalData} /> : ''}
</>
);
}
2 changes: 1 addition & 1 deletion src/pages/login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/shopcart/ShopCart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/signup/Signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function Signup() {
theme: 'light',
});
}
}, [isLoggedIn]);
}, [isSessionLoading, isLoggedIn]);

const HandleSignupSubmit = async (payload: ISignupPayload) => {
// Get response from back-end
Expand Down
26 changes: 26 additions & 0 deletions src/services/user.services.ts
Original file line number Diff line number Diff line change
@@ -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) => {
Expand All @@ -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<any> => {
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;
}
};

0 comments on commit 3863b7c

Please sign in to comment.