x
This commit is contained in:
1 parent
0d10c7a071
commit
b867063efb
2 files changed
+25
-10
No files matched your search
@@ -6,10 +6,18 @@ import AddToCartSection from '../../../components/AddToCartSection'
|
||||
import ProductCard from '../../../components/ProductCard'
|
||||
|
||||
import { API_BASE } from '../../../lib/api'
|
||||
import type { TranslatableString } from '@homaroma/types'
|
||||
|
||||
/** Resolve TranslatableString → plain string (SSR: always defaults to 'th') */
|
||||
function resolveStr(v: TranslatableString | null | undefined, lang = 'th'): string {
|
||||
if (!v) return ''
|
||||
if (typeof v === 'string') return v
|
||||
return v[lang] ?? v['th'] ?? v['en'] ?? Object.values(v)[0] ?? ''
|
||||
}
|
||||
|
||||
async function getProduct(id: string): Promise<Product | null> {
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/products/${id}`, { next: { revalidate: 60 } })
|
||||
const res = await fetch(`${API_BASE}/products/${id}?lang=th`, { next: { revalidate: 60 } })
|
||||
return res.ok ? res.json() : null
|
||||
} catch { return null }
|
||||
}
|
||||
@@ -29,10 +37,10 @@ export async function generateMetadata({ params }: { params: Promise<{ id: strin
|
||||
if (!product) return { title: 'Product Not Found | HomAroma' }
|
||||
return {
|
||||
title: `${product.scent.name} ${product.category.name} | HomAroma`,
|
||||
description: product.description ?? `Premium ${product.category.name} — ${product.scent.name}. Shop HomAroma for high-quality botanical scents.`,
|
||||
description: resolveStr(product.description) ?? `Premium ${product.category.name} — ${product.scent.name}. Shop HomAroma for high-quality botanical scents.`,
|
||||
openGraph: {
|
||||
title: product.scent.name,
|
||||
description: product.description ?? '',
|
||||
description: resolveStr(product.description) ?? '',
|
||||
images: product.images?.[0]?.url ? [product.images[0].url] : [],
|
||||
},
|
||||
}
|
||||
@@ -85,12 +93,12 @@ export default async function ProductDetailPage({ params }: { params: Promise<{
|
||||
</div>
|
||||
|
||||
{/* Full Details Section */}
|
||||
{product.details && (
|
||||
<div className="pt-16 border-t border-white/5 space-y-6">
|
||||
{resolveStr(product.details) && (
|
||||
<div className="pt-16 border-t border-white/10 space-y-6">
|
||||
<h2 className="text-3xl font-bold">Product Details</h2>
|
||||
<div
|
||||
className="prose prose-invert prose-lg max-w-4xl product-editorial"
|
||||
dangerouslySetInnerHTML={{ __html: product.details }}
|
||||
className="text-slate-300 leading-relaxed prose prose-invert max-w-none"
|
||||
dangerouslySetInnerHTML={{ __html: resolveStr(product.details) }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
"use client";
|
||||
import { useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { getCategoryImage, formatPrice, type Product } from '@homaroma/types'
|
||||
import { getCategoryImage, formatPrice, type Product, type TranslatableString } from '@homaroma/types'
|
||||
import { useCartStore } from '../store/cartStore'
|
||||
|
||||
/** Resolve TranslatableString → plain string */
|
||||
function resolveStr(v: TranslatableString | null | undefined, lang = 'th'): string {
|
||||
if (!v) return ''
|
||||
if (typeof v === 'string') return v
|
||||
return v[lang] ?? v['th'] ?? v['en'] ?? Object.values(v)[0] ?? ''
|
||||
}
|
||||
|
||||
interface Props {
|
||||
product: Product
|
||||
}
|
||||
@@ -40,8 +47,8 @@ export default function AddToCartSection({ product }: Props) {
|
||||
<p className="text-slate-400 text-sm uppercase tracking-widest">Premium Collection</p>
|
||||
</div>
|
||||
|
||||
{product.description && (
|
||||
<p className="text-slate-300 leading-relaxed">{product.description}</p>
|
||||
{resolveStr(product.description) && (
|
||||
<p className="text-slate-300 leading-relaxed">{resolveStr(product.description)}</p>
|
||||
)}
|
||||
|
||||
{/* Price */}
|
||||
|
||||
Reference in new issue
Block a user