Skip to content

feat(edit-profile): allow switch gravar / Google avatar picture#1001

Merged
moshfeu merged 7 commits into
masterfrom
gravatar-switch
Feb 28, 2026
Merged

feat(edit-profile): allow switch gravar / Google avatar picture#1001
moshfeu merged 7 commits into
masterfrom
gravatar-switch

Conversation

@moshfeu

@moshfeu moshfeu commented Jan 28, 2026

Copy link
Copy Markdown
Member

Changes

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.

Backend changes:

  • Added a new API endpoint /users/current/avatar (POST) to allow users to switch between their Google profile picture and Gravatar avatar. The endpoint updates the user's avatar URL in the database and returns the updated user object. [1] [2] [3]
  • Updated the current user handler to prefer the stored avatar, falling back to the Auth0 picture if not set, and to return both avatar and auth0Picture fields.
  • Improved error handling in user update endpoints for better type safety.

Frontend changes:

  • Added UI components (AvatarField and updates to Avatar.tsx and EditProfile.js) to let users toggle between Gravatar and Google profile avatars, including a switch and contextual help links. [1] [2] [3] [4] [5] [6] [7]
  • Integrated the new API endpoint into the frontend's API service and updated user context after avatar changes. [1] [2] [3]
  • Removed all usage of the legacy getAvatarUrl helper, updating all avatar references to use the direct avatar URL from the user object. [1] [2] [3] [4] [5] [6]

UI consistency and fallback improvements:

  • Updated avatar display logic throughout the app to consistently use the stored avatar URL, with fallback to Auth0 picture if needed, and improved error handling for broken avatar images. [1] [2] [3] [4]

Demo

Screen.Recording.2026-01-29.at.0.52.52.mov

Copilot AI left a comment

Copy link
Copy Markdown

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 feature allowing users with Google OAuth accounts to toggle between using their Google profile picture and a Gravatar avatar as their profile image.

Changes:

  • Added backend API endpoint /users/current/avatar (POST) to handle avatar switching with appropriate user lookup and URL generation
  • Added frontend UI components (AvatarField) to display avatar selection toggle with contextual help links
  • Updated avatar display logic throughout the application to use stored avatar URL with auth0Picture fallback, and removed the legacy getAvatarUrl helper function

Reviewed changes

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

Show a summary per file
File Description
src/types/models.d.ts Added auth0Picture and auth0Id optional fields to User type
src/helpers/avatar.js Removed legacy getAvatarUrl helper function
src/helpers/authProvider.ts Added new helper to detect auth provider from auth0Id
src/components/MemberArea/model.js Reorganized avatar field configuration, removed validation
src/components/MemberArea/PendingApplications.js Updated to use avatar URL directly instead of helper function
src/components/MemberArea/MemberArea.js Added avatar error handling with fallback to auth0Picture
src/components/MemberArea/EditProfile.js Integrated avatar toggle functionality with new AvatarField component
src/components/MemberArea/AvatarField.tsx New component providing avatar toggle UI for Google OAuth users
src/components/Card/Card.tsx Removed getAvatarUrl usage, minor whitespace cleanup
src/api/index.ts Added toggleAvatar API method
src/Me/Routes/Home/Avatar/Avatar.tsx Integrated avatar toggle with Switch component and user feedback
src/Me/MentorshipRequests/UsersList.tsx Updated to use avatar URL directly
netlify/functions-src/functions/users.ts Added route for avatar toggle endpoint
netlify/functions-src/functions/modules/users/userInfo.ts Improved error handling type safety
netlify/functions-src/functions/modules/users/toggleAvatar.ts New handler implementing avatar toggle logic
netlify/functions-src/functions/modules/users/current.ts Updated to return auth0Picture and prefer stored avatar

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

Comment thread src/Me/Routes/Home/Avatar/Avatar.tsx Outdated
Comment thread src/Me/Routes/Home/Avatar/Avatar.tsx Outdated
user: fromMtoVM(this.context.currentUser),
errors: [],
agree: false,
isUsingGravatar: this.context.currentUser?.avatar?.includes('gravatar.com') || false,

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

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

The logic for determining whether a user is using Gravatar relies on checking if the avatar URL contains 'gravatar.com'. However, this approach may not work correctly if the avatar URL is undefined or if a user switches from Google to Gravatar and the URL hasn't been updated yet. Consider checking the avatar URL against both the auth0Picture to determine which one is currently active, or storing the avatar preference explicitly in the database.

Copilot uses AI. Check for mistakes.
return null;
}

const isUsingGravatar = currentUser.avatar?.includes('gravatar.com') || false;

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

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

The logic for determining whether a user is using Gravatar relies on checking if the avatar URL contains 'gravatar.com'. However, this approach may not work correctly if the avatar URL is undefined or if a user switches from Google to Gravatar and the URL hasn't been updated yet. Consider checking the avatar URL against both the auth0Picture to determine which one is currently active, or storing the avatar preference explicitly in the database.

Suggested change
const isUsingGravatar = currentUser.avatar?.includes('gravatar.com') || false;
const isUsingGravatar =
!!currentUser.avatar &&
!!(currentUser as User).auth0Picture &&
currentUser.avatar !== (currentUser as User).auth0Picture;

Copilot uses AI. Check for mistakes.
Comment thread netlify/functions-src/functions/modules/users/toggleAvatar.ts Outdated
return error('User not found', 404);
}

const avatarUrl = useGravatar ? getGravatarUrl(currentUser.email) : context.user?.picture;

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

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

When useGravatar is false, the avatar URL is set to context.user?.picture, which could potentially be undefined. This could result in setting the avatar to undefined in the database. Consider adding validation to ensure context.user?.picture exists before allowing the switch, or falling back to generating a Gravatar URL if it's missing.

Suggested change
const avatarUrl = useGravatar ? getGravatarUrl(currentUser.email) : context.user?.picture;
const avatarUrl =
useGravatar || !context.user?.picture
? getGravatarUrl(currentUser.email)
: context.user.picture;

Copilot uses AI. Check for mistakes.
Comment thread src/Me/Routes/Home/Avatar/Avatar.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown

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 4 comments.


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

Comment on lines +47 to +50
const avatarUrl = avatarError && currentUser?.auth0Picture
? currentUser.auth0Picture
: currentUser?.avatar || currentUser?.auth0Picture;

Copilot AI Feb 28, 2026

Copy link

Choose a reason for hiding this comment

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

avatarUrl selection is based on avatarError, but avatarError is never reset. Once an image load fails, the component will keep preferring auth0Picture even after currentUser.avatar changes (e.g., user switches back to Gravatar), which can make the UI appear stuck. Consider resetting avatarError to false when the avatar source changes (e.g., via useEffect on currentUser.avatar) or on successful image load (onLoad).

Copilot uses AI. Check for mistakes.
Comment on lines +100 to +108
handleToggleGravatar = async (newValue) => {
const { updateCurrentUser } = this.context;
const { api } = this.props;

this.setState({ disabled: true });
try {
report('Avatar', newValue ? 'use gravatar' : 'use google profile picture');
const updatedUser = await api.toggleAvatar(newValue);
if (updatedUser) {

Copilot AI Feb 28, 2026

Copy link

Choose a reason for hiding this comment

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

handleToggleGravatar can be triggered repeatedly while a previous request is in-flight (the disabled state is set, but the Switch component isn’t disabled and there’s no early return). This can send concurrent /users/current/avatar requests and leave isUsingGravatar out of sync with the server. Add a guard at the start (e.g., if this.state.disabled return) and/or wire the disabled state into the UI so the toggle can’t be spammed while saving.

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +42
const avatarUrl = useGravatar ? getGravatarUrl(currentUser.email) : context.user?.picture;

const userDto: UserDto = new UserDto({
_id: currentUser._id,
avatar: avatarUrl,
});

Copilot AI Feb 28, 2026

Copy link

Choose a reason for hiding this comment

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

avatarUrl can become undefined when useGravatar is false and context.user.picture is missing. That would overwrite the stored avatar with an empty value and may cause clients to render a broken/blank avatar. Handle the no-picture case explicitly (e.g., return 400, fall back to the current stored avatar, or fall back to a Gravatar URL) before calling upsertUser.

Copilot uses AI. Check for mistakes.
import styled from 'styled-components/macro';
import { useUser } from '../../../../context/userContext/UserContext';
import type { User } from '../../../../types/models';
import Camera from '../../../../assets/me/camera.svg';

Copilot AI Feb 28, 2026

Copy link

Choose a reason for hiding this comment

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

There are unused imports here (useEffect and User). In a TS build with noUnusedLocals/noUnusedParameters enabled, this will fail the build/lint. Remove the unused imports or use them.

Suggested change
import Camera from '../../../../assets/me/camera.svg';

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@moshfeu moshfeu merged commit 5312d8c into master Feb 28, 2026
5 checks passed
@moshfeu moshfeu deleted the gravatar-switch branch February 28, 2026 06:40
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