diff --git a/src/app/(site)/me/page.tsx b/src/app/(site)/me/page.tsx index 7aea5294..9d6098a6 100644 --- a/src/app/(site)/me/page.tsx +++ b/src/app/(site)/me/page.tsx @@ -69,7 +69,9 @@ export default async function MePage({ let content: ReactNode; try { - const [user, imagerBase, hotelName, neededRaw, amountRaw, currencyRaw, alertRaw, recentRooms] = + const BADGE_IMG_BASE = "https://images.habbo.com/c_images/album1584"; + + const [user, imagerBase, hotelName, neededRaw, amountRaw, currencyRaw, alertRaw, recentRooms, badges, lastWebLogin, userSettings, friendCount, unreadCount] = await Promise.all([ prisma.user.findUnique({ where: { id: userId }, @@ -123,6 +125,34 @@ export default async function MePage({ take: 6, }) .catch(() => []), + prisma.usersBadges + .findMany({ + where: { userId, slotId: { gt: 0 } }, + orderBy: { slotId: "asc" }, + select: { badgeCode: true, slotId: true }, + }) + .catch(() => []), + prisma.websiteLoginLogs + .findFirst({ + where: { userId }, + orderBy: { id: "desc" }, + select: { createdAt: true }, + }) + .catch(() => null), + prisma.usersSettings + .findUnique({ + where: { userId }, + select: { achievementScore: true, respectsReceived: true }, + }) + .catch(() => null), + prisma.messengerFriendships + .count({ + where: { OR: [{ userOneId: userId }, { userTwoId: userId }] }, + }) + .catch(() => 0), + prisma.messengerOffline + .count({ where: { userId } }) + .catch(() => 0), ]); if (!user) throw new Error("user-not-found"); @@ -182,6 +212,9 @@ export default async function MePage({ const lastLoginDate = user.lastLogin ? new Date(user.lastLogin * 1000).toISOString().slice(0, 10) : "Never"; + const lastWebLoginDate = lastWebLogin?.createdAt + ? new Date(lastWebLogin.createdAt).toISOString().slice(0, 10) + : null; const lastOnlineDate = user.lastOnline ? new Date(user.lastOnline * 1000).toISOString().slice(0, 10) : "Never"; @@ -314,10 +347,13 @@ export default async function MePage({ {/* ── Stat tiles ── */} -
+
{[ { value: user.credits.toLocaleString(), label: "Credits" }, { value: `Rank ${user.rank}`, label: "Hotel rank" }, + { value: (userSettings?.achievementScore ?? 0).toLocaleString(), label: "Achievement score" }, + { value: (userSettings?.respectsReceived ?? 0).toLocaleString(), label: "Respects received" }, + { value: friendCount.toLocaleString(), label: "Friends" }, { value: lastLoginDate, label: "Last login" }, ].map((s) => (
)} + + {badges.length > 0 && ( + +
+
+

+ Badges +

+

+ {badges.length} badge{badges.length !== 1 ? "s" : ""} equipped +

+
+
+ {badges.map((badge) => ( + {badge.badgeCode} + ))} +
+
+
+ )} + + +
+
+

+ Quick links +

+
+
+ + Messages + {unreadCount > 0 && ( + + {unreadCount > 99 ? "99+" : unreadCount} + + )} + + + My profile + + + Settings + + + Shop + +
+
+
); } catch { diff --git a/src/components/room-quick-entry.tsx b/src/components/room-quick-entry.tsx new file mode 100644 index 00000000..be508e63 --- /dev/null +++ b/src/components/room-quick-entry.tsx @@ -0,0 +1,42 @@ +"use client"; + +export function RoomQuickEntry() { + return ( +
{ + const form = e.currentTarget; + const input = form.elements.namedItem("roomId") as HTMLInputElement | null; + if (input?.value) { + form.action = `/room/${input.value}`; + } + }} + > + + +
+ ); +} diff --git a/src/components/top-header.tsx b/src/components/top-header.tsx index 8e2531b8..d2e8206d 100644 --- a/src/components/top-header.tsx +++ b/src/components/top-header.tsx @@ -9,6 +9,7 @@ import { canAccess, getApiAdminContext, PERMS } from "@/lib/permissions"; import { prisma } from "@/lib/prisma"; import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; +import { RoomQuickEntry } from "@/components/room-quick-entry"; function Currency({ icon, @@ -174,39 +175,7 @@ export async function TopHeader({ session }: { session: Session | null }) { Enter -
{ - const input = (e.target as HTMLFormElement).querySelector("input"); - if (input?.value) { - e.currentTarget.action = `/room/${input.value}`; - } - }} - > - - -
+ @@ -218,6 +187,23 @@ export async function TopHeader({ session }: { session: Session | null }) {
+
+ +