The header shows T5DE's logo (the client's, also the tab icon) and Online, Rooms, Products and Catalogs; the person's pages (Account, Library, Console for moderators) and signing out are in a menu under their picture: their first linked IMVU account's avatar picture, which /me now gives (kept an hour), or their initial. Creating a product moves to Products (New product, /products/new; /create redirects there), as creating a room is on Rooms. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
76c8e0342e
commit
07bbc11565
19 files changed
+160
-79
No files matched your search
+26
-1
@@ -4,6 +4,7 @@
|
||||
import { Elysia, t } from "elysia";
|
||||
import {
|
||||
and,
|
||||
asc,
|
||||
desc,
|
||||
eq,
|
||||
ilike,
|
||||
@@ -151,6 +152,30 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
|
||||
banReason: p.banReason ?? "",
|
||||
});
|
||||
|
||||
/** A person's picture, for the website's header: their first linked IMVU account's avatar picture (null if none,
|
||||
* or IMVU can't say). Kept an hour per account, so pages don't each ask IMVU. */
|
||||
const pictures = new Map<number, { url: string | null; at: number }>();
|
||||
const picture = async (userId: string): Promise<string | null> => {
|
||||
const [first] = await db
|
||||
.select({ imvuId: imvuLink.imvuId })
|
||||
.from(imvuLink)
|
||||
.where(eq(imvuLink.userId, userId))
|
||||
.orderBy(asc(imvuLink.linkedAt))
|
||||
.limit(1);
|
||||
if (!first) return null;
|
||||
const kept = pictures.get(first.imvuId);
|
||||
if (kept && Date.now() - kept.at < 60 * 60 * 1000) return kept.url;
|
||||
let url: string | null = kept?.url ?? null;
|
||||
try {
|
||||
url = (await imvu.byId(first.imvuId)).picture;
|
||||
} catch {
|
||||
// IMVU unavailable: the last known one (or none), asked again next time.
|
||||
return url;
|
||||
}
|
||||
pictures.set(first.imvuId, { url, at: Date.now() });
|
||||
return url;
|
||||
};
|
||||
|
||||
/** Links as the website shows them: with live presence, and age by the one rule. */
|
||||
const linkViews = async (userId: string, links: Link[]) => {
|
||||
const ids = links.map((l) => l.imvuId);
|
||||
@@ -442,7 +467,7 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
|
||||
})
|
||||
|
||||
// Who's signed in, and the home page.
|
||||
.get("/me", ({ me }) => ({ person: personView(me) }), { signedIn: true })
|
||||
.get("/me", async ({ me }) => ({ person: { ...personView(me), picture: await picture(me.id) } }), { signedIn: true })
|
||||
.get("/home", async ({ person }) => {
|
||||
const online = (await visibleOnline(person)).length;
|
||||
if (!person) return { onlineCount: online };
|
||||
|
||||
Reference in new issue
Block a user