mirror of
https://git.meshkee.com/Meshkee-Websites/arad-arisman.git
synced 2026-08-12 04:30:59 +04:30
Connect products and blog to Meshkee backend API
- Add src/lib/meshkee.ts API client for the live backend (https://api.meshkee.com, tenant aradarisman.com) - Products list/detail pages now fetch real catalog data, images, categories and pricing instead of static mock data - Blog list/detail pages fetch from /tenants/{domain}/blogs with a graceful empty state since no posts are published yet - Allow the Meshkee media CDN host in next.config.ts - Remove now-unused static src/data/products.ts and posts.ts
This commit is contained in:
@@ -5,10 +5,22 @@ import { notFound } from "next/navigation";
|
||||
import Container from "@/components/Container";
|
||||
import PageBanner from "@/components/PageBanner";
|
||||
import PostCard from "@/components/PostCard";
|
||||
import { getPostBySlug, getRelatedPosts, posts } from "@/data/posts";
|
||||
import {
|
||||
getPost,
|
||||
getPosts,
|
||||
postContent,
|
||||
postDate,
|
||||
postExcerpt,
|
||||
postImage,
|
||||
postReadingTime,
|
||||
postTitle,
|
||||
} from "@/lib/meshkee";
|
||||
|
||||
export function generateStaticParams() {
|
||||
return posts.map((p) => ({ slug: p.slug }));
|
||||
export const revalidate = 300;
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const { items } = await getPosts({ page: 1, pageSize: 100 });
|
||||
return items.map((p) => ({ slug: p.slug }));
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
@@ -17,11 +29,11 @@ export async function generateMetadata({
|
||||
params: Promise<{ slug: string }>;
|
||||
}): Promise<Metadata> {
|
||||
const { slug } = await params;
|
||||
const post = getPostBySlug(slug);
|
||||
const post = await getPost(slug);
|
||||
if (!post) return {};
|
||||
return {
|
||||
title: `${post.title} | آراد آریسمان`,
|
||||
description: post.excerpt,
|
||||
title: `${postTitle(post)} | آراد آریسمان`,
|
||||
description: postExcerpt(post, 160),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,14 +43,22 @@ export default async function BlogDetailPage({
|
||||
params: Promise<{ slug: string }>;
|
||||
}) {
|
||||
const { slug } = await params;
|
||||
const post = getPostBySlug(slug);
|
||||
const post = await getPost(slug);
|
||||
if (!post) notFound();
|
||||
|
||||
const related = getRelatedPosts(post);
|
||||
const title = postTitle(post);
|
||||
const image = postImage(post);
|
||||
const content = postContent(post);
|
||||
|
||||
const related = post.categoryId
|
||||
? (await getPosts({ categoryId: post.categoryId, pageSize: 4 })).items
|
||||
.filter((p) => p.id !== post.id)
|
||||
.slice(0, 3)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageBanner title={post.title} breadcrumb="مقالات" />
|
||||
<PageBanner title={title} breadcrumb="مقالات" />
|
||||
|
||||
<section className="py-16 sm:py-20">
|
||||
<Container className="max-w-3xl">
|
||||
@@ -56,32 +76,35 @@ export default async function BlogDetailPage({
|
||||
</Link>
|
||||
|
||||
<div className="mt-6 flex items-center gap-3 text-sm text-foreground/70">
|
||||
<span className="rounded-full bg-primary/5 px-3 py-1 text-xs font-semibold text-primary">
|
||||
{post.category}
|
||||
</span>
|
||||
<span>{post.date}</span>
|
||||
{post.categoryNameFa && (
|
||||
<span className="rounded-full bg-primary/5 px-3 py-1 text-xs font-semibold text-primary">
|
||||
{post.categoryNameFa}
|
||||
</span>
|
||||
)}
|
||||
<span>{postDate(post)}</span>
|
||||
<span className="h-1 w-1 rounded-full bg-foreground/30" />
|
||||
<span>{post.readingTime}</span>
|
||||
<span>{postReadingTime(post)}</span>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-6 aspect-[16/9] rounded-3xl overflow-hidden shadow-xl bg-surface">
|
||||
<Image
|
||||
src={post.cover}
|
||||
alt={post.title}
|
||||
fill
|
||||
priority
|
||||
className="object-cover"
|
||||
sizes="(min-width: 1024px) 768px, 100vw"
|
||||
{image && (
|
||||
<div className="relative mt-6 aspect-[16/9] rounded-3xl overflow-hidden shadow-xl bg-surface">
|
||||
<Image
|
||||
src={image}
|
||||
alt={title}
|
||||
fill
|
||||
priority
|
||||
className="object-cover"
|
||||
sizes="(min-width: 1024px) 768px, 100vw"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{content && (
|
||||
<div
|
||||
className="rich-content mt-8"
|
||||
dangerouslySetInnerHTML={{ __html: content }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 space-y-5">
|
||||
{post.content.map((paragraph) => (
|
||||
<p key={paragraph} className="leading-8 text-foreground">
|
||||
{paragraph}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-10 rounded-2xl bg-surface p-6 flex flex-wrap items-center justify-between gap-4">
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user