This commit is contained in:
Your Name committed 2026-06-21 02:09:26 -04:00
1 parent 3cacaacbeb
commit 8b73b8dd2f
52 files changed
+265 -265

No files matched your search

+4 -4
View File
@@ -49,13 +49,13 @@ export default function ArticleReaderPage() {
<main className="flex-1 pt-24 pb-20">
<article className="max-w-4xl mx-auto w-full animate-fade-in relative mt-8">
<Link to="/scent-guide" className="absolute -left-16 xl:-left-24 top-0 mt-8 hidden lg:flex p-4 bg-white shadow-sm border border-spa-stone/10 border border-spa-stone/10 rounded-full hover:bg-white/10 transition-colors">
<ArrowLeft className="w-5 h-5 text-slate-300" />
<Link to="/scent-guide" className="absolute -left-16 xl:-left-24 top-0 mt-8 hidden lg:flex p-4 bg-spa-light shadow-sm border border-spa-stone/10 border border-spa-stone/10 rounded-full hover:bg-spa-light transition-colors">
<ArrowLeft className="w-5 h-5 text-spa-stone" />
</Link>
{/* Header */}
<div className="text-center px-6 py-12 space-y-6">
<Link to="/scent-guide" className="lg:hidden text-slate-400 text-sm hover:text-white inline-flex items-center gap-2 mb-4">
<Link to="/scent-guide" className="lg:hidden text-spa-stone text-sm hover:text-spa-light inline-flex items-center gap-2 mb-4">
<ArrowLeft className="w-4 h-4" /> Go Back
</Link>
<p className="text-spa-forest uppercase tracking-[0.3em] font-bold text-xs">
@@ -68,7 +68,7 @@ export default function ArticleReaderPage() {
{/* Cover Image */}
{article.coverImage && (
<div className="w-full aspect-[16/7] bg-white md:rounded-[2rem] overflow-hidden shadow-2xl mb-16 border border-spa-stone/10">
<div className="w-full aspect-[16/7] bg-spa-light md:rounded-[2rem] overflow-hidden shadow-2xl mb-16 border border-spa-stone/10">
<img src={article.coverImage} alt={article.title} className="w-full h-full object-cover" />
</div>
)}
+7 -7
View File
@@ -132,15 +132,15 @@ export default function CategoryPage() {
<div className="max-w-7xl mx-auto">
{/* Breadcrumb */}
<div className="flex items-center gap-2 text-xs text-spa-sage/80 uppercase tracking-widest mb-4 font-semibold">
<Link to="/" className="hover:text-white transition-colors">Home</Link>
<Link to="/" className="hover:text-spa-light transition-colors">Home</Link>
<span>/</span>
<Link to="/shop" className="hover:text-white transition-colors">Shop</Link>
<Link to="/shop" className="hover:text-spa-light transition-colors">Shop</Link>
<span>/</span>
<span className="text-white">{typeof category?.name === 'string' ? category.name : (category?.name as any)?.[localStorage.getItem('app_lang') || 'en'] || (category?.name as any)?.en || '...'}</span>
<span className="text-spa-light">{typeof category?.name === 'string' ? category.name : (category?.name as any)?.[localStorage.getItem('app_lang') || 'en'] || (category?.name as any)?.en || '...'}</span>
</div>
<h1 className="text-4xl md:text-5xl font-bold text-white">
<h1 className="text-4xl md:text-5xl font-bold text-spa-light">
{loading ? (
<div className="h-10 w-48 bg-white/20 animate-pulse rounded-lg" />
<div className="h-10 w-48 bg-spa-light animate-pulse rounded-lg" />
) : (
typeof category?.name === 'string' ? category.name : (category?.name as any)?.[i18n.language] || (category?.name as any)?.en || ''
)}
@@ -165,8 +165,8 @@ export default function CategoryPage() {
to={`/category/${cat.id}`}
className={`px-4 py-1.5 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${
cat.id === category?.id
? 'bg-spa-forest text-white border-spa-forest shadow-md'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
? 'bg-spa-forest text-spa-light border-spa-forest shadow-md'
: 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
}`}
>
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[localStorage.getItem('app_lang') || 'en'] || (cat.name as any)?.en || ''}
+6 -6
View File
@@ -338,7 +338,7 @@ export default function CheckoutPage() {
{/* Form Section */}
<div className="flex-1 space-y-8 order-2 lg:order-1">
<form id="checkout-form" onSubmit={handleSubmit} className="space-y-6">
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<h2 className="text-xl font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">{t('checkout.shippingInfo')}</h2>
<div className="grid md:grid-cols-2 gap-6">
@@ -433,20 +433,20 @@ export default function CheckoutPage() {
<button
type="submit"
disabled={loading || loadingSettings}
className="w-full py-4 px-6 bg-spa-forest text-white font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed flex lg:hidden justify-between items-center mt-4"
className="w-full py-4 px-6 bg-spa-forest text-spa-light font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed flex lg:hidden justify-between items-center mt-4"
>
<div className="flex items-center gap-2">
{loading && <Loader2 className="w-5 h-5 animate-spin" />}
<span>Proceed to Payment</span>
</div>
<span className="text-sm border-l border-white/20 pl-4">{formatPrice(total)}</span>
<span className="text-sm border-l border-spa-light pl-4">{formatPrice(total)}</span>
</button>
</form>
</div>
{/* Summary Section */}
<div className="lg:w-96 space-y-6 order-1 lg:order-2">
<div className="bg-white p-6 lg:p-8 rounded-2xl border border-spa-stone/10 shadow-sm sticky top-32 transition-all">
<div className="bg-spa-light p-6 lg:p-8 rounded-2xl border border-spa-stone/10 shadow-sm sticky top-32 transition-all">
<button
type="button"
onClick={() => setIsSummaryExpanded(!isSummaryExpanded)}
@@ -602,13 +602,13 @@ export default function CheckoutPage() {
form="checkout-form"
type="submit"
disabled={loading || loadingSettings}
className="w-full mt-8 py-4 px-6 bg-spa-forest text-white font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed hidden lg:flex justify-between items-center"
className="w-full mt-8 py-4 px-6 bg-spa-forest text-spa-light font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed hidden lg:flex justify-between items-center"
>
<div className="flex items-center gap-2">
{loading && <Loader2 className="w-5 h-5 animate-spin" />}
<span>Proceed to Payment</span>
</div>
<span className="text-sm border-l border-white/20 pl-4">{formatPrice(total)}</span>
<span className="text-sm border-l border-spa-light pl-4">{formatPrice(total)}</span>
</button>
</div>
</div>
+2 -2
View File
@@ -139,7 +139,7 @@ export default function CouponsPage() {
{coupons.map(coupon => (
<div
key={coupon.id}
className="group relative bg-white border border-spa-stone/10 rounded-3xl overflow-hidden hover:border-spa-forest transition-all duration-500 shadow-sm hover:shadow-md"
className="group relative bg-spa-light border border-spa-stone/10 rounded-3xl overflow-hidden hover:border-spa-forest transition-all duration-500 shadow-sm hover:shadow-md"
>
{/* Decoration */}
<div className="absolute top-0 right-0 w-32 h-32 bg-spa-sage/20 blur-3xl rounded-full -translate-y-1/2 translate-x-1/2" />
@@ -184,7 +184,7 @@ export default function CouponsPage() {
<button
onClick={() => handleUseNow(coupon.code)}
className="w-full py-4 bg-spa-forest text-white hover:bg-spa-stone font-bold rounded-xl flex items-center justify-center gap-2 transition-all duration-300 shadow-sm"
className="w-full py-4 bg-spa-forest text-spa-light hover:bg-spa-stone font-bold rounded-xl flex items-center justify-center gap-2 transition-all duration-300 shadow-sm"
>
ใช้คูปองนี้เลย
<ArrowRight className="w-4 h-4" />
+8 -8
View File
@@ -2,7 +2,7 @@ import { Link } from 'react-router-dom'
export default function NotFoundPage() {
return (
<div className="min-h-screen flex items-center justify-center px-6 bg-white">
<div className="min-h-screen flex items-center justify-center px-6 bg-spa-light">
{/* Background glow */}
<div className="absolute inset-0 pointer-events-none overflow-hidden">
<div className="absolute top-1/3 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-spa-forest/10 rounded-full blur-3xl" />
@@ -22,7 +22,7 @@ export default function NotFoundPage() {
<div className="space-y-3">
<h1 className="text-3xl font-bold">Page Not Found</h1>
<p className="text-slate-400 leading-relaxed">
<p className="text-spa-stone leading-relaxed">
The page you're looking for seems to have drifted away like morning mist. Let's guide you back to serenity.
</p>
</div>
@@ -30,23 +30,23 @@ export default function NotFoundPage() {
<div className="flex flex-col sm:flex-row gap-4 justify-center pt-2">
<Link
to="/"
className="px-8 py-3.5 bg-white text-spa-forest font-bold rounded-lg tracking-widest uppercase hover:bg-spa-forest text-white hover:shadow-[0_0_25px_rgba(102,252,241,0.4)] transition-all duration-500 text-sm"
className="px-8 py-3.5 bg-spa-light text-spa-forest font-bold rounded-lg tracking-widest uppercase hover:bg-spa-forest text-spa-light hover:shadow-[0_0_25px_rgba(102,252,241,0.4)] transition-all duration-500 text-sm"
>
Go Home
</Link>
<Link
to="/shop"
className="px-8 py-3.5 bg-white shadow-sm border border-spa-stone/10 text-white font-bold rounded-lg tracking-widest uppercase hover:bg-white/10 transition-all duration-300 border border-spa-stone/10 text-sm"
className="px-8 py-3.5 bg-spa-light shadow-sm border border-spa-stone/10 text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-light transition-all duration-300 border border-spa-stone/10 text-sm"
>
Browse Products
</Link>
</div>
<div className="pt-4 border-t border-spa-stone/10">
<div className="flex justify-center gap-6 text-xs text-slate-500">
<Link to="/scent-guide" className="hover:text-white transition-colors">Scent Guide</Link>
<Link to="/faq" className="hover:text-white transition-colors">FAQ</Link>
<Link to="/contact" className="hover:text-white transition-colors">Contact</Link>
<div className="flex justify-center gap-6 text-xs text-spa-stone">
<Link to="/scent-guide" className="hover:text-spa-light transition-colors">Scent Guide</Link>
<Link to="/faq" className="hover:text-spa-light transition-colors">FAQ</Link>
<Link to="/contact" className="hover:text-spa-light transition-colors">Contact</Link>
</div>
</div>
</div>
+17 -17
View File
@@ -258,7 +258,7 @@ export default function OrderSuccessPage() {
</div>
{/* Order Summary */}
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<h2 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">Order Items</h2>
<div className="space-y-4">
{order.items.map(item => (
@@ -293,13 +293,13 @@ export default function OrderSuccessPage() {
{order.status === 'PENDING_PAYMENT' ? (
<div className="space-y-8">
{/* Payment Method Selector */}
<div className="bg-white p-4 rounded-2xl border border-spa-stone/10 shadow-sm flex flex-col md:flex-row gap-3">
<div className="bg-spa-light p-4 rounded-2xl border border-spa-stone/10 shadow-sm flex flex-col md:flex-row gap-3">
<button
onClick={() => setPaymentMethod('bank')}
className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${
paymentMethod === 'bank'
? 'bg-spa-forest text-white border-spa-forest shadow-sm'
: 'bg-white text-spa-stone hover:bg-spa-light border-spa-stone/10'
? 'bg-spa-forest text-spa-light border-spa-forest shadow-sm'
: 'bg-spa-light text-spa-stone hover:bg-spa-light border-spa-stone/10'
}`}
>
<Landmark className="w-5 h-5" />
@@ -309,8 +309,8 @@ export default function OrderSuccessPage() {
onClick={() => setPaymentMethod('promptpay')}
className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${
paymentMethod === 'promptpay'
? 'bg-spa-forest text-white border-spa-forest shadow-sm'
: 'bg-white text-spa-stone hover:bg-spa-light border-spa-stone/10'
? 'bg-spa-forest text-spa-light border-spa-forest shadow-sm'
: 'bg-spa-light text-spa-stone hover:bg-spa-light border-spa-stone/10'
}`}
>
<QrCode className="w-5 h-5" />
@@ -320,8 +320,8 @@ export default function OrderSuccessPage() {
onClick={() => setPaymentMethod('card')}
className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${
paymentMethod === 'card'
? 'bg-spa-forest text-white border-spa-forest shadow-sm'
: 'bg-white text-spa-stone hover:bg-spa-light border-spa-stone/10'
? 'bg-spa-forest text-spa-light border-spa-forest shadow-sm'
: 'bg-spa-light text-spa-stone hover:bg-spa-light border-spa-stone/10'
}`}
>
<CreditCard className="w-5 h-5" />
@@ -332,7 +332,7 @@ export default function OrderSuccessPage() {
{/* Bank Transfer Layout */}
{paymentMethod === 'bank' && settings && (
<div className="space-y-8">
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 relative overflow-hidden shadow-sm">
<div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 relative overflow-hidden shadow-sm">
<div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" />
<h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">Payment Required</h2>
<div className="text-3xl font-bold text-spa-forest">{formatPrice(order.totalAmount)}</div>
@@ -348,7 +348,7 @@ export default function OrderSuccessPage() {
</div>
<button
onClick={copyToClipboard}
className="p-2 bg-white rounded-lg hover:bg-spa-stone/10 border border-spa-stone/20 transition-colors shrink-0 shadow-sm"
className="p-2 bg-spa-light rounded-lg hover:bg-spa-stone/10 border border-spa-stone/20 transition-colors shrink-0 shadow-sm"
title="Copy account number"
>
{copied ? <CheckCircle2 className="w-5 h-5 text-emerald-500" /> : <Copy className="w-5 h-5 text-spa-stone/80" />}
@@ -362,7 +362,7 @@ export default function OrderSuccessPage() {
<p className="text-xs text-spa-stone font-medium">Please transfer the exact amount and upload your slip below.</p>
</div>
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<h2 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">Payment Slip Verification</h2>
{order.paymentSlipUrl ? (
<div className="flex flex-col items-center justify-center space-y-4 py-4">
@@ -404,7 +404,7 @@ export default function OrderSuccessPage() {
{/* PromptPay Layout */}
{paymentMethod === 'promptpay' && (
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 relative overflow-hidden shadow-sm">
<div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 relative overflow-hidden shadow-sm">
<div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" />
<h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">PromptPay QR Code</h2>
<div className="text-3xl font-bold text-spa-forest">{formatPrice(order.totalAmount)}</div>
@@ -414,7 +414,7 @@ export default function OrderSuccessPage() {
<button
onClick={handleGeneratePromptPay}
disabled={generatingQr}
className="px-8 py-4 bg-spa-forest text-white font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-3 mx-auto"
className="px-8 py-4 bg-spa-forest text-spa-light font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-3 mx-auto"
>
{generatingQr ? <Loader2 className="w-5 h-5 animate-spin" /> : <QrCode className="w-5 h-5" />}
<span>สร้างคิวอาร์โค้ด PromptPay</span>
@@ -422,7 +422,7 @@ export default function OrderSuccessPage() {
</div>
) : (
<div className="space-y-6 max-w-sm mx-auto">
<div className="bg-white p-4 rounded-xl border border-spa-stone/20 inline-block shadow-sm">
<div className="bg-spa-light p-4 rounded-xl border border-spa-stone/20 inline-block shadow-sm">
<img src={qrCodeUrl} alt="PromptPay QR Code" className="w-64 h-64 object-contain mx-auto" />
</div>
@@ -452,7 +452,7 @@ export default function OrderSuccessPage() {
{/* Credit Card Layout */}
{paymentMethod === 'card' && (
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 relative overflow-hidden shadow-sm">
<div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 relative overflow-hidden shadow-sm">
<div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" />
<div className="text-center space-y-2">
<h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">Credit / Debit Card</h2>
@@ -527,7 +527,7 @@ export default function OrderSuccessPage() {
<button
type="submit"
disabled={payingCard}
className="w-full py-4 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-2 mt-4"
className="w-full py-4 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-2 mt-4"
>
{payingCard ? <Loader2 className="w-5 h-5 animate-spin" /> : <CreditCard className="w-5 h-5" />}
<span>ชำระเงิน {formatPrice(order.totalAmount)}</span>
@@ -537,7 +537,7 @@ export default function OrderSuccessPage() {
)}
</div>
) : (
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 shadow-sm">
<div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 shadow-sm">
<div className="w-16 h-16 bg-emerald-500/10 rounded-full flex items-center justify-center border border-emerald-500/20 mx-auto">
<CheckCircle2 className="w-8 h-8 text-emerald-500" />
</div>
+9 -9
View File
@@ -220,12 +220,12 @@ export default function ProductDetailPage() {
onClick={() => setSelectedVariant(i)}
className={`px-5 py-2.5 rounded-lg text-sm font-bold uppercase tracking-widest transition-all duration-300 border ${
selectedVariant === i
? 'bg-spa-forest text-white border-spa-forest shadow-md'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
? 'bg-spa-forest text-spa-light border-spa-forest shadow-md'
: 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
}`}
>
{v.size}
<span className={`block text-[10px] mt-0.5 ${selectedVariant === i ? 'text-white/80' : 'text-spa-stone/60'}`}>
<span className={`block text-[10px] mt-0.5 ${selectedVariant === i ? 'text-spa-light' : 'text-spa-stone/60'}`}>
{formatPrice(v.price)}
</span>
</button>
@@ -237,11 +237,11 @@ export default function ProductDetailPage() {
<div className="hidden md:flex gap-4">
<button
onClick={handleAddToCart}
className="flex-1 py-4 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300"
className="flex-1 py-4 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300"
>
{t('cart.addToCart')}
</button>
<button className="bg-white border border-spa-stone/20 text-spa-stone p-4 rounded-lg hover:border-spa-forest hover:text-spa-forest shadow-sm transition-all">
<button className="bg-spa-light border border-spa-stone/20 text-spa-stone p-4 rounded-lg hover:border-spa-forest hover:text-spa-forest shadow-sm transition-all">
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
@@ -322,7 +322,7 @@ export default function ProductDetailPage() {
<Footer categories={categories} />
{/* Mobile Sticky Add to Cart Bar */}
<div className="md:hidden fixed bottom-0 left-0 right-0 p-4 bg-white/95 backdrop-blur-xl border-t border-spa-stone/10 z-40 animate-fade-in flex flex-col gap-3 shadow-[0_-10px_30px_rgba(0,0,0,0.05)]">
<div className="md:hidden fixed bottom-0 left-0 right-0 p-4 bg-spa-light backdrop-blur-xl border-t border-spa-stone/10 z-40 animate-fade-in flex flex-col gap-3 shadow-[0_-10px_30px_rgba(0,0,0,0.05)]">
{/* Mobile Variant Selector */}
{product.variants && product.variants.length > 1 && (
@@ -333,8 +333,8 @@ export default function ProductDetailPage() {
onClick={() => setSelectedVariant(i)}
className={`flex-shrink-0 px-4 py-2 rounded-lg text-[10px] font-bold uppercase tracking-widest transition-all border whitespace-nowrap ${
selectedVariant === i
? 'bg-spa-forest border-spa-forest text-white'
: 'bg-white border-spa-stone/20 text-spa-stone'
? 'bg-spa-forest border-spa-forest text-spa-light'
: 'bg-spa-light border-spa-stone/20 text-spa-stone'
}`}
>
{v.size}
@@ -354,7 +354,7 @@ export default function ProductDetailPage() {
</div>
<button
onClick={handleAddToCart}
className="flex-1 py-3.5 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone shadow-sm transition-all flex justify-center items-center gap-2"
className="flex-1 py-3.5 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone shadow-sm transition-all flex justify-center items-center gap-2"
>
{t('cart.addToCart')}
</button>
+13 -13
View File
@@ -303,7 +303,7 @@ export default function ProfilePage() {
{!customer ? (
/* Login CTA screen */
<div className="max-w-md mx-auto text-center space-y-8 py-20 animate-fade-in bg-white p-10 rounded-3xl border border-spa-stone/10 shadow-sm mt-10">
<div className="max-w-md mx-auto text-center space-y-8 py-20 animate-fade-in bg-spa-light p-10 rounded-3xl border border-spa-stone/10 shadow-sm mt-10">
<div className="w-20 h-20 bg-spa-light rounded-full flex items-center justify-center mx-auto border border-spa-stone/10 shadow-inner">
<User className="w-10 h-10 text-spa-stone" />
</div>
@@ -320,7 +320,7 @@ export default function ProfilePage() {
alert('LINE LIFF System is initializing. Please refresh.')
}
}}
className="w-full py-4 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-xl tracking-widest uppercase transition-all duration-300 shadow-sm flex items-center justify-center gap-3"
className="w-full py-4 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-xl tracking-widest uppercase transition-all duration-300 shadow-sm flex items-center justify-center gap-3"
>
<Award className="w-5 h-5" />
<span>เข้าสู่ระบบผ่าน LINE</span>
@@ -331,7 +331,7 @@ export default function ProfilePage() {
/* Logged In Dashboard Layout */
<div className="space-y-10 animate-fade-in">
{/* Header Profile Banner */}
<div className="bg-white rounded-2xl border border-spa-stone/10 p-5 sm:p-6 flex flex-col sm:flex-row justify-between items-center sm:items-center gap-4 shadow-sm relative overflow-hidden">
<div className="bg-spa-light rounded-2xl border border-spa-stone/10 p-5 sm:p-6 flex flex-col sm:flex-row justify-between items-center sm:items-center gap-4 shadow-sm relative overflow-hidden">
<div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-spa-sage via-spa-forest to-spa-stone opacity-40" />
{/* User Avatar & Info */}
@@ -459,7 +459,7 @@ export default function ProfilePage() {
<Loader2 className="w-8 h-8 text-spa-forest animate-spin" />
</div>
) : orders.length === 0 ? (
<div className="text-center py-16 bg-white rounded-2xl border border-spa-stone/10 space-y-4 shadow-sm">
<div className="text-center py-16 bg-spa-light rounded-2xl border border-spa-stone/10 space-y-4 shadow-sm">
<Package className="w-12 h-12 text-spa-stone/40 mx-auto" />
<div>
<p className="font-bold text-pop-black">ไม่มีประวัติการสั่งซื้อ</p>
@@ -467,7 +467,7 @@ export default function ProfilePage() {
</div>
<Link
to="/shop"
className="inline-block px-6 py-2.5 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-lg text-xs uppercase tracking-wider transition-colors shadow-sm"
className="inline-block px-6 py-2.5 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-lg text-xs uppercase tracking-wider transition-colors shadow-sm"
>
ไปหน้าช้อปปิ้ง
</Link>
@@ -477,7 +477,7 @@ export default function ProfilePage() {
{orders.map(order => (
<div
key={order.id}
className="bg-white border border-spa-stone/10 rounded-2xl p-6 shadow-sm hover:border-spa-stone transition-all duration-300 space-y-4"
className="bg-spa-light border border-spa-stone/10 rounded-2xl p-6 shadow-sm hover:border-spa-stone transition-all duration-300 space-y-4"
>
{/* Card Header */}
<div className="flex flex-col md:flex-row justify-between md:items-center gap-3 border-b border-spa-stone/10 pb-4">
@@ -550,7 +550,7 @@ export default function ProfilePage() {
resetAddressForm()
setShowAddressForm(true)
}}
className="px-4 py-2 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-lg text-xs uppercase tracking-wider transition-colors shadow-sm flex items-center gap-2"
className="px-4 py-2 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-lg text-xs uppercase tracking-wider transition-colors shadow-sm flex items-center gap-2"
>
<Plus className="w-3.5 h-3.5" />
<span>เพิ่มที่อยู่ใหม่</span>
@@ -560,7 +560,7 @@ export default function ProfilePage() {
{/* Address Creation/Editing Form */}
{showAddressForm && (
<form onSubmit={handleAddressSubmit} className="bg-white border border-spa-stone/15 p-6 rounded-2xl shadow-sm space-y-5 animate-slide-down">
<form onSubmit={handleAddressSubmit} className="bg-spa-light border border-spa-stone/15 p-6 rounded-2xl shadow-sm space-y-5 animate-slide-down">
<h3 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-2">
{editingAddress ? 'แก้ไขที่อยู่จัดส่ง' : 'เพิ่มที่อยู่จัดส่งใหม่'}
</h3>
@@ -636,7 +636,7 @@ export default function ProfilePage() {
<button
type="submit"
disabled={submittingAddress}
className="px-5 py-2.5 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-lg text-xs uppercase tracking-wider transition-colors disabled:opacity-50 flex items-center gap-2"
className="px-5 py-2.5 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-lg text-xs uppercase tracking-wider transition-colors disabled:opacity-50 flex items-center gap-2"
>
{submittingAddress && <Loader2 className="w-3.5 h-3.5 animate-spin" />}
<span>บันทึกที่อยู่</span>
@@ -650,7 +650,7 @@ export default function ProfilePage() {
<Loader2 className="w-8 h-8 text-spa-forest animate-spin" />
</div>
) : addresses.length === 0 ? (
<div className="text-center py-16 bg-white rounded-2xl border border-spa-stone/10 space-y-4 shadow-sm">
<div className="text-center py-16 bg-spa-light rounded-2xl border border-spa-stone/10 space-y-4 shadow-sm">
<MapPin className="w-12 h-12 text-spa-stone/40 mx-auto" />
<div>
<p className="font-bold text-pop-black">ไม่มีข้อมูลที่อยู่จัดส่ง</p>
@@ -662,7 +662,7 @@ export default function ProfilePage() {
{addresses.map(addr => (
<div
key={addr.id}
className={`bg-white border rounded-2xl p-5 shadow-sm space-y-4 transition-all duration-300 relative ${
className={`bg-spa-light border rounded-2xl p-5 shadow-sm space-y-4 transition-all duration-300 relative ${
addr.isDefault
? 'border-spa-forest ring-1 ring-spa-forest/20'
: 'border-spa-stone/10 hover:border-spa-stone'
@@ -729,7 +729,7 @@ export default function ProfilePage() {
<span>ข้อมูลติดต่อสมาชิก</span>
</h2>
<form onSubmit={handleSettingsSubmit} className="bg-white border border-spa-stone/10 rounded-2xl p-6 shadow-sm max-w-lg space-y-5">
<form onSubmit={handleSettingsSubmit} className="bg-spa-light border border-spa-stone/10 rounded-2xl p-6 shadow-sm max-w-lg space-y-5">
{settingsSuccess && (
<div className="p-4 bg-emerald-500/10 border border-emerald-500/20 text-emerald-600 font-bold rounded-xl text-xs text-center flex items-center justify-center gap-2">
<Check className="w-4 h-4" />
@@ -763,7 +763,7 @@ export default function ProfilePage() {
<button
type="submit"
disabled={submittingSettings}
className="w-full py-3 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-lg text-xs uppercase tracking-widest transition-colors disabled:opacity-50 flex items-center justify-center gap-2"
className="w-full py-3 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-lg text-xs uppercase tracking-widest transition-colors disabled:opacity-50 flex items-center justify-center gap-2"
>
{submittingSettings ? <Loader2 className="w-4 h-4 animate-spin" /> : <Check className="w-4 h-4" />}
<span>บันทึกข้อมูลติดต่อ</span>
+7 -7
View File
@@ -59,10 +59,10 @@ export default function ScentGuidePage() {
/>
</div>
) : (
<div className="pt-32 pb-16 px-6 text-center space-y-4 border-b border-spa-stone/10 bg-white">
<div className="pt-32 pb-16 px-6 text-center space-y-4 border-b border-spa-stone/10 bg-spa-light">
<p className="text-spa-forest uppercase tracking-[0.4em] text-xs font-semibold opacity-70">Journal</p>
<h1 className="text-5xl font-bold">Scent Guide</h1>
<p className="text-slate-400 max-w-lg mx-auto">
<p className="text-spa-stone max-w-lg mx-auto">
Explore our collection of articles, guides, and sensory knowledge.
</p>
</div>
@@ -70,7 +70,7 @@ export default function ScentGuidePage() {
<div className="flex-1 max-w-7xl mx-auto px-6 py-16 w-full">
{articles.length === 0 ? (
<div className="text-center text-slate-500 italic py-20">
<div className="text-center text-spa-stone italic py-20">
Articles coming soon. Check back later!
</div>
) : (
@@ -81,12 +81,12 @@ export default function ScentGuidePage() {
to={`/article/${article.slug}`}
className="group block bg-pop-bg rounded-2xl overflow-hidden border border-spa-stone/10 hover:border-spa-forest transition-all duration-300 hover:-translate-y-1 hover:shadow-2xl flex flex-col"
>
<div className="aspect-[4/3] bg-white overflow-hidden shrink-0">
<div className="aspect-[4/3] bg-spa-light overflow-hidden shrink-0">
{article.coverImage ? (
<img src={article.coverImage} alt={article.title} className="w-full h-full object-cover opacity-80 group-hover:opacity-100 group-hover:scale-105 transition-all duration-500" />
) : (
<div className="w-full h-full bg-white/5 flex items-center justify-center">
<span className="text-slate-600 text-sm tracking-widest uppercase">No Image</span>
<div className="w-full h-full bg-spa-light flex items-center justify-center">
<span className="text-spa-stone text-sm tracking-widest uppercase">No Image</span>
</div>
)}
</div>
@@ -96,7 +96,7 @@ export default function ScentGuidePage() {
</p>
<h3 className="text-xl font-bold leading-tight group-hover:text-spa-forest transition-colors">{article.title}</h3>
{/* Remove HTML tags for purely excerpt preview */}
<div className="text-slate-400 text-sm line-clamp-3" dangerouslySetInnerHTML={{ __html: article.content }} />
<div className="text-spa-stone text-sm line-clamp-3" dangerouslySetInnerHTML={{ __html: article.content }} />
</div>
</Link>
))}
+3 -3
View File
@@ -100,7 +100,7 @@ export default function SearchPage() {
<h1 className="text-5xl font-bold text-pop-black">Search Products</h1>
<form onSubmit={handleSubmit} className="relative">
<div className="flex bg-white border border-spa-stone/20 rounded-2xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<div className="flex bg-spa-light border border-spa-stone/20 rounded-2xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<svg className="w-5 h-5 text-spa-stone m-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
@@ -114,7 +114,7 @@ export default function SearchPage() {
/>
<button
type="submit"
className="bg-spa-forest text-white px-8 font-bold text-xs uppercase tracking-widest hover:bg-spa-stone transition-colors shrink-0"
className="bg-spa-forest text-spa-light px-8 font-bold text-xs uppercase tracking-widest hover:bg-spa-stone transition-colors shrink-0"
>
Search
</button>
@@ -127,7 +127,7 @@ export default function SearchPage() {
<Link
key={cat.id}
to={`/search?q=${encodeURIComponent(typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || '')}`}
className="bg-white border border-spa-stone/20 px-4 py-1.5 rounded-full text-xs font-medium text-spa-stone hover:border-spa-forest hover:text-spa-forest shadow-sm transition-all duration-300"
className="bg-spa-light border border-spa-stone/20 px-4 py-1.5 rounded-full text-xs font-medium text-spa-stone hover:border-spa-forest hover:text-spa-forest shadow-sm transition-all duration-300"
>
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || ''}
</Link>
+6 -6
View File
@@ -154,7 +154,7 @@ export default function ShopPage() {
{/* Search */}
<div className="max-w-md mx-auto mt-6">
<div className="flex bg-white border border-spa-stone/20 rounded-xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<div className="flex bg-spa-light border border-spa-stone/20 rounded-xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<svg className="w-4 h-4 text-spa-stone m-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
@@ -173,7 +173,7 @@ export default function ShopPage() {
{/* Render Search bar below Hero block if Hero is configured */}
{heroSections.length > 0 && (
<div className="max-w-md mx-auto mt-8 px-6">
<div className="flex bg-white border border-spa-stone/20 rounded-xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<div className="flex bg-spa-light border border-spa-stone/20 rounded-xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<svg className="w-4 h-4 text-spa-stone m-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
@@ -195,8 +195,8 @@ export default function ShopPage() {
onClick={() => setActiveCategory(null)}
className={`px-5 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${
activeCategory === null
? 'bg-spa-forest text-white border-spa-forest shadow-md'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
? 'bg-spa-forest text-spa-light border-spa-forest shadow-md'
: 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
}`}
>
All
@@ -207,8 +207,8 @@ export default function ShopPage() {
onClick={() => setActiveCategory(cat.id)}
className={`px-5 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${
activeCategory === cat.id
? 'bg-spa-forest text-white border-spa-forest shadow-md'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
? 'bg-spa-forest text-spa-light border-spa-forest shadow-md'
: 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
}`}
>
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || ''}
+6 -6
View File
@@ -144,7 +144,7 @@ export default function TrackOrderPage() {
<div className="grid md:grid-cols-2 gap-12">
{/* Tracking Form */}
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 self-start shadow-sm">
<div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 self-start shadow-sm">
<h2 className="text-lg font-bold uppercase tracking-widest border-b border-spa-stone/10 pb-4 flex items-center gap-2 text-spa-forest">
<Search className="w-5 h-5" /> Manual Search
</h2>
@@ -183,7 +183,7 @@ export default function TrackOrderPage() {
<button
type="submit"
disabled={loading}
className="w-full py-4 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-2"
className="w-full py-4 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-2"
>
{loading ? <Loader2 className="w-5 h-5 animate-spin" /> : 'Find Order'}
</button>
@@ -214,7 +214,7 @@ export default function TrackOrderPage() {
<Link
key={order.id}
to={`/order/${order.id}`}
className="flex justify-between items-center p-5 bg-white rounded-xl border border-spa-stone/10 shadow-sm hover:border-spa-forest transition-all group"
className="flex justify-between items-center p-5 bg-spa-light rounded-xl border border-spa-stone/10 shadow-sm hover:border-spa-forest transition-all group"
>
<div>
<div className="flex items-center gap-2 mb-1">
@@ -235,7 +235,7 @@ export default function TrackOrderPage() {
<p className="text-[10px] text-spa-stone uppercase">{order.items.length} items</p>
</div>
<div className="w-10 h-10 rounded-full bg-spa-light flex items-center justify-center group-hover:bg-spa-forest transition-colors shrink-0">
<ChevronRight className="w-5 h-5 text-spa-stone/80 group-hover:text-white" />
<ChevronRight className="w-5 h-5 text-spa-stone/80 group-hover:text-spa-light" />
</div>
</div>
</Link>
@@ -254,14 +254,14 @@ export default function TrackOrderPage() {
<Link
key={id}
to={`/order/${id}`}
className="flex justify-between items-center p-5 bg-white rounded-xl border border-spa-stone/10 shadow-sm hover:border-spa-forest transition-all group"
className="flex justify-between items-center p-5 bg-spa-light rounded-xl border border-spa-stone/10 shadow-sm hover:border-spa-forest transition-all group"
>
<div>
<p className="text-xs text-spa-stone/80 uppercase tracking-widest mb-1 font-semibold">Order</p>
<p className="text-xl font-bold font-mono text-spa-forest">#{id.toString().padStart(4, '0')}</p>
</div>
<div className="w-10 h-10 rounded-full bg-spa-light flex items-center justify-center group-hover:bg-spa-forest transition-colors">
<ChevronRight className="w-5 h-5 text-spa-stone/80 group-hover:text-white" />
<ChevronRight className="w-5 h-5 text-spa-stone/80 group-hover:text-spa-light" />
</div>
</Link>
))}
+2 -2
View File
@@ -76,7 +76,7 @@ export default function WishlistPage() {
)}
{items.length === 0 ? (
<div className="text-center py-24 bg-white shadow-sm border border-spa-stone/10 rounded-3xl max-w-2xl mx-auto space-y-6">
<div className="text-center py-24 bg-spa-light shadow-sm border border-spa-stone/10 rounded-3xl max-w-2xl mx-auto space-y-6">
<div className="w-20 h-20 bg-spa-light rounded-full flex items-center justify-center mx-auto">
<Heart className="w-10 h-10 text-spa-stone/30" />
</div>
@@ -85,7 +85,7 @@ export default function WishlistPage() {
<div className="pt-4">
<Link
to="/shop"
className="inline-block px-8 py-3.5 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 shadow-sm"
className="inline-block px-8 py-3.5 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 shadow-sm"
>
Browse Shop
</Link>