seo check

This commit is contained in:
hamed
2026-06-05 21:28:12 +03:30
parent 3c9013ff0c
commit 35408b059a
10 changed files with 368 additions and 115 deletions
+13
View File
@@ -1,5 +1,18 @@
import AboutUsPage from "@/components/aboutUs"; import AboutUsPage from "@/components/aboutUs";
import Layout from "@/components/layout/StLayout"; import Layout from "@/components/layout/StLayout";
import { getStateInfo } from "@/lib/getStateInfo";
export async function generateMetadata() {
const { matchedCity } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
const title = `درباره ما | ${siteName}`;
const description = `آشنایی با ${siteName}، سیستم آنلاین نوبت‌دهی پزشکی. هدف ما ارائه خدمات سریع و کارآمد رزرو نوبت پزشکی برای همه مردم است.`;
return {
title,
description,
openGraph: { title, description },
};
}
function AboutUs() { function AboutUs() {
return ( return (
+68 -6
View File
@@ -1,24 +1,86 @@
import BlogPage from "@/components/blog"; import BlogPage from "@/components/blog";
import Layout from "@/components/layout/StLayout"; import Layout from "@/components/layout/StLayout";
import { fetchReq } from "@/lib/req"; import { fetchReq } from "@/lib/req";
import { getStateInfo } from "@/lib/getStateInfo";
async function Blog({ params: { slug } }) { export async function generateMetadata({ params }) {
const { slug } = await params;
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const { matchedCity } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
try {
const blog = await fetchReq(`${API_URL}/api/v1/blog/${slug}`);
if (!blog) return {};
const title = `${blog.title} | ${siteName}`;
const rawText = blog.body ? blog.body.replace(/<[^>]*>/g, "").trim() : "";
const description = rawText.slice(0, 160) || blog.title;
return {
title,
description,
openGraph: {
title,
description,
type: "article",
...(blog.created && { publishedTime: blog.created }),
images: blog.images?.[0]
? [blog.images[0]]
: ["https://www.nobat724.com/assets/images/logo.png"],
},
twitter: {
card: "summary_large_image",
title,
description,
images: blog.images?.[0]
? [blog.images[0]]
: ["https://www.nobat724.com/assets/images/logo.png"],
},
};
} catch {
return {};
}
}
async function Blog({ params }) {
const { slug } = await params;
const API_URL = process.env.NEXT_PUBLIC_API_URL; const API_URL = process.env.NEXT_PUBLIC_API_URL;
const blog = await fetchReq(`${API_URL}/api/v1/blog/${slug}`); const blog = await fetchReq(`${API_URL}/api/v1/blog/${slug}`);
// Get related blogs based on first tag
let relatedBlogs = []; let relatedBlogs = [];
if (blog?.tag?.[0]?.id) { if (blog?.tag?.[0]?.id) {
const tagId = blog.tag[0].id; const tagId = blog.tag[0].id;
const relatedResponse = await fetchReq(`${API_URL}/api/v1/blogs?page=1&limit=12&tag=${tagId}`); const relatedResponse = await fetchReq(
`${API_URL}/api/v1/blogs?page=1&limit=12&tag=${tagId}`
);
relatedBlogs = relatedResponse?.blogs || []; relatedBlogs = relatedResponse?.blogs || [];
} }
const jsonLd = blog
? {
"@context": "https://schema.org",
"@type": "Article",
headline: blog.title,
...(blog.images?.[0] && { image: blog.images[0] }),
...(blog.created && { datePublished: blog.created }),
...(blog.author && { author: { "@type": "Person", name: blog.author } }),
}
: null;
return ( return (
<Layout> <>
<BlogPage blog={blog} blogs={relatedBlogs} /> {jsonLd && (
</Layout> <script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
)}
<Layout>
<BlogPage blog={blog} blogs={relatedBlogs} />
</Layout>
</>
); );
} }
+13
View File
@@ -1,5 +1,18 @@
import BlogsPage from "@/components/blogs"; import BlogsPage from "@/components/blogs";
import Layout from "@/components/layout/StLayout"; import Layout from "@/components/layout/StLayout";
import { getStateInfo } from "@/lib/getStateInfo";
export async function generateMetadata() {
const { matchedCity } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
const title = `مقالات و اخبار پزشکی | ${siteName}`;
const description = `جدیدترین مقالات، اخبار و راهنماهای پزشکی. اطلاعات تخصصی در حوزه سلامت و پزشکی از متخصصان ${siteName}.`;
return {
title,
description,
openGraph: { title, description },
};
}
export default function Blogs() { export default function Blogs() {
return ( return (
+55 -10
View File
@@ -1,28 +1,73 @@
import ClinicPage from "@/components/clinic"; import ClinicPage from "@/components/clinic";
import Layout from "@/components/layout/StLayout"; import Layout from "@/components/layout/StLayout";
import { fetchReq } from "@/lib/req"; import { fetchReq } from "@/lib/req";
import { getStateInfo } from "@/lib/getStateInfo";
async function Clinic({ params: { slug },searchParams }) { export async function generateMetadata({ params }) {
const { slug } = await params;
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const { matchedCity } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
try {
const clinic = await fetchReq(`${API_URL}/api/v1/clinic/${slug}`);
if (!clinic) return {};
const title = `${clinic.title} | ${siteName}`;
const description = `رزرو نوبت و اطلاعات ${clinic.title}. مشاهده لیست پزشکان و خدمات درمانی موجود.`;
return {
title,
description,
openGraph: {
title,
description,
images: clinic.images_clinic?.[0]
? [clinic.images_clinic[0]]
: ["https://www.nobat724.com/assets/images/logo.png"],
},
};
} catch {
return {};
}
}
async function Clinic({ params, searchParams }) {
const { slug } = await params;
const API_URL = process.env.NEXT_PUBLIC_API_URL; const API_URL = process.env.NEXT_PUBLIC_API_URL;
const page = Number(searchParams?.page) || 1; const page = Number(searchParams?.page) || 1;
const reqClinics = await fetchReq( const limit = 50;
`${API_URL}/api/v1/clinic/${slug}`
);
const limit=50
const reqClinics = await fetchReq(`${API_URL}/api/v1/clinic/${slug}`);
const reqDoctors = await fetchReq( const reqDoctors = await fetchReq(
`${API_URL}/api/v1/clinic/doctor-list/${slug}?page=${page}&limit=${limit}` `${API_URL}/api/v1/clinic/doctor-list/${slug}?page=${page}&limit=${limit}`
); );
const clinic = reqClinics; const clinic = reqClinics;
const doctors = reqDoctors?.data || []; const doctors = reqDoctors?.data || [];
const pagedoctors=reqDoctors?.page const pagedoctors = reqDoctors?.page;
const jsonLd = clinic
? {
"@context": "https://schema.org",
"@type": "MedicalClinic",
name: clinic.title,
...(clinic.images_clinic?.[0] && { image: clinic.images_clinic[0] }),
}
: null;
return ( return (
<Layout> <>
<ClinicPage data={clinic} doctors={doctors} slug={slug} pages={pagedoctors} /> {jsonLd && (
</Layout> <script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
)}
<Layout>
<ClinicPage data={clinic} doctors={doctors} slug={slug} pages={pagedoctors} />
</Layout>
</>
); );
} }
+17
View File
@@ -4,6 +4,23 @@ import Layout from "@/components/layout/StLayout";
import { getStateInfo } from "@/lib/getStateInfo"; import { getStateInfo } from "@/lib/getStateInfo";
import { buildClinicParams } from "@/helper"; import { buildClinicParams } from "@/helper";
export async function generateMetadata() {
const { matchedCity, matchedState } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
const cityName = matchedCity?.name || matchedState?.name || "";
const title = cityName
? `کلینیک‌های ${cityName} | جستجو و رزرو نوبت | ${siteName}`
: `جستجوی کلینیک و مراکز درمانی | ${siteName}`;
const description = cityName
? `لیست کلینیک‌ها و مراکز درمانی در ${cityName}. رزرو آنلاین نوبت از بهترین مراکز درمانی ${cityName}.`
: `جستجوی کلینیک‌ها و مراکز درمانی در سراسر کشور. رزرو آنلاین نوبت سریع و آسان.`;
return {
title,
description,
openGraph: { title, description },
};
}
export default async function Clinics({ searchParams }) { export default async function Clinics({ searchParams }) {
const awaitedSearchParams = await searchParams; const awaitedSearchParams = await searchParams;
const { matchedCity, matchedState } = await getStateInfo(); const { matchedCity, matchedState } = await getStateInfo();
+70 -9
View File
@@ -1,15 +1,54 @@
import DoctorPage from "@/components/doctor"; import DoctorPage from "@/components/doctor";
import Layout from "@/components/layout/StLayout"; import Layout from "@/components/layout/StLayout";
import { getStateInfo } from "@/lib/getStateInfo";
import axios from "axios"; import axios from "axios";
async function Doctor({ params: { slug } }) { export async function generateMetadata({ params }) {
const { slug } = await params;
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const { matchedCity } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
try {
const res = await axios.get(`${API_URL}/api/v1/doctor/${slug}`);
const doctor = res.data;
if (!doctor) return {};
const specialtyNames = doctor.specialties?.map((s) => s.name).join(" و ") || "";
const title = `دکتر ${doctor.name}${specialtyNames ? " | " + specialtyNames : ""} | ${siteName}`;
const description =
doctor.detail ||
`رزرو نوبت آنلاین دکتر ${doctor.name}${specialtyNames ? " متخصص " + specialtyNames : ""}${doctor.address ? " | " + doctor.address : ""}`.trim();
return {
title,
description,
openGraph: {
title,
description,
type: "profile",
images: doctor.img ? [doctor.img] : ["https://www.nobat724.com/assets/images/logo.png"],
},
twitter: {
card: "summary",
title,
description,
images: doctor.img ? [doctor.img] : ["https://www.nobat724.com/assets/images/logo.png"],
},
};
} catch {
return {};
}
}
async function Doctor({ params }) {
const { slug } = await params;
let doctor = null; let doctor = null;
let comments = null; let comments = null;
const API_URL = process.env.NEXT_PUBLIC_API_URL; const API_URL = process.env.NEXT_PUBLIC_API_URL;
try { try {
const resDoctor = await axios.get(`${API_URL}/api/v1/doctor/${slug}`); const resDoctor = await axios.get(`${API_URL}/api/v1/doctor/${slug}`);
doctor = resDoctor.data; doctor = resDoctor.data;
if (doctor) { if (doctor) {
const resComments = await axios.get( const resComments = await axios.get(
@@ -17,15 +56,37 @@ async function Doctor({ params: { slug } }) {
); );
comments = resComments?.data?.data; comments = resComments?.data?.data;
} }
} catch (error) { } catch (error) {}
// console.error("problem with req:", error.message);
// return redirect("/unauthorized"); const specialtyNames = doctor?.specialties?.map((s) => s.name).join(" و ") || "";
} const jsonLd = doctor
? {
"@context": "https://schema.org",
"@type": "Physician",
name: `دکتر ${doctor.name}`,
...(specialtyNames && { medicalSpecialty: specialtyNames }),
...(doctor.img && { image: doctor.img }),
...(doctor.address && {
address: {
"@type": "PostalAddress",
streetAddress: doctor.address,
},
}),
}
: null;
return ( return (
<Layout> <>
<DoctorPage doctor={doctor} comments={comments} slug={slug} /> {jsonLd && (
</Layout> <script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
)}
<Layout>
<DoctorPage doctor={doctor} comments={comments} slug={slug} />
</Layout>
</>
); );
} }
+17
View File
@@ -4,6 +4,23 @@ import { buildDoctorParams } from "@/helper";
import { getStateInfo } from "@/lib/getStateInfo"; import { getStateInfo } from "@/lib/getStateInfo";
import axios from "axios"; import axios from "axios";
export async function generateMetadata() {
const { matchedCity, matchedState } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
const cityName = matchedCity?.name || matchedState?.name || "";
const title = cityName
? `پزشکان ${cityName} | جستجو و رزرو نوبت | ${siteName}`
: `جستجوی پزشک و رزرو نوبت آنلاین | ${siteName}`;
const description = cityName
? `لیست پزشکان متخصص در ${cityName}. جستجو بر اساس تخصص و منطقه. رزرو آنلاین نوبت پزشکی در ${cityName}.`
: `جستجوی پزشکان متخصص در سراسر کشور. رزرو آنلاین نوبت پزشکی سریع و آسان با نوبت 724.`;
return {
title,
description,
openGraph: { title, description },
};
}
async function Doctors({ searchParams }) { async function Doctors({ searchParams }) {
const awaitedSearchParams = await searchParams; const awaitedSearchParams = await searchParams;
const { matchedCity, matchedState } = await getStateInfo(); const { matchedCity, matchedState } = await getStateInfo();
+16 -2
View File
@@ -14,13 +14,27 @@ export async function generateMetadata() {
const canonicalUrl = await getCanonicalUrl(); const canonicalUrl = await getCanonicalUrl();
const title = matchedCity ? matchedCity.title : "نوبت724";
const description = matchedCity?.description || "نوبت 724 - سیستم آنلاین نوبت‌دهی برای پزشکان و کلینیک‌ها. با استفاده از نوبت 724، به راحتی نوبت پزشکی خود را به صورت آنلاین رزرو کنید و از خدمات سریع و کارآمد ما بهره‌مند شوید";
const baseMetadata = { const baseMetadata = {
title: matchedCity ? matchedCity.title : "نوبت724", title,
description: matchedCity?.description || "نوبت 724 - سیستم آنلاین نوبت‌دهی برای پزشکان و کلینیک‌ها. با استفاده از نوبت 724، به راحتی نوبت پزشکی خود را به صورت آنلاین رزرو کنید و از خدمات سریع و کارآمد ما بهره‌مند شوید", description,
keywords: matchedCity keywords: matchedCity
? matchedCity.keywords ? matchedCity.keywords
: "نوبت 724, نوبت دهی, رزرو نوبت, پزشک, پزشکی, کلینیک, بیمارستان, نوبت آنلاین, سیستم نوبت دهی, سیستم نوبت دهی آنلاین, سیستم نوبت دهی پزشکی, سیستم نوبت دهی کلینیک, سیستم نوبت دهی بیمارستان, سیستم نوبت دهی آنلاین پزشکی, سیستم نوبت دهی آنلاین کلینیک, سیستم نوبت دهی آنلاین بیمارستان", : "نوبت 724, نوبت دهی, رزرو نوبت, پزشک, پزشکی, کلینیک, بیمارستان, نوبت آنلاین, سیستم نوبت دهی, سیستم نوبت دهی آنلاین, سیستم نوبت دهی پزشکی, سیستم نوبت دهی کلینیک, سیستم نوبت دهی بیمارستان, سیستم نوبت دهی آنلاین پزشکی, سیستم نوبت دهی آنلاین کلینیک, سیستم نوبت دهی آنلاین بیمارستان",
openGraph: { openGraph: {
title,
description,
type: "website",
locale: "fa_IR",
siteName: matchedCity?.site_name || "نوبت 724",
images: ["https://www.nobat724.com/assets/images/logo.png"],
},
twitter: {
card: "summary_large_image",
title,
description,
images: ["https://www.nobat724.com/assets/images/logo.png"], images: ["https://www.nobat724.com/assets/images/logo.png"],
}, },
}; };
+83 -88
View File
@@ -1,7 +1,6 @@
import { headers } from 'next/headers'; import { headers } from 'next/headers';
import cityData from '../data/city.json'; import cityData from '../data/city.json';
import specialtyData from '../data/specialties.json'; import specialtyData from '../data/specialties.json';
import stateData from '../data/state.json';
import { import {
DOMAIN_CONFIG, DOMAIN_CONFIG,
isMainDomain, isMainDomain,
@@ -11,93 +10,103 @@ import {
getBaseUrl getBaseUrl
} from '../utils/sitemap'; } from '../utils/sitemap';
// Get current domain from headers
function getCurrentDomain() { function getCurrentDomain() {
try { try {
const headersList = headers(); const headersList = headers();
const host = headersList.get('host'); const host = headersList.get('host');
return host || DOMAIN_CONFIG.MAIN_DOMAIN; return host || DOMAIN_CONFIG.MAIN_DOMAIN;
} catch (error) { } catch (error) {
// Fallback for static generation
console.warn('Headers not available during static generation, using main domain'); console.warn('Headers not available during static generation, using main domain');
return DOMAIN_CONFIG.MAIN_DOMAIN; return DOMAIN_CONFIG.MAIN_DOMAIN;
} }
} }
// Get city data based on domain
function getCityByDomain(domain) { function getCityByDomain(domain) {
return cityData.find(city => city.domain === domain); return cityData.find(city => city.domain === domain);
} }
// Get state name by province_id
function getStateById(provinceId) {
return stateData.find(state => state.id === provinceId)?.name || '';
}
// Generate static pages URLs
function getStaticPages(baseUrl) { function getStaticPages(baseUrl) {
return [ return [
{ { url: baseUrl, lastModified: new Date(), changeFrequency: 'daily', priority: 1 },
url: baseUrl, { url: `${baseUrl}/about-us`, lastModified: new Date(), changeFrequency: 'monthly', priority: 0.8 },
lastModified: new Date(), { url: `${baseUrl}/contact-us`, lastModified: new Date(), changeFrequency: 'monthly', priority: 0.8 },
changeFrequency: 'daily', { url: `${baseUrl}/blogs`, lastModified: new Date(), changeFrequency: 'weekly', priority: 0.9 },
priority: 1, { url: `${baseUrl}/doctors`, lastModified: new Date(), changeFrequency: 'daily', priority: 0.9 },
}, { url: `${baseUrl}/clinics`, lastModified: new Date(), changeFrequency: 'daily', priority: 0.9 },
{ { url: `${baseUrl}/specialties`, lastModified: new Date(), changeFrequency: 'weekly', priority: 0.9 },
url: `${baseUrl}/about-us`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/contact-us`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/blogs`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.9,
},
{
url: `${baseUrl}/doctors`,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.9,
},
{
url: `${baseUrl}/clinics`,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.9,
},
{
url: `${baseUrl}/specialties`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.9,
},
]; ];
} }
// Generate doctor search URLs based on domain async function getDoctorUrls(baseUrl) {
function getDoctorSearchUrls(domain, baseUrl) { const API_URL = process.env.NEXT_PUBLIC_API_URL;
// Return empty array - no URLs with search parameters if (!API_URL) return [];
return [];
try {
const res = await fetch(`${API_URL}/api/v1/doctors?page=1&limit=500`, {
next: { revalidate: 3600 },
});
if (!res.ok) return [];
const data = await res.json();
const doctors = data?.data || data?.doctors || data || [];
return doctors
.filter((d) => d?.uuid)
.map((d) => ({
url: `${baseUrl}/doctor/${d.uuid}`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8,
}));
} catch {
return [];
}
} }
// Generate clinic search URLs async function getClinicUrls(baseUrl) {
function getClinicSearchUrls(domain, baseUrl) { const API_URL = process.env.NEXT_PUBLIC_API_URL;
// Return empty array - no URLs with search parameters if (!API_URL) return [];
return [];
try {
const res = await fetch(`${API_URL}/api/v1/clinics?page=1&limit=500`, {
next: { revalidate: 3600 },
});
if (!res.ok) return [];
const data = await res.json();
const clinics = data?.data || data?.clinics || data || [];
return clinics
.filter((c) => c?.uuid)
.map((c) => ({
url: `${baseUrl}/clinic/${c.uuid}`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.7,
}));
} catch {
return [];
}
} }
// Generate specialty pages URLs async function getBlogUrls(baseUrl) {
function getSpecialtyUrls(domain, baseUrl) { const API_URL = process.env.NEXT_PUBLIC_API_URL;
// Return empty array - no specialty URLs if (!API_URL) return [];
return [];
try {
const res = await fetch(`${API_URL}/api/v1/blogs?page=1&limit=200`, {
next: { revalidate: 3600 },
});
if (!res.ok) return [];
const data = await res.json();
const blogs = data?.blogs || data?.data || data || [];
return blogs
.filter((b) => b?.slug || b?.uuid)
.map((b) => ({
url: `${baseUrl}/blog/${b.slug || b.uuid}`,
lastModified: b.created ? new Date(b.created) : new Date(),
changeFrequency: 'monthly',
priority: 0.6,
}));
} catch {
return [];
}
} }
export default async function sitemap() { export default async function sitemap() {
@@ -105,34 +114,20 @@ export default async function sitemap() {
const domain = getCurrentDomain(); const domain = getCurrentDomain();
const baseUrl = getBaseUrl(domain); const baseUrl = getBaseUrl(domain);
console.log(`Generating sitemap for domain: ${domain}, baseUrl: ${baseUrl}`); const [staticPages, doctorUrls, clinicUrls, blogUrls] = await Promise.all([
console.log(`City data length: ${cityData.length}, Specialty data length: ${specialtyData.length}`); Promise.resolve(getStaticPages(baseUrl)),
getDoctorUrls(baseUrl),
getClinicUrls(baseUrl),
getBlogUrls(baseUrl),
]);
// Get all URLs const allUrls = [...staticPages, ...doctorUrls, ...clinicUrls, ...blogUrls];
const staticPages = getStaticPages(baseUrl);
const doctorSearchUrls = getDoctorSearchUrls(domain, baseUrl);
const clinicSearchUrls = getClinicSearchUrls(domain, baseUrl);
const specialtyUrls = getSpecialtyUrls(domain, baseUrl);
console.log(`Generated URLs - Static: ${staticPages.length}, Doctors: ${doctorSearchUrls.length}, Clinics: ${clinicSearchUrls.length}, Specialties: ${specialtyUrls.length}`); return allUrls.filter(
(item, index, arr) => arr.findIndex((i) => i.url === item.url) === index
// Combine all URLs
const allUrls = [
...staticPages,
...doctorSearchUrls,
...clinicSearchUrls,
...specialtyUrls,
];
// Remove duplicates based on URL
const uniqueUrls = allUrls.filter((item, index, arr) =>
arr.findIndex(i => i.url === item.url) === index
); );
return uniqueUrls;
} catch (error) { } catch (error) {
console.error('Error generating sitemap:', error); console.error('Error generating sitemap:', error);
return []; return [];
} }
} }
+16
View File
@@ -1,5 +1,21 @@
import Layout from "@/components/layout/StLayout"; import Layout from "@/components/layout/StLayout";
import SpecialtiesPage from "@/components/specialties"; import SpecialtiesPage from "@/components/specialties";
import { getStateInfo } from "@/lib/getStateInfo";
export async function generateMetadata() {
const { matchedCity } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
const cityName = matchedCity?.name || "";
const title = cityName
? `تخصص‌های پزشکی در ${cityName} | ${siteName}`
: `تخصص‌های پزشکی | ${siteName}`;
const description = `لیست کامل تخصص‌های پزشکی${cityName ? " در " + cityName : ""}. رزرو نوبت از متخصصین مختلف به صورت آنلاین.`;
return {
title,
description,
openGraph: { title, description },
};
}
function Specialties() { function Specialties() {
return ( return (