Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
153 lines
8.0 KiB
TypeScript
153 lines
8.0 KiB
TypeScript
import type { Metadata } from 'next'
|
|
|
|
import { ORGANIZATION_ID, WEBSITE_ID, faqPage } from '@/lib/seo/JsonLd'
|
|
import { buildCanonicalUrl, SITE_URL } from '@/lib/seo/metadata'
|
|
import { buildPublicPageMetadata } from '@/lib/seo/publicPageMetadata'
|
|
|
|
/** Jalali «۸ شهریور ۱۴۰۵» → Gregorian calendar date used in schema / sitemap. */
|
|
export const LEGAL_DOCUMENT_UPDATED_AT_ISO = '2026-08-30'
|
|
export const LEGAL_DOCUMENT_UPDATED_AT_FA = '۸ شهریور ۱۴۰۵'
|
|
|
|
export type LegalPageKey = 'terms' | 'privacy' | 'refund-policy'
|
|
|
|
interface LegalPageSeoConfig {
|
|
path: `/${LegalPageKey}`
|
|
/** Visible H1 — primary on-page topic signal. */
|
|
h1: string
|
|
breadcrumbName: string
|
|
/** Absolute document title (no root template suffix). Keep ≤ ~60 chars for SERP. */
|
|
metaTitle: string
|
|
metaDescription: string
|
|
/** schema.org primary type(s) beyond WebPage. */
|
|
schemaType: string | string[]
|
|
pageId: string
|
|
}
|
|
|
|
/**
|
|
* SEO source of truth for public legal pages.
|
|
* Titles are tuned for Persian search intent + SERP length; body copy stays in page components.
|
|
*/
|
|
export const LEGAL_PAGE_SEO: Record<LegalPageKey, LegalPageSeoConfig> = {
|
|
terms: {
|
|
path: '/terms',
|
|
h1: 'شرایط استفاده از قبیله',
|
|
breadcrumbName: 'شرایط استفاده',
|
|
metaTitle: 'شرایط استفاده قبیله | قوانین رزرو و میزبانی',
|
|
metaDescription:
|
|
'شرایط استفاده از قبیله: قوانین ساخت حساب، رزرو رویداد، پرداخت، مسئولیت مهمان و میزبان، فهرست انتظار و ارتباط با پشتیبانی را بخوانید.',
|
|
schemaType: ['WebPage', 'TermsOfService'],
|
|
pageId: `${SITE_URL}/terms#webpage`,
|
|
},
|
|
privacy: {
|
|
path: '/privacy',
|
|
h1: 'حریم خصوصی قبیله',
|
|
breadcrumbName: 'حریم خصوصی',
|
|
metaTitle: 'حریم خصوصی قبیله | حفاظت از اطلاعات کاربران',
|
|
metaDescription:
|
|
'سیاست حریم خصوصی قبیله: چه دادههایی جمع میشود، چرا استفاده میشود، چه اطلاعاتی به میزبان میرسد، نگهداری، حذف حساب و امنیت اطلاعات.',
|
|
schemaType: ['WebPage', 'PrivacyPolicy'],
|
|
pageId: `${SITE_URL}/privacy#webpage`,
|
|
},
|
|
'refund-policy': {
|
|
path: '/refund-policy',
|
|
h1: 'لغو و بازگشت وجه قبیله',
|
|
breadcrumbName: 'لغو و بازگشت وجه',
|
|
metaTitle: 'لغو و بازگشت وجه قبیله | قوانین کنسلی رویداد',
|
|
metaDescription:
|
|
'در قبیله هر رویداد قوانین لغو و بازگشت وجه خودش را دارد؛ جزئیات را در صفحه همان رویداد ببین. چارچوب کلی، کیف پول و پشتیبانی اینجا.',
|
|
schemaType: 'WebPage',
|
|
pageId: `${SITE_URL}/refund-policy#webpage`,
|
|
},
|
|
}
|
|
|
|
export function buildLegalPageMetadata(key: LegalPageKey): Metadata {
|
|
const page = LEGAL_PAGE_SEO[key]
|
|
const pageMetadata = buildPublicPageMetadata({
|
|
path: page.path,
|
|
metaTitle: page.metaTitle,
|
|
metaDescription: page.metaDescription,
|
|
})
|
|
|
|
return {
|
|
...pageMetadata,
|
|
title: { absolute: page.metaTitle },
|
|
openGraph: {
|
|
...pageMetadata.openGraph,
|
|
title: page.metaTitle,
|
|
},
|
|
twitter: { ...pageMetadata.twitter, title: page.metaTitle },
|
|
robots: { index: true, follow: true },
|
|
}
|
|
}
|
|
|
|
export function legalWebPageSchema(key: LegalPageKey) {
|
|
const page = LEGAL_PAGE_SEO[key]
|
|
const url = buildCanonicalUrl(page.path)
|
|
|
|
return {
|
|
'@context': 'https://schema.org',
|
|
'@type': page.schemaType,
|
|
'@id': page.pageId,
|
|
name: page.metaTitle,
|
|
headline: page.h1,
|
|
description: page.metaDescription,
|
|
url,
|
|
inLanguage: 'fa-IR',
|
|
isPartOf: { '@id': WEBSITE_ID },
|
|
publisher: { '@id': ORGANIZATION_ID },
|
|
datePublished: LEGAL_DOCUMENT_UPDATED_AT_ISO,
|
|
dateModified: LEGAL_DOCUMENT_UPDATED_AT_ISO,
|
|
mainEntityOfPage: {
|
|
'@type': 'WebPage',
|
|
'@id': page.pageId,
|
|
},
|
|
}
|
|
}
|
|
|
|
/** Question-shaped sections on the refund policy — used for FAQ rich results + AI extraction. */
|
|
export const REFUND_POLICY_FAQS = [
|
|
{
|
|
question: 'قوانین لغو و بازگشت وجه در قبیله چطور مشخص میشود؟',
|
|
answer:
|
|
'هر رویداد قوانین لغو و بازگشت وجه خودش را دارد. برگزارکننده هنگام ساخت رویداد قواعد و هزینه لغو را تنظیم میکند؛ مرجع نهایی صفحه همان رویداد است و قبل از رزرو باید جزئیات آنجا را بخوانی.',
|
|
},
|
|
{
|
|
question: 'اگر از کد تخفیف استفاده کرده باشم بازگشت وجه چطور حساب میشود؟',
|
|
answer:
|
|
'اگر هنگام خرید از کد تخفیف استفاده کرده باشی، محاسبه بازگشت وجه (در صورت وجود طبق قوانین همان رویداد) بر اساس مبلغ واقعی پرداختشده انجام میشود؛ نه قیمت اولیه رویداد.',
|
|
},
|
|
{
|
|
question: 'اگر برگزارکننده رویداد را لغو کند چه اتفاقی میافتد؟',
|
|
answer:
|
|
'رزروهای آن رویداد لغو میشوند، شرکتکنندگان مطلع میشوند و مبلغ پرداختشده بهطور کامل به کیف پول قبیله بازمیگردد. در حال حاضر بابت لغو رویداد توسط برگزارکننده جریمهای از شرکتکننده گرفته نمیشود.',
|
|
},
|
|
{
|
|
question: 'اگر زمان یا مکان رویداد تغییر کند چه میشود؟',
|
|
answer:
|
|
'بعد از رزرو فعال، تغییر زمان، مکان، قیمت یا شرایط اصلی حضور باید از مسیر پشتیبانی قبیله پیگیری شود و شرکتکنندگان مطلع میشوند. اگر بهخاطر تغییر دیگر نتوانی شرکت کنی، موضوع را از پشتیبانی پیگیری کن.',
|
|
},
|
|
{
|
|
question: 'اگر در رویداد حاضر نشوم مبلغ برمیگردد؟',
|
|
answer:
|
|
'اگر رزرو داشته باشی، طبق قوانین همان رویداد در بازه مجاز لغو نکرده باشی و در رویداد حاضر نشوی، مبلغ پرداختی معمولاً بازگردانده نمیشود. قبیله برای رزروهای تأییدشده یادآوری ارسال میکند، اما مسئولیت حضور با شرکتکننده است.',
|
|
},
|
|
{
|
|
question: 'اگر پرداخت انجام شد ولی رزرو ثبت نشد چه کار کنم؟',
|
|
answer:
|
|
'این موضوع لغو رزرو نیست. ابتدا وضعیت تراکنش بررسی میشود؛ اگر پرداخت ناموفق باشد مبلغ طبق فرایند شبکه پرداخت برمیگردد. برای پیگیری، شماره موبایل حساب، زمان پرداخت، مبلغ و شماره پیگیری بانکی را آماده کن و با پشتیبانی تماس بگیر.',
|
|
},
|
|
{
|
|
question: 'آیا برگزارکننده میتواند رزرو یک نفر را لغو کند؟',
|
|
answer: 'در حال حاضر برگزارکننده امکان لغو مستقیم رزرو یک شرکتکننده مشخص را ندارد و باید موضوع را از طریق پشتیبانی قبیله مطرح کند.',
|
|
},
|
|
{
|
|
question: 'آیا میتوانم رزرو را به شخص دیگر منتقل کنم؟',
|
|
answer:
|
|
'در حال حاضر انتقال رزرو یا بلیط به شخص دیگر امکانپذیر نیست. هر رزرو به حساب همان شخصی که ثبتنام کرده متصل است و برای عدم حضور باید مطابق قوانین لغو همان رویداد اقدام کنی.',
|
|
},
|
|
] as const
|
|
|
|
export function refundPolicyFaqSchema() {
|
|
return faqPage(REFUND_POLICY_FAQS)
|
|
}
|