diff --git a/src/api/ProductData.ts b/src/api/ProductData.ts index 4eea1ae..d8124c0 100644 --- a/src/api/ProductData.ts +++ b/src/api/ProductData.ts @@ -1,9 +1,8 @@ export type productData = { id: number; - name: string; - brand: string; + title: string; description: string; price: string; - photo: string; + image: string; quantity: number; }; diff --git a/src/api/products-service.ts b/src/api/products-service.ts index c990f74..380e8b1 100644 --- a/src/api/products-service.ts +++ b/src/api/products-service.ts @@ -3,10 +3,7 @@ import { useQuery } from '@tanstack/react-query'; export function GetProducts() { const { isPending, error, data } = useQuery({ queryKey: ['productsData'], - queryFn: () => - fetch('https://mks-frontend-challenge-04811e8151e6.herokuapp.com/api/v1/products/?page=1&rows=20&sortBy=id&orderBy=ASC').then(res => - res.json() - ), + queryFn: () => fetch('https://fakestoreapi.com/products').then(res => res.json()), }); return { isPending, error, data }; diff --git a/src/components/CartItem.tsx b/src/components/CartItem.tsx index 25f8e32..00a3cd1 100644 --- a/src/components/CartItem.tsx +++ b/src/components/CartItem.tsx @@ -89,31 +89,32 @@ const QuantityButton = styled.button` } `; -export default function CartItem({product}:{product: productData}) { - const {dispatch} = useContext(StoreContext); +export default function CartItem({ product }: { product: productData }) { + const { dispatch } = useContext(StoreContext); const [productQty, setProductQty] = useState(1); - useEffect(() => dispatch({type:'updateProductsPrices',newPrice:{id:product.id,price:Number(product.price) * productQty}}),[productQty,dispatch,product]); + useEffect( + () => dispatch({ type: 'updateProductsPrices', newPrice: { id: product.id, price: Number(product.price) * productQty } }), + [productQty, dispatch, product] + ); function deleteProduct() { - dispatch({type: 'deleteProduct', product: product}); - dispatch({type:'deleteProductPrice', product: product}); + dispatch({ type: 'deleteProduct', product: product }); + dispatch({ type: 'deleteProductPrice', product: product }); } return ( <> deleteProduct()}>X - {product.name} - - {product.brand} {product.name} - + {product.title} + {product.title}
{ - if(productQty > 1) setProductQty((productQty) => productQty - 1); + if (productQty > 1) setProductQty(productQty => productQty - 1); }}> - @@ -128,12 +129,12 @@ export default function CartItem({product}:{product: productData}) { { - setProductQty((productQty) => productQty + 1); + setProductQty(productQty => productQty + 1); }}> +
- R${Number(product.price) * productQty} + ${Number(product.price) * productQty}
diff --git a/src/components/Checkout.tsx b/src/components/Checkout.tsx index e099471..d1b5d9b 100644 --- a/src/components/Checkout.tsx +++ b/src/components/Checkout.tsx @@ -1,4 +1,4 @@ -import { useContext, useEffect, useState} from 'react'; +import { useContext, useEffect, useState } from 'react'; import { styled } from 'styled-components'; import { productData } from '../api/ProductData'; import { StoreContext } from './Store'; @@ -71,17 +71,17 @@ const CheckoutPurchaseButton = styled.button` export default function Checkout() { const { state, dispatch } = useContext(StoreContext); - const [totalPrice,setTotalPrice] = useState(0); + const [totalPrice, setTotalPrice] = useState(0); useEffect(() => { - setTotalPrice(state.productsPrices.reduce((acc:number,item:{id:number,price:number}) => acc + item?.price,0)); - },[state.selectedProducts, state.productsPrices]); + setTotalPrice(state.productsPrices.reduce((acc: number, item: { id: number; price: number }) => acc + item?.price, 0)); + }, [state.selectedProducts, state.productsPrices]); return ( <> - Carrinho de compras + Cart dispatch({ type: 'openCloseCheckout' })}>X @@ -91,9 +91,9 @@ export default function Checkout() {

Total:

- R${totalPrice} + ${totalPrice}
- Finalizar Compra + Checkout
); diff --git a/src/components/ProductCard.tsx b/src/components/ProductCard.tsx index bf05bef..0df6477 100644 --- a/src/components/ProductCard.tsx +++ b/src/components/ProductCard.tsx @@ -1,8 +1,8 @@ -import styled from "styled-components"; -import { productData } from "../api/ProductData"; -import { BuyButton, Card, PriceTag, Wrapper } from "./shared/styled-components"; -import { useContext } from "react"; -import { StoreContext } from "./Store"; +import styled from 'styled-components'; +import { productData } from '../api/ProductData'; +import { BuyButton, Card, PriceTag, Wrapper } from './shared/styled-components'; +import { useContext } from 'react'; +import { StoreContext } from './Store'; const ProductPhoto = styled.img` place-self: center; @@ -20,29 +20,27 @@ const P = styled.p` margin-bottom: 3.5rem; `; -export default function ProductCard({product}:{product:productData}) { - const {state,dispatch} = useContext(StoreContext); +export default function ProductCard({ product }: { product: productData }) { + const { state, dispatch } = useContext(StoreContext); return ( <> - + - - {product.brand} {product.name} - - R${Number(product.price)} + {product.title} + ${Number(product.price)}

{product.description}

{ - if (state.selectedProducts.includes(product)) return; - dispatch({type:'addProduct',product:product}); - dispatch({type:'updateProductsPrices',newPrice: {id: product.id, price: Number(product.price)}}); - }}> + onClick={() => { + if (state.selectedProducts.includes(product)) return; + dispatch({ type: 'addProduct', product: product }); + dispatch({ type: 'updateProductsPrices', newPrice: { id: product.id, price: Number(product.price) } }); + }}> shopping bag - Comprar + Add to cart
- ) + ); } diff --git a/src/components/Store.tsx b/src/components/Store.tsx index 062e6a7..6fd8973 100644 --- a/src/components/Store.tsx +++ b/src/components/Store.tsx @@ -4,7 +4,7 @@ import Checkout from './Checkout'; import { createContext, useReducer } from 'react'; import { productData } from '../api/ProductData'; import Loading from './Loading'; -import ProductCard from './ProductCard' +import ProductCard from './ProductCard'; const CartButton = styled.button` border-radius: 8px; @@ -26,8 +26,8 @@ const CartButton = styled.button` type StoreCtx = { selectedProducts: productData[]; isOpen: boolean; - productsPrices: {id: number; price: number}[]; -} + productsPrices: { id: number; price: number }[]; +}; const StoreInitialState: StoreCtx = { selectedProducts: [], @@ -36,53 +36,45 @@ const StoreInitialState: StoreCtx = { }; type Action = - | {type: 'addProduct', product: productData} - | {type: 'openCloseCheckout'} - | {type: 'deleteProduct', product: productData} - | {type: 'updateProductsPrices', newPrice: {id: number; price: number}} - | {type: 'deleteProductPrice', product: productData}; + | { type: 'addProduct'; product: productData } + | { type: 'openCloseCheckout' } + | { type: 'deleteProduct'; product: productData } + | { type: 'updateProductsPrices'; newPrice: { id: number; price: number } } + | { type: 'deleteProductPrice'; product: productData }; -export const StoreContext = createContext<{state:StoreCtx,dispatch: React.Dispatch}>({state:StoreInitialState, dispatch: () => {}}); +export const StoreContext = createContext<{ state: StoreCtx; dispatch: React.Dispatch }>({ state: StoreInitialState, dispatch: () => {} }); function reducer(state: StoreCtx, action: Action): StoreCtx { switch (action.type) { case 'addProduct': { - return {...state, - selectedProducts: state.selectedProducts.concat(action.product) - }; + return { ...state, selectedProducts: state.selectedProducts.concat(action.product) }; } case 'openCloseCheckout': { - return {...state, - isOpen: !state.isOpen - }; + return { ...state, isOpen: !state.isOpen }; } case 'deleteProduct': { - return {...state, - selectedProducts: state.selectedProducts.filter((p: productData) => p != action.product) - }; + return { ...state, selectedProducts: state.selectedProducts.filter((p: productData) => p != action.product) }; } case 'updateProductsPrices': { - if(state.productsPrices.every(p => p.id !== action.newPrice.id)) { - return {...state,productsPrices: [...state.productsPrices,action.newPrice]}; + if (state.productsPrices.every(p => p.id !== action.newPrice.id)) { + return { ...state, productsPrices: [...state.productsPrices, action.newPrice] }; } - state.productsPrices.map((product:{id:number,price:number}) => { - if(product.id === action.newPrice.id) { + state.productsPrices.map((product: { id: number; price: number }) => { + if (product.id === action.newPrice.id) { // Object.defineProperty(product,'price',{value:action.newPrice.price}); product.price = action.newPrice.price; } }); - return {...state, productsPrices: [...state.productsPrices]}; + return { ...state, productsPrices: [...state.productsPrices] }; } case 'deleteProductPrice': { - return {...state, - productsPrices: state.productsPrices.filter((price) => price.id != action.product.id) - }; + return { ...state, productsPrices: state.productsPrices.filter(price => price.id != action.product.id) }; } } } export default function Store() { - const [state,dispatch] = useReducer(reducer,StoreInitialState); + const [state, dispatch] = useReducer(reducer, StoreInitialState); const productsInCart = state.selectedProducts?.length; const fetchProducts = GetProducts(); @@ -91,13 +83,13 @@ export default function Store() { return ( <> - dispatch({type: 'openCloseCheckout'})}> + dispatch({ type: 'openCloseCheckout' })}> cart {productsInCart} - + - {fetchProducts.data?.products.map((product: productData) => ( + {fetchProducts.data?.map((product: productData) => ( ))} diff --git a/src/components/shared/styled-components.ts b/src/components/shared/styled-components.ts index c839824..8229bed 100644 --- a/src/components/shared/styled-components.ts +++ b/src/components/shared/styled-components.ts @@ -7,9 +7,10 @@ export const ProductsGrid = styled.ul` display: grid; gap: 1.5rem; justify-items: center; - margin: 1.2rem auto; + margin: 1.2rem; @media screen and (min-width: 630px) { grid-template-columns: repeat(2, 1fr); + margin: 1.2rem auto; } @media screen and (min-width: 1000px) { @@ -27,7 +28,7 @@ export const Card = styled.li` padding: 10px 15px 0; border-radius: 8px; box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.14); - max-width: 250px; + max-width: fit-content; display: grid; position: relative; `;