diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index a2dc41ec..12563156 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -1,7 +1,7 @@ @import "tailwindcss"; :root { - --background: #ffffff; + --background: white; --foreground: #171717; } @@ -20,7 +20,7 @@ } body { - background: var(--background); + background: white; color: var(--foreground); font-family: Arial, Helvetica, sans-serif; } diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index f7fa87eb..08027197 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -13,8 +13,8 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Frontend Assessment", + description: "A simple product listing page with data fetching", }; export default function RootLayout({ @@ -23,10 +23,8 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - + + {children} diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index e68abe6b..24057c13 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,103 +1,4 @@ -import Image from "next/image"; - -export default function Home() { - return ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - src/app/page.tsx - - . -
  2. -
  3. - Save and see your changes instantly. -
  4. -
- -
- - Vercel logomark - Deploy now - - - Read our docs - -
-
- -
- ); +import Main from "../components/Main"; +export default async function Home() { + return (
); } diff --git a/frontend/src/components/card.tsx b/frontend/src/components/card.tsx new file mode 100644 index 00000000..85381fab --- /dev/null +++ b/frontend/src/components/card.tsx @@ -0,0 +1,13 @@ + +export default function Card({productName, price, imageURL, onClick}) { + return ( +
+ +

{productName}

+

${price}

+
+ ); +} diff --git a/frontend/src/components/main.tsx b/frontend/src/components/main.tsx new file mode 100644 index 00000000..7514bbb7 --- /dev/null +++ b/frontend/src/components/main.tsx @@ -0,0 +1,81 @@ +"use client" + +import Card from "./Card"; +import Preview from "./Preview"; +import { useState, useEffect } from 'react'; + +export default function Main() { + + var [productData, setProductData ] = useState([]); + var [filteredData, setFilteredProductData] = useState([]); + var [previewProductData, setPreviewProductData] = useState(null); + + var searchItems = function(value){ + if(productData.length == 0) return; + + if(value.trim() == ""){ + setFilteredProductData(productData); + return; + } + + const results = productData.filter(item => + item.title.toLowerCase().includes(value.toLowerCase()) + ); + + setFilteredProductData(results); + } + + useEffect(() => { + + (async () => { + const res = await fetch('https://fakestoreapi.com/products'); + const data = await res.json(); + if(data){ + setProductData(data); + setFilteredProductData(data); + } + })() + + }, []); + + return ( +
+ searchItems(e.target.value) } type="text" placeholder="Search Product" className="z-[90] max-w-[90%] fixed top-[20px] left-[20px] rounded-[20px] p-[10px] w-[300px] bg-gray-800 text-base text-white placeholder:text-gray-500 focus:outline-none sm:text-sm/6" /> + +
+ + { previewProductData && + ( + { setPreviewProductData(null) }} + /> + ) + } + + { filteredData.length == 0 &&
No Product Avaible
} + +
+ + { + filteredData.map( data => + ( { setPreviewProductData(data) }} + />) + ) + } + +
+
+
+ + ); +} \ No newline at end of file diff --git a/frontend/src/components/preview.tsx b/frontend/src/components/preview.tsx new file mode 100644 index 00000000..ed2ff1d4 --- /dev/null +++ b/frontend/src/components/preview.tsx @@ -0,0 +1,34 @@ +export default function Preview({ productName, description, price, imageURL, ratings, onClick }) { + + var starRatingStr = ""; + for (var i = 0; i < 5; i++) { + if(i < Math.round(ratings.rate)) starRatingStr += "★"; + else starRatingStr += "☆"; + } + + return ( +
+
+ +
+ +
+
+ { productName } + ${price} +
+ +
+ { starRatingStr } + {ratings.count || 1} reviews +
+ +
{description}
+
+ + X +
+ +
+ ); +}