Skip to content

Conversation

@moshfeu
Copy link
Member

@moshfeu moshfeu commented Dec 7, 2025

This pull request introduces a new feature that allows users to toggle between using their Google profile picture and a Gravatar image as their avatar. The backend now supports updating and persisting the avatar choice, while the frontend provides a clear UI for switching and previewing the selected avatar.

Backend: Avatar selection and persistence

  • Added a new API endpoint (/current/avatar, POST) and handler (toggleAvatarHandler) to allow users to switch their avatar between Gravatar and their Auth0/Google profile picture. The handler computes the Gravatar URL and updates the user record accordingly. [1] [2]
  • Modified the current user handler to prefer the stored avatar URL, falling back to the Auth0 picture if none is set.

Frontend: Avatar UI and logic

  • Updated the avatar display logic across the app to use the avatar URL directly from the user object, removing the need for the getAvatarUrl helper. This affects components such as UsersList, Card, MemberArea, and EditProfile. [1] [2] [3] [4]
  • Added a toggle UI in the avatar/profile sections (Avatar.tsx, EditProfile.js, and new AvatarField.tsx) for Google-authenticated users to switch between Gravatar and Google profile picture. The UI provides links to update the avatar at the relevant provider. [1] [2] [3]

API integration

  • Added a new toggleAvatar method to the ApiService for calling the backend endpoint and updating the current user context after avatar changes.

Error handling and UI polish

  • Improved error handling for avatar image loading in the member menu, falling back to the Auth0 picture if the stored avatar fails to load. [1] [2] [3]
  • Updated styling for avatar previews and toggle controls for a more consistent and user-friendly interface. [1] [2]

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a custom avatar feature that allows users to set any public image URL for their profile picture, with automatic fallback to their OAuth provider's avatar if the custom URL fails to load.

Key changes:

  • Added client-side validation for avatar URLs with http/https protocol checking
  • Implemented error handling with automatic fallback to OAuth provider avatars
  • Added new modal UI component for editing avatars with user-friendly hints
  • Modified backend to support custom avatar storage while maintaining OAuth avatar as fallback

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/types/models.d.ts Added optional auth0Id field to User type for provider identification
src/components/MemberArea/model.js Updated avatar validation to accept any valid http/https URL instead of restricting to specific providers
src/components/MemberArea/MemberArea.js Added error state management and fallback logic for failed avatar URLs
src/components/MemberArea/EditProfile.js Replaced static Gravatar redirect with editable URL input field and fallback error handling
src/Me/Routes/Home/Avatar/AvatarEditModal.tsx New modal component for editing avatar URLs with clear/save functionality
src/Me/Routes/Home/Avatar/Avatar.tsx Complete refactor with modal integration, error handling, badge indicators, and state management
netlify/functions-src/functions/modules/users/current.ts Modified to prioritize custom avatar over OAuth picture and expose auth0Picture for client-side fallback

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 16 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (2)

src/Me/Routes/Home/Avatar/Avatar.tsx:1

  • Unused import useEffect.
import React, { FC, useState, useEffect } from 'react';

src/Me/Routes/Home/Avatar/Avatar.tsx:59

  • Unused variable isSaving.
  const [isSaving, setIsSaving] = useState(false);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

...currentUser,
email_verified: context.user?.email_verified,
avatar: context.user?.picture,
avatar: avatarUrl,
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auth0Picture and auth0Id fields are not being populated in the response. The frontend components like AvatarField.tsx and Avatar.tsx depend on these fields to determine if the user is a Google user and to provide fallback avatar URLs.

You should add these fields to the response:

const applicationUser = {
  ...currentUser,
  email_verified: context.user?.email_verified,
  avatar: avatarUrl,
  auth0Picture: context.user?.picture,
  auth0Id: currentUser.auth0Id,
};
Suggested change
avatar: avatarUrl,
avatar: avatarUrl,
auth0Picture: context.user?.picture,
auth0Id: currentUser.auth0Id,

Copilot uses AI. Check for mistakes.
const { currentUser } = useUser<true>();
const { currentUser, updateCurrentUser } = useUser<true>();
const api = useApi();
const [isSaving, setIsSaving] = useState(false);
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isSaving state is declared but never used to disable the UI or show a loading state during the avatar toggle operation. Consider using this state to provide visual feedback:

<Switch
  label="Use Gravatar"
  isChecked={isUsingGravatar}
  onToggle={handleToggleGravatar}
  size="small"
  disabled={isSaving}  // Add this
/>

Copilot uses AI. Check for mistakes.
const updatedUser = await upsertUser(userDto);

return success({
data: updatedUser,
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The toggleAvatarHandler should return the complete user object with auth0Picture and auth0Id fields to match what the frontend expects. Currently, upsertUser returns the database user object which may not include these fields populated from the Auth0 context.

Consider returning a complete application user similar to the current handler:

const updatedUser = await upsertUser(userDto);

return success({
  data: {
    ...updatedUser,
    auth0Picture: context.user?.picture,
    auth0Id: updatedUser.auth0Id,
  },
});
Suggested change
data: updatedUser,
data: {
...updatedUser,
auth0Picture: context.user?.picture,
auth0Id: updatedUser.auth0Id,
},

Copilot uses AI. Check for mistakes.
position="bottom"
>
<i className="fa fa-info-circle"></i>
</Tooltip>{" "}
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] There's an inconsistent space character {" "} on line 116. Consider placing the content inline or formatting it consistently with line 126:

</Tooltip>
<ToggleLabel>

or remove the space entirely as it's not needed between these elements.

Suggested change
</Tooltip>{" "}
</Tooltip>

Copilot uses AI. Check for mistakes.
moshfeu and others added 2 commits December 10, 2025 01:53
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants