fix: show a "Refresh needed" empty state for stale search results - #100176
Conversation
|
Hey, I noticed you changed If you want to automatically generate translations for other locales, an Expensify employee will have to:
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 bun ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
🦜 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 diffdiff --git a/src/languages/de.ts b/src/languages/de.ts
index 4ae8c143..10717fa2 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -9289,6 +9289,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
title: 'Keine Ausgaben zum Genehmigen',
subtitle: 'Null Ausgaben. Maximale Entspannung. Gut gemacht!',
},
+ staleResults: {title: 'Aktualisierung erforderlich', subtitle: 'Diese Seite ist veraltet, aktualisieren Sie sie, um die neuesten Inhalte zu sehen', buttonText: 'Aktualisieren'},
},
columns: 'Spalten',
editColumns: 'Spalten bearbeiten',
diff --git a/src/languages/el.ts b/src/languages/el.ts
index d5fc56a9..b671ca44 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -9499,6 +9499,7 @@ ${reportName}`,
emptyViolationSnapshotResults: {
subtitle: (formattedDate) => `Οι παραβάσεις παρακολουθούνται μόνο από ${formattedDate} και μετά. Δοκιμάστε να προσαρμόσετε τα φίλτρα ημερομηνίας σας.`,
},
+ staleResults: {title: 'Απαιτείται ανανέωση', subtitle: 'Αυτή η σελίδα είναι παρωχημένη, κάντε ανανέωση για να δείτε τα πιο πρόσφατα', buttonText: 'Ανανέωση'},
},
columns: 'Στήλες',
editColumns: 'Επεξεργασία στηλών',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 84866131..20d6ec72 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -9147,6 +9147,7 @@ ${reportName}`,
title: 'No hay gastos para aprobar',
subtitle: 'Cero gastos. Máxima relajación. ¡Bien hecho!',
},
+ staleResults: {title: 'Es necesario actualizar', subtitle: 'Esta página está desactualizada, actualiza para ver lo más reciente', buttonText: 'Actualizar'},
},
columns: 'Columnas',
editColumns: 'Editar columnas',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index a70f4f10..be09a7e9 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -9319,6 +9319,7 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
title: 'Aucune dépense à approuver',
subtitle: 'Zéro dépense. Détente maximale. Bien joué !',
},
+ staleResults: {title: 'Actualisation requise', subtitle: 'Cette page n’est plus à jour, actualisez-la pour voir les dernières informations', buttonText: 'Actualiser'},
},
columns: 'Colonnes',
editColumns: 'Modifier les colonnes',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 31d95702..c3f0f1a0 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -9253,6 +9253,7 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
title: 'Nessuna spesa da approvare',
subtitle: 'Zero spese. Massimo relax. Ben fatto!',
},
+ staleResults: {title: 'Aggiornamento necessario', subtitle: 'Questa pagina non è aggiornata, ricarica per vedere le ultime novità', buttonText: 'Aggiorna'},
},
columns: 'Colonne',
editColumns: 'Modifica colonne',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index d9c70fd9..74acf87f 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -9124,6 +9124,7 @@ ${reportName}`,
title: '承認する経費はありません',
subtitle: '経費はゼロ。リラックス度マックス。お見事です!',
},
+ staleResults: {title: '再読み込みが必要です', subtitle: 'このページは古くなっています。最新の情報を見るには再読み込みしてください。', buttonText: '更新'},
},
columns: '列',
editColumns: '列の編集',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 13b91089..6319c874 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -9216,6 +9216,7 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
title: 'Geen declaraties om goed te keuren',
subtitle: 'Nul uitgaven. Maximale chill. Goed gedaan!',
},
+ staleResults: {title: 'Vernieuwen nodig', subtitle: 'Deze pagina is verouderd, vernieuw om de laatste versie te zien', buttonText: 'Verversen'},
},
columns: 'Kolommen',
editColumns: 'Kolommen bewerken',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 3d4a2242..5c0421a8 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -9237,6 +9237,7 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
title: 'Brak wydatków do zatwierdzenia',
subtitle: 'Zero wydatków. Maksymalny luz. Dobra robota!',
},
+ staleResults: {title: 'Wymagane odświeżenie', subtitle: 'Ta strona jest nieaktualna, odśwież ją, żeby zobaczyć najnowszą wersję', buttonText: 'Odśwież'},
},
columns: 'Kolumny',
editColumns: 'Edytuj kolumny',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index c2bb06fd..14c64744 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -9220,6 +9220,7 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
title: 'Nenhuma despesa para aprovar',
subtitle: 'Zero despesas. Máximo sossego. Muito bem!',
},
+ staleResults: {title: 'É preciso atualizar', subtitle: 'Esta página está desatualizada, atualize para ver a versão mais recente', buttonText: 'Atualizar'},
},
columns: 'Colunas',
editColumns: 'Editar colunas',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index b2fe6edc..a63c59dc 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -8879,6 +8879,7 @@ ${reportName}`,
title: '没有报销可审批',
subtitle: '零报销,最大轻松。干得好!',
},
+ staleResults: {title: '需要刷新', subtitle: '此页面已过期,刷新以查看最新内容', buttonText: '刷新'},
},
columns: '列',
editColumns: '编辑列',
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2e4a14a0da
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Video seems good to me 👍 |
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
Reviewer Checklist
Screenshots/VideosiOS: HybridAppWasn't able to build for iOS (new xcode update) iOS: mWeb Safari |
|
I noticed this flick when navigating. Not a big deal but i wonder if we can easily fix it Screen.Recording.2026-09-09.at.2.38.50.in.the.afternoon.movsometimes it happens when refreshing Screen.Recording.2026-09-09.at.2.41.18.in.the.afternoon.mov |
|
Oh interesting, I thought that would be more of a global replacement, not just for Expenses. |
This comment has been minimized.
This comment has been minimized.
|
🚧 mountiny has triggered a test Expensify/App build. You can view the workflow run here. |
This comment has been minimized.
This comment has been minimized.
|
I see it too. I would rather fix it in a separate issue. I reproduced the same flick on staging, which does not have any of these changes, so it is pre existing rather than something this PR introduced. Happy to open a follow up issue for it |
# Conflicts: # src/components/Search/index.tsx
Oh ok. thanks we can handle it separately |
mountiny
left a comment
There was a problem hiding this comment.
Thanks, can you check the failing oxfmt check?
|
🚧 mountiny has triggered a test Expensify/App build. You can view the workflow run here. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/mountiny in version: 9.4.82-0 🚀
|
|
🤖 Yes, help site changes are required. Draft PR: Docs updates for E/A#100176 Refresh needed state on the Spend page This PR added two pieces of user-facing copy that no article covered:
Both went into What changed and how it was verifiedChanges (one file, +17/-1):
Copy source: every quoted string is verbatim from UI verification: Spend, Expenses, Filters, and Display were confirmed against the live dev web UI with exact casing. The Refresh needed state itself could not be reproduced on a fresh test account: enabling Simulate failing network requests on an account with no expenses left the list empty rather than stale, since there is nothing cached to go out of date. Its copy therefore comes from Guidelines applied: Not changed: @BartekObudzinski, please review the linked help site PR and confirm it reflects the current behavior. Then mark the linked help site PR |
|
This PR failing because of the issue #101520 |
|
Deploy Blocker #101520 was identified to be related to this PR. |
|
🚀 Deployed to staging by https://github.com/mountiny in version: 9.4.86-0 🚀
|
|
🚀 Deployed to staging by https://github.com/mountiny in version: 9.4.89-0 🚀
|
|
🚀 Deployed to production by https://github.com/luacmartins in version: 9.4.89-0 🚀
Bundle Size Analysis (Sentry): |




Explanation of Change
A failed Search leaves the page showing "Oops... Something went wrong" under a broken magnifying glass. Nothing is broken. The results are out of date and a refresh fixes them.
This replaces that state with the design from the issue: a folder-and-arrows illustration, the heading "Refresh needed", the line "This page is out of date, refresh to see the latest", and a "Refresh" button. The button runs the same retry handler as before. A query the server rejected as malformed keeps the old copy, since that one did fail.
FullPageErrorViewnow takes optionalillustration,illustrationWidthandillustrationHeightprops. They default to the current illustration and its sizes, so the two other call sites render as before.One detail worth flagging.
FullPageErrorViewasks for both illustration names in a single staticuseMemoizedLazyIllustrations(['BrokenMagnifyingGlass', 'FolderSync'])call rather than forwarding the prop into the hook, which is whatWorkspaceCompanyCardsTabledoes. The hook fills its asset map once per mount, so a name it never received at mount resolves toPlaceholderIcon. Search can hit that:failureDatawriteserrorsalongsideresponseJsonCode: 0, then the real response code arrives in a laterOnyx.merge, so the variant can flip while the view stays mounted.Two things are still missing from this draft. The 10 non-English locale files have no
search.searchResults.staleResultskey yet, sonpm run typecheckfails untilgenerateTranslationsruns. Screenshots are not in yet either.Fixed Issues
$ #99352
PROPOSAL:
Tests
hasErrorsinsrc/components/Search/index.tsxrequires!isOffline, so offline mode will not show this state. Use the failing-requests switch.din the Metro terminal opens the same menuWatch the screen in the first few seconds. Once 3 requests have failed and 10 seconds have passed since the first one,
FailureTrackerraises a sustained failure, which setsisOfflineto true and hides this state.Offline tests
This state cannot appear offline.
hasErrorsrequires!isOffline, and a snapshot with no data goes throughFullPageOfflineBlockingView.main, so cached results stay visible and no "Refresh needed" state appearsQA Steps
Reaching this state needs the Search API to fail, which QA cannot force on staging. Requesting
[No QA].PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Screen.Recording.2026-09-04.at.09.48.26.mov
Android: mWeb Chrome
iOS: Native
Screen.Recording.2026-09-04.at.09.38.36.mov
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-09-04.at.09.11.34.mov