fix(avatar): render onError avatars only in client components
CI / check (push) Successful in 4m33s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 1m51s

AvatarImage is used on server pages via UserAvatarThumbnail but lacked
'use client', so the onError handler on its <img> could not cross the
RSC boundary. /login rendered the error page, hanging the news e2e
journey until the 240s test timeout.

- Mark AvatarImage as a client component like ProfileImage
- Replace inline <img onError> on mod/users server pages with the
  client AvatarImage component
This commit is contained in:
openhands committed 2026-09-15 11:43:47 +02:00
1 parent faa37e7c58
commit ce93b92a81
3 files changed
+10 -15

No files matched your search

+4 -7
View File
@@ -2,11 +2,11 @@ import { eq } from "drizzle-orm";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server"; import { getTranslations } from "next-intl/server";
import Link from "@/components/link"; import Link from "@/components/link";
import { AvatarImage } from "@/components/shared/avatar-image";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { requireModPermission } from "@/lib/admin/guard"; import { requireModPermission } from "@/lib/admin/guard";
import { db, User } from "@/lib/db"; import { db, User } from "@/lib/db";
import { formatDate } from "@/lib/format-date"; import { formatDate } from "@/lib/format-date";
import { avatarImageOnError, getAvatarUrl } from "@/lib/imager";
import { PERMS } from "@/lib/permissions"; import { PERMS } from "@/lib/permissions";
export default async function ModUserDetailPage({ export default async function ModUserDetailPage({
@@ -41,15 +41,12 @@ export default async function ModUserDetailPage({
<div className="space-y-6"> <div className="space-y-6">
<div className="flex flex-wrap items-start justify-between gap-4"> <div className="flex flex-wrap items-start justify-between gap-4">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<img <AvatarImage
src={getAvatarUrl(user.look, { figure={user.look}
direction: 2, options={{ size: "m", direction: 2, headDirection: 2 }}
headDirection: 2,
})}
alt="" alt=""
width={64} width={64}
height={110} height={110}
onError={avatarImageOnError}
className="rounded" className="rounded"
/> />
<div> <div>
+4 -8
View File
@@ -2,11 +2,11 @@ import { and, asc, count, desc, eq, like, or, type SQL } from "drizzle-orm";
import { getTranslations } from "next-intl/server"; import { getTranslations } from "next-intl/server";
import { DataTable } from "@/components/admin/data-table"; import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link"; import Link from "@/components/link";
import { AvatarImage } from "@/components/shared/avatar-image";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { requireModPermission } from "@/lib/admin/guard"; import { requireModPermission } from "@/lib/admin/guard";
import { calcPagination, parseListParams } from "@/lib/admin-helpers"; import { calcPagination, parseListParams } from "@/lib/admin-helpers";
import { db, User } from "@/lib/db"; import { db, User } from "@/lib/db";
import { avatarImageOnError, getAvatarUrl } from "@/lib/imager";
import { PERMS } from "@/lib/permissions"; import { PERMS } from "@/lib/permissions";
import { logServerError } from "@/lib/server-log"; import { logServerError } from "@/lib/server-log";
import type { DataTableColumn } from "@/types/common"; import type { DataTableColumn } from "@/types/common";
@@ -29,16 +29,12 @@ const columns: DataTableColumn<ModUserRow>[] = [
sortable: true, sortable: true,
render: (_, row) => ( render: (_, row) => (
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<img <AvatarImage
src={getAvatarUrl(row.look, { figure={row.look}
size: "m", options={{ size: "m", direction: 2, headDirection: 2 }}
direction: 2,
headDirection: 2,
})}
alt="" alt=""
width={32} width={32}
height={32} height={32}
onError={avatarImageOnError}
className="rounded" className="rounded"
/> />
<span className="font-medium">{row.username}</span> <span className="font-medium">{row.username}</span>
+2
View File
@@ -1,3 +1,5 @@
"use client";
import { import {
type AvatarOptions, type AvatarOptions,
avatarImageOnError, avatarImageOnError,