Skip to content

Conversation

@WojtekBoman
Copy link
Contributor

@WojtekBoman WojtekBoman commented Jan 28, 2026

Explanation of Change

This PR adds the Discover section to HomePage.tsx. It's visible only when selfTourViewed is false.

Wide layout:
Screenshot 2026-01-28 at 17 47 21

Narrow layout:
Screenshot 2026-01-28 at 17 47 48

Fixed Issues

$ #79980
PROPOSAL:

Tests

  • Verify that no errors appear in the JS console

Precondition: access to newDotHome beta

  1. Verify if the text in the section is different if user is a policy admin.
  2. Verify if image/button redirects to storylane.

Offline tests

QA Steps

// TODO: These must be filled out, or the issue title must include "[No QA]."

  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified there are no new alerts related to the canBeMissing param for useOnyx
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I used JaimeGPT to get English > Spanish translation. I then posted it in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

@melvin-bot
Copy link

melvin-bot bot commented Jan 28, 2026

Hey, I noticed you changed src/languages/en.ts in a PR from a fork. For security reasons, translations are not generated automatically for PRs from forks.

If you want to automatically generate translations for other locales, an Expensify employee will have to:

  1. Look at the code and make sure there are no malicious changes.
  2. Run the Generate static translations GitHub workflow. If you have write access and the K2 extension, you can simply click: [this button]

Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running:

npx ts-node ./scripts/generateTranslations.ts --help

Typically, you'd want to translate only what you changed by running npx ts-node ./scripts/generateTranslations.ts --compare-ref main

@WojtekBoman WojtekBoman force-pushed the home-page/discover-section branch from 1797040 to 9c7f847 Compare January 28, 2026 22:38
@WojtekBoman WojtekBoman force-pushed the home-page/discover-section branch from 9c7f847 to 16f423c Compare January 28, 2026 22:41
@WojtekBoman WojtekBoman changed the title Home page/discover section [Home Page] Create DiscoverSection Component Jan 28, 2026
@mountiny
Copy link
Contributor

@codex review

@WojtekBoman WojtekBoman marked this pull request as ready for review January 28, 2026 22:42
@WojtekBoman WojtekBoman requested review from a team as code owners January 28, 2026 22:42
@melvin-bot melvin-bot bot requested review from ZhenjaHorbach and trjExpensify and removed request for a team January 28, 2026 22:42
@melvin-bot
Copy link

melvin-bot bot commented Jan 28, 2026

@ZhenjaHorbach Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@melvin-bot melvin-bot bot removed the request for review from a team January 28, 2026 22:42
@github-actions
Copy link
Contributor

🚧 @mountiny has triggered a test Expensify/App build. You can view the workflow run here.

@OSBotify

This comment has been minimized.


return (
<WidgetContainer title={translate('homePage.announcements')}>
<View style={{height: 400}} />
Copy link
Contributor

Choose a reason for hiding this comment

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

❌ CONSISTENCY-2 (docs)

The hardcoded height value 400 is a magic number without documentation or named constant.

Suggested fix:
Define a named constant for the placeholder height:

const ANNOUNCEMENTS_PLACEHOLDER_HEIGHT = 400;

function AnnouncementsSection() {
    const {translate} = useLocalize();

    return (
        <WidgetContainer title={translate('homePage.announcements')}>
            <View style={{height: ANNOUNCEMENTS_PLACEHOLDER_HEIGHT}} />
        </WidgetContainer>
    );
}

Or add a comment explaining the placeholder:

{/* Placeholder height for announcements section - will be replaced in upcoming PR */}
<View style={{height: 400}} />

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

onPress={handlePress}
style={styles.mb8}
wrapperStyle={styles.pl8}
numberOfLinesTitle={2}
Copy link
Contributor

Choose a reason for hiding this comment

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

❌ CONSISTENCY-2 (docs)

The hardcoded value 2 for numberOfLinesTitle is a magic number without documentation.

Suggested fix:
Define a named constant or add a comment explaining why exactly 2 lines:

const MENU_ITEM_TITLE_MAX_LINES = 2;

<MenuItemWithTopDescription
    shouldShowRightIcon
    title={isCurrentUserPolicyAdmin ? translate('homePage.discoverSection.menuItemTitleAdmin') : translate('homePage.discoverSection.menuItemTitleNonAdmin')}
    description={translate('homePage.discoverSection.menuItemDescription')}
    onPress={handlePress}
    style={styles.mb8}
    wrapperStyle={styles.pl8}
    numberOfLinesTitle={MENU_ITEM_TITLE_MAX_LINES}
/>

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true});
const styles = useThemeStyles();

const handlePress = () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

❌ CONSISTENCY-5 (docs)

The Linking.openURL call lacks error handling. If the URL is malformed or the system cannot open the link, the error will be silent.

Suggested fix:
Add error handling and user feedback:

const handlePress = () => {
    const url = getTestDriveURL(shouldUseNarrowLayout, introSelected, isCurrentUserPolicyAdmin);
    Linking.openURL(url).catch((error) => {
        Log.error('Failed to open test drive URL', error);
        // Optionally show user feedback
    });
};

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

Copy link
Contributor

Choose a reason for hiding this comment

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

Technically correct but inconsistent with existing patterns. The codebase doesn't do this anywhere else.

const {translate} = useLocalize();
const [accountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false, selector: accountIDSelector});

const handleGoToSearch = () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

❌ CONSISTENCY-3 (docs)

The four navigation handler functions (handleGoToSearch, handleGoToApproveSearch, handleGoToPaySearch, handleGoToExportSearch) contain duplicated logic with only minor variations in parameters.

Reasoning: This code duplication increases maintenance overhead. If the navigation pattern or query building logic changes, all four functions need to be updated.

Suggested fix:
Consolidate into a reusable helper function:

const navigateToSearchWithQuery = (queryParams: Record<string, unknown>) => {
    Navigation.navigate(
        ROUTES.SEARCH_ROOT.getRoute({
            query: buildQueryStringFromFilterFormValues(queryParams),
        }),
    );
};

const handleGoToSearch = () => {
    navigateToSearchWithQuery({
        type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT,
        action: CONST.SEARCH.ACTION_FILTERS.SUBMIT,
        from: [`${accountID}`],
    });
};

const handleGoToApproveSearch = () => {
    navigateToSearchWithQuery({
        type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT,
        action: CONST.SEARCH.ACTION_FILTERS.APPROVE,
        to: [`${accountID}`],
    });
};

// Similar pattern for other handlers...

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's okay for now

const styles = useThemeStyles();
const {translate} = useLocalize();
const [isSelfTourViewed = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector, canBeMissing: true});

Copy link
Contributor

Choose a reason for hiding this comment

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

❌ PERF-10 (docs)

The useEffect calling confirmReadyToOpenApp() is used for side effects rather than synchronizing with an external system. This pattern can lead to timing issues and unnecessary complexity.

Reasoning: useEffect should be reserved for synchronizing with external systems (DOM, network, third-party libraries), not for triggering actions on mount. If this needs to run on mount, consider if it belongs in the component at all, or if it should be handled by the parent/router.

Suggested fix:
If this is truly needed on component mount, consider:

  1. Moving this logic to the app initialization layer (where routing happens)
  2. Or if it must stay here, add a comment explaining why useEffect is necessary:
// confirmReadyToOpenApp must be called after HomePage mounts to signal
// that the app is ready to handle deep links and navigation
useEffect(() => {
    confirmReadyToOpenApp();
}, []);

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

</View>
)}
<View style={[styles.flexShrink1, styles.flexGrow1, styles.flexRow, styles.alignItemsCenter, styles.gap2]}>
{!!title && (
Copy link
Contributor

Choose a reason for hiding this comment

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

❌ CONSISTENCY-4 (docs)

The titleColor prop is defined with a default value via the null coalescing operator (titleColor ?? theme.text), but this creates redundancy. If titleColor is optional, it should either:

  1. Have a default value in the function signature, or
  2. Not use the ?? operator if it's meant to be required

Reasoning: The current pattern makes the component API unclear. Is titleColor optional or required? The implementation suggests it's optional, but then the fallback should be in the prop signature.

Suggested fix:

type WidgetContainerProps = {
    /** Custom color for the title text. Defaults to theme.text if not provided */
    titleColor?: string;
    // ... other props
};

function WidgetContainer({
    children,
    icon,
    title,
    titleColor, // Remove the default here
    iconWidth = variables.iconSizeNormal,
    iconHeight = variables.iconSizeNormal,
}: WidgetContainerProps) {
    const styles = useThemeStyles();
    const theme = useTheme();
    
    // Use titleColor or fall back to theme.text
    const actualTitleColor = titleColor ?? theme.text;

    return (
        <View style={styles.widgetContainer}>
            {/* ... */}
            {!!title && (
                <Text style={styles.getWidgetContainerTitleStyle(actualTitleColor)}>{title}</Text>
            )}
        </View>
    );
}

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's a good point, but we don't have access to the theme in the function declaration because it's obtained with the hook

announcements: 'Announcements',
discoverSection: {
title: 'Discover',
menuItemTitleNonAdmin: 'Learn how to create expenses and submit reports',
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to add a period here

@ZhenjaHorbach
Copy link
Contributor

And we have lint issues

@github-actions

This comment has been minimized.

@github-actions
Copy link
Contributor

🚧 @mountiny has triggered a test Expensify/App build. You can view the workflow run here.

@OSBotify
Copy link
Contributor

🦜 Polyglot Parrot! 🦜

Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues:

View the translation diff
diff --git a/src/languages/de.ts b/src/languages/de.ts
index cb882589..ab9aca8e 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -8211,6 +8211,16 @@ Hier ist ein *Testbeleg*, um dir zu zeigen, wie es funktioniert:`,
         },
         fabGpsTripExplained: 'Zur GPS-Ansicht wechseln (Schnellaktion)',
     },
+    homePage: {
+        forYou: 'Für dich',
+        announcements: 'Ankündigungen',
+        discoverSection: {
+            title: 'Entdecken',
+            menuItemTitleNonAdmin: 'Erfahren Sie, wie Sie Ausgaben erstellen und Berichte einreichen.',
+            menuItemTitleAdmin: 'Erfahren Sie, wie Sie Mitglieder einladen, Genehmigungsworkflows bearbeiten und Firmenkarten abstimmen.',
+            menuItemDescription: 'Sehen Sie, was Expensify in 2 Minuten kann',
+        },
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 37cbe700..52e3d950 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -8217,6 +8217,16 @@ Voici un *reçu test* pour vous montrer comment cela fonctionne :`,
         },
         fabGpsTripExplained: 'Aller à l’écran GPS (action flottante)',
     },
+    homePage: {
+        forYou: 'Pour vous',
+        announcements: 'Annonces',
+        discoverSection: {
+            title: 'Découvrir',
+            menuItemTitleNonAdmin: 'Découvrez comment créer des dépenses et soumettre des rapports.',
+            menuItemTitleAdmin: 'Apprenez à inviter des membres, à modifier les circuits d’approbation et à rapprocher les cartes de l’entreprise.',
+            menuItemDescription: 'Découvrez ce qu’Expensify peut faire en 2 minutes',
+        },
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/it.ts b/src/languages/it.ts
index ed81344a..1b17f3cd 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -6987,8 +6987,8 @@ Richiedi dettagli di spesa come ricevute e descrizioni, imposta limiti e valori
                 [CONST.SEARCH.GROUP_BY.CARD]: 'Carta',
                 [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID prelievo', //_/\__/_/  \_,_/\__/\__/\_,_/
                 [CONST.SEARCH.GROUP_BY.CATEGORY]: 'Categoria',
-                [CONST.SEARCH.GROUP_BY.MERCHANT]: 'Commerciante',
-                [CONST.SEARCH.GROUP_BY.TAG]: 'Etichetta',
+                [CONST.SEARCH.GROUP_BY.MERCHANT]: 'Esercente',
+                [CONST.SEARCH.GROUP_BY.TAG]: 'Tag',
                 [CONST.SEARCH.GROUP_BY.MONTH]: 'Mese',
             },
             feed: 'Feed',
@@ -8197,6 +8197,16 @@ Ecco una *ricevuta di prova* per mostrarti come funziona:`,
         },
         fabGpsTripExplained: 'Vai alla schermata GPS (azione flottante)',
     },
+    homePage: {
+        forYou: 'Per te',
+        announcements: 'Annunci',
+        discoverSection: {
+            title: 'Scopri',
+            menuItemTitleNonAdmin: 'Scopri come creare spese e inviare report.',
+            menuItemTitleAdmin: 'Scopri come invitare membri, modificare i flussi di approvazione e riconciliare le carte aziendali.',
+            menuItemDescription: 'Scopri cosa può fare Expensify in 2 minuti',
+        },
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 53da5dd9..6e70da58 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -6923,10 +6923,10 @@ ${reportName}
             reimbursable: '精算対象',
             purchaseCurrency: '購入通貨',
             groupBy: {
-                [CONST.SEARCH.GROUP_BY.FROM]: '送信者',
+                [CONST.SEARCH.GROUP_BY.FROM]: '差出人',
                 [CONST.SEARCH.GROUP_BY.CARD]: 'カード',
                 [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: '出金ID',
-                [CONST.SEARCH.GROUP_BY.CATEGORY]: 'カテゴリー',
+                [CONST.SEARCH.GROUP_BY.CATEGORY]: 'カテゴリ',
                 [CONST.SEARCH.GROUP_BY.MERCHANT]: '加盟店',
                 [CONST.SEARCH.GROUP_BY.TAG]: 'タグ',
                 [CONST.SEARCH.GROUP_BY.MONTH]: '月',
@@ -8110,6 +8110,16 @@ Expensify の使い方をお見せするための*テストレシート*がこ
         },
         fabGpsTripExplained: 'GPS画面へ移動(フローティングアクション)',
     },
+    homePage: {
+        forYou: 'あなた向け',
+        announcements: 'お知らせ',
+        discoverSection: {
+            title: '発見',
+            menuItemTitleNonAdmin: '経費の作成方法とレポートの提出方法を学びましょう。',
+            menuItemTitleAdmin: 'メンバーの招待方法、承認ワークフローの編集方法、会社カードの照合方法について学びましょう。',
+            menuItemDescription: '2 分で Expensify でできることを確認する',
+        },
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 6841f8db..2ddc9f82 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -6970,8 +6970,8 @@ Vraag verplichte uitgavedetails zoals bonnetjes en beschrijvingen, stel limieten
                 [CONST.SEARCH.GROUP_BY.CARD]: 'Kaart',
                 [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'Opname-ID',
                 [CONST.SEARCH.GROUP_BY.CATEGORY]: 'Categorie',
-                [CONST.SEARCH.GROUP_BY.MERCHANT]: 'Verkoper',
-                [CONST.SEARCH.GROUP_BY.TAG]: 'Label',
+                [CONST.SEARCH.GROUP_BY.MERCHANT]: 'Handelaar',
+                [CONST.SEARCH.GROUP_BY.TAG]: 'Tag',
                 [CONST.SEARCH.GROUP_BY.MONTH]: 'Maand',
             },
             feed: 'Feed',
@@ -8173,6 +8173,16 @@ Hier is een *testbon* om je te laten zien hoe het werkt:`,
         },
         fabGpsTripExplained: 'Ga naar GPS-scherm (Zwevende actie)',
     },
+    homePage: {
+        forYou: 'Voor jou',
+        announcements: 'Aankondigingen',
+        discoverSection: {
+            title: 'Ontdek',
+            menuItemTitleNonAdmin: 'Leer hoe je uitgaven aanmaakt en rapporten indient.',
+            menuItemTitleAdmin: 'Leer hoe u leden uitnodigt, goedkeuringsworkflows bewerkt en bedrijfskaarten afstemt.',
+            menuItemDescription: 'Ontdek wat Expensify in 2 minuten kan doen',
+        },
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 4f135c5c..d5865831 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -8159,6 +8159,16 @@ Oto *paragon testowy*, który pokazuje, jak to działa:`,
         },
         fabGpsTripExplained: 'Przejdź do ekranu GPS (przycisk akcji)',
     },
+    homePage: {
+        forYou: 'Dla ciebie',
+        announcements: 'Ogłoszenia',
+        discoverSection: {
+            title: 'Odkryj',
+            menuItemTitleNonAdmin: 'Dowiedz się, jak tworzyć wydatki i składać raporty.',
+            menuItemTitleAdmin: 'Dowiedz się, jak zapraszać członków, edytować przepływy akceptacji i uzgadniać karty firmowe.',
+            menuItemDescription: 'Zobacz, co Expensify potrafi w 2 minuty',
+        },
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index f1d837ef..0f08e19e 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -6960,7 +6960,7 @@ Exija detalhes de despesas como recibos e descrições, defina limites e padrõe
                 [CONST.SEARCH.GROUP_BY.CARD]: 'Cartão',
                 [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID da retirada',
                 [CONST.SEARCH.GROUP_BY.CATEGORY]: 'Categoria',
-                [CONST.SEARCH.GROUP_BY.MERCHANT]: 'Comerciante',
+                [CONST.SEARCH.GROUP_BY.MERCHANT]: 'Estabelecimento',
                 [CONST.SEARCH.GROUP_BY.TAG]: 'Etiqueta',
                 [CONST.SEARCH.GROUP_BY.MONTH]: 'Mês',
             },
@@ -8168,6 +8168,16 @@ Aqui está um *recibo de teste* para mostrar como funciona:`,
         },
         fabGpsTripExplained: 'Ir para a tela de GPS (Ação flutuante)',
     },
+    homePage: {
+        forYou: 'Para você',
+        announcements: 'Anúncios',
+        discoverSection: {
+            title: 'Descobrir',
+            menuItemTitleNonAdmin: 'Aprenda a criar despesas e enviar relatórios.',
+            menuItemTitleAdmin: 'Aprenda a convidar membros, editar fluxos de aprovação e reconciliar cartões corporativos.',
+            menuItemDescription: 'Veja o que o Expensify pode fazer em 2 minutos',
+        },
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 0203fdfc..a78ef128 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -6804,10 +6804,10 @@ ${reportName}
             purchaseCurrency: '购买货币',
             groupBy: {
                 [CONST.SEARCH.GROUP_BY.FROM]: '来自',
-                [CONST.SEARCH.GROUP_BY.CARD]: '卡片',
-                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: '提现 ID',
+                [CONST.SEARCH.GROUP_BY.CARD]: '卡',
+                [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: '提现编号',
                 [CONST.SEARCH.GROUP_BY.CATEGORY]: '类别',
-                [CONST.SEARCH.GROUP_BY.MERCHANT]: '商家',
+                [CONST.SEARCH.GROUP_BY.MERCHANT]: '商户',
                 [CONST.SEARCH.GROUP_BY.TAG]: '标签',
                 [CONST.SEARCH.GROUP_BY.MONTH]: '月',
             },
@@ -7933,6 +7933,16 @@ ${reportName}
         locationServicesRequiredModal: {title: '需要访问位置信息', confirm: '打开设置', prompt: '请在设备设置中允许位置访问,以开始 GPS 距离跟踪。'},
         fabGpsTripExplained: '前往 GPS 屏幕(悬浮操作)',
     },
+    homePage: {
+        forYou: '为你',
+        announcements: '公告',
+        discoverSection: {
+            title: '发现',
+            menuItemTitleNonAdmin: '了解如何创建费用并提交报表。',
+            menuItemTitleAdmin: '了解如何邀请成员、编辑审批流程以及对公司卡进行对账。',
+            menuItemDescription: '看看 Expensify 在 2 分钟内能为你做什么',
+        },
+    },
 };
 // IMPORTANT: This line is manually replaced in generate translation files by scripts/generateTranslations.ts,
 // so if you change it here, please update it there as well.

Note

You can apply these changes to your branch by copying the patch to your clipboard, then running pbpaste | git apply 😉

@dubielzyk-expensify
Copy link
Contributor

The card keeps flickering out in the test build. Also we wanna reduce the bottom padding of the card by like 12px (I'll find the real value once I can use web inspector)

@mountiny
Copy link
Contributor

ios looks good!

Screenshot 2026-01-28 at 16 35 41

@mountiny
Copy link
Contributor

Prettier failing

Comment on lines +739 to +744
discoverSection: {
title: 'Descubrir',
menuItemTitleNonAdmin: 'Aprende a crear gastos y enviar informes.',
menuItemTitleAdmin: 'Aprende a invitar a miembros, editar flujos de aprobación y conciliar tarjetas corporativas.',
menuItemDescription: 'Descubre lo que Expensify puede hacer en 2 minutos',
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets confirm these @JmillsExpensify

@mountiny mountiny merged commit 183fcad into Expensify:main Jan 29, 2026
30 checks passed
@dubielzyk-expensify
Copy link
Contributor

Just a note that I cleared the mobile padding issues in person so that'll be a follow-up

@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@shawnborton
Copy link
Contributor

And I think we want the second line here to be bold, too:
CleanShot 2026-01-29 at 07 16 32@2x

We should update the UI screenshot here to include the new sidebar navigation too 🤣
CleanShot 2026-01-29 at 07 17 27@2x

@grgia
Copy link
Contributor

grgia commented Jan 29, 2026

@shawnborton @dubielzyk-expensify @WojtekBoman

I made a follow up issue here

#80873

@shawnborton
Copy link
Contributor

Wonderful, thanks!

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by https://github.com/mountiny in version: 9.3.11-16 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

@jponikarchuk
Copy link

@WojtekBoman @mountiny @ZhenjaHorbach Could you please add a precondition how to get a Discover Section with a new Expensify account?

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.

9 participants