diff --git a/admin/prisma/schema.prisma b/admin/prisma/schema.prisma index 37d2feb..6de2cfb 100644 --- a/admin/prisma/schema.prisma +++ b/admin/prisma/schema.prisma @@ -40,6 +40,9 @@ model Business { city String? description String logoUrl String + coverUrl String? + coverPosition String? @default("50% 50%") + coverZoom Float? @default(1.0) videoUrl String? contactEmail String contactPhone String? @@ -85,12 +88,6 @@ model Country { updatedAt DateTime @updatedAt } -enum Plan { - STARTER - BOOSTER - EMPIRE -} - model PricingPlan { id String @id @default(uuid()) tier Plan @unique @@ -265,6 +262,12 @@ enum UserRole { ADMIN } +enum Plan { + STARTER + BOOSTER + EMPIRE +} + enum OfferType { PRODUCT SERVICE @@ -287,8 +290,17 @@ model SiteSetting { instagramUrl String? linkedinUrl String? footerText String? @default("© 2025 Afrohub. Tous droits réservés.") + homeBlogShow Boolean @default(true) + homeBlogTitle String @default("Derniers Articles") + homeBlogSubtitle String @default("Toutes les actualités de l'entrepreneuriat africain.") + homeBlogCount Int @default(3) + homeBlogSelection String @default("latest") + homeBlogIds String[] @default([]) + homeBlogCategories String[] @default([]) + homeCategories String[] @default(["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"]) updatedAt DateTime @updatedAt } + model LegalDocument { id String @id @default(uuid()) type String @unique // 'CGU' or 'CGV' diff --git a/admin/src/app/actions/blog.ts b/admin/src/app/actions/blog.ts index 94c2023..ef89234 100644 --- a/admin/src/app/actions/blog.ts +++ b/admin/src/app/actions/blog.ts @@ -75,3 +75,14 @@ export async function deleteBlogPost(id: string) { return { success: false, error: "Erreur lors de la suppression" }; } } + +export async function getBlogPosts() { + try { + return await prisma.blogPost.findMany({ + orderBy: { date: 'desc' } + }); + } catch (error) { + console.error("Failed to fetch blog posts:", error); + return []; + } +} diff --git a/admin/src/app/actions/settings.ts b/admin/src/app/actions/settings.ts index efcb5d9..ffa50a1 100644 --- a/admin/src/app/actions/settings.ts +++ b/admin/src/app/actions/settings.ts @@ -20,7 +20,15 @@ export async function getSiteSettings() { twitterUrl: "", instagramUrl: "", linkedinUrl: "", - footerText: "© 2025 Afrohub. Tous droits réservés." + footerText: "© 2025 Afrohub. Tous droits réservés.", + homeBlogShow: true, + homeBlogTitle: "Derniers Articles", + homeBlogSubtitle: "Toutes les actualités de l'entrepreneuriat africain.", + homeBlogCount: 3, + homeBlogSelection: "latest", + homeBlogIds: [], + homeBlogCategories: [], + homeCategories: ["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"] }; if (!settings) return defaultSettings; @@ -43,7 +51,7 @@ export async function updateSiteSettings(data: any) { }); revalidatePath('/settings'); - revalidatePath('/', 'layout'); // Revalidate all public pages because footer/header might use it + revalidatePath('/', 'layout'); return { success: true, settings }; } catch (error) { diff --git a/admin/src/app/settings/page.tsx b/admin/src/app/settings/page.tsx index 3016412..fa8b231 100644 --- a/admin/src/app/settings/page.tsx +++ b/admin/src/app/settings/page.tsx @@ -1,19 +1,58 @@ "use client"; import React, { useState, useEffect, useTransition } from 'react'; -import { Save, Globe, Mail, Phone, MapPin, Share2, Link as LinkIcon, Loader2 } from 'lucide-react'; +import { Save, Globe, Mail, Phone, MapPin, Share2, Link as LinkIcon, Loader2, Newspaper, Briefcase } from 'lucide-react'; import { getSiteSettings, updateSiteSettings } from '@/app/actions/settings'; import { toast } from 'react-hot-toast'; +import { getBlogPosts } from '@/app/actions/blog'; + +const BUSINESS_CATEGORIES = [ + "Technologie & IT", + "Agriculture & Agrobusiness", + "Mode & Textile", + "Cosmétique & Beauté", + "Services aux entreprises", + "Restauration & Alimentation", + "Construction & BTP", + "Éducation & Formation", + "Santé & Bien-être", + "Artisanat & Déco", + "Tourisme & Loisirs", + "Finance & Assurance", + "Immobilier", + "Transport & Logistique", + "Média & Communication", + "Autre" +]; + +const BLOG_CATEGORIES = [ + "Actualité", + "Conseils", + "Success Story", + "Événement", + "Formation" +]; export default function SettingsPage() { const [isPending, startTransition] = useTransition(); const [settings, setSettings] = useState(null); + const [allPosts, setAllPosts] = useState([]); const [loading, setLoading] = useState(true); + const [selectedPostIds, setSelectedPostIds] = useState([]); + const [selectedHomeCategories, setSelectedHomeCategories] = useState([]); + const [selectedBlogCategories, setSelectedBlogCategories] = useState([]); useEffect(() => { async function loadData() { - const data = await getSiteSettings(); - setSettings(data); + const [settingsData, postsData] = await Promise.all([ + getSiteSettings(), + getBlogPosts() + ]); + setSettings(settingsData); + setAllPosts(postsData); + setSelectedPostIds(settingsData?.homeBlogIds || []); + setSelectedHomeCategories(settingsData?.homeCategories || []); + setSelectedBlogCategories(settingsData?.homeBlogCategories || []); setLoading(false); } loadData(); @@ -33,6 +72,14 @@ export default function SettingsPage() { instagramUrl: formData.get('instagramUrl'), linkedinUrl: formData.get('linkedinUrl'), footerText: formData.get('footerText'), + homeBlogShow: formData.get('homeBlogShow') === 'on', + homeBlogTitle: formData.get('homeBlogTitle'), + homeBlogSubtitle: formData.get('homeBlogSubtitle'), + homeBlogCount: parseInt(formData.get('homeBlogCount') as string || '3'), + homeBlogSelection: formData.get('homeBlogSelection'), + homeBlogIds: selectedPostIds, + homeBlogCategories: selectedBlogCategories, + homeCategories: selectedHomeCategories, }; startTransition(async () => { @@ -45,6 +92,24 @@ export default function SettingsPage() { }); }; + const togglePostId = (id: string) => { + setSelectedPostIds(prev => + prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id] + ); + }; + + const toggleHomeCategory = (cat: string) => { + setSelectedHomeCategories(prev => + prev.includes(cat) ? prev.filter(c => c !== cat) : [...prev, cat] + ); + }; + + const toggleBlogCategory = (cat: string) => { + setSelectedBlogCategories(prev => + prev.includes(cat) ? prev.filter(c => c !== cat) : [...prev, cat] + ); + }; + if (loading) { return (
@@ -97,6 +162,149 @@ export default function SettingsPage() {
+ {/* Section Page d'Accueil - Secteurs */} +
+
+ +

Secteurs en Vedette (Home)

+
+
+

Sélectionnez les secteurs d'activité à afficher sur la page d'accueil.

+
+ {BUSINESS_CATEGORIES.map(cat => ( + + ))} +
+
+
+ + {/* Section Page d'Accueil - Blog */} +
+
+ +

Section Blog sur l'Accueil

+
+
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ +
+ + + +
+
+ +
+
+ + +
+ + {/* Manual Selection UI */} +
+ +
+ {allPosts.map(post => ( + + ))} +
+
+ + {/* Category Selection UI */} +
+ +
+ {BLOG_CATEGORIES.map(cat => ( + + ))} +
+
+
+
+
+ {/* Section Contact */}
diff --git a/app/page.tsx b/app/page.tsx index 88e66d7..dab10d8 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -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([]); + const [posts, setPosts] = useState([]); 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 = () => {

Secteurs en vedette

- {CATEGORIES.slice(0, 4).map((cat, idx) => ( + {(settings?.homeCategories || CATEGORIES.slice(0, 4)).map((cat: string, idx: number) => ( { )}
+ + {/* Blog Section */} + {settings?.homeBlogShow !== false && ( +
+
+
+
+

{settings?.homeBlogTitle || "Derniers Articles"}

+

{settings?.homeBlogSubtitle || "Toutes les actualités de l'entrepreneuriat africain."}

+
+ + Voir tout le blog + +
+ + {loadingPosts ? ( +
+ +
+ ) : ( +
+ {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 => ( + +
+ {post.title} +
+
+

{post.title}

+

{post.excerpt}

+
+ {new Date(post.date).toLocaleDateString('fr-FR')} + Lire la suite → +
+
+ + ))} +
+ )} +
+
+ )}
); }; diff --git a/lib/settings.ts b/lib/settings.ts index 43face7..696c4f2 100644 --- a/lib/settings.ts +++ b/lib/settings.ts @@ -11,7 +11,15 @@ export async function getSiteSettings() { twitterUrl: "#", instagramUrl: "#", linkedinUrl: "#", - footerText: "© 2025 Afrohub. Tous droits réservés." + footerText: "© 2025 Afrohub. Tous droits réservés.", + homeBlogShow: true, + homeBlogTitle: "Derniers Articles", + homeBlogSubtitle: "Toutes les actualités de l'entrepreneuriat africain.", + homeBlogCount: 3, + homeBlogSelection: "latest", + homeBlogIds: [], + homeBlogCategories: [], + homeCategories: ["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"] }; try { diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d237d8e..96bbcb7 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -256,6 +256,14 @@ model SiteSetting { instagramUrl String? linkedinUrl String? footerText String? @default("© 2025 Afrohub. Tous droits réservés.") + homeBlogShow Boolean @default(true) + homeBlogTitle String @default("Derniers Articles") + homeBlogSubtitle String @default("Toutes les actualités de l'entrepreneuriat africain.") + homeBlogCount Int @default(3) + homeBlogSelection String @default("latest") + homeBlogIds String[] @default([]) + homeBlogCategories String[] @default([]) + homeCategories String[] @default(["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"]) updatedAt DateTime @updatedAt }