Skip to content

Update system message CREATED_REPORT_FOR_UNAPPROVED_TRANSACTIONS when original report is deleted #81283

Merged
cristipaval merged 17 commits intoExpensify:mainfrom
hoangzinh:fix/show-reportid-when-report-deleted
Mar 4, 2026
Merged

Update system message CREATED_REPORT_FOR_UNAPPROVED_TRANSACTIONS when original report is deleted #81283
cristipaval merged 17 commits intoExpensify:mainfrom
hoangzinh:fix/show-reportid-when-report-deleted

Conversation

@hoangzinh
Copy link
Contributor

@hoangzinh hoangzinh commented Feb 3, 2026

Explanation of Change

Based on this discussion #79411 (comment), we need to update the current system message to include a plain text report ID when the original report is deleted, instead of an anchor link to the original report.

  • When the original report still exists
    created this report for any held expenses from <a href="${reportUrl}">${reportName}</a>

  • When the original report is deleted
    created this report for any held expenses from deleted report #${reportID}

Fixed Issues

$ #79411
PROPOSAL:

Tests

Same as QA

  • Verify that no errors appear in the JS console

Offline tests

Same as QA

QA Steps

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

  1. Sign in ND
  2. Go to workspace chat
  3. Submit 2 expenses
  4. Hold one of them
  5. Tap the "Approve" button => Only approve unheld expenses
  6. Verify that the held expenses are moved to a new report
  7. Delete the original iou report in step 3
  8. Open the report that was created in step 6
  9. Verify that the report displays a message with a plain text reportID
    created this report for any held expenses from deleted report #{reportID}
  • 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
    • 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
Screen.Recording.2026-02-03.at.17.27.02.android.mov
Android: mWeb Chrome
Screen.Recording.2026-02-03.at.17.34.15.android.c.mov
iOS: Native
Screen.Recording.2026-02-04.at.11.37.50.mov
iOS: mWeb Safari
Screen.Recording.2026-02-04.at.09.06.45.ios.s.mov

…message

When a report is deleted, reportName becomes empty causing an empty anchor link.
This change displays the plain reportID (e.g., #123456) instead when reportName
is not available, ensuring the message remains meaningful across all languages.
@melvin-bot
Copy link

melvin-bot bot commented Feb 3, 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

@hoangzinh
Copy link
Contributor Author

@cristipaval can you help to trigger translation workflow here? Thank you.

@OSBotify

This comment has been minimized.

- Add "deleted report" text when reportName is empty across all language files
- Update test to verify "deleted report" text is included
@hoangzinh
Copy link
Contributor Author

hoangzinh commented Feb 3, 2026

@cristipaval can you help to trigger another translation workflow here? I just updated the translation message. Please wait me a bit. I need to rethink about my solution

Changed from embedded ternary to complete separate sentences for better
translation quality. Translators now see full context for both cases:
- When report exists: link with report name
- When report deleted: text with reportID

This improves translation accuracy across all 10 languages.
@hoangzinh
Copy link
Contributor Author

@cristipaval when you have a moment, can you help to trigger translation workflow here? I just updated the message again

@OSBotify
Copy link
Contributor

OSBotify commented Feb 4, 2026

🦜 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 422b5377..4e8ff424 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -927,8 +927,8 @@ const translations: TranslationDeepObject<typeof en> = {
             `hat diesen Bericht erstellt, um alle Ausgaben aus <a href="${reportUrl}">${reportName}</a> aufzunehmen, die nicht mit der von dir gewählten Häufigkeit eingereicht werden konnten`,
         createdReportForUnapprovedTransactions: ({reportUrl, reportName, reportID, isReportDeleted}: CreatedReportForUnapprovedTransactionsParams) =>
             isReportDeleted
-                ? `erstellte diesen Bericht für alle zurückgehaltenen Ausgaben aus gelöschtem Bericht #${reportID}`
-                : `erstellte diesen Bericht für alle zurückgehaltenen Ausgaben aus <a href="${reportUrl}">${reportName}</a>`,
+                ? `hat diesen Bericht für alle zurückgehaltenen Ausgaben aus dem gelöschten Bericht #${reportID} erstellt`
+                : `hat diesen Bericht für alle zurückgehaltenen Ausgaben aus <a href="${reportUrl}">${reportName}</a> erstellt`,
     },
     mentionSuggestions: {
         hereAlternateText: 'Alle in dieser Unterhaltung benachrichtigen',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 094e0cb8..2fb2b0d2 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -931,8 +931,8 @@ const translations: TranslationDeepObject<typeof en> = {
             `a créé cette note de frais pour regrouper toutes les dépenses de <a href="${reportUrl}">${reportName}</a> qui n'ont pas pu être soumises à la fréquence que vous avez choisie`,
         createdReportForUnapprovedTransactions: ({reportUrl, reportName, reportID, isReportDeleted}: CreatedReportForUnapprovedTransactionsParams) =>
             isReportDeleted
-                ? `a créé cette note de frais pour toutes les dépenses en attente de rapport supprimé #${reportID}`
-                : `a créé cette note de frais pour toutes les dépenses en attente de <a href="${reportUrl}">${reportName}</a>`,
+                ? `a créé cette note de frais pour toutes les dépenses retenues de la note de frais supprimée n°${reportID}`
+                : `a créé cette note de frais pour toutes les dépenses retenues provenant de <a href="${reportUrl}">${reportName}</a>`,
     },
     mentionSuggestions: {
         hereAlternateText: 'Notifier tout le monde dans cette conversation',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index d9d84c7a..7f05698d 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -927,7 +927,7 @@ const translations: TranslationDeepObject<typeof en> = {
             `ha creato questo report per raccogliere tutte le spese da <a href="${reportUrl}">${reportName}</a> che non potevano essere inviate con la frequenza scelta`,
         createdReportForUnapprovedTransactions: ({reportUrl, reportName, reportID, isReportDeleted}: CreatedReportForUnapprovedTransactionsParams) =>
             isReportDeleted
-                ? `ha creato questo report per tutte le spese in sospeso da report eliminato #${reportID}`
+                ? `ha creato questo rendiconto per tutte le spese in sospeso dal rendiconto eliminato n. ${reportID}`
                 : `ha creato questo report per tutte le spese in sospeso da <a href="${reportUrl}">${reportName}</a>`,
     },
     mentionSuggestions: {
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 09dcf0b3..94854bd1 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -923,8 +923,8 @@ const translations: TranslationDeepObject<typeof en> = {
             `選択した頻度で提出できなかった、<a href="${reportUrl}">${reportName}</a> のすべての経費を保持するためにこのレポートを作成しました`,
         createdReportForUnapprovedTransactions: ({reportUrl, reportName, reportID, isReportDeleted}: CreatedReportForUnapprovedTransactionsParams) =>
             isReportDeleted
-                ? `削除されたレポート #${reportID} から保留中の経費を対象としてこのレポートを作成しました`
-                : `<a href="${reportUrl}">${reportName}</a> から保留中の経費を対象としてこのレポートを作成しました`,
+                ? `削除されたレポート #${reportID} に保留されていた経費のためにこのレポートを作成しました`
+                : `<a href="${reportUrl}">${reportName}</a> の保留中経費すべてに対してこのレポートを作成しました`,
     },
     mentionSuggestions: {
         hereAlternateText: 'この会話の全員に通知',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 1ba072ef..466d374b 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -926,8 +926,8 @@ const translations: TranslationDeepObject<typeof en> = {
             `heeft dit rapport gemaakt om alle uitgaven van <a href="${reportUrl}">${reportName}</a> te bewaren die niet konden worden ingediend op de door jou gekozen frequentie`,
         createdReportForUnapprovedTransactions: ({reportUrl, reportName, reportID, isReportDeleted}: CreatedReportForUnapprovedTransactionsParams) =>
             isReportDeleted
-                ? `heeft dit rapport gemaakt voor uitgestelde uitgaven van verwijderd rapport #${reportID}`
-                : `heeft dit rapport gemaakt voor uitgestelde uitgaven van <a href="${reportUrl}">${reportName}</a>`,
+                ? `heeft dit rapport gemaakt voor alle vastgehouden uitgaven uit verwijderd rapport nr. ${reportID}`
+                : `heeft dit rapport gemaakt voor alle vastgehouden uitgaven van <a href="${reportUrl}">${reportName}</a>`,
     },
     mentionSuggestions: {
         hereAlternateText: 'Laat iedereen in dit gesprek een melding krijgen',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index f4d85a7f..257b492e 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -927,8 +927,8 @@ const translations: TranslationDeepObject<typeof en> = {
             `utworzył(-a) ten raport, aby zawierał wszystkie wydatki z <a href="${reportUrl}">${reportName}</a>, których nie można było złożyć z wybraną przez Ciebie częstotliwością`,
         createdReportForUnapprovedTransactions: ({reportUrl, reportName, reportID, isReportDeleted}: CreatedReportForUnapprovedTransactionsParams) =>
             isReportDeleted
-                ? `utworzył/-a ten raport dla wszystkich wstrzymanych wydatków z usuniętego raportu #${reportID}`
-                : `utworzył/-a ten raport dla wszystkich wstrzymanych wydatków z <a href="${reportUrl}">${reportName}</a>`,
+                ? `utworzono ten raport dla wszystkich wstrzymanych wydatków z usuniętego raportu nr ${reportID}`
+                : `utworzył(-a) ten raport dla wszystkich wstrzymanych wydatków z <a href="${reportUrl}">${reportName}</a>`,
     },
     mentionSuggestions: {
         hereAlternateText: 'Powiadom wszystkich w tej konwersacji',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index e0133cde..5066195b 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -926,8 +926,8 @@ const translations: TranslationDeepObject<typeof en> = {
             `criou este relatório para manter todas as despesas de <a href="${reportUrl}">${reportName}</a> que não puderam ser enviadas na frequência escolhida por você`,
         createdReportForUnapprovedTransactions: ({reportUrl, reportName, reportID, isReportDeleted}: CreatedReportForUnapprovedTransactionsParams) =>
             isReportDeleted
-                ? `criou este relatório para quaisquer despesas em espera de relatório excluído #${reportID}`
-                : `criou este relatório para quaisquer despesas em espera de <a href="${reportUrl}">${reportName}</a>`,
+                ? `criou este relatório para quaisquer despesas retidas do relatório excluído nº ${reportID}`
+                : `criou este relatório para quaisquer despesas retidas de <a href="${reportUrl}">${reportName}</a>`,
     },
     mentionSuggestions: {
         hereAlternateText: 'Notificar todas as pessoas nesta conversa',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index de32afcd..0488cc58 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -914,9 +914,7 @@ const translations: TranslationDeepObject<typeof en> = {
         asCopilot: '作为副驾驶,用于',
         harvestCreatedExpenseReport: (reportUrl: string, reportName: string) => `创建了此报销单,用于保存所有来自 <a href="${reportUrl}">${reportName}</a> 且无法按照你选择的频率提交的费用`,
         createdReportForUnapprovedTransactions: ({reportUrl, reportName, reportID, isReportDeleted}: CreatedReportForUnapprovedTransactionsParams) =>
-            isReportDeleted
-                ? `从已删除的报告 #${reportID}创建了此报表,用于查看任何被暂扣的报销费用`
-                : `从<a href="${reportUrl}">${reportName}</a>创建了此报表,用于查看任何被暂扣的报销费用`,
+            isReportDeleted ? `为已删除报销单 #${reportID} 中的所有暂挂报销创建了此报销单` : `为从<a href="${reportUrl}">${reportName}</a>中被暂挂的任何报销创建了此报表`,
     },
     mentionSuggestions: {
         hereAlternateText: '通知此会话中的所有人',

Note

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

View workflow run

@codecov
Copy link

codecov bot commented Feb 4, 2026

Codecov Report

❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.

Files with missing lines Coverage Δ
...m/CreatedReportForUnapprovedTransactionsAction.tsx 100.00% <ø> (ø)
src/libs/DebugUtils.ts 68.76% <100.00%> (+0.06%) ⬆️
src/libs/ReportActionsUtils.ts 53.56% <100.00%> (+0.19%) ⬆️
src/libs/ReportNameUtils.ts 81.09% <100.00%> (ø)
...ges/inbox/report/ReportActionsListItemRenderer.tsx 85.71% <ø> (ø)
src/libs/ReportUtils.ts 76.36% <0.00%> (+0.06%) ⬆️
...es/inbox/report/ContextMenu/ContextMenuActions.tsx 25.49% <0.00%> (-0.05%) ⬇️
... and 16 files with indirect coverage changes

@hoangzinh hoangzinh marked this pull request as ready for review February 4, 2026 13:28
@hoangzinh hoangzinh requested review from a team as code owners February 4, 2026 13:28
@melvin-bot
Copy link

melvin-bot bot commented Feb 4, 2026

@parasharrajat 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 request for a team February 4, 2026 13:29
@hoangzinh
Copy link
Contributor Author

@cristipaval, just wanna confirm, are you working on BE PR for this? #81283 (comment)

@cristipaval
Copy link
Contributor

@hoangzinh yes, I'm opening a PR asap.

@parasharrajat
Copy link
Member

parasharrajat commented Feb 24, 2026

@hoangzinh Can you please update the title to have HOLD so that we are clear that we are waiting on changes here?

@cristipaval
Copy link
Contributor

cristipaval commented Feb 24, 2026

The backend fix was merged earlier today. It is awaiting deployment.

@parasharrajat
Copy link
Member

No Hold needed. 😄

@cristipaval
Copy link
Contributor

cristipaval commented Feb 28, 2026

The backend PRs that add the isOriginalReportDeleted flag to the CREATED_REPORT_FOR_UNAPPROVED_TRANSACTIONS report actions have been deployed to staging.

@hoangzinh @parasharrajat, the flag is on the report action object, not on the originalMessage

The lightweight action mapper in ReportActionsListItemRenderer was filtering out the isOriginalReportDeleted field, preventing it from reaching components that need it. Added the field to both the action construction object and useMemo dependency array.

Also updated ReportNameUtils getReportName to pass the isOriginalReportDeleted flag to getCreatedReportForUnapprovedTransactionsMessage.
Updated both ReportAction validation schemas in DebugUtils to include the isOriginalReportDeleted field, fixing TypeScript compilation errors.
Added the missing isOriginalReportDeleted case in validateReportActionDraftProperty switch statement to fix ESLint exhaustiveness check error.
… deletion states

- Created isOriginalReportDeleted() utility function in ReportActionsUtils
- Function checks both backend flag (action.isOriginalReportDeleted) and optimistic offline state (originalReport.pendingFields.preview === DELETE)
- Updated 3 usage sites to use the new utility:
  * CreatedReportForUnapprovedTransactionsAction component
  * ReportNameUtils.getReportName()
  * ContextMenuActions copy message handler
- Added comprehensive unit tests covering all edge cases
@hoangzinh
Copy link
Contributor Author

@parasharrajat @cristipaval PR is ready for review

@parasharrajat
Copy link
Member

Thanks, I will check soon.

@parasharrajat
Copy link
Member

parasharrajat commented Mar 3, 2026

Screenshots

🔲 iOS / native

04.03.2026_21.28.30_REC.mp4

🔲 MacOS / Chrome

image

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

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

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible 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 checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified tests pass on all platforms & I tested again on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (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 the left part of a conditional rendering a React component is a boolean and NOT a string, e.g. myBool && <MyComponent />.
    • 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
    • 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 approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • 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 verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • 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.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • 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 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 form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label 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.
  • 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.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

🎀 👀 🎀 C+ reviewed

@melvin-bot melvin-bot bot requested a review from cristipaval March 4, 2026 16:04
@cristipaval
Copy link
Contributor

@hoangzinh, could you please resolve conflicts? 🙏

@hoangzinh
Copy link
Contributor Author

@cristipaval I resolved conflicts

Copy link
Contributor

@cristipaval cristipaval left a comment

Choose a reason for hiding this comment

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

Thank you both for working on this! 🙏

@cristipaval cristipaval merged commit 21b4c68 into Expensify:main Mar 4, 2026
30 checks passed
@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

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

@OSBotify
Copy link
Contributor

OSBotify commented Mar 4, 2026

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

@OSBotify
Copy link
Contributor

OSBotify commented Mar 6, 2026

🚀 Deployed to staging by https://github.com/cristipaval in version: 9.3.32-0 🚀

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

@OSBotify
Copy link
Contributor

OSBotify commented Mar 6, 2026

🚀 Deployed to production by https://github.com/blimpich in version: 9.3.32-3 🚀

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

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.

5 participants