'use client'; import { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { ArrowLeft, Calendar, User, Tag, Clock, Share2, BookOpen, Anchor } from 'lucide-react'; import { Link } from '@/i18n/navigation'; import { LandingHeader, LandingFooter } from '@/components/layout'; import { getBlogPost, type BlogPost } from '@/lib/api/blog'; import DOMPurify from 'isomorphic-dompurify'; const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; function resolveUrl(url: string | null | undefined): string | undefined { if (!url) return undefined; if (url.startsWith('http')) return url; return `${API_BASE_URL}${url}`; } function formatDate(dateStr: string): string { return new Date(dateStr).toLocaleDateString('fr-FR', { year: 'numeric', month: 'long', day: 'numeric', }); } function estimateReadingTime(content: string): number { const text = content.replace(/<[^>]*>/g, ''); const words = text.trim().split(/\s+/).length; return Math.max(1, Math.ceil(words / 200)); } const CATEGORY_LABELS: Record = { industry: 'Industrie', technology: 'Technologie', guides: 'Guides', news: 'Actualités', }; function LoadingSkeleton() { return (
{[...Array(6)].map((_, i) => (
))}
); } function NotFoundView() { return (

Article introuvable

Cet article n'existe pas ou n'est pas encore publié.

Retour au blog
); } export default function BlogPostContent({ slug }: { slug: string }) { const [post, setPost] = useState(null); const [loading, setLoading] = useState(true); const [notFound, setNotFound] = useState(false); useEffect(() => { if (!slug) return; let cancelled = false; getBlogPost(slug) .then(p => { if (!cancelled) setPost(p); }) .catch(() => { if (!cancelled) setNotFound(true); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [slug]); if (loading) return ; if (notFound || !post) return ; const readingTime = estimateReadingTime(post.content); // Sanitize the admin-authored HTML before rendering (stored-XSS defense in depth) const processedContent = DOMPurify.sanitize( post.content.replace(/src="(\/api\/v1\/blog\/images\/[^"]+)"/g, `src="${API_BASE_URL}$1"`) ); const handleShare = () => { if (navigator.share) { navigator.share({ title: post.title, url: window.location.href }); } else { navigator.clipboard.writeText(window.location.href); } }; return (
{/* Hero */}
Retour au blog
{CATEGORY_LABELS[post.category] ?? post.category} {post.isFeatured && ( À la une )}

{post.title}

{post.excerpt}

{post.authorName}
{post.publishedAt && (
{formatDate(post.publishedAt)}
)}
{readingTime} min de lecture
{post.tags.length > 0 && (
{post.tags.join(', ')}
)}
{/* Cover Image */} {post.coverImageUrl && (
{post.title}
)} {/* Content + Sidebar */}
{/* En bref (AI summary / TL;DR) */} {post.aiSummary && (

En bref

{post.aiSummary}

)}
{/* Article body */} {/* Floating share button (desktop) */}
{/* À retenir (key takeaways) */} {post.keyTakeaways && post.keyTakeaways.length > 0 && (

À retenir

    {post.keyTakeaways.map((item, i) => (
  • {item}
  • ))}
)} {/* FAQ */} {post.faq && post.faq.length > 0 && (

Questions fréquentes

{post.faq.map((item, i) => (
{item.question} +

{item.answer}

))}
)} {/* Tags */} {post.tags.length > 0 && (
{post.tags.map(tag => ( #{tag} ))}
)} {/* CTA */}

Prêt à tester Xpeditis ?

Créez votre compte en 2 minutes et lancez votre premier chiffrage maritime instantané. C'est gratuit et sans engagement.

Créer mon compte gratuitement
{/* Back + Share */}
Retour au blog
); }