fix(public): distinguish unavailable data from empty results and missing pages
CI / check (push) Successful in 56s
CI / deploy (push) Successful in 1m30s
CI / publish-container (push) Successful in 44s

This commit is contained in:
Simo committed 2026-09-11 00:39:53 +02:00
1 parent db4acbb46e
commit 445ef13846
16 files changed
+608 -169

No files matched your search

+29 -8
View File
@@ -2,10 +2,12 @@ import { asc, eq, inArray } from "drizzle-orm";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { PublicLoadError } from "@/components/public/load-error";
import { ContentCard, EmptyState, StatBlock } from "@/components/public/ui";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { db, Guilds, GuildsMembers, User } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
import { publicReadFailure } from "@/lib/services/public-read";
type GuildView = {
id: number;
@@ -50,14 +52,22 @@ export default async function GuildPage({
.where(eq(Guilds.id, guildId))
.limit(1);
guild = row ?? null;
} catch {
guild = null;
} catch (error) {
publicReadFailure("guild.detail")(error);
return (
<main className="page-grid">
<ContentCard>
<PublicLoadError href={`/guilds/${guildId}`} />
</ContentCard>
</main>
);
}
if (!guild) notFound();
// Members come from guilds_members; there is no relation in the schema, so we
// join the users table manually by id.
let membersFailed = false;
let memberRows: { userId: number; memberSince: number }[] = [];
try {
memberRows = await db
@@ -69,7 +79,9 @@ export default async function GuildPage({
.where(eq(GuildsMembers.guildId, guild.id))
.orderBy(asc(GuildsMembers.memberSince))
.limit(200);
} catch {
} catch (error) {
publicReadFailure("guild.members")(error);
membersFailed = true;
memberRows = [];
}
@@ -93,7 +105,9 @@ export default async function GuildPage({
.from(User)
.where(inArray(User.id, memberIds))
: [];
} catch {
} catch (error) {
publicReadFailure("guild.member-users")(error);
membersFailed = true;
users = [];
}
@@ -159,7 +173,7 @@ export default async function GuildPage({
<div className="stat-grid" style={{ marginTop: "1.1rem" }}>
<StatBlock
icon="👥"
value={members.length}
value={membersFailed ? "—" : members.length}
label={
members.length === 1 ? t("memberSingular") : t("memberPlural")
}
@@ -185,11 +199,18 @@ export default async function GuildPage({
<ContentCard
icon="👥"
title={t("membersTitle")}
subtitle={`${members.length} ${members.length === 1 ? t("memberLowerSingular") : t("memberLowerPlural")}`}
padded={members.length === 0}
subtitle={
membersFailed
? undefined
: `${members.length} ${members.length === 1 ? t("memberLowerSingular") : t("memberLowerPlural")}`
}
padded={members.length === 0 || membersFailed}
>
{membersFailed && <PublicLoadError href={`/guilds/${guild.id}`} />}
{members.length === 0 ? (
<EmptyState icon="👥">{t("noMembers")}</EmptyState>
membersFailed ? null : (
<EmptyState icon="👥">{t("noMembers")}</EmptyState>
)
) : (
<div className="card-grid sm-2 lg-3" style={{ padding: "1rem" }}>
{members.map((m) => (