Skip to content

[Tracking][New Feature][Avatar] - Expensify Avatar Customization #71653

@grgia

Description

@grgia

Mini Feature: Custom Expensify Avatars [OCT 20 DEADLINE]

Background

[Slack convo]

Mini-feature request: Build an avatar customization page.

Figma

User has not set avatar (using a default):
Image

Using has a custom avatar:
Image

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.
Image

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

  1. 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
  1. 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:
    - Add AvatarPage to the settings navigator.
    - Add a link from ProfilePage.tsx to this new page.

  2. Create: /src/pages/settings/Profile/Avatar/AvatarGenerator.tsx - dedicated component to render the selected avatar for capturing
    - Render the selected SVG: use existingAvatar component/react-native-svg- Pass the user's selected color as a fill prop to the SVG component.
    - Capture the view: use exisiting react-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 existing UpdateUserAvatar action. Convert the image URI from the generator into a file object, similar to how it's done in ProfilePage.js for photo library uploads.

Assets:

  • Create src/components/Icon/CustomAvatars.ts.
    - All existing user avatars are in src/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

App/src/libs/ReportUtils.ts

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

    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

Sub-issues

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions