From e00e9ca2dc5c31ab7fccf9791fbccc6a15e7ccec Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 22 Jul 2026 18:45:43 +0200 Subject: [PATCH] refactor: centralize hotel name fallback via FALLBACK_HOTEL_NAME Route all user-facing Atom hotel defaults through resolveHotelName (settings then HOTEL_NAME env then brand constant). Exclude Playwright e2e from tsconfig until deps are installed. Co-authored-by: Cursor --- src/actions/email-verify.ts | 5 ++-- src/app/(site)/apply/staff/page.tsx | 4 +-- src/app/(site)/apply/team/page.tsx | 4 +-- src/app/(site)/help/[category]/page.tsx | 4 +-- src/app/(site)/login/page.tsx | 5 ++-- src/app/(site)/logo/page.tsx | 6 +++-- src/app/(site)/maintenance/page.tsx | 5 ++-- src/app/(site)/me/page.tsx | 5 ++-- src/app/(site)/page.tsx | 9 ++++--- src/app/(site)/register/page.tsx | 5 ++-- src/app/(site)/settings/2fa/page.tsx | 4 +-- src/app/admin/radio/embed/page.tsx | 4 +-- src/app/admin/settings/cms-settings-config.ts | 3 ++- src/app/api/home/route.ts | 7 ++--- src/app/api/paypal/capture/route.ts | 5 ++-- src/app/api/paypal/create/route.ts | 5 ++-- src/app/client/page.tsx | 7 ++--- src/app/layout.tsx | 3 ++- src/app/manifest.ts | 3 ++- src/components/home/guest-view.tsx | 1 - src/components/home/user-view.tsx | 3 ++- src/components/mobile-nav.tsx | 3 ++- src/components/navigation.tsx | 3 +++ src/components/public/logo-generator.tsx | 9 +++++-- src/components/site-footer.tsx | 6 ++--- src/components/site-header.tsx | 7 ++--- src/env.ts | 3 ++- src/lib/brand.ts | 10 +++++++ src/lib/hotel-name.ts | 26 +++++++++++++++++++ src/lib/services/site-settings.ts | 3 ++- tsconfig.json | 2 +- 31 files changed, 113 insertions(+), 56 deletions(-) create mode 100644 src/lib/brand.ts create mode 100644 src/lib/hotel-name.ts diff --git a/src/actions/email-verify.ts b/src/actions/email-verify.ts index 9cb351bb2e..456385a005 100644 --- a/src/actions/email-verify.ts +++ b/src/actions/email-verify.ts @@ -3,8 +3,8 @@ import { createHmac, timingSafeEqual } from "node:crypto"; import { getTranslations } from "next-intl/server"; import { env } from "@/env"; +import { resolveHotelName } from "@/lib/hotel-name"; import { sendMail } from "@/lib/services/email"; -import { siteSettings } from "@/lib/services/site-settings"; // Stateless email verification with a time-limited HMAC token. // @@ -78,8 +78,7 @@ export async function sendVerification(email: string): Promise { const base = env.APP_URL.replace(/\/+$/, ""); const link = `${base}/verify?token=${encodeURIComponent(token)}&email=${encodeURIComponent(normalised)}`; - const hotelName = - (await siteSettings.get("hotel_name", env.HOTEL_NAME)) ?? env.HOTEL_NAME; + const hotelName = await resolveHotelName(); let subject = `Verify your email · ${hotelName}`; let heading = "Verify your email"; diff --git a/src/app/(site)/apply/staff/page.tsx b/src/app/(site)/apply/staff/page.tsx index bf16a818ee..6ebc164985 100644 --- a/src/app/(site)/apply/staff/page.tsx +++ b/src/app/(site)/apply/staff/page.tsx @@ -5,7 +5,7 @@ import { applyStaff } from "@/actions/applications"; import { ContentCard, EmptyState } from "@/components/public/ui"; import { auth } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; -import { siteSettings } from "@/lib/services/site-settings"; +import { resolveHotelName } from "@/lib/hotel-name"; export const dynamic = "force-dynamic"; @@ -53,7 +53,7 @@ export default async function ApplyStaffPage({ : null; const userId = Number(session.user.id); - const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom"; + const hotelName = await resolveHotelName(); function formatDeadline(d: Date | null | undefined): string { if (!d) return t("noDeadline"); diff --git a/src/app/(site)/apply/team/page.tsx b/src/app/(site)/apply/team/page.tsx index 790cfa2f9e..907b9b36ac 100644 --- a/src/app/(site)/apply/team/page.tsx +++ b/src/app/(site)/apply/team/page.tsx @@ -5,7 +5,7 @@ import { applyTeam } from "@/actions/applications"; import { ContentCard, EmptyState } from "@/components/public/ui"; import { auth } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; -import { siteSettings } from "@/lib/services/site-settings"; +import { resolveHotelName } from "@/lib/hotel-name"; export const dynamic = "force-dynamic"; @@ -53,7 +53,7 @@ export default async function ApplyTeamPage({ : null; const userId = Number(session.user.id); - const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom"; + const hotelName = await resolveHotelName(); // ── Teams open for application ────────────────────────────── // The Prisma slice exposes teams directly (no separate team-position table diff --git a/src/app/(site)/help/[category]/page.tsx b/src/app/(site)/help/[category]/page.tsx index 8f3128f902..6e7c1a7acb 100644 --- a/src/app/(site)/help/[category]/page.tsx +++ b/src/app/(site)/help/[category]/page.tsx @@ -5,7 +5,7 @@ import { ContentCard } from "@/components/public/ui"; import { prisma } from "@/lib/prisma"; import { sanitize } from "@/lib/sanitize"; import { SanitizedHtml } from "@/components/shared/sanitized-html"; -import { siteSettings } from "@/lib/services/site-settings"; +import { resolveHotelName } from "@/lib/hotel-name"; export const revalidate = 300; @@ -75,7 +75,7 @@ export default async function HelpCategoryPage({ if (!cat) notFound(); - const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom"; + const hotelName = await resolveHotelName(); // Sibling help topics, so the reader can jump between categories. Isolated // query: a DB hiccup degrades this list to empty rather than 500-ing. diff --git a/src/app/(site)/login/page.tsx b/src/app/(site)/login/page.tsx index ce7f041b31..cd7c44e76e 100644 --- a/src/app/(site)/login/page.tsx +++ b/src/app/(site)/login/page.tsx @@ -7,13 +7,14 @@ import { cached } from "@/lib/cache"; import { avatarImageUrl } from "@/lib/format"; import { prisma } from "@/lib/prisma"; import { captchaConfig } from "@/lib/services/captcha"; +import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; export default async function LoginPage() { const t = await getTranslations("pages.login"); const th = await getTranslations("header"); const [hotelName, imagerRaw, cfg] = await Promise.all([ - siteSettings.get("hotel_name", "Atom"), + resolveHotelName(), siteSettings.get( "habbo_imaging_url", "https://www.habbo.com/habbo-imaging/avatarimage", @@ -87,7 +88,7 @@ export default async function LoginPage() { className="text-xs mt-1 mx-auto max-w-[200px] leading-relaxed" style={{ color: "var(--color-text-muted)" }} > - {t("welcomeBackSub", { hotelName: hotelName ?? "Atom" })} + {t("welcomeBackSub", { hotelName })}

diff --git a/src/app/(site)/logo/page.tsx b/src/app/(site)/logo/page.tsx index cda9701ac1..d74f5b5954 100644 --- a/src/app/(site)/logo/page.tsx +++ b/src/app/(site)/logo/page.tsx @@ -1,5 +1,6 @@ import LogoGenerator from "@/components/public/logo-generator"; import { ContentCard } from "@/components/public/ui"; +import { resolveHotelName } from "@/lib/hotel-name"; export const metadata = { title: "Logo generator" }; @@ -9,7 +10,8 @@ export const metadata = { title: "Logo generator" }; * client-side , which does all styling, live preview, and PNG * export in the browser (no server data, no DB). */ -export default function LogoPage() { +export default async function LogoPage() { + const initialText = await resolveHotelName(); return (
- +
); } diff --git a/src/app/(site)/maintenance/page.tsx b/src/app/(site)/maintenance/page.tsx index 118db2b648..c814913148 100644 --- a/src/app/(site)/maintenance/page.tsx +++ b/src/app/(site)/maintenance/page.tsx @@ -1,5 +1,6 @@ import { getTranslations } from "next-intl/server"; import { ContentCard } from "@/components/public/ui"; +import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; export const revalidate = 300; @@ -7,7 +8,7 @@ export const revalidate = 300; export default async function MaintenancePage() { const t = await getTranslations("pages.maintenance"); const [hotel, message] = await Promise.all([ - siteSettings.get("hotel_name", "Atom"), + resolveHotelName(), siteSettings.get( "maintenance_message", "We are currently performing maintenance. Please check back soon.", @@ -18,7 +19,7 @@ export default async function MaintenancePage() {

{message}

diff --git a/src/app/(site)/me/page.tsx b/src/app/(site)/me/page.tsx index 6904b5c187..02e45cf31b 100644 --- a/src/app/(site)/me/page.tsx +++ b/src/app/(site)/me/page.tsx @@ -6,6 +6,7 @@ import { claimReferral } from "@/actions/referral"; import { ContentCard, EmptyState, OnlineBadge } from "@/components/public/ui"; import { auth } from "@/lib/auth"; import { avatarImageUrl } from "@/lib/format"; +import { resolveHotelName } from "@/lib/hotel-name"; import { prisma } from "@/lib/prisma"; import { siteSettings } from "@/lib/services/site-settings"; import CopyReferralButton from "./CopyReferralButton"; @@ -85,7 +86,7 @@ export default async function MePage({ "habbo_imaging_url", "https://www.habbo.com/habbo-imaging/avatarimage", ), - siteSettings.get("hotel_name", "Atom"), + resolveHotelName(), prisma.websiteSetting .findUnique({ where: { key: "referrals_needed" }, @@ -251,7 +252,7 @@ export default async function MePage({ height={22} unoptimized /> - Enter {hotelName ?? "Hotel"} + Enter {hotelName} {/* ── Stat tiles ── */} diff --git a/src/app/(site)/page.tsx b/src/app/(site)/page.tsx index 29f1c3438d..d1fab9823e 100644 --- a/src/app/(site)/page.tsx +++ b/src/app/(site)/page.tsx @@ -6,6 +6,7 @@ import { cached } from "@/lib/cache"; import { avatarImageUrl } from "@/lib/format"; import { formatDate } from "@/lib/format-date"; import { prisma } from "@/lib/prisma"; +import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; import { auth } from "@/lib/auth"; @@ -13,7 +14,7 @@ export const revalidate = 120; async function getHotelData() { const [hotelName, imagerRaw] = await Promise.all([ - siteSettings.get("hotel_name", "Atom"), + resolveHotelName(), siteSettings.get( "habbo_imaging_url", "https://www.habbo.com/habbo-imaging/avatarimage", @@ -103,13 +104,13 @@ export default async function Home() { - {th("online", { count: online, hotel: hotelName ?? "Atom" })} + {th("online", { count: online, hotel: hotelName })}

- {tp("welcome", { hotelName: hotelName ?? "Atom" })} + {tp("welcome", { hotelName })}

- {tp("joinNow", { hotelName: hotelName ?? "Atom" })} + {tp("joinNow", { hotelName })}

{tp("welcomeBody")} diff --git a/src/app/(site)/register/page.tsx b/src/app/(site)/register/page.tsx index ce066d364a..0e42bd2c28 100644 --- a/src/app/(site)/register/page.tsx +++ b/src/app/(site)/register/page.tsx @@ -7,13 +7,14 @@ import { cached } from "@/lib/cache"; import { avatarImageUrl } from "@/lib/format"; import { prisma } from "@/lib/prisma"; import { captchaConfig } from "@/lib/services/captcha"; +import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; export default async function RegisterPage() { const th = await getTranslations("header"); const tpr = await getTranslations("pages.register"); const [hotelName, imagerRaw, cfg] = await Promise.all([ - siteSettings.get("hotel_name", "Hotel"), + resolveHotelName(), siteSettings.get( "habbo_imaging_url", "https://www.habbo.com/habbo-imaging/avatarimage", @@ -167,7 +168,7 @@ export default async function RegisterPage() {

v ?? "Atom"), + resolveHotelName(), ]); return { articles, online, hotelName }; }, ); return apiJson(data); } catch { - return apiJson({ articles: [], online: 0, hotelName: "Atom" }, { status: 200 }); + return apiJson({ articles: [], online: 0, hotelName: FALLBACK_HOTEL_NAME }, { status: 200 }); } } diff --git a/src/app/api/paypal/capture/route.ts b/src/app/api/paypal/capture/route.ts index d541b89142..6e2e247459 100644 --- a/src/app/api/paypal/capture/route.ts +++ b/src/app/api/paypal/capture/route.ts @@ -19,7 +19,7 @@ import { } from "@/lib/services/paypal-topup"; import { rcon } from "@/lib/services/rcon"; import { sendCurrency } from "@/lib/services/send-currency"; -import { siteSettings } from "@/lib/services/site-settings"; +import { resolveHotelName } from "@/lib/hotel-name"; export const dynamic = "force-dynamic"; @@ -158,8 +158,7 @@ export async function POST(req: Request): Promise { ); } - const hotelName = - (await siteSettings.get("hotel_name", env.HOTEL_NAME)) ?? env.HOTEL_NAME; + const hotelName = await resolveHotelName(); if (result.status !== "COMPLETED") { // Record the non-completed attempt so support can trace it. diff --git a/src/app/api/paypal/create/route.ts b/src/app/api/paypal/create/route.ts index 6ac40e26aa..8be20f7a3c 100644 --- a/src/app/api/paypal/create/route.ts +++ b/src/app/api/paypal/create/route.ts @@ -11,7 +11,7 @@ import { PAYPAL_CURRENCY, } from "@/lib/services/paypal"; import { recordCreatedTopup } from "@/lib/services/paypal-topup"; -import { siteSettings } from "@/lib/services/site-settings"; +import { resolveHotelName } from "@/lib/hotel-name"; export const dynamic = "force-dynamic"; @@ -69,8 +69,7 @@ export async function POST(req: Request): Promise { const credits = Math.floor(amount * creditsPerUnit()); const base = env.APP_URL.replace(/\/+$/, ""); - const hotelName = - (await siteSettings.get("hotel_name", env.HOTEL_NAME)) ?? env.HOTEL_NAME; + const hotelName = await resolveHotelName(); try { const order = await createOrder(amount, { diff --git a/src/app/client/page.tsx b/src/app/client/page.tsx index 5028b1fdd6..c84b10afbd 100644 --- a/src/app/client/page.tsx +++ b/src/app/client/page.tsx @@ -4,6 +4,7 @@ import { auth } from "@/lib/auth"; import { issueSsoTicket } from "@/lib/auth/sso-ticket"; import { cached } from "@/lib/cache"; import { prisma } from "@/lib/prisma"; +import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; import { ClientView } from "./client-view"; @@ -16,12 +17,12 @@ export default async function ClientPage() { const userId = Number(session.user.id); const [hotelName, clientUrl] = await Promise.all([ - siteSettings.get("hotel_name", "Atom"), + resolveHotelName(), siteSettings.get("nitro_client_url", ""), ]); const ip = (await headers()).get("x-real-client-ip") ?? "0.0.0.0"; - const ticket = await issueSsoTicket(prisma, userId, hotelName ?? "Atom", ip); + const ticket = await issueSsoTicket(prisma, userId, hotelName, ip); const onlineCount = await cached("online_count", 10_000, () => prisma.user.count({ where: { online: "1" } }), @@ -31,7 +32,7 @@ export default async function ClientPage() { ); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f3aa9eea98..dbccfa813b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -10,6 +10,7 @@ import { PwaRegister } from "@/components/pwa-register"; import { ThemeVars } from "@/components/theme-vars"; import { SmoothScroll } from "@/components/smooth-scroll"; import { enforceSiteAccess } from "@/lib/access-guard"; +import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; import "./globals.css"; @@ -29,7 +30,7 @@ const pixelFont = Pixelify_Sans({ export async function generateMetadata(): Promise { const appUrl = process.env.APP_URL ?? "http://localhost:3000"; - const hotel = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom"; + const hotel = await resolveHotelName(); const customFavicon = await siteSettings.get("cms_favicon"); const faviconUrl = customFavicon ?? "/favicon.svg"; const icons = [ diff --git a/src/app/manifest.ts b/src/app/manifest.ts index b3d26ec398..884d1a8463 100644 --- a/src/app/manifest.ts +++ b/src/app/manifest.ts @@ -1,11 +1,12 @@ import type { MetadataRoute } from "next"; +import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; // Web app manifest — makes the hotel installable as a PWA (AtomCMS exposed PWA // settings but the rewrite ships a real, themeable manifest). Name + theme // colour follow the live website_settings; falls back to defaults with no DB. export default async function manifest(): Promise { - const name = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom"; + const name = await resolveHotelName(); const theme = (await siteSettings.get("color_primary", "#f59e0b")) ?? "#f59e0b"; diff --git a/src/components/home/guest-view.tsx b/src/components/home/guest-view.tsx index 971c560c16..cf9fc3eb76 100644 --- a/src/components/home/guest-view.tsx +++ b/src/components/home/guest-view.tsx @@ -11,7 +11,6 @@ import { siteSettings } from "@/lib/services/site-settings"; export default async function GuestView() { const t = await getTranslations("pages.home"); - const _hotelName = await siteSettings.get("hotel_name", "Atom"); const imager = (await siteSettings.get( "habbo_imaging_url", diff --git a/src/components/home/user-view.tsx b/src/components/home/user-view.tsx index c7b55bc7a5..85dcc7ad7d 100644 --- a/src/components/home/user-view.tsx +++ b/src/components/home/user-view.tsx @@ -3,6 +3,7 @@ import Link from "next/link"; import { getTranslations } from "next-intl/server"; import { Reveal } from "@/components/motion-reveal"; import { avatarImageUrl, excerpt } from "@/lib/format"; +import { resolveHotelName } from "@/lib/hotel-name"; import { prisma } from "@/lib/prisma"; import { siteSettings } from "@/lib/services/site-settings"; @@ -20,7 +21,7 @@ export default async function UserView({ motto, }: UserViewProps) { const t = await getTranslations("pages.home"); - const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom"; + const hotelName = await resolveHotelName(); const imager = (await siteSettings.get( "habbo_imaging_url", diff --git a/src/components/mobile-nav.tsx b/src/components/mobile-nav.tsx index d1a55c2072..de76d8e19d 100644 --- a/src/components/mobile-nav.tsx +++ b/src/components/mobile-nav.tsx @@ -3,6 +3,7 @@ import { AnimatePresence, motion } from "framer-motion"; import Image from "next/image"; import { type ReactNode, useRef, useState } from "react"; +import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; import { mobileMenuVariants } from "@/lib/motion"; interface MobileNavProps { @@ -16,7 +17,7 @@ export function MobileNav({ children, menuLabel = "Open menu", closeLabel = "Close menu", - brandLabel = "Atom", + brandLabel = FALLBACK_HOTEL_NAME, }: MobileNavProps) { const [open, setOpen] = useState(false); const detailsRef = useRef(null); diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx index 6b44aec441..57c3ba4bb2 100644 --- a/src/components/navigation.tsx +++ b/src/components/navigation.tsx @@ -3,6 +3,7 @@ import Link from "next/link"; import { getTranslations } from "next-intl/server"; import type { Session } from "next-auth"; import { LanguageSwitcher } from "@/components/language-switcher"; +import { resolveHotelName } from "@/lib/hotel-name"; import { MobileNav } from "@/components/mobile-nav"; import { NavDropdown } from "@/components/nav-dropdown"; import { NavbarColorPicker } from "@/components/navbar-color-picker"; @@ -10,6 +11,7 @@ import { ThemeSwitcher } from "@/components/theme-switcher"; export async function Navigation({ session }: { session: Session | null }) { const t = await getTranslations("nav"); + const brandLabel = await resolveHotelName(); const isStaff = (session?.user?.rank ?? 0) >= 7; return ( @@ -170,6 +172,7 @@ export async function Navigation({ session }: { session: Session | null }) {
- {t("copyright", { year, hotel: hotelName ?? "Atom" })} + {t("copyright", { year, hotel: hotelName })}
diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx index fd4bef3824..8a07e8b07a 100644 --- a/src/components/site-header.tsx +++ b/src/components/site-header.tsx @@ -3,12 +3,13 @@ import Link from "next/link"; import { getTranslations } from "next-intl/server"; import { cached } from "@/lib/cache"; import { prisma } from "@/lib/prisma"; +import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; export async function SiteHeader() { const t = await getTranslations("header"); const [hotelName, header, logo] = await Promise.all([ - siteSettings.get("hotel_name", "Atom"), + resolveHotelName(), siteSettings.get("cms_header", "/assets/images/background.png"), siteSettings.get("cms_logo", ""), ]); @@ -77,7 +78,7 @@ export async function SiteHeader() { {hotelName - {t("online", { count: online, hotel: hotelName ?? "Atom" })} + {t("online", { count: online, hotel: hotelName })}
diff --git a/src/env.ts b/src/env.ts index 598a3f82ec..c635a8b63b 100644 --- a/src/env.ts +++ b/src/env.ts @@ -1,4 +1,5 @@ import { z } from "zod"; +import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; // Minimal validated env for the foundation. When the Next.js app is added this // will move to @t3-oss/env-nextjs (the habbo-next pattern), but the data layer @@ -15,7 +16,7 @@ const schema = z.object({ .int() .positive() .default(10_000), - HOTEL_NAME: z.string().default("Atom"), + HOTEL_NAME: z.string().default(FALLBACK_HOTEL_NAME), APP_URL: z.string().url().default("http://localhost:3000"), // Resend API key (preferred — simpler HTTP API, always works). RESEND_API_KEY: z.string().optional(), diff --git a/src/lib/brand.ts b/src/lib/brand.ts new file mode 100644 index 0000000000..8c3551beba --- /dev/null +++ b/src/lib/brand.ts @@ -0,0 +1,10 @@ +/** + * Single hardcoded fallback hotel brand. + * Override order at runtime: + * 1. website_settings.hotel_name + * 2. HOTEL_NAME env + * 3. this constant + * + * Safe for client components (no env / DB imports). + */ +export const FALLBACK_HOTEL_NAME = "Atom"; diff --git a/src/lib/hotel-name.ts b/src/lib/hotel-name.ts new file mode 100644 index 0000000000..53d15a97ac --- /dev/null +++ b/src/lib/hotel-name.ts @@ -0,0 +1,26 @@ +import "server-only"; + +import { env } from "@/env"; +import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; +import { siteSettings } from "@/lib/services/site-settings"; + +/** + * Resolve the public hotel name: CMS setting → HOTEL_NAME env → FALLBACK_HOTEL_NAME. + */ +export async function resolveHotelName(): Promise { + const fromSettings = await siteSettings.get("hotel_name", env.HOTEL_NAME); + const trimmed = fromSettings?.trim(); + if (trimmed) return trimmed; + const fromEnv = env.HOTEL_NAME?.trim(); + if (fromEnv) return fromEnv; + return FALLBACK_HOTEL_NAME; +} + +/** Coalesce an already-fetched hotel name string. */ +export function coalesceHotelName(value: string | null | undefined): string { + const trimmed = value?.trim(); + if (trimmed) return trimmed; + const fromEnv = env.HOTEL_NAME?.trim(); + if (fromEnv) return fromEnv; + return FALLBACK_HOTEL_NAME; +} diff --git a/src/lib/services/site-settings.ts b/src/lib/services/site-settings.ts index 1a07311cf0..93722dce92 100644 --- a/src/lib/services/site-settings.ts +++ b/src/lib/services/site-settings.ts @@ -1,10 +1,11 @@ import "server-only"; +import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; import { prisma } from "@/lib/prisma"; import { redis } from "@/lib/redis"; const DEFAULTS: Record = { - hotel_name: "Atom", + hotel_name: FALLBACK_HOTEL_NAME, habbo_imaging_url: "/imaging", logo_url: "", nitro_client_url: "", diff --git a/tsconfig.json b/tsconfig.json index 4e271d297e..b7b565306b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,5 +30,5 @@ ".next/types/**/*.ts", ".next/dev/types/**/*.ts" ], - "exclude": ["node_modules"] + "exclude": ["node_modules", "e2e", "playwright.config.ts"] }