This commit is contained in:
Your Name committed 2026-06-13 23:22:40 -04:00
1 parent 310e48fe6a
commit 0d10c7a071
2 files changed
+32 -5

No files matched your search

@@ -0,0 +1,19 @@
-- CreateTable
CREATE TABLE "ProductTranslation" (
"id" SERIAL NOT NULL,
"productId" INTEGER NOT NULL,
"langCode" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT,
"details" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "ProductTranslation_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "ProductTranslation_productId_langCode_key" ON "ProductTranslation"("productId", "langCode");
-- AddForeignKey
ALTER TABLE "ProductTranslation" ADD CONSTRAINT "ProductTranslation_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+13 -5
View File
@@ -7,9 +7,17 @@ import ProductCard from '../components/ProductCard'
import ProductReviews from '../components/ProductReviews' import ProductReviews from '../components/ProductReviews'
import ProductImageGallery from '../components/ProductImageGallery' import ProductImageGallery from '../components/ProductImageGallery'
import DynamicPageRenderer from '../components/DynamicPageRenderer' import DynamicPageRenderer from '../components/DynamicPageRenderer'
import { API_BASE, getCategoryImage, formatPrice, type Category, type Product, type PageSection } from '../types' import { API_BASE, getCategoryImage, formatPrice, type Category, type Product, type PageSection, type TranslatableString } from '../types'
import { useCartStore } from '../store/cartStore' import { useCartStore } from '../store/cartStore'
/** แปลง TranslatableString (string | Record<string,string>) เป็น string ตาม locale */
function resolveTranslatable(value: TranslatableString | null | undefined, lang: string): string {
if (!value) return ''
if (typeof value === 'string') return value
// Record<string, string>: ลอง lang เต็ม → ลอง prefix 2 ตัว → fallback 'th'/'en'
return value[lang] ?? value[lang.slice(0, 2)] ?? value['th'] ?? value['en'] ?? Object.values(value)[0] ?? ''
}
export default function ProductDetailPage() { export default function ProductDetailPage() {
const { id } = useParams<{ id: string }>() const { id } = useParams<{ id: string }>()
@@ -176,8 +184,8 @@ export default function ProductDetailPage() {
</p> </p>
</div> </div>
{product.description && ( {resolveTranslatable(product.description, i18n.language) && (
<p className="text-spa-stone leading-relaxed">{product.description}</p> <p className="text-spa-stone leading-relaxed">{resolveTranslatable(product.description, i18n.language)}</p>
)} )}
{/* Price */} {/* Price */}
@@ -250,12 +258,12 @@ export default function ProductDetailPage() {
</div> </div>
{/* Full Details Section */} {/* Full Details Section */}
{product.details && ( {resolveTranslatable(product.details, i18n.language) && (
<div className="pt-16 border-t border-spa-stone/10 space-y-6"> <div className="pt-16 border-t border-spa-stone/10 space-y-6">
<h2 className="text-3xl font-bold text-pop-black">Product Details</h2> <h2 className="text-3xl font-bold text-pop-black">Product Details</h2>
<div <div
className="prose prose-spa prose-lg max-w-4xl product-editorial text-spa-stone" className="prose prose-spa prose-lg max-w-4xl product-editorial text-spa-stone"
dangerouslySetInnerHTML={{ __html: product.details }} dangerouslySetInnerHTML={{ __html: resolveTranslatable(product.details, i18n.language) }}
/> />
</div> </div>
)} )}