Refactor code structure for improved readability and maintainability

This commit is contained in:
hamed
2026-07-06 09:35:17 +03:30
parent f6475d1a7d
commit a9fcfea12a
3 changed files with 34 additions and 25 deletions
+10 -4
View File
@@ -1,9 +1,12 @@
import { headers } from "next/headers";
// استراتژی چند-دامنه‌ای: هر دامنه‌ی شهری یک property مستقل و first-class است.
// هر صفحه self-canonical روی هاست جاری می‌گیرد؛ هرگز به دامنه‌ی اصلی canonical نمی‌دهیم.
// استراتژی canonical: محتوای همه‌ی دامنه‌های شهری از nobat724.com تغذیه می‌شود —
// پس canonical هر صفحه (روی هر دامنه‌ای) به همان مسیر روی دامنه‌ی اصلی اشاره می‌کند.
// دامنه‌ی اصلی هم self-canonical می‌گیرد.
// توجه: buildCanonicalUrl per-host است و برای JSON-LD/sitemap/robots استفاده می‌شود — به آن دست نزن.
const DEFAULT_HOST = "nobat724.com";
const MAIN_ORIGIN = "https://nobat724.com";
export function normalizeHost(rawHost) {
return (rawHost || DEFAULT_HOST).toLowerCase().replace(/^www\./, "");
@@ -34,15 +37,18 @@ export async function getRequestOrigin() {
}
}
export function buildMainCanonicalUrl(pathname) {
return `${MAIN_ORIGIN}${buildCanonicalPath(pathname)}`;
}
export async function getCanonicalUrl() {
try {
const headersList = await headers();
const host = headersList.get("host");
const pathname = headersList.get("x-pathname");
// مسیرهای خارج از matcher میدل‌ور (panel/dashboard/login) این هدر را ندارند —
// آن‌ها noindex هستند و نباید canonical جعلی به ریشه بگیرند.
if (!pathname) return null;
return buildCanonicalUrl(host, pathname);
return buildMainCanonicalUrl(pathname);
} catch (error) {
console.error("Error generating canonical URL:", error);
return null;
+21 -1
View File
@@ -1,6 +1,11 @@
import { describe, it, expect } from 'vitest';
import { getStateInfoClient } from '@/lib/getStateInfoClient';
import { buildCanonicalUrl, buildCanonicalPath, normalizeHost } from '@/lib/getCanonicalUrl';
import {
buildCanonicalUrl,
buildCanonicalPath,
buildMainCanonicalUrl,
normalizeHost,
} from '@/lib/getCanonicalUrl';
function setLocation(loc) {
Object.defineProperty(window, 'location', { value: loc, writable: true, configurable: true });
@@ -56,3 +61,18 @@ describe('buildCanonicalUrl (self-canonical per-host)', () => {
expect(buildCanonicalUrl(null, '/x')).toBe('https://nobat724.com/x');
});
});
describe('buildMainCanonicalUrl (canonical متادیتا → دامنه‌ی اصلی)', () => {
it('هر مسیری → همان مسیر روی nobat724.com', () => {
expect(buildMainCanonicalUrl('/doctors')).toBe('https://nobat724.com/doctors');
expect(buildMainCanonicalUrl('/doctor/abc-123')).toBe('https://nobat724.com/doctor/abc-123');
});
it('ریشه → با trailing slash', () => {
expect(buildMainCanonicalUrl('/')).toBe('https://nobat724.com/');
});
it('query و trailing slash حذف می‌شوند', () => {
expect(buildMainCanonicalUrl('/doctors/?specialty=قلب')).toBe('https://nobat724.com/doctors');
});
});
+3 -20
View File
@@ -2,34 +2,17 @@
const nextConfig = {
// Add other configurations below
reactStrictMode: true,
// متادیتا (canonical/OG/keywords) باید داخل <head> رندر شود نه استریم در <body>.
// از Next 15.2 استریم متادیتا پیش‌فرض است؛ این regex همه‌ی UAها را blocking می‌کند.
htmlLimitedBots: /.*/,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'api.clinic-pro.ir',
},
{
protocol: 'https',
hostname: 'clinicpro.liara.run',
},
{
protocol: 'http',
hostname: 'clinic-pro.ir',
},
{
protocol: 'https',
hostname: 'back-dev.clinic-pro.ir',
},
{
protocol: 'https',
hostname: 'clinic-pro-back.ddev.site',
},
{
protocol: 'https',
hostname: 'clinic-pro.ddev.site',
},
{
protocol: 'http',
hostname: 'clinic-pro.ddev.site',
},
],