diff --git a/src/app/(site)/page.tsx b/src/app/(site)/page.tsx
index fa14ee7e..c52e7899 100644
--- a/src/app/(site)/page.tsx
+++ b/src/app/(site)/page.tsx
@@ -3,458 +3,323 @@ import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { cached } from "@/lib/cache";
import { formatDate } from "@/lib/format-date";
+import { avatarImageUrl } from "@/lib/format";
import { prisma } from "@/lib/prisma";
import { siteSettings } from "@/lib/services/site-settings";
export const revalidate = 120;
async function getHotelData() {
- const hotelName = await siteSettings.get("hotel_name", "Hotel");
- const [online, users, rooms, articles] = await Promise.all([
- cached("online_count", 10_000, () =>
- prisma.user.count({ where: { online: "1" } }),
- ).catch(() => 0),
- cached("total_users", 30_000, () => prisma.user.count()).catch(() => 0),
- cached("total_rooms", 30_000, () => prisma.rooms.count()).catch(() => 0),
- prisma.websiteArticles
- .findMany({ orderBy: { createdAt: "desc" }, take: 3 })
- .catch(() => []),
+ const [hotelName, imagerRaw] = await Promise.all([
+ siteSettings.get("hotel_name", "Hotel"),
+ siteSettings.get(
+ "habbo_imaging_url",
+ "https://www.habbo.com/habbo-imaging/avatarimage",
+ ),
]);
- return { hotelName, online, users, rooms, articles };
+ const imager = imagerRaw ?? "https://www.habbo.com/habbo-imaging/avatarimage";
+
+ const [online, users, rooms, articles, recentUsers, recentPhotos] =
+ await Promise.all([
+ cached("online_count", 10_000, () =>
+ prisma.user.count({ where: { online: "1" } }),
+ ).catch(() => 0),
+ cached("total_users", 30_000, () => prisma.user.count()).catch(() => 0),
+ cached("total_rooms", 30_000, () => prisma.rooms.count()).catch(() => 0),
+ prisma.websiteArticles
+ .findMany({ orderBy: { createdAt: "desc" }, take: 5 })
+ .catch(() => []),
+ prisma.user
+ .findMany({
+ where: { online: "1" },
+ select: { username: true, look: true },
+ take: 12,
+ })
+ .catch(() => []),
+ prisma.cameraWeb
+ .findMany({ orderBy: { timestamp: "desc" }, take: 4 })
+ .catch(() => []),
+ ]);
+
+ return {
+ hotelName,
+ imager,
+ online,
+ users,
+ rooms,
+ articles,
+ recentUsers,
+ recentPhotos,
+ };
}
export default async function Home() {
const t = await getTranslations("header");
- const { hotelName, online, users, rooms, articles } = await getHotelData();
+ const {
+ hotelName,
+ imager,
+ online,
+ users,
+ rooms,
+ articles,
+ recentUsers,
+ recentPhotos,
+ } = await getHotelData();
+
+ const featuredArticle = articles[0];
+ const remainingArticles = articles.slice(1, 5);
return (
-
- {/* ── 1. Lobby — full-width hero with depth ── */}
-
+
+ {/* ── Hero ── */}
+
-
+ />
+
+
-
-
-
-
- {online.toLocaleString()} online now
-
-
- Your story starts{" "}
-
- here
-
-
- at {hotelName}
-
-
- {t("tagline")}
-
-
-
- Join for free
-
- arrow
-
-
-
-
-
- Enter hotel
-
-
-
-
-
+
+ {online.toLocaleString()} online now
+
+
+ Welcome to{" "}
+
+ {hotelName}
+
+
+
+ {t("tagline")}
+
+
+
+
-
+ Enter {hotelName}
+
+
+ Play now
+
+
+
+
+
+
+ {recentUsers.slice(0, 4).map((u) => (
+
-
-
- Hey there! 👋
-
-
- Ready for an adventure? Create your account and let's go!
-
-
+ {u.username}
+
-
+ ))}
- {/* ── 2. Hotel stats — reimagined as service pillars ── */}
-
-
- {[
- {
- value: online.toLocaleString(),
- label: "Guests online",
- detail: "Exploring right now",
- },
- {
- value: users.toLocaleString(),
- label: "Total citizens",
- detail: "And counting",
- },
- {
- value: rooms.toLocaleString(),
- label: "Rooms built",
- detail: "Waiting to be explored",
- },
- {
- value: "∞",
- label: "Adventures await",
- detail: "New experiences daily",
- },
- ].map((stat) => (
-
-
-
-
- {stat.value}
-
-
- {stat.label}
-
-
- {stat.detail}
-
-
-
- ))}
-
-
-
- {/* ── 3. Experiences — what makes the hotel special ── */}
-
-
-
+ {[
+ { value: online.toLocaleString(), label: "Guests online" },
+ { value: users.toLocaleString(), label: "Total citizens" },
+ { value: rooms.toLocaleString(), label: "Rooms built" },
+ ].map((s) => (
+
- Everything{" "}
-
- {hotelName}
- {" "}
- has to offer
-
-
- From styling your avatar to building empires — it all happens here
-
-
-
- {[
- {
- icon: "/assets/images/icons/star.gif",
- title: "Avatar studio",
- desc: "Mix, match and stand out with thousands of outfits, accessories and effects.",
- },
- {
- icon: "/assets/images/icons/catalog.png",
- title: "Furniture catalog",
- desc: "Deck out your room with an ever-growing collection of furniture and decor.",
- },
- {
- icon: "/assets/images/icons/navigation/community.png",
- title: "Community hub",
- desc: "Meet people from around the world, join groups and make lifelong friends.",
- },
- {
- icon: "/assets/images/icons/navigation/bb.png",
- title: "Battle & play",
- desc: "Compete in snowstorm, battleball, and weekly events with rewards.",
- },
- ].map((item) => (
+ {s.value}
+
+ {s.label}
+
+
+ ))}
+
+
+ {/* ── Main content: News + Sidebar ── */}
+
+ {/* News feed (left, 2/3) */}
+
+ {featuredArticle && (
+
-
-
-
+
+ {featuredArticle.image ? (
+ ) : (
+
+ )}
+
+
+
+ {featuredArticle.title}
+
+
+ {formatDate(featuredArticle.createdAt, "date", "")}
+
-
- {item.title}
-
-
+
+ )}
+
+ {remainingArticles.length > 0 && (
+
+ {remainingArticles.map((a) => (
+
- {item.desc}
-
-
-
- ))}
-
-
-
- {/* ── 4. Bulletin — latest articles ── */}
- {articles.length > 0 && (
-
-
-
-
- Hotel bulletin
-
-
- Stay up to date with the latest from {hotelName}
-
-
-
- Browse all articles
-
- arrow
-
-
-
-
-
-
- {articles.map((a, i) => (
-
-
- {a.image ? (
-
- ) : (
-
- )}
-
- {i === 0 && (
-
-
+ {a.image ? (
+
+ ) : (
+
- {a.title}
-
-
- {formatDate(a.createdAt, "date", "")}
-
-
- )}
-
- {i > 0 && (
-
+ />
+ )}
+
+
- )}
-
- ))}
-
-
-
- Browse all articles →
-
-
-
- )}
+
+ ))}
+
+ )}
- {/* ── 5. Final CTA — doors are open ── */}
-
-
-
-
+
+
+ {/* Sidebar (right, 1/3) */}
+
+
+
+ {/* ── CTA ── */}
+
+
+ See you inside!
+
+
+ {hotelName} is free, forever. Create your account and start your
+ adventure today.
+
+
+
+ Join for free
+
);
diff --git a/src/app/(site)/register/page.tsx b/src/app/(site)/register/page.tsx
index 5de5a400..f8641872 100644
--- a/src/app/(site)/register/page.tsx
+++ b/src/app/(site)/register/page.tsx
@@ -4,175 +4,187 @@ import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { RegisterForm } from "@/components/auth/register-form";
import { cached } from "@/lib/cache";
+import { avatarImageUrl } from "@/lib/format";
import { prisma } from "@/lib/prisma";
import { captchaConfig } from "@/lib/services/captcha";
import { siteSettings } from "@/lib/services/site-settings";
export default async function RegisterPage() {
const t = await getTranslations("header");
- const [hotelName, cfg] = await Promise.all([
+ const [hotelName, imagerRaw, cfg] = await Promise.all([
siteSettings.get("hotel_name", "Hotel"),
+ siteSettings.get(
+ "habbo_imaging_url",
+ "https://www.habbo.com/habbo-imaging/avatarimage",
+ ),
captchaConfig(),
]);
+ const imager = imagerRaw ?? "https://www.habbo.com/habbo-imaging/avatarimage";
const nonce = (await headers()).get("x-nonce") ?? undefined;
- const online = await cached("online_count", 10_000, () =>
- prisma.user.count({ where: { online: "1" } }),
- ).catch(() => 0);
+ const [online, recentUsers] = await Promise.all([
+ cached("online_count", 10_000, () =>
+ prisma.user.count({ where: { online: "1" } }),
+ ).catch(() => 0),
+ prisma.user
+ .findMany({
+ where: { online: "1" },
+ select: { username: true, look: true },
+ take: 8,
+ })
+ .catch(() => []),
+ ]);
return (
-
- {/* ── Left: Reception desk ── */}
-
+
+ {/* ── Left panel: Frank + avatars ── */}
+
-
-
-
-
-
-
-
-
-
-
- {online.toLocaleString()} here now
-
-
-
- Welcome to{" "}
-
- {hotelName}
-
-
-
- {t("tagline")}
-
-
-
-
+ Join{" "}
+
- {[
- { icon: "🎨", text: "Unique avatar" },
- { icon: "🏠", text: "Your own room" },
- { icon: "💬", text: "Meet new people" },
- ].map((item) => (
-
- {item.icon}
- {item.text}
-
- ))}
-
-
-
-
-
- {/* ── Right: Check-in desk (registration form) ── */}
-
-
-
-
- Create your account
-
-
- It takes less than a minute. No email required.
-
-
-
-
-
+ {hotelName}
+
+
- Already checked in?{" "}
-
+
+
+ {online.toLocaleString()} online now
+
+
+
+ {recentUsers.length > 0 && (
+
+
- Sign in here
-
+ Who's online
+
+
+ {recentUsers.map((u) => (
+
+
+
+ {u.username}
+
+
+ ))}
+
+
+ )}
+
+
+ Already have an account?{" "}
+
+ Sign in
+
+
+
+
+ {/* ── Right: Registration form ── */}
+
+
+
+ Create your account
+
+
+ Free and takes less than a minute
+
);