feat(website): Next.js 16 marketing website with RTL/Farsi

Marketing website for Meezi platform:
- Server-side rendered pages: home, demo, blog, pricing
- RTL/Farsi layout with Vazirmatn font
- SEO metadata and Open Graph tags
- proxy.ts for Next.js 16 middleware convention
- MEEZI_API_URL internal Docker network routing

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-05-27 21:34:32 +03:30
parent 131ecdbbe6
commit d62bb8d3ad
84 changed files with 16985 additions and 0 deletions
+137
View File
@@ -0,0 +1,137 @@
type JsonLdType = "SoftwareApplication" | "Organization" | "BlogPosting" | "WebSite" | "FAQPage";
interface JsonLdProps {
type: JsonLdType;
locale: string;
data?: Record<string, unknown>;
}
const BASE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://meezi.ir";
function buildSoftwareApplication(locale: string) {
return {
"@context": "https://schema.org",
"@type": "SoftwareApplication",
name: "Meezi",
alternateName: "میزی",
applicationCategory: "BusinessApplication",
operatingSystem: "Web, Android, iOS",
url: BASE_URL,
description:
locale === "fa"
? "پلتفرم هوشمند مدیریت کافه و رستوران — منوی QR، سیستم POS، تحلیل فروش و مدیریت کارکنان"
: "Smart cafe & restaurant management — QR menu, POS system, sales analytics and staff management",
offers: {
"@type": "Offer",
price: "0",
priceCurrency: "IRR",
name: locale === "fa" ? "پلن رایگان" : "Free Plan",
},
publisher: {
"@type": "Organization",
name: "Meezi",
url: BASE_URL,
},
inLanguage: locale === "fa" ? "fa-IR" : "en",
};
}
function buildOrganization(locale: string) {
return {
"@context": "https://schema.org",
"@type": "Organization",
name: "Meezi",
alternateName: "میزی",
url: BASE_URL,
logo: `${BASE_URL}/logo.png`,
description:
locale === "fa"
? "پلتفرم هوشمند مدیریت کافه و رستوران ایران"
: "Smart cafe & restaurant management platform for Iran",
foundingDate: "2022",
foundingLocation: "Tehran, Iran",
contactPoint: {
"@type": "ContactPoint",
contactType: locale === "fa" ? "پشتیبانی" : "Customer Support",
availableLanguage: ["Persian", "English"],
},
};
}
function buildFAQPage(locale: string) {
const faqs =
locale === "fa"
? [
{ q: "آیا برای استفاده از میزی به دانش فنی نیاز است؟", a: "خیر. میزی برای استفاده توسط افراد غیرفنی طراحی شده. راه‌اندازی اولیه توسط تیم پشتیبانی انجام می‌شود." },
{ q: "آیا داده‌هایم امن هستند؟", a: "بله. تمام داده‌های شما روی سرورهای ایرانی با رمزگذاری TLS ذخیره می‌شوند. پشتیبان‌گیری خودکار روزانه انجام می‌شود." },
{ q: "آیا می‌توانم پلن را تغییر دهم؟", a: "بله. می‌توانید هر زمان پلن‌تان را ارتقا یا تغییر دهید. هزینه به‌صورت پرو-ریت محاسبه می‌شود." },
{ q: "آیا میزی با دستگاه‌های موجودم کار می‌کند؟", a: "بله. میزی یک وب‌اپلیکیشن است و روی هر دستگاهی با مرورگر مدرن کار می‌کند — ویندوز، مک، تبلت و موبایل." },
{ q: "پشتیبانی چگونه است؟", a: "پلن استارتر پشتیبانی ایمیلی دارد. پلن کسب‌وکار پشتیبانی تلفنی و چت دارد. پلن سازمانی پشتیبانی ۲۴/۷ با مدیر حساب اختصاصی." },
]
: [
{ q: "Do I need technical knowledge to use Meezi?", a: "No. Meezi is designed for non-technical users. Initial setup is handled by our support team." },
{ q: "Is my data secure?", a: "Yes. All data is stored on Iranian servers with TLS encryption. Automatic daily backups are performed." },
{ q: "Can I change my plan?", a: "Yes. You can upgrade or change your plan at any time. Upgrades are pro-rated." },
{ q: "Does Meezi work with my existing devices?", a: "Yes. Meezi is a web application that works on any modern browser — Windows, Mac, tablet, and mobile." },
{ q: "What's your support like?", a: "Starter has email support. Business has phone and chat support. Enterprise has 24/7 support with a dedicated account manager." },
];
return {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: faqs.map(({ q, a }) => ({
"@type": "Question",
name: q,
acceptedAnswer: { "@type": "Answer", text: a },
})),
};
}
function buildWebSite(locale: string) {
return {
"@context": "https://schema.org",
"@type": "WebSite",
name: "Meezi",
alternateName: "میزی",
url: BASE_URL,
inLanguage: locale === "fa" ? "fa-IR" : "en",
potentialAction: {
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: `${BASE_URL}/${locale}/blog?q={search_term_string}`,
},
"query-input": "required name=search_term_string",
},
};
}
export function JsonLd({ type, locale, data }: JsonLdProps) {
let schema: Record<string, unknown>;
switch (type) {
case "SoftwareApplication":
schema = buildSoftwareApplication(locale);
break;
case "Organization":
schema = buildOrganization(locale);
break;
case "WebSite":
schema = buildWebSite(locale);
break;
case "FAQPage":
schema = buildFAQPage(locale);
break;
case "BlogPosting":
schema = { "@context": "https://schema.org", "@type": "BlogPosting", ...data };
break;
default:
return null;
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema, null, 0) }}
/>
);
}