feat(edit-profile): allow switch gravar / Google avatar picture#1001
feat(edit-profile): allow switch gravar / Google avatar picture#1001
Conversation
There was a problem hiding this comment.
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
getAvatarUrlhelper 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.
| @@ -1,14 +1,17 @@ | |||
| import React, { FC } from 'react'; | |||
| import React, { FC, useState, useEffect } from 'react'; | |||
There was a problem hiding this comment.
The useEffect import is unused in this file. It should be removed from the imports to keep the code clean.
| import React, { FC, useState, useEffect } from 'react'; | |
| import React, { FC, useState } from 'react'; |
| import React, { FC, useState, useEffect } from 'react'; | ||
| import styled from 'styled-components/macro'; | ||
| import { useUser } from '../../../../context/userContext/UserContext'; | ||
| import type { User } from '../../../../types/models'; |
There was a problem hiding this comment.
The User type import is unused in this file. It should be removed from the imports to keep the code clean.
| import type { User } from '../../../../types/models'; |
| user: fromMtoVM(this.context.currentUser), | ||
| errors: [], | ||
| agree: false, | ||
| isUsingGravatar: this.context.currentUser?.avatar?.includes('gravatar.com') || false, |
There was a problem hiding this comment.
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.
| return null; | ||
| } | ||
|
|
||
| const isUsingGravatar = currentUser.avatar?.includes('gravatar.com') || false; |
There was a problem hiding this comment.
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.
| const isUsingGravatar = currentUser.avatar?.includes('gravatar.com') || false; | |
| const isUsingGravatar = | |
| !!currentUser.avatar && | |
| !!(currentUser as User).auth0Picture && | |
| currentUser.avatar !== (currentUser as User).auth0Picture; |
| const avatarUrl = useGravatar ? getGravatarUrl(currentUser.email) : context.user?.picture; | ||
|
|
There was a problem hiding this comment.
The backend handler should validate that the user is a Google OAuth user before allowing them to switch to their Google profile picture. Currently, any user can call this endpoint with useGravatar=false, which would set their avatar to context.user?.picture even if they're not a Google OAuth user. Consider adding validation similar to the frontend's isGoogleOAuthUser check to ensure only Google OAuth users can switch to their Google profile picture.
| const avatarUrl = useGravatar ? getGravatarUrl(currentUser.email) : context.user?.picture; | |
| const isGoogleOAuthUser = auth0Id.startsWith('google-oauth2|'); | |
| if (!useGravatar) { | |
| if (!isGoogleOAuthUser || !context.user?.picture) { | |
| return error( | |
| 'Switching to Google profile picture is only allowed for Google OAuth users.', | |
| 400 | |
| ); | |
| } | |
| } | |
| const avatarUrl = useGravatar ? getGravatarUrl(currentUser.email) : context.user.picture; |
| return error('User not found', 404); | ||
| } | ||
|
|
||
| const avatarUrl = useGravatar ? getGravatarUrl(currentUser.email) : context.user?.picture; |
There was a problem hiding this comment.
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.
| const avatarUrl = useGravatar ? getGravatarUrl(currentUser.email) : context.user?.picture; | |
| const avatarUrl = | |
| useGravatar || !context.user?.picture | |
| ? getGravatarUrl(currentUser.email) | |
| : context.user.picture; |
| @@ -1,14 +1,17 @@ | |||
| import React, { FC } from 'react'; | |||
| import React, { FC, useState, useEffect } from 'react'; | |||
There was a problem hiding this comment.
Unused import useEffect.
| import React, { FC, useState, useEffect } from 'react'; | |
| import React, { FC } from 'react'; |
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:
/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]Frontend changes:
AvatarFieldand updates toAvatar.tsxandEditProfile.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]getAvatarUrlhelper, 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:
Demo
Screen.Recording.2026-01-29.at.0.52.52.mov