From 8255b3ff9ea3b2c128cd669a1df0a6956fe970c3 Mon Sep 17 00:00:00 2001 From: Daniel Carvalho Date: Thu, 24 Apr 2025 13:05:52 +0100 Subject: [PATCH] List All Products --- src/App.css | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/App.tsx | 83 +++++++++++++++++++++++++++++++----------------- 2 files changed, 145 insertions(+), 28 deletions(-) diff --git a/src/App.css b/src/App.css index b9d355d..fadabe4 100644 --- a/src/App.css +++ b/src/App.css @@ -40,3 +40,93 @@ .read-the-docs { color: #888; } + +.App { + max-width: 1200px; + margin: 0 auto; + padding: 2rem; +} + +h1 { + text-align: center; + margin-bottom: 2rem; + color: #333; +} + +.loading { + text-align: center; + font-size: 1.5rem; + color: #666; + margin-top: 2rem; +} + +.products-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 2rem; + padding: 1rem; +} + +.product-card { + background: white; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + padding: 1rem; + transition: transform 0.2s ease-in-out; + display: flex; + flex-direction: column; +} + +.product-card:hover { + transform: translateY(-5px); +} + +.product-card img { + width: 100%; + height: 200px; + object-fit: contain; + margin-bottom: 1rem; + background: #f5f5f5; + border-radius: 4px; +} + +.product-card h3 { + font-size: 1rem; + margin: 0.5rem 0; + color: #333; + flex-grow: 1; +} + +.price { + font-size: 1.25rem; + font-weight: bold; + color: #2c3e50; + margin: 0.5rem 0; +} + +.category { + font-size: 0.9rem; + color: #666; + text-transform: capitalize; + margin: 0.5rem 0; +} + +.rating { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.9rem; + color: #666; + margin-top: auto; +} + +@media (max-width: 768px) { + .products-grid { + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1rem; + } + + .App { + padding: 1rem; + } +} diff --git a/src/App.tsx b/src/App.tsx index 3d7ded3..1e1b5dd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,35 +1,62 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' -import './App.css' +import { useEffect, useState } from "react"; +import "./App.css"; + +interface Product { + id: number; + title: string; + price: number; + description: string; + category: string; + image: string; + rating: { + rate: number; + count: number; + }; +} function App() { - const [count, setCount] = useState(0) + const [products, setProducts] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchProducts = async () => { + try { + const response = await fetch("https://fakestoreapi.com/products"); + const data = await response.json(); + setProducts(data); + } catch (error) { + console.error("Error fetching products:", error); + } finally { + setLoading(false); + } + }; + + fetchProducts(); + }, []); + + if (loading) { + return
Loading products...
; + } return ( - <> -
- - Vite logo - - - React logo - -
-

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

+
+

Products

+
+ {products.map((product) => ( +
+ {product.title} +

{product.title}

+

${product.price}

+

{product.category}

+
+ ⭐ {product.rating.rate} + ({product.rating.count} reviews) +
+
+ ))}
-

- Click on the Vite and React logos to learn more -

- - ) +
+ ); } -export default App +export default App;