feat(web): replace placeholder avatars with minidenticon-based UserAvatar#1072
feat(web): replace placeholder avatars with minidenticon-based UserAvatar#1072brendan-kellam merged 6 commits intomainfrom
Conversation
…atar component Adds the minidenticons library and a new UserAvatar component that generates deterministic avatar icons from email addresses. Replaces all placeholder avatar usage across chat, settings, and redeem pages with this unified component. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a client-side Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Client UI
participant UA as UserAvatar
participant API as /api/minidenticon
participant Gen as minidenticons+sharp
UI->>UA: render(email?, imageUrl?)
alt imageUrl provided
UA->>UI: use imageUrl as src
else no imageUrl but email present
UA->>API: GET /api/minidenticon?email=<encoded>
API->>Gen: generate SVG (minidenticons) -> convert to PNG (sharp)
Gen-->>API: PNG bytes
API-->>UA: image/png (Cache-Control: public, max-age=31536000, immutable)
UA->>UI: use returned PNG as src
else no email/image
UA->>UI: render existing placeholder/fallback
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This comment has been minimized.
This comment has been minimized.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
License Audit❌ Status: FAIL
Fail Reasons
Unresolved Packages
Weak Copyleft Packages (informational)
Resolved Packages (7)
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/web/src/components/userAvatar.tsx (1)
22-30: Consider adding a generic fallback when no email is available.When both
imageUrlandAvatarFallbackrendersnull, leaving an empty circle with only thebg-mutedbackground. Consider displaying a generic icon or initials placeholder for this edge case.💡 Optional: Add a generic fallback
<AvatarFallback className="bg-muted"> {identiconUri ? ( <img src={identiconUri} alt={email ?? 'avatar'} className="h-full w-full" /> - ) : null} + ) : ( + <span className="text-muted-foreground text-xs">?</span> + )} </AvatarFallback>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/web/src/components/userAvatar.tsx` around lines 22 - 30, The AvatarFallback currently renders null when both imageUrl and identiconUri are missing and email is falsy; update the fallback logic inside the Avatar component (references: Avatar, AvatarImage, AvatarFallback, identiconUri, imageUrl, email) to render a generic placeholder (e.g., a simple SVG/person icon or a single-character placeholder like '?' or initials derived from a displayName prop) whenever identiconUri is falsy and email is falsy, ensuring you provide sensible alt text and keep existing classes (e.g., "bg-muted" and "h-full w-full") so the visual size and styling remain consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/web/src/components/userAvatar.tsx`:
- Around line 22-30: The AvatarFallback currently renders null when both
imageUrl and identiconUri are missing and email is falsy; update the fallback
logic inside the Avatar component (references: Avatar, AvatarImage,
AvatarFallback, identiconUri, imageUrl, email) to render a generic placeholder
(e.g., a simple SVG/person icon or a single-character placeholder like '?' or
initials derived from a displayName prop) whenever identiconUri is falsy and
email is falsy, ensuring you provide sensible alt text and keep existing classes
(e.g., "bg-muted" and "h-full w-full") so the visual size and styling remain
consistent.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2f19f897-b8c4-455b-b0ab-2f85afaec97c
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (13)
CHANGELOG.mdpackages/web/package.jsonpackages/web/src/app/[domain]/chat/[id]/opengraph-image.tsxpackages/web/src/app/[domain]/chat/components/shareChatPopover/ee/invitePanel.tsxpackages/web/src/app/[domain]/chat/components/shareChatPopover/shareSettings.tsxpackages/web/src/app/[domain]/components/meControlDropdownMenu.tsxpackages/web/src/app/[domain]/settings/members/components/invitesList.tsxpackages/web/src/app/[domain]/settings/members/components/membersList.tsxpackages/web/src/app/[domain]/settings/members/components/requestsList.tsxpackages/web/src/app/redeem/components/acceptInviteCard.tsxpackages/web/src/app/redeem/components/inviteNotFoundCard.tsxpackages/web/src/components/userAvatar.tsxpackages/web/src/features/chat/components/chatThread/messageAvatar.tsx
The org avatar should use the placeholder image, not a minidenticon generated from the org name. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace placeholder avatars in email templates with dynamically generated minidenticon PNGs. The new endpoint converts minidenticon SVGs to PNGs via sharp, making them compatible with email clients that don't support data URIs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/web/src/app/api/minidenticon/route.ts`:
- Around line 11-17: The handler currently reads the raw email from
request.nextUrl.searchParams.get('email') and passes it to minidenticon, which
can leak PII; instead, derive a non-PII deterministic seed by normalizing and
hashing the email (e.g., normalizedEmail = email.trim().toLowerCase(); seed =
sha256(normalizedEmail).hex()) and pass that seed into minidenticon (replace the
use of the raw email variable). Also stop echoing or logging the plain email
anywhere in this route and consider accepting a query param named "seed" (or
continue accepting "email" but immediately replace it with the hashed seed) so
the produced SVG/PNG uses the hash-only seed.
- Around line 10-14: Replace the manual email check in the GET route with
Zod-based query validation: add a Zod schema for the query (e.g. const
minidenticonQuerySchema = z.object({ email: z.string().email() })) and import
queryParamsSchemaValidationError and serviceErrorResponse, then call
minidenticonQuerySchema.safeParse(Object.fromEntries(request.nextUrl.searchParams))
inside the apiHandler; if safeParse returns success, read email from
parsed.data, otherwise return
queryParamsSchemaValidationError(parseResult.error) (or wrap with
serviceErrorResponse if the project pattern requires it). Ensure imports and
references use GET, apiHandler, queryParamsSchemaValidationError, and
serviceErrorResponse so the route follows the established
listReposQueryParamsSchema pattern.
In `@packages/web/src/emails/inviteUserEmail.tsx`:
- Line 76: The image src currently uses the nullish coalescing operator with
host.avatarUrl which doesn’t guard against empty strings; update the expression
that builds the src in inviteUserEmail.tsx to use a truthy/trim check on
host.avatarUrl (e.g. check host.avatarUrl?.trim()) and fall back to the
minidenticon URL using baseUrl and encodeURIComponent(host.email) when the
avatar is empty or whitespace so broken empty URLs never render.
In `@packages/web/src/emails/joinRequestSubmittedEmail.tsx`:
- Line 72: The img src currently uses requestor.avatarUrl ?? fallback which
leaves an empty string as src; change the expression to treat empty strings as
absent (e.g. use requestor.avatarUrl && requestor.avatarUrl.trim() !== '' ?
requestor.avatarUrl :
`${baseUrl}/api/minidenticon?email=${encodeURIComponent(requestor.email)}` or
simply requestor.avatarUrl?.trim() ||
`${baseUrl}/api/minidenticon?email=${encodeURIComponent(requestor.email)}`) so
the minidenticon fallback is used when avatarUrl is empty.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6e2c42c5-1226-49dc-89e2-343b5ba4c49c
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (6)
packages/web/package.jsonpackages/web/src/actions.tspackages/web/src/app/api/minidenticon/route.tspackages/web/src/components/userAvatar.tsxpackages/web/src/emails/inviteUserEmail.tsxpackages/web/src/emails/joinRequestSubmittedEmail.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/web/package.json
- packages/web/src/components/userAvatar.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/web/src/actions.ts`:
- Line 726: InviteUserEmail is being given baseUrl: env.AUTH_URL, which points
at the auth-service and causes minidenticon image URLs to 404; change the
baseUrl passed to InviteUserEmail (in packages/web/src/actions.ts where
InviteUserEmail is called) to the public web app origin where
packages/web/src/app/api/minidenticon/route.ts is hosted (for example use the
public/web origin env var such as NEXT_PUBLIC_APP_URL or WEB_APP_ORIGIN instead
of AUTH_URL) so the generated `${baseUrl}/api/minidenticon` links resolve
correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: cf6fe3b8-dde4-4e3d-8ca4-237a067af85e
📒 Files selected for processing (2)
packages/web/src/actions.tspackages/web/src/app/[domain]/settings/members/components/requestsList.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/web/src/app/[domain]/settings/members/components/requestsList.tsx
Summary
minidenticonslibrary and a newUserAvatarcomponent that generates deterministic avatar icons from email addressesUserAvatarusesforwardRefand spreads props so it works correctly as a RadixasChildtarget (e.g.,DropdownMenuTrigger)/api/minidenticonendpoint that generates minidenticon PNGs via sharp, used as fallback avatars in email templates where data URIs aren't supportedinviteUserEmailandjoinRequestSubmittedEmailto use the new endpoint instead of the generic placeholder avatarTest plan
forwardRef+asChildintegration)/api/minidenticon?email=test@example.comreturns a valid PNG with muted background🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores