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 <[email protected]>
This commit is contained in:
1 parent
6b2819aa20
commit
e00e9ca2dc
31 files changed
+113
-56
No files matched your search
@@ -3,8 +3,8 @@
|
|||||||
import { createHmac, timingSafeEqual } from "node:crypto";
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { env } from "@/env";
|
import { env } from "@/env";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { sendMail } from "@/lib/services/email";
|
import { sendMail } from "@/lib/services/email";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
|
||||||
|
|
||||||
// Stateless email verification with a time-limited HMAC token.
|
// Stateless email verification with a time-limited HMAC token.
|
||||||
//
|
//
|
||||||
@@ -78,8 +78,7 @@ export async function sendVerification(email: string): Promise<boolean> {
|
|||||||
const base = env.APP_URL.replace(/\/+$/, "");
|
const base = env.APP_URL.replace(/\/+$/, "");
|
||||||
const link = `${base}/verify?token=${encodeURIComponent(token)}&email=${encodeURIComponent(normalised)}`;
|
const link = `${base}/verify?token=${encodeURIComponent(token)}&email=${encodeURIComponent(normalised)}`;
|
||||||
|
|
||||||
const hotelName =
|
const hotelName = await resolveHotelName();
|
||||||
(await siteSettings.get("hotel_name", env.HOTEL_NAME)) ?? env.HOTEL_NAME;
|
|
||||||
|
|
||||||
let subject = `Verify your email · ${hotelName}`;
|
let subject = `Verify your email · ${hotelName}`;
|
||||||
let heading = "Verify your email";
|
let heading = "Verify your email";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { applyStaff } from "@/actions/applications";
|
|||||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||||
import { auth } from "@/lib/auth";
|
import { auth } from "@/lib/auth";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ export default async function ApplyStaffPage({
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
const userId = Number(session.user.id);
|
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 {
|
function formatDeadline(d: Date | null | undefined): string {
|
||||||
if (!d) return t("noDeadline");
|
if (!d) return t("noDeadline");
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { applyTeam } from "@/actions/applications";
|
|||||||
import { ContentCard, EmptyState } from "@/components/public/ui";
|
import { ContentCard, EmptyState } from "@/components/public/ui";
|
||||||
import { auth } from "@/lib/auth";
|
import { auth } from "@/lib/auth";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ export default async function ApplyTeamPage({
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
const userId = Number(session.user.id);
|
const userId = Number(session.user.id);
|
||||||
const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom";
|
const hotelName = await resolveHotelName();
|
||||||
|
|
||||||
// ── Teams open for application ──────────────────────────────
|
// ── Teams open for application ──────────────────────────────
|
||||||
// The Prisma slice exposes teams directly (no separate team-position table
|
// The Prisma slice exposes teams directly (no separate team-position table
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ContentCard } from "@/components/public/ui";
|
|||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { sanitize } from "@/lib/sanitize";
|
import { sanitize } from "@/lib/sanitize";
|
||||||
import { SanitizedHtml } from "@/components/shared/sanitized-html";
|
import { SanitizedHtml } from "@/components/shared/sanitized-html";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
|
|
||||||
export const revalidate = 300;
|
export const revalidate = 300;
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ export default async function HelpCategoryPage({
|
|||||||
|
|
||||||
if (!cat) notFound();
|
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
|
// Sibling help topics, so the reader can jump between categories. Isolated
|
||||||
// query: a DB hiccup degrades this list to empty rather than 500-ing.
|
// query: a DB hiccup degrades this list to empty rather than 500-ing.
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import { cached } from "@/lib/cache";
|
|||||||
import { avatarImageUrl } from "@/lib/format";
|
import { avatarImageUrl } from "@/lib/format";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { captchaConfig } from "@/lib/services/captcha";
|
import { captchaConfig } from "@/lib/services/captcha";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
|
|
||||||
export default async function LoginPage() {
|
export default async function LoginPage() {
|
||||||
const t = await getTranslations("pages.login");
|
const t = await getTranslations("pages.login");
|
||||||
const th = await getTranslations("header");
|
const th = await getTranslations("header");
|
||||||
const [hotelName, imagerRaw, cfg] = await Promise.all([
|
const [hotelName, imagerRaw, cfg] = await Promise.all([
|
||||||
siteSettings.get("hotel_name", "Atom"),
|
resolveHotelName(),
|
||||||
siteSettings.get(
|
siteSettings.get(
|
||||||
"habbo_imaging_url",
|
"habbo_imaging_url",
|
||||||
"https://www.habbo.com/habbo-imaging/avatarimage",
|
"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"
|
className="text-xs mt-1 mx-auto max-w-[200px] leading-relaxed"
|
||||||
style={{ color: "var(--color-text-muted)" }}
|
style={{ color: "var(--color-text-muted)" }}
|
||||||
>
|
>
|
||||||
{t("welcomeBackSub", { hotelName: hotelName ?? "Atom" })}
|
{t("welcomeBackSub", { hotelName })}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import LogoGenerator from "@/components/public/logo-generator";
|
import LogoGenerator from "@/components/public/logo-generator";
|
||||||
import { ContentCard } from "@/components/public/ui";
|
import { ContentCard } from "@/components/public/ui";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
|
|
||||||
export const metadata = { title: "Logo generator" };
|
export const metadata = { title: "Logo generator" };
|
||||||
|
|
||||||
@@ -9,7 +10,8 @@ export const metadata = { title: "Logo generator" };
|
|||||||
* client-side <LogoGenerator>, which does all styling, live preview, and PNG
|
* client-side <LogoGenerator>, which does all styling, live preview, and PNG
|
||||||
* export in the browser (no server data, no DB).
|
* export in the browser (no server data, no DB).
|
||||||
*/
|
*/
|
||||||
export default function LogoPage() {
|
export default async function LogoPage() {
|
||||||
|
const initialText = await resolveHotelName();
|
||||||
return (
|
return (
|
||||||
<main
|
<main
|
||||||
style={{
|
style={{
|
||||||
@@ -25,7 +27,7 @@ export default function LogoPage() {
|
|||||||
subtitle="Design a logo for your hotel — pick a font, colours and size, then download it as a PNG."
|
subtitle="Design a logo for your hotel — pick a font, colours and size, then download it as a PNG."
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<LogoGenerator />
|
<LogoGenerator initialText={initialText} />
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { ContentCard } from "@/components/public/ui";
|
import { ContentCard } from "@/components/public/ui";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
|
|
||||||
export const revalidate = 300;
|
export const revalidate = 300;
|
||||||
@@ -7,7 +8,7 @@ export const revalidate = 300;
|
|||||||
export default async function MaintenancePage() {
|
export default async function MaintenancePage() {
|
||||||
const t = await getTranslations("pages.maintenance");
|
const t = await getTranslations("pages.maintenance");
|
||||||
const [hotel, message] = await Promise.all([
|
const [hotel, message] = await Promise.all([
|
||||||
siteSettings.get("hotel_name", "Atom"),
|
resolveHotelName(),
|
||||||
siteSettings.get(
|
siteSettings.get(
|
||||||
"maintenance_message",
|
"maintenance_message",
|
||||||
"We are currently performing maintenance. Please check back soon.",
|
"We are currently performing maintenance. Please check back soon.",
|
||||||
@@ -18,7 +19,7 @@ export default async function MaintenancePage() {
|
|||||||
<main style={{ maxWidth: 560, margin: "2rem auto" }}>
|
<main style={{ maxWidth: 560, margin: "2rem auto" }}>
|
||||||
<ContentCard
|
<ContentCard
|
||||||
icon="🛠️"
|
icon="🛠️"
|
||||||
title={t("title", { hotel: hotel ?? "Atom" })}
|
title={t("title", { hotel })}
|
||||||
subtitle={t("subtitle")}
|
subtitle={t("subtitle")}
|
||||||
>
|
>
|
||||||
<p style={{ marginTop: 0 }}>{message}</p>
|
<p style={{ marginTop: 0 }}>{message}</p>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { claimReferral } from "@/actions/referral";
|
|||||||
import { ContentCard, EmptyState, OnlineBadge } from "@/components/public/ui";
|
import { ContentCard, EmptyState, OnlineBadge } from "@/components/public/ui";
|
||||||
import { auth } from "@/lib/auth";
|
import { auth } from "@/lib/auth";
|
||||||
import { avatarImageUrl } from "@/lib/format";
|
import { avatarImageUrl } from "@/lib/format";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
import CopyReferralButton from "./CopyReferralButton";
|
import CopyReferralButton from "./CopyReferralButton";
|
||||||
@@ -85,7 +86,7 @@ export default async function MePage({
|
|||||||
"habbo_imaging_url",
|
"habbo_imaging_url",
|
||||||
"https://www.habbo.com/habbo-imaging/avatarimage",
|
"https://www.habbo.com/habbo-imaging/avatarimage",
|
||||||
),
|
),
|
||||||
siteSettings.get("hotel_name", "Atom"),
|
resolveHotelName(),
|
||||||
prisma.websiteSetting
|
prisma.websiteSetting
|
||||||
.findUnique({
|
.findUnique({
|
||||||
where: { key: "referrals_needed" },
|
where: { key: "referrals_needed" },
|
||||||
@@ -251,7 +252,7 @@ export default async function MePage({
|
|||||||
height={22}
|
height={22}
|
||||||
unoptimized
|
unoptimized
|
||||||
/>
|
/>
|
||||||
Enter {hotelName ?? "Hotel"}
|
Enter {hotelName}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* ── Stat tiles ── */}
|
{/* ── Stat tiles ── */}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { cached } from "@/lib/cache";
|
|||||||
import { avatarImageUrl } from "@/lib/format";
|
import { avatarImageUrl } from "@/lib/format";
|
||||||
import { formatDate } from "@/lib/format-date";
|
import { formatDate } from "@/lib/format-date";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
import { auth } from "@/lib/auth";
|
import { auth } from "@/lib/auth";
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ export const revalidate = 120;
|
|||||||
|
|
||||||
async function getHotelData() {
|
async function getHotelData() {
|
||||||
const [hotelName, imagerRaw] = await Promise.all([
|
const [hotelName, imagerRaw] = await Promise.all([
|
||||||
siteSettings.get("hotel_name", "Atom"),
|
resolveHotelName(),
|
||||||
siteSettings.get(
|
siteSettings.get(
|
||||||
"habbo_imaging_url",
|
"habbo_imaging_url",
|
||||||
"https://www.habbo.com/habbo-imaging/avatarimage",
|
"https://www.habbo.com/habbo-imaging/avatarimage",
|
||||||
@@ -103,13 +104,13 @@ export default async function Home() {
|
|||||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
|
||||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-green-500" />
|
<span className="relative inline-flex rounded-full h-2 w-2 bg-green-500" />
|
||||||
</span>
|
</span>
|
||||||
{th("online", { count: online, hotel: hotelName ?? "Atom" })}
|
{th("online", { count: online, hotel: hotelName })}
|
||||||
</div>
|
</div>
|
||||||
<h1
|
<h1
|
||||||
className="text-4xl md:text-5xl lg:text-6xl font-black leading-[1.05] tracking-tight mb-4"
|
className="text-4xl md:text-5xl lg:text-6xl font-black leading-[1.05] tracking-tight mb-4"
|
||||||
style={{ color: "var(--color-text-readable)" }}
|
style={{ color: "var(--color-text-readable)" }}
|
||||||
>
|
>
|
||||||
{tp("welcome", { hotelName: hotelName ?? "Atom" })}
|
{tp("welcome", { hotelName })}
|
||||||
</h1>
|
</h1>
|
||||||
<p
|
<p
|
||||||
className="text-base md:text-lg leading-relaxed max-w-xl mb-8"
|
className="text-base md:text-lg leading-relaxed max-w-xl mb-8"
|
||||||
@@ -317,7 +318,7 @@ export default async function Home() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h2 className="text-2xl md:text-3xl font-black tracking-tight mb-2" style={{ color: "var(--color-text-readable)" }}>
|
<h2 className="text-2xl md:text-3xl font-black tracking-tight mb-2" style={{ color: "var(--color-text-readable)" }}>
|
||||||
{tp("joinNow", { hotelName: hotelName ?? "Atom" })}
|
{tp("joinNow", { hotelName })}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm mb-6 max-w-sm mx-auto" style={{ color: "var(--color-text-muted)" }}>
|
<p className="text-sm mb-6 max-w-sm mx-auto" style={{ color: "var(--color-text-muted)" }}>
|
||||||
{tp("welcomeBody")}
|
{tp("welcomeBody")}
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import { cached } from "@/lib/cache";
|
|||||||
import { avatarImageUrl } from "@/lib/format";
|
import { avatarImageUrl } from "@/lib/format";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { captchaConfig } from "@/lib/services/captcha";
|
import { captchaConfig } from "@/lib/services/captcha";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
|
|
||||||
export default async function RegisterPage() {
|
export default async function RegisterPage() {
|
||||||
const th = await getTranslations("header");
|
const th = await getTranslations("header");
|
||||||
const tpr = await getTranslations("pages.register");
|
const tpr = await getTranslations("pages.register");
|
||||||
const [hotelName, imagerRaw, cfg] = await Promise.all([
|
const [hotelName, imagerRaw, cfg] = await Promise.all([
|
||||||
siteSettings.get("hotel_name", "Hotel"),
|
resolveHotelName(),
|
||||||
siteSettings.get(
|
siteSettings.get(
|
||||||
"habbo_imaging_url",
|
"habbo_imaging_url",
|
||||||
"https://www.habbo.com/habbo-imaging/avatarimage",
|
"https://www.habbo.com/habbo-imaging/avatarimage",
|
||||||
@@ -167,7 +168,7 @@ export default async function RegisterPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<RegisterForm
|
<RegisterForm
|
||||||
hotelName={hotelName ?? "Hotel"}
|
hotelName={hotelName}
|
||||||
captcha={{
|
captcha={{
|
||||||
provider: cfg.provider,
|
provider: cfg.provider,
|
||||||
siteKey: cfg.siteKey || undefined,
|
siteKey: cfg.siteKey || undefined,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { auth } from "@/lib/auth";
|
|||||||
import { LaravelEncrypter } from "@/lib/auth/laravel-encrypter";
|
import { LaravelEncrypter } from "@/lib/auth/laravel-encrypter";
|
||||||
import { totpKeyUri } from "@/lib/auth/totp";
|
import { totpKeyUri } from "@/lib/auth/totp";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ export default async function TwoFactorPage({
|
|||||||
const hasAppKey = Boolean(env.APP_KEY);
|
const hasAppKey = Boolean(env.APP_KEY);
|
||||||
const enabled = Boolean(user?.twoFactorConfirmedAt);
|
const enabled = Boolean(user?.twoFactorConfirmedAt);
|
||||||
const pending = Boolean(user?.twoFactorSecret && !user?.twoFactorConfirmedAt);
|
const pending = Boolean(user?.twoFactorSecret && !user?.twoFactorConfirmedAt);
|
||||||
const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom";
|
const hotelName = await resolveHotelName();
|
||||||
|
|
||||||
let secret = "";
|
let secret = "";
|
||||||
let uri = "";
|
let uri = "";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { StatusCard } from "@/components/admin/dashboard";
|
import { StatusCard } from "@/components/admin/dashboard";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
import { EmbedSnippet } from "./embed-snippet";
|
import { EmbedSnippet } from "./embed-snippet";
|
||||||
|
|
||||||
@@ -18,8 +19,7 @@ export default async function AdminRadioEmbedPage() {
|
|||||||
streamUrl = (await siteSettings.get("radio_stream_url", "")) ?? "";
|
streamUrl = (await siteSettings.get("radio_stream_url", "")) ?? "";
|
||||||
radioName =
|
radioName =
|
||||||
(await siteSettings.get("radio_name", null)) ??
|
(await siteSettings.get("radio_name", null)) ??
|
||||||
(await siteSettings.get("hotel_name", "Radio")) ??
|
(await resolveHotelName());
|
||||||
"Radio";
|
|
||||||
nowPlayingApiUrl =
|
nowPlayingApiUrl =
|
||||||
(await siteSettings.get("radio_now_playing_api_url", "")) ?? "";
|
(await siteSettings.get("radio_now_playing_api_url", "")) ?? "";
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { HABBO_GAMEDATA_HOTELS } from "@/lib/habbo-gamedata-hotel";
|
import { HABBO_GAMEDATA_HOTELS } from "@/lib/habbo-gamedata-hotel";
|
||||||
|
import { FALLBACK_HOTEL_NAME } from "@/lib/brand";
|
||||||
|
|
||||||
export type FieldType =
|
export type FieldType =
|
||||||
| "text"
|
| "text"
|
||||||
@@ -49,7 +50,7 @@ export const SETTINGS_GROUPS: SettingsGroup[] = [
|
|||||||
label: "Hotel name",
|
label: "Hotel name",
|
||||||
type: "text",
|
type: "text",
|
||||||
placeholder: "Epicnabbo",
|
placeholder: "Epicnabbo",
|
||||||
defaultValue: "Atom",
|
defaultValue: FALLBACK_HOTEL_NAME,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "cms_logo",
|
key: "cms_logo",
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import { FALLBACK_HOTEL_NAME } from "@/lib/brand";
|
||||||
import { apiJson } from "@/lib/api";
|
import { apiJson } from "@/lib/api";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { redisCache, apiCacheKey } from "@/lib/redis-cache";
|
import { redisCache, apiCacheKey } from "@/lib/redis-cache";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -30,13 +31,13 @@ export async function GET(_req: Request) {
|
|||||||
take: 4,
|
take: 4,
|
||||||
}),
|
}),
|
||||||
prisma.user.count({ where: { online: "1" } }),
|
prisma.user.count({ where: { online: "1" } }),
|
||||||
siteSettings.get("hotel_name", "Atom").then((v) => v ?? "Atom"),
|
resolveHotelName(),
|
||||||
]);
|
]);
|
||||||
return { articles, online, hotelName };
|
return { articles, online, hotelName };
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return apiJson(data);
|
return apiJson(data);
|
||||||
} catch {
|
} catch {
|
||||||
return apiJson({ articles: [], online: 0, hotelName: "Atom" }, { status: 200 });
|
return apiJson({ articles: [], online: 0, hotelName: FALLBACK_HOTEL_NAME }, { status: 200 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
} from "@/lib/services/paypal-topup";
|
} from "@/lib/services/paypal-topup";
|
||||||
import { rcon } from "@/lib/services/rcon";
|
import { rcon } from "@/lib/services/rcon";
|
||||||
import { sendCurrency } from "@/lib/services/send-currency";
|
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";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -158,8 +158,7 @@ export async function POST(req: Request): Promise<Response> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hotelName =
|
const hotelName = await resolveHotelName();
|
||||||
(await siteSettings.get("hotel_name", env.HOTEL_NAME)) ?? env.HOTEL_NAME;
|
|
||||||
|
|
||||||
if (result.status !== "COMPLETED") {
|
if (result.status !== "COMPLETED") {
|
||||||
// Record the non-completed attempt so support can trace it.
|
// Record the non-completed attempt so support can trace it.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
PAYPAL_CURRENCY,
|
PAYPAL_CURRENCY,
|
||||||
} from "@/lib/services/paypal";
|
} from "@/lib/services/paypal";
|
||||||
import { recordCreatedTopup } from "@/lib/services/paypal-topup";
|
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";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -69,8 +69,7 @@ export async function POST(req: Request): Promise<Response> {
|
|||||||
|
|
||||||
const credits = Math.floor(amount * creditsPerUnit());
|
const credits = Math.floor(amount * creditsPerUnit());
|
||||||
const base = env.APP_URL.replace(/\/+$/, "");
|
const base = env.APP_URL.replace(/\/+$/, "");
|
||||||
const hotelName =
|
const hotelName = await resolveHotelName();
|
||||||
(await siteSettings.get("hotel_name", env.HOTEL_NAME)) ?? env.HOTEL_NAME;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const order = await createOrder(amount, {
|
const order = await createOrder(amount, {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { auth } from "@/lib/auth";
|
|||||||
import { issueSsoTicket } from "@/lib/auth/sso-ticket";
|
import { issueSsoTicket } from "@/lib/auth/sso-ticket";
|
||||||
import { cached } from "@/lib/cache";
|
import { cached } from "@/lib/cache";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
import { ClientView } from "./client-view";
|
import { ClientView } from "./client-view";
|
||||||
|
|
||||||
@@ -16,12 +17,12 @@ export default async function ClientPage() {
|
|||||||
const userId = Number(session.user.id);
|
const userId = Number(session.user.id);
|
||||||
|
|
||||||
const [hotelName, clientUrl] = await Promise.all([
|
const [hotelName, clientUrl] = await Promise.all([
|
||||||
siteSettings.get("hotel_name", "Atom"),
|
resolveHotelName(),
|
||||||
siteSettings.get("nitro_client_url", ""),
|
siteSettings.get("nitro_client_url", ""),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const ip = (await headers()).get("x-real-client-ip") ?? "0.0.0.0";
|
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, () =>
|
const onlineCount = await cached("online_count", 10_000, () =>
|
||||||
prisma.user.count({ where: { online: "1" } }),
|
prisma.user.count({ where: { online: "1" } }),
|
||||||
@@ -31,7 +32,7 @@ export default async function ClientPage() {
|
|||||||
<ClientView
|
<ClientView
|
||||||
ticket={ticket}
|
ticket={ticket}
|
||||||
clientUrl={clientUrl || "/nitro-client/"}
|
clientUrl={clientUrl || "/nitro-client/"}
|
||||||
hotelName={hotelName ?? "Atom"}
|
hotelName={hotelName}
|
||||||
initialOnline={onlineCount}
|
initialOnline={onlineCount}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
+2
-1
@@ -10,6 +10,7 @@ import { PwaRegister } from "@/components/pwa-register";
|
|||||||
import { ThemeVars } from "@/components/theme-vars";
|
import { ThemeVars } from "@/components/theme-vars";
|
||||||
import { SmoothScroll } from "@/components/smooth-scroll";
|
import { SmoothScroll } from "@/components/smooth-scroll";
|
||||||
import { enforceSiteAccess } from "@/lib/access-guard";
|
import { enforceSiteAccess } from "@/lib/access-guard";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ const pixelFont = Pixelify_Sans({
|
|||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const appUrl = process.env.APP_URL ?? "http://localhost:3000";
|
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 customFavicon = await siteSettings.get("cms_favicon");
|
||||||
const faviconUrl = customFavicon ?? "/favicon.svg";
|
const faviconUrl = customFavicon ?? "/favicon.svg";
|
||||||
const icons = [
|
const icons = [
|
||||||
|
|||||||
+2
-1
@@ -1,11 +1,12 @@
|
|||||||
import type { MetadataRoute } from "next";
|
import type { MetadataRoute } from "next";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
|
|
||||||
// Web app manifest — makes the hotel installable as a PWA (AtomCMS exposed PWA
|
// Web app manifest — makes the hotel installable as a PWA (AtomCMS exposed PWA
|
||||||
// settings but the rewrite ships a real, themeable manifest). Name + theme
|
// settings but the rewrite ships a real, themeable manifest). Name + theme
|
||||||
// colour follow the live website_settings; falls back to defaults with no DB.
|
// colour follow the live website_settings; falls back to defaults with no DB.
|
||||||
export default async function manifest(): Promise<MetadataRoute.Manifest> {
|
export default async function manifest(): Promise<MetadataRoute.Manifest> {
|
||||||
const name = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom";
|
const name = await resolveHotelName();
|
||||||
const theme =
|
const theme =
|
||||||
(await siteSettings.get("color_primary", "#f59e0b")) ?? "#f59e0b";
|
(await siteSettings.get("color_primary", "#f59e0b")) ?? "#f59e0b";
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { siteSettings } from "@/lib/services/site-settings";
|
|||||||
|
|
||||||
export default async function GuestView() {
|
export default async function GuestView() {
|
||||||
const t = await getTranslations("pages.home");
|
const t = await getTranslations("pages.home");
|
||||||
const _hotelName = await siteSettings.get("hotel_name", "Atom");
|
|
||||||
const imager =
|
const imager =
|
||||||
(await siteSettings.get(
|
(await siteSettings.get(
|
||||||
"habbo_imaging_url",
|
"habbo_imaging_url",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Link from "next/link";
|
|||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { Reveal } from "@/components/motion-reveal";
|
import { Reveal } from "@/components/motion-reveal";
|
||||||
import { avatarImageUrl, excerpt } from "@/lib/format";
|
import { avatarImageUrl, excerpt } from "@/lib/format";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ export default async function UserView({
|
|||||||
motto,
|
motto,
|
||||||
}: UserViewProps) {
|
}: UserViewProps) {
|
||||||
const t = await getTranslations("pages.home");
|
const t = await getTranslations("pages.home");
|
||||||
const hotelName = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom";
|
const hotelName = await resolveHotelName();
|
||||||
const imager =
|
const imager =
|
||||||
(await siteSettings.get(
|
(await siteSettings.get(
|
||||||
"habbo_imaging_url",
|
"habbo_imaging_url",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { AnimatePresence, motion } from "framer-motion";
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { type ReactNode, useRef, useState } from "react";
|
import { type ReactNode, useRef, useState } from "react";
|
||||||
|
import { FALLBACK_HOTEL_NAME } from "@/lib/brand";
|
||||||
import { mobileMenuVariants } from "@/lib/motion";
|
import { mobileMenuVariants } from "@/lib/motion";
|
||||||
|
|
||||||
interface MobileNavProps {
|
interface MobileNavProps {
|
||||||
@@ -16,7 +17,7 @@ export function MobileNav({
|
|||||||
children,
|
children,
|
||||||
menuLabel = "Open menu",
|
menuLabel = "Open menu",
|
||||||
closeLabel = "Close menu",
|
closeLabel = "Close menu",
|
||||||
brandLabel = "Atom",
|
brandLabel = FALLBACK_HOTEL_NAME,
|
||||||
}: MobileNavProps) {
|
}: MobileNavProps) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const detailsRef = useRef<HTMLDivElement>(null);
|
const detailsRef = useRef<HTMLDivElement>(null);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Link from "next/link";
|
|||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import type { Session } from "next-auth";
|
import type { Session } from "next-auth";
|
||||||
import { LanguageSwitcher } from "@/components/language-switcher";
|
import { LanguageSwitcher } from "@/components/language-switcher";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { MobileNav } from "@/components/mobile-nav";
|
import { MobileNav } from "@/components/mobile-nav";
|
||||||
import { NavDropdown } from "@/components/nav-dropdown";
|
import { NavDropdown } from "@/components/nav-dropdown";
|
||||||
import { NavbarColorPicker } from "@/components/navbar-color-picker";
|
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 }) {
|
export async function Navigation({ session }: { session: Session | null }) {
|
||||||
const t = await getTranslations("nav");
|
const t = await getTranslations("nav");
|
||||||
|
const brandLabel = await resolveHotelName();
|
||||||
const isStaff = (session?.user?.rank ?? 0) >= 7;
|
const isStaff = (session?.user?.rank ?? 0) >= 7;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -170,6 +172,7 @@ export async function Navigation({ session }: { session: Session | null }) {
|
|||||||
<MobileNav
|
<MobileNav
|
||||||
menuLabel={t("openMenu") || "Open menu"}
|
menuLabel={t("openMenu") || "Open menu"}
|
||||||
closeLabel={t("closeMenu") || "Close menu"}
|
closeLabel={t("closeMenu") || "Close menu"}
|
||||||
|
brandLabel={brandLabel}
|
||||||
>
|
>
|
||||||
<Link href="/" className="nav-item">
|
<Link href="/" className="nav-item">
|
||||||
<Image
|
<Image
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
useTransition,
|
useTransition,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { saveLogo } from "@/actions/save-logo";
|
import { saveLogo } from "@/actions/save-logo";
|
||||||
|
import { FALLBACK_HOTEL_NAME } from "@/lib/brand";
|
||||||
import { HABBO_FONT_GROUPS } from "@/components/public/habbo-fonts";
|
import { HABBO_FONT_GROUPS } from "@/components/public/habbo-fonts";
|
||||||
import {
|
import {
|
||||||
getFontInfo,
|
getFontInfo,
|
||||||
@@ -17,8 +18,12 @@ import {
|
|||||||
} from "@/components/public/sprite-font";
|
} from "@/components/public/sprite-font";
|
||||||
import { ContentCard } from "@/components/public/ui";
|
import { ContentCard } from "@/components/public/ui";
|
||||||
|
|
||||||
export default function LogoGenerator() {
|
export default function LogoGenerator({
|
||||||
const [text, setText] = useState("Atom");
|
initialText = FALLBACK_HOTEL_NAME,
|
||||||
|
}: {
|
||||||
|
initialText?: string;
|
||||||
|
}) {
|
||||||
|
const [text, setText] = useState(initialText);
|
||||||
const [styleName, setStyleName] = useState("habbo");
|
const [styleName, setStyleName] = useState("habbo");
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [saveStatus, setSaveStatus] = useState<
|
const [saveStatus, setSaveStatus] = useState<
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { CmsInfoPopup } from "@/components/cms-info-popup";
|
import { CmsInfoPopup } from "@/components/cms-info-popup";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
|
|
||||||
export async function SiteFooter() {
|
export async function SiteFooter() {
|
||||||
const hotelName = await siteSettings.get("hotel_name", "Atom");
|
const hotelName = await resolveHotelName();
|
||||||
const year = new Date().getFullYear();
|
const year = new Date().getFullYear();
|
||||||
const t = await getTranslations("footer");
|
const t = await getTranslations("footer");
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ export async function SiteFooter() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="md:font-semibold text-[12px] md:text-[14px]">
|
<div className="md:font-semibold text-[12px] md:text-[14px]">
|
||||||
{t("copyright", { year, hotel: hotelName ?? "Atom" })}
|
{t("copyright", { year, hotel: hotelName })}
|
||||||
</div>
|
</div>
|
||||||
<CmsInfoPopup />
|
<CmsInfoPopup />
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ import Link from "next/link";
|
|||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { cached } from "@/lib/cache";
|
import { cached } from "@/lib/cache";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
|
import { resolveHotelName } from "@/lib/hotel-name";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
|
|
||||||
export async function SiteHeader() {
|
export async function SiteHeader() {
|
||||||
const t = await getTranslations("header");
|
const t = await getTranslations("header");
|
||||||
const [hotelName, header, logo] = await Promise.all([
|
const [hotelName, header, logo] = await Promise.all([
|
||||||
siteSettings.get("hotel_name", "Atom"),
|
resolveHotelName(),
|
||||||
siteSettings.get("cms_header", "/assets/images/background.png"),
|
siteSettings.get("cms_header", "/assets/images/background.png"),
|
||||||
siteSettings.get("cms_logo", ""),
|
siteSettings.get("cms_logo", ""),
|
||||||
]);
|
]);
|
||||||
@@ -77,7 +78,7 @@ export async function SiteHeader() {
|
|||||||
<Image
|
<Image
|
||||||
className="drop-shadow-2xl block"
|
className="drop-shadow-2xl block"
|
||||||
src={logo}
|
src={logo}
|
||||||
alt={hotelName ?? "Hotel"}
|
alt={hotelName}
|
||||||
width={200}
|
width={200}
|
||||||
height={120}
|
height={120}
|
||||||
style={{ maxHeight: 120, width: "auto", height: "auto" }}
|
style={{ maxHeight: 120, width: "auto", height: "auto" }}
|
||||||
@@ -130,7 +131,7 @@ export async function SiteHeader() {
|
|||||||
className="text-sm font-bold tracking-wide"
|
className="text-sm font-bold tracking-wide"
|
||||||
style={{ color: "rgba(255,255,255,0.9)" }}
|
style={{ color: "rgba(255,255,255,0.9)" }}
|
||||||
>
|
>
|
||||||
{t("online", { count: online, hotel: hotelName ?? "Atom" })}
|
{t("online", { count: online, hotel: hotelName })}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
import { z } from "zod";
|
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
|
// 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
|
// will move to @t3-oss/env-nextjs (the habbo-next pattern), but the data layer
|
||||||
@@ -15,7 +16,7 @@ const schema = z.object({
|
|||||||
.int()
|
.int()
|
||||||
.positive()
|
.positive()
|
||||||
.default(10_000),
|
.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"),
|
APP_URL: z.string().url().default("http://localhost:3000"),
|
||||||
// Resend API key (preferred — simpler HTTP API, always works).
|
// Resend API key (preferred — simpler HTTP API, always works).
|
||||||
RESEND_API_KEY: z.string().optional(),
|
RESEND_API_KEY: z.string().optional(),
|
||||||
|
|||||||
@@ -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";
|
||||||
@@ -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<string> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import "server-only";
|
import "server-only";
|
||||||
|
|
||||||
|
import { FALLBACK_HOTEL_NAME } from "@/lib/brand";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { redis } from "@/lib/redis";
|
import { redis } from "@/lib/redis";
|
||||||
|
|
||||||
const DEFAULTS: Record<string, string> = {
|
const DEFAULTS: Record<string, string> = {
|
||||||
hotel_name: "Atom",
|
hotel_name: FALLBACK_HOTEL_NAME,
|
||||||
habbo_imaging_url: "/imaging",
|
habbo_imaging_url: "/imaging",
|
||||||
logo_url: "",
|
logo_url: "",
|
||||||
nitro_client_url: "",
|
nitro_client_url: "",
|
||||||
|
|||||||
+1
-1
@@ -30,5 +30,5 @@
|
|||||||
".next/types/**/*.ts",
|
".next/types/**/*.ts",
|
||||||
".next/dev/types/**/*.ts"
|
".next/dev/types/**/*.ts"
|
||||||
],
|
],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules", "e2e", "playwright.config.ts"]
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user