fix(desktop): degrade missing avatar image to letter circle
Avatar rendered a bare <img> with no error handling, so an avatar_url whose storage object is unreachable (e.g. a 404 after the server move) showed a broken image instead of the coloured letter-circle fallback. Track an onError flag and fall back to the circle; reset it when the URL changes so a fresh valid avatar is retried. This is client-side resilience only — it does not restore a genuinely missing storage object. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
// Reusable avatar that prefers an uploaded image and falls back to a coloured
|
// Reusable avatar that prefers an uploaded image and falls back to a coloured
|
||||||
// letter circle. Use this everywhere the app needs to render a profile.
|
// letter circle. Use this everywhere the app needs to render a profile.
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { useCachedAvatarUrl } from '../lib/avatarCache';
|
import { useCachedAvatarUrl } from '../lib/avatarCache';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -27,7 +29,13 @@ export function Avatar({
|
|||||||
loading = 'lazy',
|
loading = 'lazy',
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const effectiveUrl = useCachedAvatarUrl(url);
|
const effectiveUrl = useCachedAvatarUrl(url);
|
||||||
if (effectiveUrl) {
|
// If the image URL is non-empty but unreachable (e.g. the storage object is
|
||||||
|
// missing / 404s), the bare <img> would render broken with no fallback.
|
||||||
|
// Track a load error and degrade to the letter circle instead. Reset on URL
|
||||||
|
// change so a fresh, valid avatar is retried.
|
||||||
|
const [failed, setFailed] = useState(false);
|
||||||
|
useEffect(() => setFailed(false), [effectiveUrl]);
|
||||||
|
if (effectiveUrl && !failed) {
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
src={effectiveUrl}
|
src={effectiveUrl}
|
||||||
@@ -35,6 +43,7 @@ export function Avatar({
|
|||||||
className={'shrink-0 rounded-full object-cover ' + className}
|
className={'shrink-0 rounded-full object-cover ' + className}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
onError={() => setFailed(true)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user