diff --git a/src/app/admin/achievements/page.tsx b/src/app/admin/achievements/page.tsx index e2e127dc..e4872d11 100644 --- a/src/app/admin/achievements/page.tsx +++ b/src/app/admin/achievements/page.tsx @@ -1,4 +1,5 @@ import { Award } from "lucide-react"; +import { getTranslations } from "next-intl/server"; import { StatusCard } from "@/components/admin/dashboard"; import { prisma } from "@/lib/prisma"; @@ -15,6 +16,8 @@ type Achievement = { }; export default async function AdminAchievements() { + const t = await getTranslations("pages.admin.achievements"); + let achievements: Achievement[] = []; try { achievements = await prisma.achievements.findMany({ @@ -33,7 +36,6 @@ export default async function AdminAchievements() { achievements = []; } - // Group by category (already sorted by category, then name, then level). const groups = new Map(); for (const a of achievements) { const list = groups.get(a.category) ?? []; @@ -41,7 +43,6 @@ export default async function AdminAchievements() { groups.set(a.category, list); } - // Distinct achievement names (each name can have multiple level rows). const distinctNames = new Set(achievements.map((a) => a.name)).size; return ( @@ -51,19 +52,19 @@ export default async function AdminAchievements() {
-

Achievements

-

Read-only · {achievements.length} rows across {groups.size} categories.

+

{t("title")}

+

{t("subtitle", { rows: achievements.length, categories: groups.size })}

- - - + + +
{groups.size === 0 ? ( -
No achievements found.
+
{t("noAchievements")}
) : ( [...groups.entries()].map(([category, rows]) => (
@@ -75,12 +76,12 @@ export default async function AdminAchievements() { - - - - - - + + + + + + diff --git a/src/app/admin/ads/page.tsx b/src/app/admin/ads/page.tsx index 28310f4f..b5071fbe 100644 --- a/src/app/admin/ads/page.tsx +++ b/src/app/admin/ads/page.tsx @@ -1,4 +1,5 @@ import Link from "next/link"; +import { getTranslations } from "next-intl/server"; import { Megaphone } from "lucide-react"; import { StatusCard } from "@/components/admin/dashboard"; import { prisma } from "@/lib/prisma"; @@ -6,6 +7,7 @@ import { prisma } from "@/lib/prisma"; export const dynamic = "force-dynamic"; export default async function AdminAds() { + const t = await getTranslations("pages.admin.ads"); let ads: Awaited> = []; try { ads = await prisma.websiteAds.findMany({ @@ -27,30 +29,30 @@ export default async function AdminAds() {
-

Advertisements

-

Website advertisement banners (website_ads). Each ad is an image URL shown across the site.

+

{t("title")}

+

{t("subtitle")}

- + New ad + + {t("newAd")}
- - + +
-

All ads

+

{t("allAds")}

{ads.length === 0 ? ( -
No advertisements yet.
+
{t("noAds")}
) : (
NameLevelProgress neededReward typeReward amountPoints{t("colName")}{t("colLevel")}{t("colProgress")}{t("colRewardType")}{t("colRewardAmount")}{t("colPoints")}
- - - + + + @@ -68,7 +70,7 @@ export default async function AdminAds() { {ad.createdAt ? ad.createdAt.toISOString().slice(0, 10) : "—"} ))} diff --git a/src/app/admin/alerts/page.tsx b/src/app/admin/alerts/page.tsx index 7ba4471b..47fdccfd 100644 --- a/src/app/admin/alerts/page.tsx +++ b/src/app/admin/alerts/page.tsx @@ -1,3 +1,4 @@ +import { getTranslations } from "next-intl/server"; import { Bell } from "lucide-react"; import { sendHotelAlert } from "@/actions/admin-alerts"; import { StatusCard } from "@/components/admin/dashboard"; @@ -8,16 +9,10 @@ export const dynamic = "force-dynamic"; const CRITICAL = new Set(["critical", "error", "danger"]); const WARNING = new Set(["warning", "warn"]); -// Read-only feed of alert_logs (prisma.alertLogs delegate): the emulator and -// CMS write rows here when hotel/user alerts fire. Auto-gated by the admin -// layout (requireStaff); only the mutation re-asserts staff in the action. - function fromDate(d: Date | null | undefined): string { return d ? d.toISOString().slice(0, 16).replace("T", " ") : "—"; } -// Map a free-text severity to a theme-token colour. Unknown severities fall -// back to muted grey rather than inventing a new palette. function severityColor(severity: string): string { switch (severity.toLowerCase()) { case "critical": @@ -59,6 +54,8 @@ function Badge({ label, color }: { label: string; color: string }) { } export default async function AdminAlerts() { + const t = await getTranslations("pages.admin.alerts"); + let alerts: Awaited> = []; try { alerts = await prisma.alertLogs.findMany({ @@ -80,27 +77,27 @@ export default async function AdminAlerts() {
-

Alerts

-

Read-only · 100 most recent alert_logs (newest first).

+

{t("title")}

+

{t("subtitle")}

- + 0 ? "danger" : "ok"} icon="🚨" /> 0 ? "warn" : "neutral"} icon="⚠️" /> 0 ? "warn" : "ok"} icon="📨" @@ -108,9 +105,11 @@ export default async function AdminAlerts() {
-

Send hotel alert

+

{t("form.send")}

- Broadcasts a message to every online user via RCON (hotelalert). + {t.rich("form.description", { + code: (chunks) => {chunks}, + })}

PreviewImage URLCreated{t("colPreview")}{t("colImage")}{t("colCreated")}
- Edit + {t("edit")}