-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Mini Feature: Custom Expensify Avatars [OCT 20 DEADLINE]
Background
Mini-feature request: Build an avatar customization page.
Figma
User has not set avatar (using a default):

User will see various pre-existing options and options using the first letter of their first name. Not set or if SMS log in, we will not show these options.

Video Mock
CleanShot.2025-10-01.at.14.52.34.mp4
Detailed Design Constraints [OUTDATED - Pending update as of Oct 2 11am BST]
Due to the nature of this feature (NON-CRITICAL), we will limit scope and complexity. The design is actively being discussed.
Page Details
Route:
<*>new.expensify.com:8082/settings/profile/avatar
Components
- Move existing avatar components into a new folder for organization
- Old:
/src/pages/settings/Profile/ProfileAvatar.tsx - New:
/src/pages/settings/Profile/Avatar/ProfileAvatar.tsx
-
Create:
/src/pages/settings/Profile/Avatar/AvatarPage.tsx- page for updating the profile picture
- Build the UI with a preview, an avatar grid, and a color selector.
- Manage user's selection in local state.
- On "Save", call the generator and the upload action.
Navigation:
- AddAvatarPageto the settings navigator.
- Add a link fromProfilePage.tsxto this new page. -
Create:
/src/pages/settings/Profile/Avatar/AvatarGenerator.tsx- dedicated component to render the selected avatar for capturing
- Render the selected SVG: use existingAvatarcomponent/react-native-svg- Pass the user's selected color as a fill prop to the SVG component.
- Capture the view: use exisitingreact-native-view-shot- Wrap in<ViewShot>component and capture View as a 400x400 png.
- Generate the image: Expose a capture function via ref that returns the image file URI.
- Upload the image: Use the existingUpdateUserAvataraction. Convert the image URI from the generator into a file object, similar to how it's done inProfilePage.jsfor photo library uploads.
Assets:
-
Create
src/components/Icon/CustomAvatars.ts.
- All existing user avatars are insrc/components/Icon/DefaultAvatars.ts.
- Import all new icon options to use in this file -
For the custom initial avatar:
How we grab A-Z for workspace
https://github.com/Expensify/App/blob/4f2680eeda2a101bad5362c96e557ca814114de0/src/components/Icon/WorkspaceDefaultAvatars.ts
How we fetch workspace SVG
Lines 2787 to 2805 in 4f2680e
| /** | |
| * Helper method to return the default avatar associated with the given login | |
| */ | |
| function getDefaultWorkspaceAvatar(workspaceName?: string): React.FC<SvgProps> { | |
| if (!workspaceName) { | |
| return defaultWorkspaceAvatars.WorkspaceBuilding; | |
| } | |
| // Remove all chars not A-Z or 0-9 including underscore | |
| const alphaNumeric = workspaceName | |
| .normalize('NFD') | |
| .replace(/[^0-9a-z]/gi, '') | |
| .toUpperCase(); | |
| const workspace = `Workspace${alphaNumeric[0]}` as keyof typeof defaultWorkspaceAvatars; | |
| const defaultWorkspaceAvatar = defaultWorkspaceAvatars[workspace]; | |
| return !alphaNumeric ? defaultWorkspaceAvatars.WorkspaceBuilding : defaultWorkspaceAvatar; | |
| } |
-
We can create color map similar to
Lines 54 to 73 in fa5e06d
const workspaceColorOptions: SVGAvatarColorStyle[] = [ {backgroundColor: colors.blue200, fill: colors.blue700}, {backgroundColor: colors.blue400, fill: colors.blue800}, {backgroundColor: colors.blue700, fill: colors.blue200}, {backgroundColor: colors.green200, fill: colors.green700}, {backgroundColor: colors.green400, fill: colors.green800}, {backgroundColor: colors.green700, fill: colors.green200}, {backgroundColor: colors.yellow200, fill: colors.yellow700}, {backgroundColor: colors.yellow400, fill: colors.yellow800}, {backgroundColor: colors.yellow700, fill: colors.yellow200}, {backgroundColor: colors.tangerine200, fill: colors.tangerine700}, {backgroundColor: colors.tangerine400, fill: colors.tangerine800}, {backgroundColor: colors.tangerine700, fill: colors.tangerine400}, {backgroundColor: colors.pink200, fill: colors.pink700}, {backgroundColor: colors.pink400, fill: colors.pink800}, {backgroundColor: colors.pink700, fill: colors.pink200}, {backgroundColor: colors.ice200, fill: colors.ice700}, {backgroundColor: colors.ice400, fill: colors.ice800}, {backgroundColor: colors.ice700, fill: colors.ice200}, ]; -
See how we color workspace SVGs here
