Add performance optimizations and component refactors
CI / check (push) Successful in 34s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m23s

- Cache read-heavy public API routes via redisCache (leaderboard, values,
  shop, articles, photos, guilds, teams, staff, users, home, radio, badges)
- Add single-flight and bounded-memory cache layer with unit tests
- Parallelize independent DB queries on search, rares, shop, staff, polls
  and profile pages
- Push radio points leaderboard aggregation to SQL with a LIMIT
- Split studio-client and import-furni-client into focused modules
- Clean up next.config.ts
This commit is contained in:
openhands committed 2026-08-17 22:02:21 +02:00
1 parent 54f2bc5e0c
commit f285a7cd98
42 files changed
+1616 -1205

No files matched your search

@@ -0,0 +1,40 @@
import type { SyntheticEvent } from "react";
import type { FurniItem } from "./studio-types";
export function getFurniImageUrl(item: FurniItem) {
if (item.iconUrl) return item.iconUrl;
const base = item.classname.includes("*")
? item.classname.substring(0, item.classname.indexOf("*"))
: item.classname;
return `https://images.habbo.com/dcr/hof_furni/${item.revision}/${encodeURIComponent(base)}_icon.png`;
}
export function getFurniIconUrl(classname: string, revision: number) {
const iconName = classname.replace(/\*/g, "_");
return `https://images.habbo.com/dcr/hof_furni/${revision}/${encodeURIComponent(iconName)}_icon.png`;
}
export function handleImgError(
e: SyntheticEvent<HTMLImageElement>,
item: FurniItem,
) {
const img = e.target as HTMLImageElement;
const iconName = item.classname.replace(/\*/g, "_");
if (!img.dataset.fallback) {
img.dataset.fallback = "1";
img.src = getFurniIconUrl(item.classname, item.revision);
} else if (img.dataset.fallback === "1") {
img.dataset.fallback = "2";
img.src = `/swf/dcr/hof_furni/icons/${encodeURIComponent(iconName)}_icon.png`;
} else {
img.style.opacity = "0.3";
img.src =
'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="%23666" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>';
}
}
export const TYPE_LABELS: Record<string, string> = {
flooritem: "Floor",
wallitem: "Wall",
};