From 1c2abef4b07f52871769e6542cc65d0e1caeaee9 Mon Sep 17 00:00:00 2001 From: Amritanshu Date: Thu, 17 Oct 2024 22:27:12 +0530 Subject: [PATCH] Made the product detail page server side. --- .../products/[handle]/ProductDetails.tsx | 80 +++---------------- .../(storefront)/products/[handle]/page.tsx | 68 +++++++++------- 2 files changed, 53 insertions(+), 95 deletions(-) diff --git a/src/app/(storefront)/products/[handle]/ProductDetails.tsx b/src/app/(storefront)/products/[handle]/ProductDetails.tsx index 8784adf..6c04f3a 100644 --- a/src/app/(storefront)/products/[handle]/ProductDetails.tsx +++ b/src/app/(storefront)/products/[handle]/ProductDetails.tsx @@ -3,80 +3,23 @@ import { HttpTypes } from '@medusajs/types'; import { ShoppingCart, Star } from 'lucide-react'; import Image from 'next/image'; -import { FC, useEffect, useState } from 'react'; +import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { useCart } from '@/providers/cart'; -import { useRegion } from '@/providers/region'; interface ProductDetailsProps { - handle: string; + product: HttpTypes.StoreProduct; } -const ProductDetails: FC = ({ handle }) => { +export default function ProductDetails({ product }: ProductDetailsProps) { const [quantity, setQuantity] = useState(1); - const [product, setProduct] = useState(); - const [selectedVariant, setSelectedVariant] = useState(null); + const [selectedVariant, setSelectedVariant] = useState(); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - const { region } = useRegion(); - const { cart, addToCart } = useCart(); - - useEffect(() => { - if (!region || !cart) { - return; - } - const fetchProduct = async () => { - try { - const params = new URLSearchParams({ - handle: handle, - fields: `*variants.calculated_price`, - region_id: region?.id as string, - }); - const products: HttpTypes.StoreProduct[] = await fetch( - `${process.env.NEXT_PUBLIC_STORE_URL}/store/products?${params}`, - { - credentials: 'include', - headers: { - 'Content-Type': 'application/json', - 'x-publishable-api-key': process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY as string, - }, - }, - ) - .then((res) => res.json()) - .then((data) => data.products); - - if (products && products.length) { - setProduct(products[0]); - setSelectedVariant(products[0].variants?.[0] || null); - } else { - setProduct(null); - } - } catch (err: unknown) { - setError(err); - } finally { - setIsLoading(false); - } - }; - fetchProduct(); - }, [handle, region, cart]); - - if (!region || isLoading) { - return
Loading...
; // Or a skeleton/loading component - } - if (error) { - console.log('Something went wrong error: ', error); - return
Something went wrong
; - } - - if (!product) { - return
Product not found.
; - } + const { addToCart } = useCart(); return (
@@ -112,15 +55,18 @@ const ProductDetails: FC = ({ handle }) => {
(128 reviews) -

${selectedVariant?.calculated_price?.calculated_amount?.toFixed(2)}

+

₹{selectedVariant?.calculated_price?.calculated_amount?.toFixed(2)}

{product.description}

Choose Variant:

- setSelectedVariant(product.variants?.find((v) => v.id === value) || product.variants?.[0] || null) + setSelectedVariant( + product.variants?.find((v) => v.id === value) || + (product.variants?.[0] as HttpTypes.StoreProductVariant), + ) } > {product.variants?.map((variant) => ( @@ -205,6 +151,4 @@ const ProductDetails: FC = ({ handle }) => {
); -}; - -export default ProductDetails; +} diff --git a/src/app/(storefront)/products/[handle]/page.tsx b/src/app/(storefront)/products/[handle]/page.tsx index d615cb7..f5d34b4 100644 --- a/src/app/(storefront)/products/[handle]/page.tsx +++ b/src/app/(storefront)/products/[handle]/page.tsx @@ -1,5 +1,4 @@ -// import { HttpTypes } from '@medusajs/types'; -import { FC } from 'react'; +import { HttpTypes } from '@medusajs/types'; import ProductDetails from './ProductDetails'; @@ -8,35 +7,50 @@ interface ProductPageProps { handle: string; }; } -// export async function generateStaticParams() { -// // Fetch the list of products -// const products: HttpTypes.StoreProduct[] = await fetch(`${process.env.NEXT_PUBLIC_STORE_URL}/store/products`, { -// credentials: 'include', -// headers: { -// 'Content-Type': 'application/json', -// 'x-publishable-api-key': process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY as string, -// }, -// }) -// .then((res) => res.json()) -// .then((data) => data.products); -// if (!products) { -// return []; -// } -// // Generate static params based on product handles -// const staticParams = products.map((product) => ({ -// handle: product.handle, -// })); -// return staticParams; -// } +async function fetchProduct(handle: string, region: HttpTypes.StoreRegion | undefined) { + try { + const params = new URLSearchParams({ + handle: handle, + fields: `*variants.calculated_price`, + region_id: region?.id || (process.env.NEXT_PUBLIC_DEFAULT_REGION_ID as string), + }); + const response = await fetch( + // const products: HttpTypes.StoreProduct[] = await fetch( + `${process.env.NEXT_PRIVATE_BASE_URL}/store/products?${params}`, + { + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + 'x-publishable-api-key': process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY as string, + }, + }, + ); -const ProductPage: FC = ({ params }) => { + if (!response.ok) { + console.error('Failed to fetch product:', response.statusText); + return null; + } + + const data = await response.json(); + if (!data.products || !data.products.length) { + console.error('No products found'); + return null; + } + return data.products[0]; + } catch (error) { + console.error('Error fetching product:', error); + return null; + } +} + +export default async function ProductPage({ params }: ProductPageProps) { + // const { region } = useRegion(); const { handle } = params; // Extract the handle from the params + const product: HttpTypes.StoreProduct = await fetchProduct(handle, undefined); return ( // Render the client component and pass necessary props - + ); -}; - -export default ProductPage; +}