mirror of
https://github.com/vercel/commerce.git
synced 2025-06-07 16:56:59 +00:00
This commit applies the Next.js 15 PageProps convention (where `params` and `searchParams` are Promises) to all relevant dynamic server route page components. This resolves the build error: "Type '...' does not satisfy the constraint 'PageProps'. Types of property 'params' are incompatible. Type '{...}' is missing the following properties from type 'Promise<any>': then, catch, finally, [Symbol.toStringTag]" The following pages were updated: - `app/content/[slug]/page.tsx` - `app/product/[handle]/page.tsx` - `app/search/[collection]/page.tsx` In each of these files, the props interface was updated to define `params` and `searchParams` as Promises, and the component logic was modified to `await params` to access their resolved values. `app/search/page.tsx` was verified as a Client Component using `useSearchParams()` and did not require these changes.
78 lines
3.9 KiB
TypeScript
78 lines
3.9 KiB
TypeScript
// app/product/[handle]/page.tsx
|
|
|
|
// Simulate fetching product data
|
|
async function getProduct(handle: string) {
|
|
const allProducts: { [key: string]: any } = { // Use 'any' for simplicity in this mock
|
|
'sample-product-1': { id: 'prod-1', name: 'Awesome T-Shirt', description: 'This is the best t-shirt ever. Made from 100% organic cotton.', price: { amount: '29.99', currencyCode: 'USD' }, images: [ { src: '/placeholder-tshirt-blue.jpg', alt: 'Awesome T-Shirt - Blue' }, { src: '/placeholder-tshirt-red.jpg', alt: 'Awesome T-Shirt - Red' } ], variants: [ { id: 'v1-color', name: 'Color', value: 'Blue' }, { id: 'v1-size', name: 'Size', value: 'L' }, { id: 'v1-material', name: 'Material', value: 'Cotton' } ] },
|
|
'sample-product-2': { id: 'prod-2', name: 'Cool Gadget Pro', description: 'The latest and greatest gadget with amazing features.', price: { amount: '199.50', currencyCode: 'USD' }, images: [ { src: '/placeholder-gadget-main.jpg', alt: 'Cool Gadget Pro' }, { src: '/placeholder-gadget-angle.jpg', alt: 'Cool Gadget Pro - Angle View' } ], variants: [ { id: 'v2-color', name: 'Color', value: 'Black' }, { id: 'v2-storage', name: 'Storage', value: '256GB' } ] },
|
|
'another-item': { id: 'prod-3', name: 'Simple Mug', description: 'A simple mug for your daily coffee or tea.', price: { amount: '12.00', currencyCode: 'USD' }, images: [ { src: '/placeholder-mug.jpg', alt: 'Simple Mug' } ], variants: [ { id: 'v3-color', name: 'Color', value: 'White' }, { id: 'v3-size', name: 'Size', value: 'Standard' } ] }
|
|
};
|
|
await new Promise(resolve => setTimeout(resolve, 50)); // Simulate network delay
|
|
return allProducts[String(handle)] || null; // Ensure handle is string
|
|
}
|
|
|
|
interface ProductPageProps {
|
|
params: Promise<{ handle: string }>;
|
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
|
}
|
|
|
|
export default async function ProductPage({ params, searchParams }: ProductPageProps) {
|
|
const resolvedParams = await params;
|
|
// const resolvedSearchParams = await searchParams; // If needed
|
|
|
|
const product = await getProduct(resolvedParams.handle);
|
|
|
|
if (!product) {
|
|
return <div style={{ padding: '20px', textAlign: 'center' }}>Product not found for handle: {resolvedParams.handle}</div>;
|
|
}
|
|
|
|
return (
|
|
// ... (rest of the JSX should be the same, just ensure 'params.handle' is replaced with 'resolvedParams.handle' if it was used in the notFound message)
|
|
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif', maxWidth: '800px', margin: '0 auto' }}>
|
|
<h1>{product.name}</h1>
|
|
|
|
{product.images && product.images.length > 0 && (
|
|
<img
|
|
src={product.images[0].src}
|
|
alt={product.images[0].alt || product.name}
|
|
style={{ maxWidth: '100%', height: 'auto', maxHeight: '400px', marginBottom: '20px', border: '1px solid #ddd' }}
|
|
/>
|
|
)}
|
|
|
|
<p style={{ fontSize: '1.1em', lineHeight: '1.6' }}>{product.description}</p>
|
|
|
|
<p style={{ fontSize: '1.2em', fontWeight: 'bold', margin: '20px 0' }}>
|
|
Price: {product.price.amount} {product.price.currencyCode}
|
|
</p>
|
|
|
|
<h2>Variants:</h2>
|
|
{product.variants && product.variants.length > 0 ? (
|
|
<ul style={{ listStyle: 'none', padding: 0 }}>
|
|
{product.variants.map((variant: any) => ( // Using any for mock simplicity
|
|
<li key={variant.id} style={{ marginBottom: '8px', borderBottom: '1px solid #eee', paddingBottom: '8px' }}>
|
|
<strong>{variant.name}:</strong> {variant.value}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : (
|
|
<p>No variants available for this product.</p>
|
|
)}
|
|
|
|
<button
|
|
style={{
|
|
padding: '10px 20px',
|
|
fontSize: '1em',
|
|
color: 'white',
|
|
backgroundColor: '#007bff',
|
|
border: 'none',
|
|
borderRadius: '5px',
|
|
cursor: 'pointer',
|
|
marginTop: '20px'
|
|
}}
|
|
>
|
|
Add to Cart
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|