From 456a44685071ecca7e1e91d358709aadeae43e24 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Mon, 15 Jun 2026 15:47:00 +0330 Subject: [PATCH] feat(meta): per-page titles + favicon/app icons + PWA across the panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The app had no metadata anywhere — pages showed no and no favicon or app icon. Added: - Root metadata in [locale]/layout: title default + "%s — میزی" template, description, icons (favicon + apple-touch-icon → /icons), manifest link, appleWebApp, themeColor viewport, noindex (private panel). - Per-page title on all 22 dashboard route pages (داشبورد, منو, گزارش‌ها, …). - Guest menu (/q) layout: own title + icon + manifest. PWA + favicon now use the Meezi icon everywhere. Verified via SSR: titles render (e.g. "منو — میزی") and icon/manifest/apple-touch-icon links present. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --- .../[locale]/(dashboard)/branches/page.tsx | 4 ++ .../app/[locale]/(dashboard)/coupons/page.tsx | 4 ++ .../src/app/[locale]/(dashboard)/crm/page.tsx | 4 ++ .../[locale]/(dashboard)/expenses/page.tsx | 4 ++ .../src/app/[locale]/(dashboard)/hr/page.tsx | 4 ++ .../src/app/[locale]/(dashboard)/kds/page.tsx | 4 ++ .../app/[locale]/(dashboard)/menu/page.tsx | 4 ++ .../(dashboard)/notifications/page.tsx | 4 ++ .../src/app/[locale]/(dashboard)/page.tsx | 4 ++ .../app/[locale]/(dashboard)/queue/page.tsx | 4 ++ .../app/[locale]/(dashboard)/reports/page.tsx | 4 ++ .../(dashboard)/reservations/page.tsx | 4 ++ .../app/[locale]/(dashboard)/reviews/page.tsx | 4 ++ .../[locale]/(dashboard)/settings/page.tsx | 4 ++ .../app/[locale]/(dashboard)/shifts/page.tsx | 4 ++ .../src/app/[locale]/(dashboard)/sms/page.tsx | 4 ++ .../subscription/checkout/page.tsx | 4 ++ .../(dashboard)/subscription/page.tsx | 4 ++ .../(dashboard)/support/[ticketId]/page.tsx | 4 ++ .../app/[locale]/(dashboard)/support/page.tsx | 4 ++ .../app/[locale]/(dashboard)/tables/page.tsx | 4 ++ .../app/[locale]/(dashboard)/taxes/page.tsx | 4 ++ web/dashboard/src/app/[locale]/layout.tsx | 37 +++++++++++++++++++ web/dashboard/src/app/q/layout.tsx | 15 ++++++++ 24 files changed, 140 insertions(+) diff --git a/web/dashboard/src/app/[locale]/(dashboard)/branches/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/branches/page.tsx index 557f090..f6bd9eb 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/branches/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/branches/page.tsx @@ -1,5 +1,9 @@ import { BranchesScreen } from "@/components/branches/branches-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "شعب" }; + export default function BranchesPage() { return <BranchesScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/coupons/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/coupons/page.tsx index 8adab67..9c15188 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/coupons/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/coupons/page.tsx @@ -1,5 +1,9 @@ import { CouponsScreen } from "@/components/coupons/coupons-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "کوپن‌ها" }; + export default function CouponsPage() { return <CouponsScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/crm/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/crm/page.tsx index 2ca6d4c..fef049f 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/crm/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/crm/page.tsx @@ -1,5 +1,9 @@ import { CrmScreen } from "@/components/crm/crm-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "مشتریان" }; + export default function CrmPage() { return <CrmScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/expenses/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/expenses/page.tsx index b7eda66..4e2a348 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/expenses/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/expenses/page.tsx @@ -1,5 +1,9 @@ import { ExpensesScreen } from "@/components/expenses/expenses-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "هزینه‌ها" }; + export default function ExpensesPage() { return <ExpensesScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/hr/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/hr/page.tsx index e0b7754..ab8aa57 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/hr/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/hr/page.tsx @@ -1,5 +1,9 @@ import { HrScreen } from "@/components/hr/hr-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "منابع انسانی" }; + export default function HrPage() { return <HrScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/kds/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/kds/page.tsx index 9d2d21f..ee8e020 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/kds/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/kds/page.tsx @@ -1,5 +1,9 @@ import { KdsScreen } from "@/components/kds/kds-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "آشپزخانه" }; + export default function KdsPage() { return <KdsScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/menu/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/menu/page.tsx index 8611910..31a4582 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/menu/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/menu/page.tsx @@ -1,5 +1,9 @@ import { MenuAdminScreen } from "@/components/menu/menu-admin-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "منو" }; + export default function MenuPage() { return <MenuAdminScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/notifications/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/notifications/page.tsx index 03aecda..5324812 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/notifications/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/notifications/page.tsx @@ -1,5 +1,9 @@ import { NotificationsScreen } from "@/components/notifications/notifications-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "اعلان‌ها" }; + export default function NotificationsPage() { return <NotificationsScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/page.tsx index 2d062ba..9968a4e 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/page.tsx @@ -1,5 +1,9 @@ import { OverviewScreen } from "@/components/overview/overview-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "داشبورد" }; + export default function HomePage() { return <OverviewScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/queue/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/queue/page.tsx index 171dcda..116b69d 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/queue/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/queue/page.tsx @@ -1,5 +1,9 @@ import { QueueScreen } from "@/components/queue/queue-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "نوبت‌دهی" }; + export default function QueuePage() { return <QueueScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/reports/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/reports/page.tsx index 3311d2b..9102079 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/reports/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/reports/page.tsx @@ -1,5 +1,9 @@ import { ReportsScreen } from "@/components/reports/reports-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "گزارش‌ها" }; + export default function ReportsPage() { return <ReportsScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/reservations/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/reservations/page.tsx index 1f4e5ef..09d90c0 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/reservations/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/reservations/page.tsx @@ -1,5 +1,9 @@ import { ReservationsScreen } from "@/components/reservations/reservations-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "رزرو" }; + export default function ReservationsPage() { return <ReservationsScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/reviews/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/reviews/page.tsx index b1c30e9..7d35683 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/reviews/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/reviews/page.tsx @@ -1,5 +1,9 @@ import { ReviewsScreen } from "@/components/reviews/reviews-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "نظرات" }; + export default function ReviewsPage() { return <ReviewsScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/settings/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/settings/page.tsx index ace034a..622981f 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/settings/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/settings/page.tsx @@ -1,6 +1,10 @@ import { Suspense } from "react"; import { SettingsScreen } from "@/components/settings/settings-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "تنظیمات" }; + export default function SettingsPage() { return ( <Suspense fallback={null}> diff --git a/web/dashboard/src/app/[locale]/(dashboard)/shifts/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/shifts/page.tsx index da68689..7fb50ca 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/shifts/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/shifts/page.tsx @@ -1,5 +1,9 @@ import { ShiftsScreen } from "@/components/shifts/shifts-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "بستن شیفت" }; + export default function ShiftsPage() { return <ShiftsScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/sms/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/sms/page.tsx index 41d83c3..bed71cd 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/sms/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/sms/page.tsx @@ -1,5 +1,9 @@ import { SmsScreen } from "@/components/sms/sms-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "پیامک" }; + export default function SmsPage() { return <SmsScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/subscription/checkout/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/subscription/checkout/page.tsx index 44f403b..6ecbcd4 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/subscription/checkout/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/subscription/checkout/page.tsx @@ -1,6 +1,10 @@ import { Suspense } from "react"; import { CheckoutScreen } from "@/components/subscription/checkout-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "تسویه اشتراک" }; + export default function SubscriptionCheckoutPage() { return ( <Suspense fallback={null}> diff --git a/web/dashboard/src/app/[locale]/(dashboard)/subscription/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/subscription/page.tsx index b8ccfff..652ef50 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/subscription/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/subscription/page.tsx @@ -1,6 +1,10 @@ import { Suspense } from "react"; import { SubscriptionScreen } from "@/components/subscription/subscription-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "اشتراک و پلن" }; + export default function SubscriptionPage() { return ( <Suspense fallback={null}> diff --git a/web/dashboard/src/app/[locale]/(dashboard)/support/[ticketId]/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/support/[ticketId]/page.tsx index ad63be3..b4d818c 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/support/[ticketId]/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/support/[ticketId]/page.tsx @@ -1,5 +1,9 @@ import { SupportTicketDetailScreen } from "@/components/support/support-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "تیکت پشتیبانی" }; + export default function SupportTicketPage() { return <SupportTicketDetailScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/support/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/support/page.tsx index a4e8f82..2ce4f47 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/support/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/support/page.tsx @@ -1,5 +1,9 @@ import { SupportScreen } from "@/components/support/support-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "پشتیبانی" }; + export default function SupportPage() { return <SupportScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/tables/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/tables/page.tsx index 7f03cfc..b6f6b2d 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/tables/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/tables/page.tsx @@ -1,5 +1,9 @@ import { TablesScreen } from "@/components/tables/tables-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "میزها" }; + export default function TablesPage() { return <TablesScreen />; } diff --git a/web/dashboard/src/app/[locale]/(dashboard)/taxes/page.tsx b/web/dashboard/src/app/[locale]/(dashboard)/taxes/page.tsx index ac42724..266cdea 100644 --- a/web/dashboard/src/app/[locale]/(dashboard)/taxes/page.tsx +++ b/web/dashboard/src/app/[locale]/(dashboard)/taxes/page.tsx @@ -1,5 +1,9 @@ import { TaxesScreen } from "@/components/taxes/taxes-screen"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { title: "مالیات" }; + export default function TaxesPage() { return <TaxesScreen />; } diff --git a/web/dashboard/src/app/[locale]/layout.tsx b/web/dashboard/src/app/[locale]/layout.tsx index cf63b45..c9e2e3d 100644 --- a/web/dashboard/src/app/[locale]/layout.tsx +++ b/web/dashboard/src/app/[locale]/layout.tsx @@ -1,3 +1,4 @@ +import type { Metadata, Viewport } from "next"; import { NextIntlClientProvider } from "next-intl"; import { getMessages, setRequestLocale } from "next-intl/server"; import { notFound } from "next/navigation"; @@ -6,6 +7,42 @@ import { routing } from "@/i18n/routing"; import { Providers } from "@/components/providers"; import "../globals.css"; +const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://app.meezi.ir"; + +// Default metadata for the whole panel. `title.template` gives every page a +// "<page> — میزی" title; per-page `metadata.title` fills in the page name. +// Icons/manifest here also fix pages that previously had no favicon/app icon. +export const metadata: Metadata = { + metadataBase: new URL(SITE_URL), + title: { + default: "میزی — پنل مدیریت کافه", + template: "%s — میزی", + }, + description: "پنل مدیریت کافه و رستوران میزی — صندوق، منو، گزارش و مدیریت.", + applicationName: "میزی", + manifest: "/manifest.webmanifest", + icons: { + icon: [ + { url: "/icons/icon-192.png", sizes: "192x192", type: "image/png" }, + { url: "/icons/icon-512.png", sizes: "512x512", type: "image/png" }, + ], + shortcut: "/icons/icon-192.png", + apple: "/icons/icon-192.png", + }, + appleWebApp: { + capable: true, + title: "میزی", + statusBarStyle: "default", + }, + robots: { index: false, follow: false }, // private merchant panel +}; + +export const viewport: Viewport = { + themeColor: "#0F6E56", + width: "device-width", + initialScale: 1, +}; + const vazirmatn = localFont({ src: "../../fonts/Vazirmatn-Variable.woff2", variable: "--font-vazirmatn", diff --git a/web/dashboard/src/app/q/layout.tsx b/web/dashboard/src/app/q/layout.tsx index 2ad9dcb..7a14d4f 100644 --- a/web/dashboard/src/app/q/layout.tsx +++ b/web/dashboard/src/app/q/layout.tsx @@ -1,9 +1,24 @@ +import type { Metadata, Viewport } from "next"; import { NextIntlClientProvider } from "next-intl"; import localFont from "next/font/local"; import faMessages from "../../../messages/fa.json"; import { MeeziToaster } from "@/components/ui/meezi-toaster"; import "../globals.css"; +export const metadata: Metadata = { + title: "منوی کافه — میزی", + description: "مشاهده منو و ثبت سفارش از میز", + manifest: "/manifest.webmanifest", + icons: { icon: "/icons/icon-192.png", apple: "/icons/icon-192.png" }, + robots: { index: false, follow: false }, +}; + +export const viewport: Viewport = { + themeColor: "#0F6E56", + width: "device-width", + initialScale: 1, +}; + const vazirmatn = localFont({ src: "../../fonts/Vazirmatn-Variable.woff2", variable: "--font-vazirmatn",