feat: implement dynamic home page with configurable blog and category settings

This commit is contained in:
2026-04-23 13:41:51 +02:00
parent 33ec11d6db
commit 88e4c13b9f
7 changed files with 341 additions and 15 deletions

View File

@@ -3,15 +3,19 @@
import React, { useState, useEffect } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { Search, MapPin, Briefcase, TrendingUp, Loader2 } from 'lucide-react';
import { CATEGORIES, Business } from '../types';
import { Search, MapPin, Briefcase, TrendingUp, Loader2, ArrowRight } from 'lucide-react';
import { CATEGORIES, Business, BlogPost } from '../types';
import BusinessCard from '../components/BusinessCard';
import { useUser } from '../components/UserProvider';
const HomePage = () => {
const router = useRouter();
const { settings } = useUser();
const [searchTerm, setSearchTerm] = useState('');
const [featuredBusinesses, setFeaturedBusinesses] = useState<Business[]>([]);
const [posts, setPosts] = useState<BlogPost[]>([]);
const [loading, setLoading] = useState(true);
const [loadingPosts, setLoadingPosts] = useState(true);
useEffect(() => {
const fetchFeatured = async () => {
@@ -28,6 +32,21 @@ const HomePage = () => {
}
};
fetchFeatured();
const fetchPosts = async () => {
try {
const res = await fetch('/api/blog');
const data = await res.json();
if (Array.isArray(data)) {
setPosts(data);
}
} catch (error) {
console.error('Error fetching blog posts:', error);
} finally {
setLoadingPosts(false);
}
};
fetchPosts();
}, []);
const handleSearch = (e: React.FormEvent) => {
@@ -77,7 +96,7 @@ const HomePage = () => {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
<h2 className="text-3xl font-bold text-gray-900 mb-8 font-serif">Secteurs en vedette</h2>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{CATEGORIES.slice(0, 4).map((cat, idx) => (
{(settings?.homeCategories || CATEGORIES.slice(0, 4)).map((cat: string, idx: number) => (
<Link
key={idx}
href={`/annuaire?category=${encodeURIComponent(cat)}`}
@@ -118,6 +137,58 @@ const HomePage = () => {
)}
</div>
</div>
{/* Blog Section */}
{settings?.homeBlogShow !== false && (
<div className="py-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-end mb-8">
<div>
<h2 className="text-3xl font-bold text-gray-900 font-serif">{settings?.homeBlogTitle || "Derniers Articles"}</h2>
<p className="text-gray-500 mt-2">{settings?.homeBlogSubtitle || "Toutes les actualités de l'entrepreneuriat africain."}</p>
</div>
<Link href="/blog" className="text-brand-600 font-medium hover:text-brand-700 flex items-center">
Voir tout le blog <ArrowRight className="w-4 h-4 ml-1" />
</Link>
</div>
{loadingPosts ? (
<div className="flex justify-center py-12">
<Loader2 className="w-10 h-10 text-brand-600 animate-spin" />
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{posts
.filter(post => {
if (settings?.homeBlogSelection === 'manual') {
return settings.homeBlogIds?.includes(post.id);
}
if (settings?.homeBlogSelection === 'category') {
return post.tags?.some((tag: string) => settings.homeBlogCategories?.includes(tag));
}
return true;
})
.slice(0, settings?.homeBlogCount || 3)
.map(post => (
<Link key={post.id} href={`/blog/${post.slug || post.id}`} className="group bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden hover:shadow-md transition-all">
<div className="h-48 overflow-hidden">
<img src={post.imageUrl} alt={post.title} className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500" />
</div>
<div className="p-6">
<h3 className="text-xl font-bold text-gray-900 mb-2 line-clamp-2 group-hover:text-brand-600 transition-colors">{post.title}</h3>
<p className="text-gray-500 text-sm line-clamp-3 mb-4">{post.excerpt}</p>
<div className="flex items-center justify-between mt-auto pt-4 border-t border-gray-50">
<span className="text-xs font-medium text-gray-400">{new Date(post.date).toLocaleDateString('fr-FR')}</span>
<span className="text-brand-600 font-bold text-xs">Lire la suite </span>
</div>
</div>
</Link>
))}
</div>
)}
</div>
</div>
)}
</div>
);
};