Files
GNX-WEB/frontEnd/components/pages/blog/BlogSingle.tsx
Iliyan Angelov 366f28677a update
2025-11-24 03:52:08 +02:00

273 lines
11 KiB
TypeScript

"use client";
import { useParams } from "next/navigation";
import Image from "next/legacy/image";
import Link from "next/link";
import { useBlogPost } from "@/lib/hooks/useBlog";
import { getValidImageUrl, getValidImageAlt, FALLBACK_IMAGES } from "@/lib/imageUtils";
const BlogSingle = () => {
const params = useParams();
const slug = params?.slug as string;
const { post, loading, error } = useBlogPost(slug);
if (loading) {
return (
<section className="blog-single-section fix-top pb-120">
<div className="container">
<div className="row justify-content-center">
<div className="col-12 col-lg-10 col-xl-8">
<div className="loading-state text-center py-5">
<div className="spinner-border text-primary mb-3" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<p className="text-tertiary">Loading insight...</p>
</div>
</div>
</div>
</div>
</section>
);
}
if (error || !post) {
return (
<section className="blog-single-section fix-top pb-120">
<div className="container">
<div className="row justify-content-center">
<div className="col-12 col-lg-10 col-xl-8">
<div className="error-state text-center py-5">
<div className="error-icon mb-4">
<i className="fa-solid fa-exclamation-circle fa-4x text-tertiary"></i>
</div>
<h2 className="text-secondary mb-3">Insight Not Found</h2>
<p className="text-tertiary mb-4">
The insight you're looking for doesn't exist or has been removed.
</p>
<Link href="/insights" className="btn btn-primary">
<i className="fa-solid fa-arrow-left me-2"></i>
Back to Insights
</Link>
</div>
</div>
</div>
</div>
</section>
);
}
return (
<section className="blog-single-section fix-top pb-120">
<div className="container">
{/* Article Content */}
<div className="row">
<div className="col-12">
<article className="blog-single-article">
{/* Article Header */}
<header className="article-header">
{/* Top Meta Bar */}
<div className="article-top-meta d-flex flex-wrap align-items-center justify-content-between mb-4">
<div className="left-meta d-flex align-items-center gap-3">
{/* Category Badge */}
{post.category && (
<Link href={`/insights?category=${post.category.slug}`} className="category-badge">
<i className="fa-solid fa-folder-open me-2"></i>
{post.category.title}
</Link>
)}
{/* Date */}
<div className="meta-item d-flex align-items-center">
<i className="fa-solid fa-calendar me-2"></i>
<span>
{new Date(post.published_at || post.created_at).toLocaleDateString('en-US', {
day: 'numeric',
month: 'short',
year: 'numeric'
})}
</span>
</div>
</div>
<div className="right-meta d-flex align-items-center gap-3">
{/* Reading Time */}
<div className="meta-item d-flex align-items-center">
<i className="fa-solid fa-clock me-2"></i>
<span>{post.reading_time} min</span>
</div>
{/* Views */}
<div className="meta-item d-flex align-items-center">
<i className="fa-solid fa-eye me-2"></i>
<span>{post.views_count}</span>
</div>
</div>
</div>
{/* Title */}
<h1 className="article-title">
{post.title}
</h1>
{/* Author and Tags Bar */}
<div className="article-bottom-meta d-flex flex-wrap align-items-center justify-content-between mt-4 pt-4">
{/* Author */}
<div className="author-meta d-flex align-items-center">
<div className="author-avatar me-3">
{post.author?.avatar ? (
<Image
src={post.author.avatar}
alt={post.author.name}
width={48}
height={48}
className="rounded-circle"
/>
) : (
<div className="avatar-placeholder">
<i className="fa-solid fa-user"></i>
</div>
)}
</div>
<div className="author-info">
<div className="author-label">Written by</div>
<div className="author-name">
{post.author?.name || post.author_name || 'Admin'}
</div>
</div>
</div>
{/* Tags */}
{post.tags && post.tags.length > 0 && (
<div className="article-tags d-flex flex-wrap align-items-center gap-2">
{post.tags.map((tag) => (
<Link
key={tag.id}
href={`/insights?tag=${tag.slug}`}
className="tag-badge"
>
#{tag.name}
</Link>
))}
</div>
)}
</div>
</header>
{/* Featured Image */}
{(post.featured_image || post.thumbnail) && (
<div className="article-featured-image">
<div className="image-wrapper">
<Image
src={getValidImageUrl(
post.featured_image || post.thumbnail,
FALLBACK_IMAGES.BLOG
)}
alt={getValidImageAlt(post.title)}
width={1200}
height={600}
layout="responsive"
className="featured-image"
/>
</div>
</div>
)}
{/* Article Body */}
<div className="article-body">
{/* Excerpt */}
{post.excerpt && (
<div className="article-excerpt">
<p className="lead">{post.excerpt}</p>
</div>
)}
{/* Content */}
{post.content && (
<div
className="article-content enterprise-content"
dangerouslySetInnerHTML={{ __html: post.content }}
/>
)}
</div>
{/* Footer Section */}
<footer className="article-footer">
{/* Share Section */}
<div className="article-share">
<div className="share-container">
<h6 className="share-title">
Share this insight
</h6>
<div className="social-share">
<Link
href={`https://www.linkedin.com/shareArticle?mini=true&url=${typeof window !== 'undefined' ? encodeURIComponent(window.location.href) : ''}&title=${encodeURIComponent(post.title)}`}
target="_blank"
rel="noopener noreferrer"
className="share-btn share-linkedin"
aria-label="Share on LinkedIn"
>
<i className="fa-brands fa-linkedin-in"></i>
<span>LinkedIn</span>
</Link>
<button
onClick={() => {
if (typeof window !== 'undefined' && navigator.clipboard) {
navigator.clipboard.writeText(window.location.href);
alert('Link copied to clipboard!');
}
}}
className="share-btn share-copy"
aria-label="Copy link"
>
<i className="fa-solid fa-link"></i>
<span>Copy</span>
</button>
</div>
</div>
</div>
{/* Author Bio */}
{post.author && post.author.bio && (
<div className="author-bio-section">
<div className="author-bio-card">
<div className="author-avatar-container">
{post.author.avatar ? (
<Image
src={post.author.avatar}
alt={post.author.name}
width={90}
height={90}
className="rounded-circle"
/>
) : (
<div className="author-avatar-large">
<i className="fa-solid fa-user"></i>
</div>
)}
</div>
<div className="author-bio-content">
<div className="bio-label">About the Author</div>
<h6 className="author-name">{post.author.name}</h6>
<p className="author-bio-text">{post.author.bio}</p>
</div>
</div>
</div>
)}
{/* Navigation */}
<div className="article-navigation">
<Link href="/insights" className="btn-back-insights">
<i className="fa-solid fa-arrow-left me-2"></i>
Back to All Insights
</Link>
</div>
</footer>
</article>
</div>
</div>
</div>
</section>
);
};
export default BlogSingle;