Skip to content

[Payment due @dmkt9] Show a needs re-auth message for card scrape codes 438/532 (NewDot) - #97893

Merged
tgolen merged 11 commits into
mainfrom
claude-cardReauthErrorNewDot
Aug 12, 2026
Merged

[Payment due @dmkt9] Show a needs re-auth message for card scrape codes 438/532 (NewDot)#97893
tgolen merged 11 commits into
mainfrom
claude-cardReauthErrorNewDot

Conversation

@MelvinBot

@MelvinBot MelvinBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Explanation of Change

Card scrape codes 438 (account refresh required) and 532 (session expired) both mean the bank connection needs to be re-authenticated by the user, as opposed to a generic broken connection. On the Wallet cards surface, NewDot currently shows the same generic "Please fix this connection" copy for these as for any other broken code.

This PR adds a distinct "needs re-auth" message for these two codes on the card-level Wallet surface

Fixed Issues

PROPOSAL: see slack (internal only)

Tests

I manually updated a company card I had on dev with lastScrapeResult = 532

image

I then manually updated it with fundID = 0 to turn it into a personal card
image

  • Verify that no errors appear in the JS console

Offline tests

Same as tests

QA Steps

  • Look for a user with a card where lastScrapeResult = 532 and fundID != 0 using logs and database queries if needed (ping @cead22 if you need help) and confirm the error message looks like the first screenshot above
  • Look for a user with a card where lastScrapeResult = 532 and fundID = 0 using logs and database queries if needed (ping @cead22 if you need help) and confirm the error message looks like the second screenshot above
  • 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 followed proper code patterns (see Reviewing the code)
    • 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 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)
  • 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)
  • 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.
  • 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 image image

Co-authored-by: Carlos Alvarez <cead22@users.noreply.github.com>
@MelvinBot
MelvinBot requested a review from a team August 5, 2026 17:04
@OSBotify

This comment has been minimized.

Co-authored-by: Carlos Alvarez <cead22@users.noreply.github.com>
@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

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 Δ
src/CONST/index.ts 94.85% <100.00%> (+0.03%) ⬆️
src/libs/CardUtils.ts 83.62% <60.00%> (-0.14%) ⬇️
src/pages/settings/Wallet/PaymentMethodList.tsx 0.00% <0.00%> (ø)
.../settings/Wallet/PersonalCardDetailsHeaderMenu.tsx 0.00% <0.00%> (ø)
... and 7 files with indirect coverage changes

Comment thread src/CONST/index.ts Outdated
Comment thread src/CONST/index.ts Outdated
Comment thread src/libs/CardUtils.ts Outdated
Comment thread src/libs/CardUtils.ts Outdated
Comment thread src/libs/CardUtils.ts Outdated
Comment thread tests/unit/CardUtilsTest.ts Outdated
Comment thread tests/unit/CardUtilsTest.ts Outdated
… and test names

Co-authored-by: Carlos Alvarez <cead22@users.noreply.github.com>
@MelvinBot

This comment has been minimized.

@cead22

This comment has been minimized.

Co-authored-by: Carlos Alvarez <cead22@users.noreply.github.com>
@MelvinBot

This comment has been minimized.

Comment thread src/languages/en.ts Outdated
Co-authored-by: Carlos Alvarez <cead22@users.noreply.github.com>
@MelvinBot

This comment has been minimized.

@MelvinBot

This comment has been minimized.

1 similar comment
@MelvinBot

This comment has been minimized.

@OSBotify

OSBotify commented Aug 5, 2026

Copy link
Copy Markdown
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 aae951ee87c..a0210223467 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -2612,7 +2612,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: 'Bitte beheben Sie diese Verbindung',
             fixConnectionIn: (companyCardsRoute: string) => `Bitte beheben Sie diese Verbindung in <a href="${companyCardsRoute}">Firmenkarten</a>`,
             askAdminToFixConnection: 'Bitte bitten Sie eine(n) Admin, diese Verbindung zu reparieren',
-            reconnectBank: 'Bitte verbinden Sie Ihre Bank erneut',
+            reconnectBank: 'Ihre Bankverbindung muss erneut authentifiziert werden',
         },
         bankAccountStatus: {
             active: 'Aktiv',
diff --git a/src/languages/el.ts b/src/languages/el.ts
index 5bd72da3382..0460dda9ee2 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -2672,7 +2672,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: 'Παρακαλούμε διορθώστε αυτήν τη σύνδεση',
             fixConnectionIn: (companyCardsRoute: string) => `Παρακαλούμε διορθώστε αυτήν τη σύνδεση στις <a href="${companyCardsRoute}">εταιρικές κάρτες</a>`,
             askAdminToFixConnection: 'Παρακαλούμε ζητήστε από έναν διαχειριστή να διορθώσει αυτήν τη σύνδεση',
-            reconnectBank: 'Παρακαλούμε επανασυνδέστε την τράπεζά σας',
+            reconnectBank: 'Η σύνδεσή σας με την τράπεζα χρειάζεται επαναπιστοποίηση',
         },
         bankAccountStatus: {
             active: 'Ενεργό',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 4909744831a..dc8f409bbc3 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -2617,7 +2617,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: 'Veuillez corriger cette connexion',
             fixConnectionIn: (companyCardsRoute: string) => `Veuillez corriger cette connexion dans <a href="${companyCardsRoute}">cartes d’entreprise</a>`,
             askAdminToFixConnection: 'Veuillez demander à un administrateur de corriger cette connexion',
-            reconnectBank: 'Veuillez reconnecter votre banque',
+            reconnectBank: 'Votre connexion bancaire doit être réauthentifiée',
         },
         bankAccountStatus: {
             active: 'Actif',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 707dc47bf52..f8d7d8acfd7 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -2604,7 +2604,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: 'Sistema questa connessione per favore',
             fixConnectionIn: (companyCardsRoute: string) => `Correggi questa connessione in <a href="${companyCardsRoute}">carte aziendali</a>`,
             askAdminToFixConnection: 'Chiedi a un amministratore di correggere questa connessione',
-            reconnectBank: 'Ricollega la tua banca',
+            reconnectBank: 'La connessione con la tua banca deve essere nuovamente autenticata',
         },
         bankAccountStatus: {
             active: 'Attiva',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 0693fa38476..4e423f5d695 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -2581,7 +2581,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: 'この接続を修正してください',
             fixConnectionIn: (companyCardsRoute: string) => `この接続を<a href="${companyCardsRoute}">会社カード</a>で修正してください`,
             askAdminToFixConnection: '管理者にこの接続の修正を依頼してください',
-            reconnectBank: '銀行を再接続してください',
+            reconnectBank: '銀行連携の再認証が必要です',
         },
         bankAccountStatus: {
             active: 'アクティブ',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index ce120e8613f..4ebb9de7b80 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -2606,7 +2606,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: 'Repareer deze verbinding alsjeblieft',
             fixConnectionIn: (companyCardsRoute: string) => `Repareer deze verbinding in <a href="${companyCardsRoute}">bedrijfskaarten</a>`,
             askAdminToFixConnection: 'Vraag een/beheerder om deze verbinding te herstellen',
-            reconnectBank: 'Verbind je bank opnieuw',
+            reconnectBank: 'Je bankverbinding moet opnieuw worden geverifieerd',
         },
         bankAccountStatus: {
             active: 'Actief',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index b0cdb204eb2..a7bb5c4df23 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -2597,7 +2597,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: 'Napraw to połączenie',
             fixConnectionIn: (companyCardsRoute: string) => `Napraw to połączenie w <a href="${companyCardsRoute}">firmowe karty</a>`,
             askAdminToFixConnection: 'Poproś administratora o naprawienie tego połączenia',
-            reconnectBank: 'Połącz ponownie swój bank',
+            reconnectBank: 'Twoje połączenie z bankiem wymaga ponownego uwierzytelnienia',
         },
         bankAccountStatus: {
             active: 'Aktywne',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 67b33a44bfc..b66f3105c7d 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -2598,7 +2598,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: 'Corrija esta conexão',
             fixConnectionIn: (companyCardsRoute: string) => `Corrija esta conexão em <a href="${companyCardsRoute}">cartões corporativos</a>`,
             askAdminToFixConnection: 'Peça para um administrador corrigir essa conexão',
-            reconnectBank: 'Por favor, reconecte seu banco',
+            reconnectBank: 'Sua conexão bancária precisa ser autenticada novamente',
         },
         bankAccountStatus: {
             active: 'Ativo',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index d484434e624..7cc369ee35d 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -2514,7 +2514,7 @@ const translations: TranslationDeepObject<typeof en> = {
             fixConnection: '请修复此连接',
             fixConnectionIn: (companyCardsRoute: string) => `请在<a href="${companyCardsRoute}">公司卡</a>中修复此连接`,
             askAdminToFixConnection: '请联系管理员修复此连接',
-            reconnectBank: '请重新连接您的银行',
+            reconnectBank: '您的银行连接需要重新验证',
         },
         bankAccountStatus: {
             active: '活跃',

Note

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

View workflow run

@MelvinBot

This comment has been minimized.

@cead22 cead22 added the InternalQA This pull request required internal QA label Aug 6, 2026
@cead22
cead22 marked this pull request as ready for review August 6, 2026 19:58
@cead22
cead22 requested a review from a team as a code owner August 6, 2026 19:58
@melvin-bot
melvin-bot Bot requested review from JmillsExpensify and Valforte and removed request for a team August 6, 2026 19:58
@melvin-bot

melvin-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

@Valforte 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 August 6, 2026 19:58
@cead22

This comment has been minimized.

Comment thread src/CONST/index.ts
BROKEN_CONNECTION_IGNORED_STATUSES: brokenConnectionScrapeStatuses,

// Scrape result codes where the connection is broken because the user needs to re-authenticate with their bank
REAUTH_SCRAPE_STATUSES: reauthScrapeStatuses,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
REAUTH_SCRAPE_STATUSES: reauthScrapeStatuses,
REAUTH_SCRAPE_STATUSES: reauthScrapeStatuses,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Applied in 68b0d0f. ✅

Comment on lines +60 to +61
// Guard against an invalid scrapeMinDate: date-fns `format` throws `RangeError: Invalid time value`
// when `parseISO` can't parse the value, which crashes the whole page (e.g. for a broken/never-synced card)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Guard against an invalid scrapeMinDate: date-fns `format` throws `RangeError: Invalid time value`
// when `parseISO` can't parse the value, which crashes the whole page (e.g. for a broken/never-synced card)
// Guard against an invalid scrapeMinDate, since`format` throws `RangeError: Invalid time value`
// when `parseISO` can't parse the value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Applied in 68b0d0f. ✅

@melvin-bot melvin-bot Bot changed the title Show a needs re-auth message for card scrape codes 438/532 (NewDot) [Payment due @dmkt9] Show a needs re-auth message for card scrape codes 438/532 (NewDot) Aug 11, 2026
@melvin-bot

melvin-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

🎯 @dmkt9, thanks for reviewing and testing this PR! 🎉

A payment issue will be created for your review once this PR is deployed to production.
E/E issue linked to the PR - no internal issue.

If payment is not needed (e.g., regression PR review fix etc), react with 👎 to this comment to prevent the payment issue from being created.

@MelvinBot

This comment has been minimized.

cead22
cead22 previously approved these changes Aug 11, 2026
@cead22
cead22 requested review from tgolen and removed request for Valforte August 11, 2026 12:21
@MelvinBot

This comment has been minimized.

Comment thread src/libs/CardUtils.ts Outdated
Comment thread src/libs/CardUtils.ts Outdated
Comment thread src/libs/CardUtils.ts Outdated
const shouldShowMessage = isCardBroken || shouldShowRBR || isCardInactiveStatus;
const shouldUsePersonalCardFix = shouldShowMessage && isPersonalCardStatus;
const shouldUseCompanyCardsLink = shouldShowMessage && !isPersonalCardStatus && isAdminForCardPolicy && !!policyID;
const shouldUseReauthMessage = shouldShowMessage && !!isCardNeedsReauth && isPersonalCardStatus;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should the isPersonalCardStatus instead be part of doesCardConnectionNeedReauth()?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No because re-authentication also applies to company cards. Though not sure if that really answers your question

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nah, that's fine. It answers it. Thanks!

@MelvinBot

This comment has been minimized.

@cead22

cead22 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Updated

Co-authored-by: Carlos Alvarez <cead22@users.noreply.github.com>
@MelvinBot

This comment has been minimized.

@MelvinBot

This comment has been minimized.

@MelvinBot

This comment has been minimized.

@MelvinBot

This comment has been minimized.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

There's nothing to fix by pushing code here — all code checks are green.

The only failing check is Check independent approval, and it's a process gate, not a code failure:

Insufficient independent peer review { approvers: [], independentApprovers: [] }
Expensify/App#97893 does not have enough independent Expensify employee approvals.

It just means the PR has no independent reviewer approval yet. It will clear once an independent Expensify employee approves the PR (the author and assignees don't count).

Everything else passed — tests, typecheck, ESLint, Oxfmt, generateTranslations, Storybook, Bun tests, and the perf tests (validate-perf-tests). approveAndMerge shows skipping, which is expected until the PR is approved.

So no push is needed from me; the PR is just waiting on a review approval.

@tgolen
tgolen merged commit 6db3b91 into main Aug 12, 2026
45 of 46 checks passed
@tgolen
tgolen deleted the claude-cardReauthErrorNewDot branch August 12, 2026 16:06
@OSBotify

Copy link
Copy Markdown
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.

@github-actions

Copy link
Copy Markdown
Contributor

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

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/tgolen in version: 9.4.53-0 🚀

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

@MelvinBot

Copy link
Copy Markdown
Contributor Author

🤖 I reviewed the changes in this PR against the help site files under App/docs/articles.

Conclusion: No help site changes are required.

This PR is a UI copy refinement — for personal (Wallet) cards whose lastScrapeResult is 438 or 532, it swaps the generic "Please fix this connection" text for a more specific "Your bank connection needs to be re-authenticated" message. It doesn't add or change any user-facing flow, navigation, feature, or capability.

The relevant help article, Manage-Personal-Cards.md, already documents this behavior accurately and remains correct after this change:

The docs describe the broken-connection behavior at a flow level and don't enumerate exact per-scrape-code error strings, so the new message variant introduces nothing the article needs to reflect. Documenting one specific error-string variant would set a precedent of listing every code's copy, which isn't how these articles are written.

I did not create a draft help site PR since none is needed. If you'd prefer to add an explicit note about the re-auth message anyway, reply and I'll draft one.

@tgolen

tgolen commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

@cead22 could you QA this one, please?

@cead22

cead22 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

It works
image

image

I had to enable the walletConnectionStatus beta running this from the console

Onyx.get('betas')
  .then(b => Onyx.set('betas', Array.from(new Set([...(b || []), 'walletConnectionStatus']))))
  .then(() => Onyx.get('betas'))
  .then(console.log)

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

Labels

InternalQA This pull request required internal QA

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants