2025-12-22 22:51:18 +05:30

177 lines
11 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import { useParams } from 'next/navigation';
import axios from 'axios';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import Link from 'next/link';
const BlogPost = () => {
const params = useParams();
const [blog, setBlog] = useState<any>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchBlog = async () => {
try {
const response = await axios.get(`http://localhost:3020/api/blog/${params.id}`);
if (response.data.ok) {
setBlog(response.data.data);
}
} catch (error) {
console.error("Fetch error:", error);
} finally {
setLoading(false);
}
};
if (params.id) fetchBlog();
}, [params.id]);
if (loading) return (
<div className="flex items-center justify-center min-h-[60vh]">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div>
</div>
);
if (!blog) return <div className="text-center py-20 text-2xl">Blog not found</div>;
return (
<div className="max-w-[1000px] mx-auto px-5 py-10">
<Link href="/blog-generator" className="btn btn-outline-primary mb-8 inline-flex items-center gap-2">
Back to Generator
</Link>
<article className="panel shadow-xl overflow-hidden border-none outline-none">
{/* Header Section */}
<div className="relative h-[400px] w-full overflow-hidden">
<img
src={blog.generatedImageUrls?.[0] || 'https://images.unsplash.com/photo-1499750310107-5fef28a66643?auto=format&fit=crop&q=80&w=1500'}
alt={blog.title}
className="w-full h-full object-cover transition-transform duration-700 hover:scale-105"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent flex flex-col justify-end p-8 lg:p-12">
<div className="flex gap-2 mb-4">
<span className="badge badge-primary bg-primary/20 backdrop-blur-md text-primary-light border-none">Industry Insight</span>
<span className="badge badge-secondary bg-secondary/20 backdrop-blur-md text-secondary-light border-none">AI Generated</span>
</div>
<h1 className="text-3xl lg:text-5xl font-bold text-white leading-tight">
{blog.title}
</h1>
<div className="flex items-center gap-6 mt-6 text-gray-300 text-sm">
<span>{new Date(blog.createdAt).toLocaleDateString()}</span>
<span></span>
<span>{blog.wordCount || 1800}+ Words</span>
<span></span>
<span className="flex items-center gap-1">
<span className="w-2 h-2 rounded-full bg-green-500"></span>
SEO Score: {blog.seoScore}%
</span>
</div>
</div>
</div>
{/* Performance Metrics Bar */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 p-6 bg-white dark:bg-black/20 border-b">
<div className="text-center p-4 rounded-xl bg-primary/5">
<p className="text-[10px] text-secondary-dark uppercase font-black mb-1 tracking-wider">SEO Score</p>
<p className="text-3xl font-black text-primary">{blog.seoScore}%</p>
</div>
<div className="text-center p-4 rounded-xl bg-info/5">
<p className="text-[10px] text-secondary-dark uppercase font-black mb-1 tracking-wider">Human Score</p>
<p className="text-3xl font-black text-info">{blog.aiDetectionScore || 92}%</p>
</div>
<div className="text-center p-4 rounded-xl bg-success/5">
<p className="text-[10px] text-secondary-dark uppercase font-black mb-1 tracking-wider">Readability</p>
<p className="text-3xl font-black text-success">{blog.readabilityScore || 85}%</p>
</div>
<div className="text-center p-4 rounded-xl bg-warning/5 border border-warning/20">
<p className="text-[10px] text-secondary-dark uppercase font-black mb-1 tracking-wider">Focus Keyword</p>
<p className="text-sm font-bold text-warning truncate px-2">{blog.focusKeyword || 'Optimized'}</p>
</div>
</div>
{/* Content Section */}
<div className="p-8 lg:p-16 prose prose-slate prose-lg dark:prose-invert max-w-none
prose-headings:text-black dark:prose-headings:text-white
prose-h1:text-4xl lg:prose-h1:text-5xl prose-h1:mb-8
prose-h2:text-3xl prose-h2:mt-12 prose-h2:mb-6
prose-h3:text-2xl prose-h3:mt-8
prose-p:text-gray-700 dark:prose-p:text-gray-300 prose-p:leading-relaxed prose-p:text-lg
prose-li:text-gray-700 dark:prose-li:text-gray-300
prose-blockquote:border-primary prose-blockquote:bg-primary/5 prose-blockquote:py-2 prose-blockquote:px-8 prose-blockquote:rounded-r-2xl prose-blockquote:italic prose-blockquote:text-lg">
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{blog.content}
</ReactMarkdown>
</div>
{/* SEO Analysis Detail */}
{blog.seoDetails && blog.seoDetails.length > 0 && (
<div className="px-8 lg:px-16 pb-8">
<div className="p-8 rounded-2xl bg-gray-50 dark:bg-white/5 border border-gray-100 dark:border-white/10 shadow-sm">
<h3 className="text-xl font-bold mb-6 flex items-center gap-3 text-primary">
<svg xmlns="http://www.w3.org/2000/svg" className="h-7 w-7" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
SEO Quality Checklist
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{blog.seoDetails.map((detail: string, i: number) => (
<div key={i} className="flex items-start gap-3 p-3 rounded-lg bg-white dark:bg-black/20 border border-gray-100 dark:border-white/5 text-gray-700 dark:text-gray-300">
<div className={`mt-1 h-5 w-5 flex-shrink-0 flex items-center justify-center rounded-full ${detail.toLowerCase().includes('missing') ? 'bg-red-100 text-red-600' : 'bg-green-100 text-green-600'}`}>
{detail.toLowerCase().includes('missing') ? (
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20"><path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" /></svg>
) : (
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20"><path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" /></svg>
)}
</div>
<span className="text-sm font-medium">{detail}</span>
</div>
))}
</div>
</div>
</div>
)}
{/* FAQ Section */}
{blog.faqs && blog.faqs.length > 0 && (
<div className="px-8 lg:px-16 pb-16">
<div className="p-8 rounded-3xl bg-primary/5 dark:bg-primary/10 border border-primary/10">
<h3 className="text-2xl font-black mb-8 text-black dark:text-white flex items-center gap-3">
<span className="p-2 bg-primary text-white rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
</svg>
</span>
Frequently Asked Questions
</h3>
<div className="space-y-4">
{blog.faqs.map((faq: any, i: number) => (
<div key={i} className="p-6 rounded-2xl bg-white dark:bg-black/40 border border-gray-100 dark:border-white/5 hover:border-primary/30 transition-all shadow-sm group">
<h4 className="text-lg font-bold mb-3 text-black dark:text-white group-hover:text-primary transition-colors">
{faq.question}
</h4>
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
{faq.answer}
</p>
</div>
))}
</div>
</div>
</div>
)}
</article>
{/* Float CTA */}
<div className="mt-12 text-center p-12 rounded-3xl bg-gradient-to-r from-primary to-secondary text-white">
<h2 className="text-3xl font-bold mb-4">Want content like this for your site?</h2>
<p className="text-lg opacity-90 mb-8 max-w-xl mx-auto">Our AI-powered engine analyzes your target niche and builds expert topical authority in seconds.</p>
<Link href="/pricing" className="btn btn-white bg-white text-primary font-bold px-10 py-4 rounded-full text-lg hover:shadow-xl transition-all">
Upgrade to Pro Plan
</Link>
</div>
</div>
);
};
export default BlogPost;