import { desc, eq } from "drizzle-orm"; import type { Metadata } from "next"; import { headers } from "next/headers"; import Image from "next/image"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { AuthPageFrame, AuthUsersCards, } from "@/components/auth/auth-page-frame"; import { LoginForm } from "@/components/auth/login-form"; import { SurfaceCard } from "@/components/surface-card"; import { auth } from "@/lib/auth"; import { safeRedirectPath } from "@/lib/auth/safe-redirect"; import { cached } from "@/lib/cache"; import { db, User } from "@/lib/db"; import { resolveHotelName } from "@/lib/hotel-name"; import { captchaConfig } from "@/lib/services/captcha"; import { cachedOnlineCount } from "@/lib/services/public-counters"; import { siteSettings } from "@/lib/services/site-settings"; export async function generateMetadata(): Promise { const t = await getTranslations("pages.login"); const title = t("title"); const description = t("subtitle"); return { title, description, // Sign-in is a dead end for crawlers and duplicates the homepage copy. robots: { index: false, follow: false }, openGraph: { title, description, type: "website" }, }; } export default async function LoginPage({ searchParams, }: { searchParams: Promise<{ from?: string; registered?: string; reset?: string; }>; }) { const t = await getTranslations("pages.login"); const [hotelName, cfg, logo] = await Promise.all([ resolveHotelName(), captchaConfig(), siteSettings.get("cms_logo", ""), ]); const nonce = (await headers()).get("x-nonce") ?? undefined; const sp = await searchParams; const redirectTo = safeRedirectPath(sp.from); // Already signed in: the form has nothing to do here. Honour `from` first so // an admin bounced off /admin lands back where they were heading. const session = await auth(); if (session?.user?.id) redirect(redirectTo); const [online, recentUsers, latestUsers] = await Promise.all([ cachedOnlineCount().catch(() => 0), cached( "auth_online_users", 10_000, () => db .select({ id: User.id, username: User.username, look: User.look }) .from(User) .where(eq(User.online, "1")) .limit(8), { staleMs: 30000 }, ).catch(() => []), cached( "auth_latest_users", 30_000, () => db .select({ id: User.id, username: User.username, look: User.look }) .from(User) .orderBy(desc(User.accountCreated)) .limit(8), { staleMs: 60000 }, ).catch(() => []), ]); // `/login?registered=1` is where the sign-up form lands when it could not // auto sign-in (e-mail verification still pending). Without this notice the // visitor would only see an empty login form and no sign their account // exists. const notice = sp.registered === "1" ? (

{t("registeredSuccess")}

) : sp.reset === "1" ? ( // `?reset=1` comes from a successful password reset; saying so matters // because the visitor just changed their password and a silent form // reads like the reset failed.

{t("passwordChanged")}

) : undefined; return ( } >