Skip to content

[Due for Payment 2026-05-18] [$250] Android - Workspace - Currency symbol disappear for some currencies after selecting different currency #76996

Closed

Description

@jponikarchuk

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 9.2.73-0
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from BrowserStack: https://test-management.browserstack.com/projects/2219752/test-runs/TR-2305/folder/13177080/41237927/1060193274?p=2
Email or phone of affected tester (no customers): kiatest.78+ck12525100@gmail.com
Issue reported by: Applause Internal Team
Bug source: Regression TC Execution
Device used: Pixel 8a/Android 16
App Component: Workspace Settings

Action Performed:

  1. Launch Hybrid app
  2. Create new workspace
  3. Go to Workspace settings >> Overview page
  4. Select default currency option
  5. Scroll down the list & observe currency icons displayed for all regions (Note: Sometime currency icon missing for VND or XAF
  6. Select a different currency which has symbol
  7. Select default currency option and srcoll the list

Expected Result:

Currency symbol should not disappear for some currencies after selecting different currency

Actual Result:

Currency symbol disappear for some currencies (AFN, ALL< ANG, AWG, VND, XOF, XAF) after selecting different currency

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

1.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021999574703930541403
  • Upwork Job ID: 1999574703930541403
  • Last Price Increase: 2026-01-02
  • Automatic offers:
    • abzokhattab | Reviewer | 110008674
Issue OwnerCurrent Issue Owner: @abzokhattab

Activity

  1. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Dec 8, 2025
  2. melvin-bot commented on Dec 8, 2025

    @melvin-bot

    Triggered auto assignment to @lydiabarclay (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

  3. abbasifaizan70 commented on Dec 8, 2025

    @abbasifaizan70
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    In the Android app, when selecting a default currency in workspace settings, currency symbols disappear for certain currencies (AFN, ALL, ANG, AWG, VND, XOF, XAF) after selecting a different currency and then reopening the currency selection list.

    What is the root cause of that problem?

    The CurrencySelectionList component uses getCurrencySymbol() function from CurrencyUtils.ts to retrieve currency symbols. This function relies on a module-level currencyList variable that is updated via an Onyx connection callback.

    However, the component also uses useOnyx hook to get the currencyList directly. When a currency is selected and the component re-renders, there's a timing issue where:

    1. The useMemo hook recalculates the currency options using the currencyList from useOnyx
    2. But getCurrencySymbol() accesses the module-level currencyList variable which may be stale or not yet synchronized
    3. This causes getCurrencySymbol() to return undefined for some currencies, resulting in missing symbols

    The root cause is a mismatch between the reactive currencyList from useOnyx hook and the module-level cached currencyList used by getCurrencySymbol(). After a currency selection triggers a re-render, the module-level cache may not be immediately updated, causing symbols to disappear.

    What changes do you think we should make in order to solve the problem?

    Replace the getCurrencySymbol() function calls with direct access to the currencyList from the useOnyx hook in the CurrencySelectionList component. This ensures we're always using the most up-to-date currency data that's already available in the component.

    File: App/src/components/CurrencySelectionList/index.tsx

    1. Remove the import of getCurrencySymbol:

      • Remove: import {getCurrencySymbol} from '@libs/CurrencyUtils';
    2. Update the currency options mapping to use currencyInfo?.symbol directly:

      • Change: text: \${currencyCode} - ${getCurrencySymbol(currencyCode)}``
      • To: text: \${currencyCode} - ${currencyInfo?.symbol ?? ''}``
    3. Update the recently used currencies mapping similarly:

      • Change: text: \${currencyCode} - ${getCurrencySymbol(currencyCode)}``
      • To: text: \${currencyCode} - ${currencyInfo?.symbol ?? ''}``

    Why this works:

    1. Eliminates timing issues: Uses the same currencyList data that's already available in the component via useOnyx, ensuring consistency
    2. Reactive updates: The currencyList from useOnyx is automatically updated when Onyx data changes, so symbols will always reflect the current state
    3. Simpler code: Removes dependency on the module-level cache and uses the data source directly
    4. No breaking changes: The component already has access to currencyList and currencyInfo, so this is just using the data more directly

    What alternative solutions did you explore? (Optional)

    None

  4. lorretheboy commented on Dec 8, 2025

    @lorretheboy
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    Currency symbol disappear for some currencies (AFN, ALL< ANG, AWG, VND, XOF, XAF) after selecting different currency

    What is the root cause of that problem?

    It is due to Onyx Data Synchronization Race Condition. The components were calling getCurrencySymbol(currencyCode) which relies on a module-level variable (currencyList) in CurrencyUtils.ts that is populated via a separate Onyx connection

    let currencyList: OnyxValues[typeof ONYXKEYS.CURRENCY_LIST] = {};
    Onyx.connect({
    key: ONYXKEYS.CURRENCY_LIST,
    callback: (val) => {
    if (!val || Object.keys(val).length === 0) {
    return;
    }
    currencyList = val;
    },
    });

    What changes do you think we should make in order to solve the problem?

    We should update to use direct data from currency

                    options.push({text: `${currencyCode} - ${currencyList?.[currencyCode]?.symbol ?? ''}`, value: currencyCode});

    options.push({text: `${currencyCode} - ${getCurrencySymbol(currencyCode)}`, value: currencyCode});

     import useOnyx from '@hooks/useOnyx';
     import useThemeStyles from '@hooks/useThemeStyles';
     import {updateAdvancedFilters} from '@libs/actions/Search';
    -import {getCurrencySymbol} from '@libs/CurrencyUtils';
     import Navigation from '@libs/Navigation/Navigation';
     import type {TranslationPaths} from '@src/languages/types';
     import ONYXKEYS from '@src/ONYXKEYS';
    @@ -39,16 +38,18 @@ function SearchFiltersCurrencyBase({title, filterKey, multiselect = false}: Sear
                     continue;
                 }
     
    +            const currencySymbol = currencyList?.[currencyCode]?.symbol ?? '';
    +
                 if (Array.isArray(selectedCurrencyData) && selectedCurrencyData?.includes(currencyCode) && !selectedCurrencies.some((currencyItem) => currencyItem.value === currencyCode)) {
    -                selectedCurrencies.push({name: `${currencyCode} - ${getCurrencySymbol(currencyCode)}`, value: currencyCode});
    +                selectedCurrencies.push({name: `${currencyCode} - ${currencySymbol}`, value: currencyCode});
                 }
     
                 if (!Array.isArray(selectedCurrencyData) && selectedCurrencyData === currencyCode) {
    -                selectedCurrencies.push({name: `${currencyCode} - ${getCurrencySymbol(currencyCode)}`, value: currencyCode});
    +                selectedCurrencies.push({name: `${currencyCode} - ${currencySymbol}`, value: currencyCode});
                 }
     
                 if (!currencies.some((item) => item.value === currencyCode)) {
    -                currencies.push({name: `${currencyCode} - ${getCurrencySymbol(currencyCode)}`, value: currencyCode});
    +                currencies.push({name: `${currencyCode} - ${currencySymbol}`, value: currencyCode});
                 }
             }

    function SearchFiltersCurrencyBase({title, filterKey, multiselect = false}: SearchFiltersCurrencyBaseProps) {

     import useOnyx from '@hooks/useOnyx';
    -import {getCurrencySymbol} from '@libs/CurrencyUtils';
     import getMatchScore from '@libs/getMatchScore';
     import ONYXKEYS from '@src/ONYXKEYS';
     import {isEmptyObject} from '@src/types/utils/EmptyObject';
    @@ -32,7 +31,7 @@ function CurrencySelectionList({
                 if (!excludedCurrencies.includes(currencyCode) && (isSelectedCurrency || !currencyInfo?.retired)) {
                     acc.push({
                         currencyName: currencyInfo?.name ?? '',
    -                    text: `${currencyCode} - ${getCurrencySymbol(currencyCode)}`,
    +                    text: `${currencyCode} - ${currencyInfo?.symbol ?? ''}`,
                         currencyCode,
                         keyForList: currencyCode,
                         isSelected: isSelectedCurrency,
    @@ -47,7 +46,7 @@ function CurrencySelectionList({
                       const isSelectedCurrency = currencyCode === initiallySelectedCurrencyCode;
                       return {
                           currencyName: currencyInfo?.name ?? '',
    -                      text: `${currencyCode} - ${getCurrencySymbol(currencyCode)}`,
    +                      text: `${currencyCode} - ${currencyInfo?.symbol ?? ''}`,
                           currencyCode,
                           keyForList: currencyCode,
                           isSelected: isSelectedCurrency,

    function CurrencySelectionList({

    What alternative solutions did you explore? (Optional)

    We should subscribe to ONYXKEYS.CURRENCY_LIST using useOnyx, then pass data from parent component to getCurrencySymbol function

    Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.

  5. melvin-bot commented on Dec 12, 2025

    @melvin-bot

    @lydiabarclay Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

  6. added
    ExternalAdded to denote the issue can be worked on by a contributor
    on Dec 12, 2025
  7. changed the title [-]Android - Workspace - Currency symbol disappear for some currencies after selecting different currency[/-] [+][$250] Android - Workspace - Currency symbol disappear for some currencies after selecting different currency[/+] on Dec 12, 2025
  8. melvin-bot commented on Dec 12, 2025

    @melvin-bot
  9. added
    Help WantedApply this label when an issue is open to proposals by contributors
    on Dec 12, 2025
  10. melvin-bot commented on Dec 12, 2025

    @melvin-bot

    Triggered auto assignment to Contributor-plus team member for initial proposal review - @abzokhattab (External)

  11. 63 remaining items

  12. Eskalifer1 commented on May 11, 2026

    @Eskalifer1
    Contributor

    Hi everyone!

    Can we ask the QA team to test this issue again? I can't reproduce this bug on the latest main branch.

    It seems that the bug was fixed using a similar approach to the one I suggested, specifically by completely removing isMultilineSupported from the SelectionList component:

    function SelectionList<TItem extends ListItem>(props: SelectionListWithSectionsProps<TItem>) {
    return (
    <BaseSelectionList
    // Props spreading is necessary here to pass through all SelectionList props while adding native-specific behavior
    // eslint-disable-next-line react/jsx-props-no-spreading
    {...props}
    onScrollBeginDrag={Keyboard.dismiss}
    />
    );
    }

    Meanwhile, in my proposal, I suggested setting the isRowMultilineSupported value to false (which is equivalent to no value) for the currency list, and keeping the existing logic for everything else to avoid breaking anything.

    And in this PR, this value is already set to false by default, which means that the line is no longer considered multiline, so the bug doesn’t reproduce:
    #83561

    cc: @mallenexpensify @abzokhattab @srikarparsi

  13. mallenexpensify commented on May 12, 2026

    @mallenexpensify
    Contributor

    retest requested

  14. m-natarajan commented on May 13, 2026

    @m-natarajan

    Issue not reproducible using build v9.3.70-6

    2026-05-13.7.33.35.AM.mp4
  15. Eskalifer1 commented on May 14, 2026

    @Eskalifer1
    Contributor

    Hi @mallenexpensify we are good to pay and close here!

  16. mallenexpensify commented on May 19, 2026

    @mallenexpensify
    Contributor

    Payment Summary

    Contributor: @Eskalifer1 paid $250 via Upwork
    Contributor+: @abzokhattab due $125 Newdot.

    @Eskalifer1 can you please accept the job below? Please reply here and tag me once you have.
    https://www.upwork.com/jobs/~021999574703930541403

    @abzokhattab You want to be paid via Upwork or NewDot? Looks like you were hired in Upwork, your eligibility date was last year so we can pay via NewDot if you prefer. $125 cuz you didn't do tests on the PR.

    Hi @mallenexpensify we are good to pay and close here!

    For edge cases, please provide more details, it can take a while to look through issues and PRs.

  17. changed the title [-][HOLD FOR #76531] [$250] Android - Workspace - Currency symbol disappear for some currencies after selecting different currency[/-] [+][Due for Payment 2026-05-18] [$250] Android - Workspace - Currency symbol disappear for some currencies after selecting different currency[/+] on May 19, 2026
  18. abzokhattab commented on May 20, 2026

    @abzokhattab
    Contributor

    Thanks Matt @mallenexpensify ... i would prefer to receive it on newdot

  19. mallenexpensify commented on May 20, 2026

    @mallenexpensify
    Contributor

    @Eskalifer1 and @abzokhattab paid, summary updated above. Thx.

  20. quinthar commented on Jun 13, 2026

    @quinthar
    Contributor

    Approved $125 to @abzokhattab

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugSomething is broken. Auto assigns a BugZero manager.ExternalAdded to denote the issue can be worked on by a contributorNot a priorityReviewingHas a PR in reviewWeeklyKSv2

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions