117 lines
4.8 KiB
TypeScript
117 lines
4.8 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
import { Link } from 'react-router-dom'
|
|
import Navbar from '../components/Navbar'
|
|
import Footer from '../components/Footer'
|
|
import DynamicPageRenderer from '../components/DynamicPageRenderer'
|
|
import { API_BASE, type Category, type Article, type PageSection } from '../types'
|
|
|
|
export default function ScentGuidePage() {
|
|
const [categories, setCategories] = useState<Category[]>([])
|
|
const [articles, setArticles] = useState<Article[]>([])
|
|
const [cmsSections, setCmsSections] = useState<PageSection[]>([])
|
|
|
|
useEffect(() => {
|
|
fetch(`${API_BASE}/categories`).then(r => r.json()).then(setCategories).catch(console.error)
|
|
fetch(`${API_BASE}/articles?publishedOnly=true`).then(r => r.json()).then(setArticles).catch(console.error)
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
fetch(`${API_BASE}/pages/scent-guide-layout`)
|
|
.then((r) => {
|
|
if (!r.ok) throw new Error('Page not found');
|
|
return r.json();
|
|
})
|
|
.then((data) => {
|
|
if (data && data.sections) {
|
|
setCmsSections(data.sections);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.log('Scent guide dynamic layout sections not loaded:', err.message);
|
|
});
|
|
}, [])
|
|
|
|
const announcementSections = cmsSections.filter(s => s.isActive && s.type.toUpperCase() === 'ANNOUNCEMENT_BAR');
|
|
const heroSections = cmsSections.filter(s => s.isActive && (s.type.toUpperCase() === 'HERO' || s.type.toUpperCase() === 'BANNER'));
|
|
const bottomSections = cmsSections.filter(s => s.isActive && s.type.toUpperCase() !== 'ANNOUNCEMENT_BAR' && s.type.toUpperCase() !== 'HERO' && s.type.toUpperCase() !== 'BANNER');
|
|
|
|
return (
|
|
<div className="min-h-screen flex flex-col">
|
|
{announcementSections.length > 0 && (
|
|
<DynamicPageRenderer
|
|
sections={announcementSections}
|
|
categories={categories}
|
|
categoriesLoading={false}
|
|
/>
|
|
)}
|
|
|
|
<Navbar categories={categories} />
|
|
|
|
{/* Header */}
|
|
{heroSections.length > 0 ? (
|
|
<div className="pt-20">
|
|
<DynamicPageRenderer
|
|
sections={heroSections}
|
|
categories={categories}
|
|
categoriesLoading={false}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<div className="pt-32 pb-16 px-6 text-center space-y-4 border-b border-spa-stone/10 bg-white">
|
|
<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">
|
|
Explore our collection of articles, guides, and sensory knowledge.
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
<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">
|
|
Articles coming soon. Check back later!
|
|
</div>
|
|
) : (
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
|
{articles.map(article => (
|
|
<Link
|
|
key={article.id}
|
|
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">
|
|
{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>
|
|
)}
|
|
</div>
|
|
<div className="p-6 space-y-3 flex-1 flex flex-col">
|
|
<p className="text-[10px] text-spa-forest font-bold tracking-widest uppercase">
|
|
{new Date(article.createdAt).toLocaleDateString()}
|
|
</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>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{bottomSections.length > 0 && (
|
|
<DynamicPageRenderer
|
|
sections={bottomSections}
|
|
categories={categories}
|
|
categoriesLoading={false}
|
|
/>
|
|
)}
|
|
|
|
<Footer categories={categories} />
|
|
</div>
|
|
)
|
|
}
|