188 lines
8.0 KiB
TypeScript
188 lines
8.0 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from 'react'
|
|
import Link from 'next/link'
|
|
import type { Category, MenuItem, StoreSettings } from '@homaroma/types'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { resolveLocalized } from '../lib/localization'
|
|
import { useLang } from '../hooks/useLang'
|
|
|
|
interface FooterProps {
|
|
categories?: Category[]
|
|
exploreMenu?: MenuItem[]
|
|
supportMenu?: MenuItem[]
|
|
settings?: StoreSettings | null
|
|
}
|
|
|
|
export default function Footer({
|
|
categories = [],
|
|
exploreMenu = [],
|
|
supportMenu = [],
|
|
settings = null,
|
|
}: FooterProps) {
|
|
const { t } = useTranslation()
|
|
const lang = useLang()
|
|
const [mounted, setMounted] = useState(false)
|
|
useEffect(() => { setMounted(true) }, [])
|
|
// Before mount: always 'th' to match SSR output → no hydration mismatch
|
|
// After mount: real user language → correct content
|
|
const effectiveLang = mounted ? lang : 'th'
|
|
|
|
// Translate a menu item label using its translations array or i18n key map
|
|
const translateMenuLabel = (item: MenuItem): string => {
|
|
// Use outer `lang` from closure — hooks cannot be called inside nested functions
|
|
if (effectiveLang !== 'en' && item.translations && item.translations.length > 0) {
|
|
const trans = item.translations.find((tr: any) => tr.langCode === effectiveLang)
|
|
if (trans?.label) return trans.label
|
|
}
|
|
const map: Record<string, string> = {
|
|
'Home': 'nav.home',
|
|
'Shop': 'nav.shop',
|
|
'Scent Guide': 'nav.scentGuide',
|
|
'About Us': 'nav.about',
|
|
'About': 'nav.about',
|
|
'FAQ': 'nav.faq',
|
|
'Contact': 'nav.contact',
|
|
'Contact Us': 'nav.contact',
|
|
'Track Order': 'nav.trackOrder',
|
|
'Delivery & Returns': 'nav.delivery',
|
|
}
|
|
return map[item.label] ? t(map[item.label]) : item.label
|
|
}
|
|
|
|
// Social links — use settings if available, fallback to placeholder buttons
|
|
const hasSocialLinks = settings && (settings.facebookUrl || settings.instagramUrl || settings.tiktokUrl)
|
|
const brandName = settings?.brandName || 'HomAroma'
|
|
|
|
return (
|
|
<footer className="border-t border-gray-200 bg-white px-6 py-20 text-pop-black">
|
|
<div className="mx-auto grid max-w-7xl grid-cols-1 gap-12 md:grid-cols-4">
|
|
|
|
{/* Col 1 — Brand */}
|
|
<div className="space-y-6">
|
|
<div className="text-2xl font-bold tracking-widest">
|
|
{brandName} <span className="text-sm font-semibold italic text-pop-pink">Essential</span>
|
|
</div>
|
|
<p className="text-sm leading-relaxed text-gray-600">
|
|
{resolveLocalized(settings?.footerDescription, effectiveLang) || t('footer.catchphrase')}
|
|
</p>
|
|
<div className="flex gap-4">
|
|
{hasSocialLinks ? (
|
|
<>
|
|
{settings!.facebookUrl && (
|
|
<a
|
|
href={settings!.facebookUrl}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
className="flex h-9 w-9 items-center justify-center rounded-full border border-gray-200 bg-pop-bg text-[10px] font-bold text-pop-black transition-all duration-300 hover:border-pop-pink hover:bg-pop-pink hover:text-white"
|
|
>
|
|
FB
|
|
</a>
|
|
)}
|
|
{settings!.instagramUrl && (
|
|
<a
|
|
href={settings!.instagramUrl}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
className="flex h-9 w-9 items-center justify-center rounded-full border border-gray-200 bg-pop-bg text-[10px] font-bold text-pop-black transition-all duration-300 hover:border-pop-pink hover:bg-pop-pink hover:text-white"
|
|
>
|
|
IG
|
|
</a>
|
|
)}
|
|
{settings!.tiktokUrl && (
|
|
<a
|
|
href={settings!.tiktokUrl}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
className="flex h-9 w-9 items-center justify-center rounded-full border border-gray-200 bg-pop-bg text-[10px] font-bold text-pop-black transition-all duration-300 hover:border-pop-pink hover:bg-pop-pink hover:text-white"
|
|
>
|
|
TT
|
|
</a>
|
|
)}
|
|
</>
|
|
) : (
|
|
['IG', 'FB', 'TW', 'YT'].map((s) => (
|
|
<a
|
|
key={s}
|
|
href="#"
|
|
className="flex h-9 w-9 items-center justify-center rounded-full border border-gray-200 bg-pop-bg text-[10px] font-bold text-pop-black transition-all duration-300 hover:border-pop-pink hover:bg-pop-pink hover:text-white"
|
|
>
|
|
{s}
|
|
</a>
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Col 2 — Explore */}
|
|
<div className="space-y-4">
|
|
<h4 className="text-xs font-bold uppercase tracking-widest text-pop-black">{t('footer.explore')}</h4>
|
|
<div className="flex flex-col space-y-2 text-sm text-gray-600">
|
|
{exploreMenu.length > 0 ? (
|
|
exploreMenu.map((item) => (
|
|
<Link key={item.id} href={item.url} className="transition-colors hover:text-pop-pink">
|
|
{translateMenuLabel(item)}
|
|
</Link>
|
|
))
|
|
) : (
|
|
<>
|
|
<Link href="/" className="transition-colors hover:text-pop-pink">{t('nav.home')}</Link>
|
|
<Link href="/shop" className="transition-colors hover:text-pop-pink">{t('nav.shop')}</Link>
|
|
<Link href="/scent-guide" className="transition-colors hover:text-pop-pink">{t('nav.scentGuide')}</Link>
|
|
<Link href="/about" className="transition-colors hover:text-pop-pink">{t('nav.about')}</Link>
|
|
<Link href="/contact" className="transition-colors hover:text-pop-pink">{t('nav.contact')}</Link>
|
|
<Link href="/faq" className="transition-colors hover:text-pop-pink">{t('nav.faq')}</Link>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Col 3 — Collections */}
|
|
<div className="space-y-4">
|
|
<h4 className="text-xs font-bold uppercase tracking-widest text-pop-black">{t('nav.collections')}</h4>
|
|
<div className="flex flex-col space-y-2 text-sm text-gray-600">
|
|
{categories.map((c) => (
|
|
<Link key={c.id} href={`/category/${c.id}`} className="transition-colors hover:text-pop-pink">
|
|
{resolveLocalized(c.name, effectiveLang)}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Col 4 — Support & Legal */}
|
|
<div className="space-y-4">
|
|
<h4 className="text-xs font-bold uppercase tracking-widest text-pop-black">
|
|
{settings?.footerSupportHeading
|
|
? (typeof settings.footerSupportHeading === 'string'
|
|
? settings.footerSupportHeading
|
|
: settings.footerSupportHeading[effectiveLang]
|
|
|| settings.footerSupportHeading.en
|
|
|| 'Support & Legal')
|
|
: t('footer.support', 'Support & Legal')}
|
|
</h4>
|
|
<div className="flex flex-col space-y-2 text-sm text-gray-600">
|
|
{supportMenu.map((item) => (
|
|
<Link key={item.id} href={item.url} className="transition-colors hover:text-pop-pink">
|
|
{translateMenuLabel(item)}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
|
|
<div className="pt-4">
|
|
<p className="text-[10px] uppercase tracking-widest text-gray-500">
|
|
{settings?.footerCopyrightText
|
|
? (typeof settings.footerCopyrightText === 'string'
|
|
? settings.footerCopyrightText
|
|
: settings.footerCopyrightText[effectiveLang]
|
|
|| settings.footerCopyrightText.en
|
|
|| `© ${new Date().getFullYear()} ${brandName}. ${t('footer.rights')}`)
|
|
: `© ${new Date().getFullYear()} ${brandName}. ${t('footer.rights')}`}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</footer>
|
|
)
|
|
}
|