mirror of
https://github.com/vercel/commerce.git
synced 2025-06-15 11:51:21 +00:00
Fix: Align all dynamic server pages with Next.js 15 Promise props
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.
This commit is contained in:
parent
17e5ae33a8
commit
b23fd423a5
@ -27,24 +27,26 @@ async function getContent(slug: string) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return allContent[slug] || null;
|
// Ensure slug is a string before using it as an index
|
||||||
|
return allContent[String(slug)] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define an interface for the page's props, including searchParams
|
// Define an interface for the page's props, with params and searchParams as Promises
|
||||||
interface ContentPageProps {
|
interface ContentPageProps {
|
||||||
params: {
|
params: Promise<{ slug: string }>;
|
||||||
slug: string;
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||||
};
|
|
||||||
searchParams: { [key: string]: string | string[] | undefined };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function ContentPage({ params, searchParams }: ContentPageProps) {
|
export default async function ContentPage({ params, searchParams }: ContentPageProps) {
|
||||||
// searchParams is now destructured but not necessarily used if the page doesn't need it.
|
// Await the params promise to get its value
|
||||||
// This is to satisfy the PageProps constraint.
|
const resolvedParams = await params;
|
||||||
const content = await getContent(params.slug);
|
// Await searchParams if you need to use them, e.g.:
|
||||||
|
// const resolvedSearchParams = await searchParams;
|
||||||
|
|
||||||
|
const content = await getContent(resolvedParams.slug);
|
||||||
|
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return <div>Content not found for {params.slug}</div>;
|
return <div>Content not found for {resolvedParams.slug}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -57,7 +59,7 @@ export default async function ContentPage({ params, searchParams }: ContentPageP
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: Generate static paths if you have a known set of content pages
|
// Optional: Generate static params still works the same way
|
||||||
// export async function generateStaticParams() {
|
// export async function generateStaticParams() {
|
||||||
// return [{ slug: 'about-us' }, { slug: 'contact-us' }, { slug: 'privacy-policy' }];
|
// return [{ slug: 'about-us' }, { slug: 'contact-us' }, { slug: 'privacy-policy' }];
|
||||||
// }
|
// }
|
||||||
|
@ -3,63 +3,31 @@
|
|||||||
// Simulate fetching product data
|
// Simulate fetching product data
|
||||||
async function getProduct(handle: string) {
|
async function getProduct(handle: string) {
|
||||||
const allProducts: { [key: string]: any } = { // Use 'any' for simplicity in this mock
|
const allProducts: { [key: string]: any } = { // Use 'any' for simplicity in this mock
|
||||||
'sample-product-1': {
|
'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' } ] },
|
||||||
id: 'prod-1',
|
'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' } ] },
|
||||||
name: 'Awesome T-Shirt',
|
'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' } ] }
|
||||||
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' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// Simulate network delay
|
await new Promise(resolve => setTimeout(resolve, 50)); // Simulate network delay
|
||||||
await new Promise(resolve => setTimeout(resolve, 50));
|
return allProducts[String(handle)] || null; // Ensure handle is string
|
||||||
return allProducts[handle] || null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function ProductPage({ params }: { params: { handle: string } }) {
|
interface ProductPageProps {
|
||||||
const product = await getProduct(params.handle);
|
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) {
|
if (!product) {
|
||||||
// In a real app, you might use Next.js's notFound() function here
|
return <div style={{ padding: '20px', textAlign: 'center' }}>Product not found for handle: {resolvedParams.handle}</div>;
|
||||||
return <div style={{ padding: '20px', textAlign: 'center' }}>Product not found for handle: {params.handle}</div>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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' }}>
|
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif', maxWidth: '800px', margin: '0 auto' }}>
|
||||||
<h1>{product.name}</h1>
|
<h1>{product.name}</h1>
|
||||||
|
|
||||||
@ -90,7 +58,6 @@ export default async function ProductPage({ params }: { params: { handle: string
|
|||||||
<p>No variants available for this product.</p>
|
<p>No variants available for this product.</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Add to cart button can be a simple placeholder */}
|
|
||||||
<button
|
<button
|
||||||
style={{
|
style={{
|
||||||
padding: '10px 20px',
|
padding: '10px 20px',
|
||||||
|
@ -22,12 +22,21 @@ async function getProductsByCollection(collectionName: string) {
|
|||||||
]
|
]
|
||||||
// Add more dummy collections and products as needed
|
// Add more dummy collections and products as needed
|
||||||
};
|
};
|
||||||
return allProducts[collectionName.toLowerCase()] || [];
|
// Ensure collectionName is string and lowercase for object key access
|
||||||
|
return allProducts[String(collectionName).toLowerCase()] || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function CollectionPage({ params }: { params: { collection: string } }) {
|
interface CollectionPageProps {
|
||||||
const products = await getProductsByCollection(params.collection);
|
params: Promise<{ collection: string }>;
|
||||||
const collectionName = params.collection.charAt(0).toUpperCase() + params.collection.slice(1);
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function CollectionPage({ params, searchParams }: CollectionPageProps) {
|
||||||
|
const resolvedParams = await params;
|
||||||
|
// const resolvedSearchParams = await searchParams; // Await if needed for filtering, etc.
|
||||||
|
|
||||||
|
const products = await getProductsByCollection(resolvedParams.collection);
|
||||||
|
const collectionName = resolvedParams.collection.charAt(0).toUpperCase() + resolvedParams.collection.slice(1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
|
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user