Loading repository data…
Loading repository data…
rojaence / repository
Solution for the 'Curso práctico de React' - Platzi
A solution to the Platzi - React practice course.
This is a simple Frontend app that simulates a client for an e-commerce using
the Platzi Fake Store API
Project live site URL: GH Pages - Live site
Users should be able to:
input fieldselect fieldbutton to add a product to cartBuit with Webpack and Babel + plugins
npm install
npm run start
npm run build
Global state for products data got from API, using context API
Define functions in ProductState, then wrap with useMemo to send changes to Provider:
const getProductsByCategory = async (categoryId) => {
const options = { method: "GET" };
const request = await fetch(`${baseURL}/categories/${categoryId}/products`, options);
const response = await request.json();
dispatch({ type: GET_PRODUCTS, payload: response });
};
const value = useMemo(() => ({
getProducts,
getCategories,
addToCart,
deleteFromCart,
decreaseItemCart,
getProductsByCategory,
products: state.products,
categories: state.categories,
shoopingCart: state.shoopingCart,
}));
return (
<ProductContext.Provider value={value}>
{props.children}
</ProductContext.Provider>
);
Then in a component only what is required is called
import ProductContext from "@context/products/ProductContext";
// ProductCard.jsx
const { addToCart } = useContext(ProductContext);
// ShoopingCart.jsx
const { shoopingCart } = useContext(ProductContext);
// CartItem.jsx
const { addToCart, deleteFromCart, decreaseItemCart } = useContext(ProductContext);
// Home.jsx
const {
products,
getCategories,
getProducts,
shoopingCart,
getProductsByCategory,
} = useContext(ProductContext);
Drawer is a container that allows to wrap elements to show on side as a modal, the component 'AsideDrawer.jsx' is used in conjunction with a custom hook 'useAsideDrawer':
// useAsideDrawer.jsx
import React, { useState, useEffect } from "react";
export const useAsideDrawer = (initialShowValue = false) => {
const [isOpen, setIsOpen] = useState(initialShowValue);
useEffect(() => {
if (isOpen) document.documentElement.classList.add('scrollbar-none');
else document.documentElement.classList.remove('scrollbar-none');
}, [isOpen]);
const hideDrawer = () => setIsOpen(false);
const showDrawer = () => setIsOpen(true);
const toggleDrawer = () => setIsOpen((value) => !value);
return { isOpen, hideDrawer, showDrawer, toggleDrawer };
};
In the same way a custom hook is used for the product image carousel.
// useImageCarrousel.jsx
import React, { useState, useEffect } from 'react';
export const useImageCarrousel = (initialSlides = []) => {
const [slides, setSlides] = useState(initialSlides);
const [current, setCurrent] = useState({});
useEffect(() => {
if (slides.length > 0) {
setCurrent(slides[0]);
}
}, [slides]);
const setPrevious = () => {
if (current.index > 0) setCurrent(slides[slides.indexOf(current) - 1])
else if (current.index === 0) setCurrent(slides[slides.length - 1])
}
const setNext = () => {
if (current.index < slides.length - 1) setCurrent(slides[slides.indexOf(current) + 1])
else if (current.index === slides.length - 1) setCurrent(slides[0])
}
return { slides, current, setCurrent, setSlides, setPrevious, setNext }
}
The 'react-hot-toast' library has a feature that allows you to set your own component to display the alerts and customize the styles:
// render in Snackbar.jsx
return (
<article
className={`snackbar${severity ? ` snackbar--${severity}` : ""}`}
style={{
...style,
...toastAnimation,
}}
>
<Icon name={iconName[severity]} size={28} />
<h2 className="snackbar__message">{message}</h2>
<Button icon="close" iconSize={30} fab flat onClick={closeAction} />
</article>
);
Using custom Snackbar component with react-hot-toast
// ProductCard.jsx
import toast from "react-hot-toast";
import Snackbar from "@containers/Snackbar";
const handleCartBtnClick = (e) => {
e.stopPropagation();
try {
addToCart(data);
toast.custom((t) => (
<Snackbar
show={t.visible}
message="Product added to cart"
severity="success"
closeAction={() => toast.dismiss(t.id)}
/>
));
} catch (error) {
console.log(error);
toast.custom((t) => (
<Snackbar
show={t.visible}
message="An error has occurred"
severity="error"
closeAction={() => toast.dismiss(t.id)}
/>
));
}
More API functions could be integrated like: