canina/frontend/application/app/blog/[slug]/page.tsx
parsa aghaei 7615aa0e51 fix: resolve seed encoding, search param, and wiki data source issues
- Fix seed-products.ts TS error (implicit any) and BOM handling
- Re-run full seed to restore correct Persian encoding in DB
- Fix productService query→search param mismatch
- Fix IngredientWiki hardcoded port 4000→use settingsStore
- Restore seed-products-data.json from git after accidental corruption
2026-07-11 15:40:49 +03:30

124 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react";
import { ChevronRight, Calendar, User, Sparkles } from "lucide-react";
import Link from 'next/link';
import type { Metadata } from 'next';
async function getBlog(slug: string) {
try {
const res = await fetch(`http://localhost:4001/api/blogs/${slug}`, { next: { revalidate: 60 } });
if (!res.ok) throw new Error('Failed to fetch blog');
const b = await res.json();
return {
id: b.id,
slug: b.slug,
title: b.title,
excerpt: b.metaDescription || b.content.substring(0, 150).replace(/<[^>]+>/g, '') + '...',
image: b.imageUrl,
date: new Date(b.createdAt).toLocaleDateString('fa-IR'),
author: b.author ? `${b.author.firstName} ${b.author.lastName}` : 'نویسنده کانینا',
content: b.content
};
} catch (error) {
console.error(error);
return null;
}
}
export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
const blog = await getBlog(params.slug);
if (!blog) return { title: 'مقاله یافت نشد' };
return {
title: blog.title,
description: blog.excerpt,
};
}
export default async function BlogPostPage({ params }: { params: { slug: string } }) {
const selectedPost = await getBlog(params.slug);
if (!selectedPost) {
return (
<div className="min-h-[50vh] flex flex-col items-center justify-center font-vazir text-center" dir="rtl">
<h1 className="text-3xl font-black text-medical-gray-900 mb-4">مقالهای یافت نشد</h1>
<Link href="/blog" className="text-canina-blue font-bold flex items-center gap-2">
<ChevronRight className="w-4 h-4" />
بازگشت به مجله سلامت
</Link>
</div>
);
}
return (
<div className="min-h-screen bg-medical-gray-50 pt-8 pb-20 px-4 font-vazir" dir="rtl">
<div className="max-w-7xl mx-auto">
{/* Breadcrumbs */}
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-10">
<Link href="/" className="hover:text-canina-blue transition-colors">خانه</Link>
<ChevronRight className="w-2.5 h-2.5" />
<Link href="/blog" className="hover:text-canina-blue transition-colors">مجله سلامت</Link>
<ChevronRight className="w-2.5 h-2.5" />
<span className="text-canina-blue">{selectedPost.title}</span>
</div>
<div className="grid lg:grid-cols-12 gap-12">
<div className="lg:col-span-8">
<div className="bg-white rounded-[3.5rem] border border-medical-gray-200 shadow-2xl overflow-hidden">
<div className="aspect-video w-full overflow-hidden">
<img src={selectedPost.image} alt={selectedPost.title} className="w-full h-full object-cover" />
</div>
<div className="p-12">
<div className="flex items-center gap-4 text-xs font-bold text-canina-blue mb-8">
<div className="bg-canina-blue/10 px-4 py-1.5 rounded-full uppercase tracking-widest">تحقیق بالینی</div>
<div className="flex items-center gap-1">
<Calendar className="w-4 h-4" />
{selectedPost.date}
</div>
</div>
<h1 className="text-4xl lg:text-5xl font-black text-medical-gray-900 mb-10 leading-tight">
{selectedPost.title}
</h1>
<div className="prose prose-lg max-w-none text-medical-gray-600 leading-[2] text-justify space-y-6">
<p className="font-bold text-medical-gray-900 italic text-xl border-r-4 border-canina-blue pr-6 py-2">
{selectedPost.excerpt}
</p>
<div className="whitespace-pre-line" dangerouslySetInnerHTML={{ __html: selectedPost.content }} />
</div>
<div className="mt-16 pt-10 border-t border-medical-gray-100 flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="w-14 h-14 bg-medical-gray-100 rounded-full flex items-center justify-center text-medical-gray-400 border-2 border-white shadow-lg">
<User className="w-8 h-8" />
</div>
<div>
<div className="font-black text-medical-gray-900 text-lg">{selectedPost.author}</div>
<div className="font-bold text-medical-gray-400">نویسنده کانینا</div>
</div>
</div>
<div className="flex gap-4">
<button className="p-4 bg-medical-gray-100 rounded-2xl hover:bg-canina-blue hover:text-white transition-all text-medical-gray-400">
<Sparkles className="w-6 h-6" />
</button>
</div>
</div>
</div>
</div>
</div>
<div className="lg:col-span-4 space-y-10">
<div className="bg-canina-blue rounded-[3rem] p-10 text-white shadow-2xl relative overflow-hidden">
<div className="absolute top-0 left-0 p-8 opacity-10">
<Sparkles className="w-20 h-20" />
</div>
<h4 className="text-2xl font-black mb-6 italic relative z-10">ارتباط با کارشناسان</h4>
<div className="space-y-6 relative z-10 text-white/90">
برای دریافت مشاوره تخصصی و انتخاب بهترین مکمل برای حیوان خانگی خود، با ما در تماس باشید.
</div>
</div>
</div>
</div>
</div>
</div>
);
}