|
1 |
| -import type { Product } from '@type/products'; |
| 1 | +'use client'; |
| 2 | +import largeData from '@/src/mock/large/products.json'; |
| 3 | +import smallData from '@/src/mock/small/products.json'; |
| 4 | +import { useState, useEffect } from 'react'; |
| 5 | +import Link from 'next/link'; |
| 6 | + |
| 7 | +const PAGE_SIZE = 20; |
2 | 8 |
|
3 | 9 | export default function Products() {
|
4 |
| - const products: Array<Product> = [ |
5 |
| - { |
6 |
| - id: 1, |
7 |
| - name: 'Product 1', |
8 |
| - price: 100, |
9 |
| - description: 'This is a product', |
10 |
| - category: 'Category 1', |
11 |
| - rating: 4.5, |
12 |
| - numReviews: 10, |
13 |
| - countInStock: 6, |
14 |
| - }, |
15 |
| - { |
16 |
| - id: 2, |
17 |
| - name: 'Product 2', |
18 |
| - price: 200, |
19 |
| - description: 'This is a product', |
20 |
| - category: 'Category 2', |
21 |
| - rating: 4.0, |
22 |
| - numReviews: 10, |
23 |
| - countInStock: 6, |
24 |
| - }, |
25 |
| - { |
26 |
| - id: 3, |
27 |
| - name: 'Product 3', |
28 |
| - price: 300, |
29 |
| - description: 'This is a product', |
30 |
| - category: 'Category 3', |
31 |
| - rating: 3.5, |
32 |
| - numReviews: 10, |
33 |
| - countInStock: 6, |
34 |
| - }, |
35 |
| - { |
36 |
| - id: 4, |
37 |
| - name: 'Product 4', |
38 |
| - price: 400, |
39 |
| - description: 'This is a product', |
40 |
| - category: 'Category 4', |
41 |
| - rating: 3.0, |
42 |
| - numReviews: 10, |
43 |
| - countInStock: 6, |
44 |
| - }, |
45 |
| - { |
46 |
| - id: 5, |
47 |
| - name: 'Product 5', |
48 |
| - price: 500, |
49 |
| - description: 'This is a product', |
50 |
| - category: 'Category 5', |
51 |
| - rating: 2.5, |
52 |
| - numReviews: 10, |
53 |
| - countInStock: 6, |
54 |
| - }, |
55 |
| - ]; |
| 10 | + const [currentPage, setCurrentPage] = useState(1); |
| 11 | + const data = [...largeData, ...smallData]; |
| 12 | + const startIndex = (currentPage - 1) * PAGE_SIZE; |
| 13 | + const endIndex = startIndex + PAGE_SIZE; |
| 14 | + const productData = data.slice(startIndex, endIndex); |
| 15 | + const totalPages = Math.ceil(data.length / PAGE_SIZE); |
| 16 | + |
| 17 | + const nextPage = () => { |
| 18 | + setCurrentPage(currentPage + 1); |
| 19 | + }; |
| 20 | + |
| 21 | + const prevPage = () => { |
| 22 | + setCurrentPage(currentPage - 1); |
| 23 | + }; |
| 24 | + |
| 25 | + useEffect(() => { |
| 26 | + window.scrollTo(0, 0); |
| 27 | + }, [currentPage]); |
56 | 28 |
|
57 | 29 | return (
|
58 | 30 | <main className='flex min-h-screen flex-col items-center p-24'>
|
59 | 31 | <div className='z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex'>
|
60 | 32 | <div className='grid lg:max-w-5xl lg:w-full lg:grid-cols-2 lg:text-left'>
|
61 |
| - {products.map((product) => ( |
| 33 | + {productData.map((product) => ( |
62 | 34 | <div
|
63 | 35 | key={product.id}
|
64 | 36 | className='group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30'
|
65 | 37 | >
|
66 |
| - <h3 className={`mb-3 text-2xl font-semibold`}>{product.name}</h3> |
67 |
| - <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Price: {product.price}</p> |
68 |
| - <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Description: {product.description}</p> |
69 |
| - <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Category: {product.category}</p> |
70 |
| - <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Rating: {product.rating}</p> |
71 |
| - <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Reviews: {product.numReviews}</p> |
72 |
| - <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Stock: {product.countInStock}</p> |
| 38 | + <Link href={`/products/${product.id}`}> |
| 39 | + <h3 className={`mb-3 text-2xl font-semibold`}>{product.name}</h3> |
| 40 | + <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Price: {product.price}</p> |
| 41 | + <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Description: {product.description}</p> |
| 42 | + <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Category: {product.category}</p> |
| 43 | + <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Rating: {product.rating}</p> |
| 44 | + <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Reviews: {product.numReviews}</p> |
| 45 | + <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>Stock: {product.countInStock}</p> |
| 46 | + </Link> |
73 | 47 | </div>
|
74 | 48 | ))}
|
75 | 49 | </div>
|
76 | 50 | </div>
|
| 51 | + |
| 52 | + <div className='flex justify-around w-full border-t-2 pt-4'> |
| 53 | + <button onClick={prevPage} disabled={currentPage === 1}> |
| 54 | + Previous |
| 55 | + </button> |
| 56 | + <span> |
| 57 | + Page {currentPage} of {totalPages} |
| 58 | + </span> |
| 59 | + <button onClick={nextPage} disabled={currentPage === totalPages}> |
| 60 | + Next |
| 61 | + </button> |
| 62 | + </div> |
77 | 63 | </main>
|
78 | 64 | );
|
79 | 65 | }
|
0 commit comments