Persist PDF modal and let user trigger download manually to fix transient activation bug#76766
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 ts-node ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
|
@puneetlath 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] |
🦜 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 a0c363e4..643d885f 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -2288,9 +2288,10 @@ ${amount} für ${merchant} - ${date}`,
},
reportDetailsPage: {
inWorkspace: ({policyName}: ReportPolicyNameParams) => `in ${policyName}`,
- generatingPDF: 'PDF wird generiert...',
+ generatingPDF: 'PDF wird erstellt',
waitForPDF: 'Bitte warten Sie, während wir das PDF erstellen.',
errorPDF: 'Beim Versuch, Ihr PDF zu erstellen, ist ein Fehler aufgetreten.',
+ successPDF: 'Ihr PDF wurde erstellt! Falls es nicht automatisch heruntergeladen wurde, verwenden Sie die Schaltfläche unten.',
},
reportDescriptionPage: {
roomDescription: 'Zimmerbeschreibung',
@@ -2554,13 +2555,13 @@ ${amount} für ${merchant} - ${date}`,
4. Suche nach ${integrationName}.
5. Klicke auf *Connect*.
- ${
- integrationName && CONST.connectionsVideoPaths[integrationName]
- ? `[Zur Buchhaltung](${workspaceAccountingLink}).
+${
+ integrationName && CONST.connectionsVideoPaths[integrationName]
+ ? `[Zur Buchhaltung](${workspaceAccountingLink}).
`
- : `[Zur Buchhaltung](${workspaceAccountingLink}).`
- }`),
+ : `[Zur Buchhaltung](${workspaceAccountingLink}).`
+}`),
},
connectCorporateCardTask: {
title: ({corporateCardLink}) => `Verbinden Sie [Ihre Firmenkarten](${corporateCardLink})`,
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 485dc3fb..a8e350a6 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -2288,9 +2288,10 @@ ${amount} pour ${merchant} - ${date}`,
},
reportDetailsPage: {
inWorkspace: ({policyName}: ReportPolicyNameParams) => `dans ${policyName}`,
- generatingPDF: 'Génération du PDF...',
+ generatingPDF: 'Génération du PDF',
waitForPDF: 'Veuillez patienter pendant que nous générons le PDF',
errorPDF: "Une erreur s'est produite lors de la tentative de génération de votre PDF.",
+ successPDF: 'Votre PDF a été généré ! S’il ne s’est pas téléchargé automatiquement, utilisez le bouton ci-dessous.',
},
reportDescriptionPage: {
roomDescription: 'Description de la chambre',
@@ -2554,13 +2555,13 @@ ${amount} pour ${merchant} - ${date}`,
4. Recherchez ${integrationName}.
5. Cliquez sur *Connect*.
- ${
- integrationName && CONST.connectionsVideoPaths[integrationName]
- ? `[Accéder à la comptabilité](${workspaceAccountingLink}).
+${
+ integrationName && CONST.connectionsVideoPaths[integrationName]
+ ? `[Accéder à la comptabilité](${workspaceAccountingLink}).
`
- : `[Accéder à la comptabilité](${workspaceAccountingLink})`
- }`),
+ : `[Accéder à la comptabilité](${workspaceAccountingLink})`
+}`),
},
connectCorporateCardTask: {
title: ({corporateCardLink}) => `Connectez [vos cartes d’entreprise](${corporateCardLink})`,
diff --git a/src/languages/it.ts b/src/languages/it.ts
index f105be40..9bc214d7 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -2280,9 +2280,10 @@ ${amount} per ${merchant} - ${date}`,
},
reportDetailsPage: {
inWorkspace: ({policyName}: ReportPolicyNameParams) => `in ${policyName}`,
- generatingPDF: 'Generazione PDF...',
+ generatingPDF: 'Generazione del PDF',
waitForPDF: 'Attendere mentre generiamo il PDF',
errorPDF: 'Si è verificato un errore durante il tentativo di generare il tuo PDF.',
+ successPDF: 'Il tuo PDF è stato generato! Se non si è scaricato automaticamente, usa il pulsante qui sotto.',
},
reportDescriptionPage: {
roomDescription: 'Descrizione della stanza',
@@ -2542,13 +2543,13 @@ ${amount} per ${merchant} - ${date}`,
4. Trova ${integrationName}.
5. Fai clic su *Connect*.
- ${
- integrationName && CONST.connectionsVideoPaths[integrationName]
- ? `[Portami alla contabilità](${workspaceAccountingLink}).
+${
+ integrationName && CONST.connectionsVideoPaths[integrationName]
+ ? `[Portami alla contabilità](${workspaceAccountingLink}).
`
- : `[Portami alla contabilità](${workspaceAccountingLink}).`
- }`),
+ : `[Portami alla contabilità](${workspaceAccountingLink}).`
+}`),
},
connectCorporateCardTask: {
title: ({corporateCardLink}) => `Collega [le tue carte aziendali](${corporateCardLink})`,
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index fcc2b863..f910d827 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -2270,9 +2270,10 @@ ${date} - ${merchant}に${amount}`,
},
reportDetailsPage: {
inWorkspace: ({policyName}: ReportPolicyNameParams) => `${policyName} 内`,
- generatingPDF: 'PDFを生成中...',
+ generatingPDF: 'PDFを生成中',
waitForPDF: 'PDFを生成するまでお待ちください',
errorPDF: 'PDFの生成中にエラーが発生しました。',
+ successPDF: 'PDFの生成が完了しました!自動的にダウンロードされない場合は、下のボタンを使用してください。',
},
reportDescriptionPage: {
roomDescription: '部屋の説明',
@@ -2523,7 +2524,7 @@ ${date} - ${merchant}に${amount}`,
`${integrationName === CONST.ONBOARDING_ACCOUNTING_MAPPING.other ? '' : 'と'}[${integrationName === CONST.ONBOARDING_ACCOUNTING_MAPPING.other ? 'あなたの' : ''} ${integrationName}](${workspaceAccountingLink})と接続する`,
description: ({integrationName, workspaceAccountingLink}) =>
dedent(`
- ${integrationName === CONST.ONBOARDING_ACCOUNTING_MAPPING.other ? 'あなたの' : 'まで'} の ${integrationName} を接続して、経費の自動分類と同期で月末締めをスムーズに。
+${integrationName === CONST.ONBOARDING_ACCOUNTING_MAPPING.other ? 'あなたの' : 'まで'} の ${integrationName} を接続して、経費の自動分類と同期で月末締めをスムーズに。
1. *Workspaces* をクリックします。
2. ワークスペースを選択します。
@@ -2531,13 +2532,13 @@ ${date} - ${merchant}に${amount}`,
4. ${integrationName} を見つけます。
5. *Connect* をクリックします。
- ${
- integrationName && CONST.connectionsVideoPaths[integrationName]
- ? `[会計に移動](${workspaceAccountingLink}).
+${
+ integrationName && CONST.connectionsVideoPaths[integrationName]
+ ? `[会計に移動](${workspaceAccountingLink}).
`
- : `[会計に移動](${workspaceAccountingLink}).`
- }`),
+ : `[会計に移動](${workspaceAccountingLink}).`
+}`),
},
connectCorporateCardTask: {
title: ({corporateCardLink}) => `[法人カード](${corporateCardLink})を連携する`,
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 213b44bd..dfc14a9a 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -2278,9 +2278,10 @@ ${amount} voor ${merchant} - ${date}`,
},
reportDetailsPage: {
inWorkspace: ({policyName}: ReportPolicyNameParams) => `in ${policyName}`,
- generatingPDF: 'PDF genereren...',
+ generatingPDF: 'PDF wordt gegenereerd',
waitForPDF: 'Even geduld terwijl we de PDF genereren.',
errorPDF: 'Er is een fout opgetreden bij het genereren van uw PDF.',
+ successPDF: 'Je PDF is gegenereerd! Als het niet automatisch is gedownload, gebruik dan de knop hieronder.',
},
reportDescriptionPage: {
roomDescription: 'Kamerbeschrijving',
@@ -2541,13 +2542,13 @@ ${amount} voor ${merchant} - ${date}`,
4. Zoek ${integrationName}.
5. Klik op *Verbinden*.
- ${
- integrationName && CONST.connectionsVideoPaths[integrationName]
- ? `[Breng me naar de boekhouding](${workspaceAccountingLink}).
+${
+ integrationName && CONST.connectionsVideoPaths[integrationName]
+ ? `[Breng me naar de boekhouding](${workspaceAccountingLink}).
`
- : `[Breng me naar de boekhouding](${workspaceAccountingLink}).`
- }`),
+ : `[Breng me naar de boekhouding](${workspaceAccountingLink}).`
+}`),
},
connectCorporateCardTask: {
title: ({corporateCardLink}) => `Koppel [je bedrijfskaarten](${corporateCardLink})`,
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 5543e376..07548632 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -2274,9 +2274,10 @@ ${amount} dla ${merchant} - ${date}`,
},
reportDetailsPage: {
inWorkspace: ({policyName}: ReportPolicyNameParams) => `w ${policyName}`,
- generatingPDF: 'Generowanie PDF...',
+ generatingPDF: 'Generowanie pliku PDF',
waitForPDF: 'Proszę czekać, generujemy PDF',
errorPDF: 'Wystąpił błąd podczas próby wygenerowania Twojego PDF-a.',
+ successPDF: 'Twój plik PDF został wygenerowany! Jeśli nie pobrał się automatycznie, użyj przycisku poniżej.',
},
reportDescriptionPage: {
roomDescription: 'Opis pokoju',
@@ -2536,13 +2537,13 @@ ${amount} dla ${merchant} - ${date}`,
4. Znajdź ${integrationName}.
5. Kliknij *Connect*.
- ${
- integrationName && CONST.connectionsVideoPaths[integrationName]
- ? `[Przejdź do księgowości](${workspaceAccountingLink}).
+${
+ integrationName && CONST.connectionsVideoPaths[integrationName]
+ ? `[Przejdź do księgowości](${workspaceAccountingLink}).
`
- : `[Przejdź do księgowości](${workspaceAccountingLink}).`
- }`),
+ : `[Przejdź do księgowości](${workspaceAccountingLink}).`
+}`),
},
connectCorporateCardTask: {
title: ({corporateCardLink}) => `Połącz [swoje karty firmowe](${corporateCardLink})`,
@@ -5253,7 +5254,7 @@ ${amount} dla ${merchant} - ${date}`,
cardType: 'Typ karty',
limit: 'Limit',
limitType: 'Typ limitu',
- name: 'Imię',
+ name: 'Nazwa',
disabledApprovalForSmartLimitError: 'Proszę włączyć zatwierdzenia w <strong>Przepływy pracy > Dodaj zatwierdzenia</strong> przed skonfigurowaniem inteligentnych limitów',
},
deactivateCardModal: {
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 45859d32..680e76b6 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -2274,9 +2274,10 @@ ${amount} para ${merchant} - ${date}`,
},
reportDetailsPage: {
inWorkspace: ({policyName}: ReportPolicyNameParams) => `em ${policyName}`,
- generatingPDF: 'Gerando PDF...',
+ generatingPDF: 'Gerando PDF',
waitForPDF: 'Por favor, aguarde enquanto geramos o PDF.',
errorPDF: 'Ocorreu um erro ao tentar gerar seu PDF.',
+ successPDF: 'Seu PDF foi gerado! Se não foi baixado automaticamente, use o botão abaixo.',
},
reportDescriptionPage: {
roomDescription: 'Descrição do quarto',
@@ -2536,13 +2537,13 @@ ${amount} para ${merchant} - ${date}`,
4. Encontre ${integrationName}.
5. Clique em *Conectar*.
- ${
- integrationName && CONST.connectionsVideoPaths[integrationName]
- ? `[Ir para a contabilidade](${workspaceAccountingLink}).
+${
+ integrationName && CONST.connectionsVideoPaths[integrationName]
+ ? `[Ir para a contabilidade](${workspaceAccountingLink}).
`
- : `[Ir para a contabilidade](${workspaceAccountingLink}).`
- }`),
+ : `[Ir para a contabilidade](${workspaceAccountingLink}).`
+}`),
},
connectCorporateCardTask: {
title: ({corporateCardLink}) => `Conecte [seus cartões corporativos](${corporateCardLink})`,
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index ca03bff5..3741cc86 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -2243,9 +2243,10 @@ ${merchant}的${amount} - ${date}`,
},
reportDetailsPage: {
inWorkspace: ({policyName}: ReportPolicyNameParams) => `在${policyName}中`,
- generatingPDF: '生成PDF...',
+ generatingPDF: '正在生成 PDF',
waitForPDF: '请稍候,我们正在生成 PDF。',
errorPDF: '生成PDF时出现错误。',
+ successPDF: '您的 PDF 已生成!如果没有自动下载,请使用下方按钮。',
},
reportDescriptionPage: {
roomDescription: '房间描述',
@@ -2504,13 +2505,13 @@ ${merchant}的${amount} - ${date}`,
4. 找到 ${integrationName}。
5. 点击*连接*。
- ${
- integrationName && CONST.connectionsVideoPaths[integrationName]
- ? `[前往会计](${workspaceAccountingLink}).
+${
+ integrationName && CONST.connectionsVideoPaths[integrationName]
+ ? `[前往会计](${workspaceAccountingLink}).
`
- : `[前往会计](${workspaceAccountingLink}).`
- }`),
+ : `[前往会计](${workspaceAccountingLink}).`
+}`),
},
connectCorporateCardTask: {
title: ({corporateCardLink}) => `连接[您的公司卡](${corporateCardLink})`,
@@ -5159,7 +5160,7 @@ ${merchant}的${amount} - ${date}`,
cardType: '卡类型',
limit: '限制',
limitType: '限制类型',
- name: '名称',
+ name: '姓名',
disabledApprovalForSmartLimitError: '请在<strong>工作流程 > 添加审批</strong>中启用审批,然后再设置智能限制',
},
deactivateCardModal: {
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
|
@situchan are you able to review ASAP? |
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.
|
|
reviewing... Please fix lint errors |
situchan
left a comment
There was a problem hiding this comment.
- Forbidden non-null assertion
- This assertion is unnecessary since it does not change the type of the expression
- Unnecessary 'else' after 'return'
- React Hook useMemo has a missing dependency: 'hasFinishedPDFDownload'. Either include it or remove the dependency array
- React Hook useEffect has missing dependencies: 'moneyRequestReport?.reportName' and 'reportPDFFilename'. Either include them or remove the dependency array
- Do not use negated variable names
Please address all these check failures
src/languages/en.ts
Outdated
| reportDetailsPage: { | ||
| inWorkspace: ({policyName}: ReportPolicyNameParams) => `in ${policyName}`, | ||
| generatingPDF: 'Generating PDF...', | ||
| generatingPDF: 'Generating PDF', |
There was a problem hiding this comment.
@trjExpensify Just for context, I removed it because that's how it looks in the reference image for OD.
There was a problem hiding this comment.
Also, is it expected that there's ... even when the generation already completed?
There was a problem hiding this comment.
Ah, the second point is fair tbh. We're persisting this modal now even after completion, so we probably should drop the ... In fact, maybe we should just call it "Generate PDF" at this point?
There was a problem hiding this comment.
I like PDF generated
There was a problem hiding this comment.
Ended up going with @trjExpensify's suggestion:
Should I keep the other languages as "Generating PDF"? 🤔
There was a problem hiding this comment.
Yeah, I was just thinking of making the logic easier by having something static. The other option maybe is "Download PDF" - bit more evergreen?
Download PDF
Please wait while we generate the PDF.
Download PDF
Your PDF has been generated! If it didn't automatically download, use the button below.
[Download]
There was a problem hiding this comment.
Love that, just added a period in the first body. The option itself in the More dropdown should be named that, too, but that's another issue 😆
|
Looks like the AI modified some other translations in the patch and I didn't notice, working on reverting them now. |
|
Ready for a review. |
|
@situchan Did you delete a comment about using |
Ignore that. We can use Pressable to be consistent. App/src/components/HeaderWithBackButton/index.tsx Lines 288 to 298 in 68d4da3 |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppandroid.movAndroid: mWeb Chromemchrome.moviOS: HybridAppios.moviOS: mWeb Safarimsafari.movMacOS: Chrome / Safariweb.mov |
|
🚧 @puneetlath has triggered a test Expensify/App build. You can view the workflow run here. |
|
@situchan I think you forgot to upload the video for |
Done. Btw download cannot be tested properly on dev as it's redirected to internal link (expensify.com.dev) |
|
@LorenzoBloedow can you re-upload videos against latest commit? Text is still centered in your videos. |
|
@situchan When I upload the new videos, should I change this line to test download like I did before or just let the download fail? App/src/libs/Environment/Environment.ts Line 55 in 4169a2e return OLDDOT_ENVIRONMENT_URLS["production"]; |
no problem at all. you can hardcode that locally to make sure that download works |
|
Just updated the videos. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
trjExpensify
left a comment
There was a problem hiding this comment.
Works great! I think we can change the title to "Download PDF" in a follow-up, no problem.
2025-12-05_17-04-16.mp4
|
Nice work, thanks! This'll make the deploy today if we get one out. 🎉 |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚀 Deployed to staging by https://github.com/puneetlath in version: 9.2.73-0 🚀
|
|
🚀 Deployed to production by https://github.com/thienlnam in version: 9.2.73-5 🚀
|
Explanation of Change
Sometimes the download can't be automatically triggered because
ExportReportToPDFtakes longer than the browser's transient activation time.To fix this, we're persisting the PDF modal to allow the user to trigger the download if it didn't automatically get triggered.
We'll persist the modal until the user closes it because there's no API to know if the download was successful, we also can't guess it because transient activation is not deterministic.
Fixed Issues
$ #76172
PROPOSAL: #76172 (comment)
Tests
Offline tests
N/A (This feature requires an internet connection).
QA Steps
Same as tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, 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.ScrollViewcomponent to make it scrollable when more elements are added to the page.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
Android.-.Native.mov
Android: mWeb Chrome
Android.-.Chrome.mov
iOS: Native
iOS.-.Native.mov
iOS: mWeb Safari
iOS.-.Safari.mov
MacOS: Chrome / Safari
macOS.-.Chrome.mov