Add recovery code feature in auth form#72003
Conversation
|
@shawnborton @dannymcclain Does this look good? It is similar to the login page experience. CC: @jayeshmangwani TwoFactCode.mov |
|
That's looking pretty good to me! |
Codecov Report❌ Patch coverage is
... and 8 files with indirect coverage changes 🚀 New features to boost your workflow:
|
|
Can you also share a recording of how we handle this on the login page, just to make sure they are super consistent? Thanks! |
Screen.Recording.2025-10-07.at.3.18.14.PM.mov |
|
Thanks for confirming, that works for me 👍 |
|
@jayeshmangwani 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] |
|
@ShridharGoel For the recovery code input, this note doesn't make sense. We need to update it to indicate adding the recovery code. |
|
@jayeshmangwani @shawnborton @dannymcclain @trjExpensify Does this look good? |
|
Sounds good to me, let's see what others think. |
|
Yeah that sounds good to me. Good catch! |
|
Yup, works for me 👍 |
|
@ShridharGoel Please request the translation for this copy #72003 (comment) on Slack. We can move forward with this. |
|
Updated. Screen.Recording.2025-10-07.at.10.04.11.PM.mov |
|
Posted on Slack for |
|
Translations for other languages can be added via the workflow. |
|
@ShridharGoel On iOS, when you keep the simulator keyboard open and then press the toggle, it doesn’t work the first time, it closes the keyboard on the first tap and only works on the second. bug.mov |
|
@jayeshmangwani It's fixed, thanks for pointing it out. |
Looks good to me, too. |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid.mp4Android: mWeb Chromemweb-chrome.mp4iOS: HybridAppiOS.moviOS: mWeb Safarimweb-safari.movMacOS: Chrome / Safariweb.movMacOS: Desktopdesktop.mov |
|
@ShridharGoel PR looks good to me! I think we’re just waiting on the Spanish translation now. Not sure why the other language strings didn’t auto-generate though. |
|
Spanish translation was confirmed on Slack. For other languages, some internal employee would need to start the workflow. |
|
@ShridharGoel , before approving, just one suggestion , can we please split the |
|
Looks like there's some failing checks |
|
@madmax330 Jest test failures are unrelated. And TS checks are failing because of missing translations, can you run this workflow to add them? |
|
Can you merge main then to see if that fixes the Jest failure? |
|
@madmax330 The tests had got fixed after merging main. |
|
@madmax330 Can you have a look when possible? |
|
I tried to run the workflow for the translations, but it's not running. I'm trying to figure out how to fix it |
|
@madmax330 Can you check this? #71340 (comment) |
🦜 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 25e2ba4d..b011f04a 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -1850,6 +1850,7 @@ const translations = {
'Ihre Xero-Buchhaltungsverbindung erfordert die Verwendung der Zwei-Faktor-Authentifizierung. Um Expensify weiterhin zu nutzen, aktivieren Sie diese bitte.',
twoFactorAuthCannotDisable: '2FA kann nicht deaktiviert werden.',
twoFactorAuthRequired: 'Die Zwei-Faktor-Authentifizierung (2FA) ist für Ihre Xero-Verbindung erforderlich und kann nicht deaktiviert werden.',
+ explainProcessToRemoveWithRecovery: 'Um die Zwei-Faktor-Authentifizierung (2FA) zu deaktivieren, geben Sie bitte einen gültigen Wiederherstellungscode ein.',
},
recoveryCodeForm: {
error: {
@@ -2023,7 +2024,7 @@ const translations = {
workflowTitle: 'Ausgaben',
workflowDescription: 'Konfigurieren Sie einen Workflow ab dem Moment, in dem Ausgaben anfallen, einschließlich Genehmigung und Zahlung.',
submissionFrequency: 'Einreichungshäufigkeit',
- submissionFrequencyDescription: 'Wählen Sie einen benutzerdefinierten Zeitplan für die Einreichung von Ausgaben oder lassen Sie dies für Echtzeit-Updates zu Ausgaben aus.',
+ submissionFrequencyDescription: 'Wählen Sie einen benutzerdefinierten Zeitplan für die Einreichung von Ausgaben oder lassen Sie dies aus für Echtzeit-Updates zu Ausgaben.',
submissionFrequencyDateOfMonth: 'Datum des Monats',
addApprovalsTitle: 'Genehmigungen hinzufügen',
addApprovalButton: 'Genehmigungsworkflow hinzufügen',
@@ -6216,8 +6217,7 @@ const translations = {
groupBy: 'Gruppe nach',
moneyRequestReport: {
emptyStateTitle: 'Dieser Bericht enthält keine Ausgaben.',
- emptyStateSubtitle:
- 'Sie können diesem Bericht Ausgaben hinzufügen,\n indem Sie auf die Schaltfläche unten klicken oder die Option „Ausgabe hinzufügen“ im Menü „Mehr“ oben verwenden.',
+ emptyStateSubtitle: 'Sie können Ausgaben zu diesem Bericht hinzufügen, indem Sie den untenstehenden Button oder die Option "Ausgabe hinzufügen" im Menü "Mehr" oben verwenden.',
},
noCategory: 'Keine Kategorie',
noTag: 'Kein Tag',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index a1cc923a..705e5bbf 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -1850,6 +1850,7 @@ const translations = {
"Votre connexion comptable Xero nécessite l'utilisation de l'authentification à deux facteurs. Pour continuer à utiliser Expensify, veuillez l'activer.",
twoFactorAuthCannotDisable: 'Impossible de désactiver la 2FA',
twoFactorAuthRequired: "L'authentification à deux facteurs (2FA) est requise pour votre connexion Xero et ne peut pas être désactivée.",
+ explainProcessToRemoveWithRecovery: "Pour désactiver l'authentification à deux facteurs (2FA), veuillez entrer un code de récupération valide.",
},
recoveryCodeForm: {
error: {
@@ -2024,7 +2025,7 @@ const translations = {
workflowDescription: "Configurez un flux de travail dès que la dépense survient, y compris l'approbation et le paiement.",
submissionFrequency: 'Fréquence de soumission',
submissionFrequencyDescription:
- 'Choisissez un calendrier personnalisé pour soumettre les dépenses, ou laissez cette option désactivée pour des mises à jour en temps réel sur les dépenses.',
+ 'Choisissez un calendrier personnalisé pour soumettre les dépenses, ou laissez cette option désactivée pour des mises à jour en temps réel des dépenses.',
submissionFrequencyDateOfMonth: 'Date du mois',
addApprovalsTitle: 'Ajouter des approbations',
addApprovalButton: "Ajouter un flux de travail d'approbation",
@@ -6227,7 +6228,7 @@ const translations = {
groupBy: 'Groupe par',
moneyRequestReport: {
emptyStateTitle: "Ce rapport n'a pas de dépenses.",
- emptyStateSubtitle: "Vous pouvez ajouter des dépenses à ce rapport\n en utilisant le bouton ci-dessous ou l'option « Ajouter une dépense » dans le menu Plus ci-dessus.",
+ emptyStateSubtitle: 'Vous pouvez ajouter des dépenses à ce rapport en utilisant le bouton ci-dessous ou l\'option "Ajouter une dépense" dans le menu Plus ci-dessus.',
},
noCategory: 'Aucune catégorie',
noTag: 'Aucun tag',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 8c081c7a..a19470bf 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -1841,6 +1841,7 @@ const translations = {
"La tua connessione contabile Xero richiede l'uso dell'autenticazione a due fattori. Per continuare a utilizzare Expensify, ti preghiamo di abilitarla.",
twoFactorAuthCannotDisable: "Impossibile disabilitare l'autenticazione a due fattori (2FA)",
twoFactorAuthRequired: "L'autenticazione a due fattori (2FA) è necessaria per la tua connessione Xero e non può essere disabilitata.",
+ explainProcessToRemoveWithRecovery: "Per disabilitare l'autenticazione a due fattori (2FA), inserisci un codice di recupero valido.",
},
recoveryCodeForm: {
error: {
@@ -2014,7 +2015,7 @@ const translations = {
workflowTitle: 'Spendere',
workflowDescription: 'Configura un flusso di lavoro dal momento in cui si verifica una spesa, inclusi approvazione e pagamento.',
submissionFrequency: 'Frequenza di invio',
- submissionFrequencyDescription: "Scegli un programma personalizzato per l'invio delle spese, oppure lascia disattivato per aggiornamenti in tempo reale sulle spese.",
+ submissionFrequencyDescription: "Scegli un programma personalizzato per l'invio delle spese o lascia questa opzione disattivata per aggiornamenti in tempo reale sulle spese.", //_/\__/_/ \_,_/\__/\__/\_,_/
submissionFrequencyDateOfMonth: 'Data del mese',
addApprovalsTitle: 'Aggiungi approvazioni',
addApprovalButton: 'Aggiungi flusso di lavoro di approvazione',
@@ -6229,7 +6230,7 @@ const translations = {
groupBy: 'Gruppo per',
moneyRequestReport: {
emptyStateTitle: 'Questo report non ha spese.',
- emptyStateSubtitle: 'Puoi aggiungere spese a questo report\n utilizzando il pulsante in basso o l\'opzione "Aggiungi spesa" nel menu Altro sopra.',
+ emptyStateSubtitle: 'Puoi aggiungere spese a questo report utilizzando il pulsante qui sotto o l\'opzione "Aggiungi spesa" nel menu Altro sopra.',
},
noCategory: 'Nessuna categoria',
noTag: 'Nessun tag',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 6b5f0cd5..4fa3d01f 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -1837,6 +1837,7 @@ const translations = {
twoFactorAuthIsRequiredForAdminsDescription: 'Xeroの会計接続には二要素認証の使用が必要です。Expensifyを引き続き使用するには、有効にしてください。',
twoFactorAuthCannotDisable: '2FAを無効にできません',
twoFactorAuthRequired: 'Xeroの接続には二要素認証(2FA)が必要であり、無効にすることはできません。',
+ explainProcessToRemoveWithRecovery: '二要素認証 (2FA) を無効にするには、有効なリカバリーコードを入力してください。',
},
recoveryCodeForm: {
error: {
@@ -2007,7 +2008,7 @@ const translations = {
workflowTitle: '支出',
workflowDescription: '支出が発生した瞬間から、承認および支払いを含むワークフローを設定します。',
submissionFrequency: '提出頻度',
- submissionFrequencyDescription: '経費提出のカスタムスケジュールを選択するか、支出のリアルタイム更新のためにこれをオフにしておいてください。',
+ submissionFrequencyDescription: '経費提出のカスタムスケジュールを選択するか、支出のリアルタイム更新のためにこれをオフにしてください。',
submissionFrequencyDateOfMonth: '月の日付',
addApprovalsTitle: '承認を追加',
addApprovalButton: '承認ワークフローを追加',
@@ -6167,7 +6168,7 @@ const translations = {
groupBy: 'グループ',
moneyRequestReport: {
emptyStateTitle: 'このレポートには経費がありません。',
- emptyStateSubtitle: 'このレポートに経費を追加するには、\n 下のボタンを使用するか、上の「その他」メニューから「経費を追加」を選択してください。',
+ emptyStateSubtitle: 'このレポートに経費を追加するには、下のボタンまたは上の「その他」メニューの「経費を追加」オプションを使用してください。',
},
noCategory: 'カテゴリなし',
noTag: 'タグなし',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 111e1017..32e68368 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -1840,6 +1840,7 @@ const translations = {
twoFactorAuthIsRequiredForAdminsDescription: 'Uw Xero-boekhoudkoppeling vereist het gebruik van tweefactorauthenticatie. Om Expensify te blijven gebruiken, schakelt u dit in.',
twoFactorAuthCannotDisable: 'Kan 2FA niet uitschakelen',
twoFactorAuthRequired: 'Twee-factor authenticatie (2FA) is vereist voor uw Xero-verbinding en kan niet worden uitgeschakeld.',
+ explainProcessToRemoveWithRecovery: 'Om tweefactorauthenticatie (2FA) uit te schakelen, voer een geldige herstelcode in.',
},
recoveryCodeForm: {
error: {
@@ -6214,7 +6215,7 @@ const translations = {
groupBy: 'Groep per',
moneyRequestReport: {
emptyStateTitle: 'Dit rapport heeft geen uitgaven.',
- emptyStateSubtitle: 'U kunt uitgaven aan dit rapport toevoegen\n via de knop hieronder of de optie "Uitgave toevoegen" in het menu Meer hierboven.',
+ emptyStateSubtitle: 'Je kunt uitgaven aan dit rapport toevoegen met de knop hieronder of de optie "Uitgave toevoegen" in het Meer-menu hierboven.',
},
noCategory: 'Geen categorie',
noTag: 'Geen tag',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 7f85991c..9b294c96 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -1837,6 +1837,7 @@ const translations = {
twoFactorAuthIsRequiredForAdminsDescription: 'Twoje połączenie z Xero wymaga użycia uwierzytelniania dwuskładnikowego. Aby kontynuować korzystanie z Expensify, proszę je włączyć.',
twoFactorAuthCannotDisable: 'Nie można wyłączyć 2FA',
twoFactorAuthRequired: 'Do połączenia z Xero wymagana jest uwierzytelnianie dwuskładnikowe (2FA) i nie można go wyłączyć.',
+ explainProcessToRemoveWithRecovery: 'Aby wyłączyć uwierzytelnianie dwuskładnikowe (2FA), wprowadź prawidłowy kod odzyskiwania.',
},
recoveryCodeForm: {
error: {
@@ -2010,8 +2011,7 @@ const translations = {
workflowTitle: 'Wydatki',
workflowDescription: 'Skonfiguruj przepływ pracy od momentu wystąpienia wydatku, w tym zatwierdzenie i płatność.',
submissionFrequency: 'Częstotliwość składania wniosków',
- submissionFrequencyDescription:
- 'Wybierz niestandardowy harmonogram przesyłania wydatków lub pozostaw to wyłączone, aby otrzymywać aktualizacje w czasie rzeczywistym dotyczące wydatków.',
+ submissionFrequencyDescription: 'Wybierz niestandardowy harmonogram przesyłania wydatków lub pozostaw to wyłączone, aby otrzymywać aktualizacje wydatków w czasie rzeczywistym.',
submissionFrequencyDateOfMonth: 'Data miesiąca',
addApprovalsTitle: 'Dodaj zatwierdzenia',
addApprovalButton: 'Dodaj przepływ pracy zatwierdzania',
@@ -6201,7 +6201,7 @@ const translations = {
groupBy: 'Grupa według',
moneyRequestReport: {
emptyStateTitle: 'Ten raport nie zawiera wydatków.',
- emptyStateSubtitle: 'Możesz dodać wydatki do tego raportu\n za pomocą przycisku poniżej lub opcji „Dodaj wydatek” w menu Więcej powyżej.',
+ emptyStateSubtitle: 'Możesz dodać wydatki do tego raportu, używając przycisku poniżej lub opcji "Dodaj wydatek" w menu Więcej powyżej.',
},
noCategory: 'Brak kategorii',
noTag: 'Brak tagu',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 131552df..82ecab2a 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -1840,6 +1840,7 @@ const translations = {
'Sua conexão de contabilidade com a Xero requer o uso de autenticação de dois fatores. Para continuar usando o Expensify, por favor, ative-a.',
twoFactorAuthCannotDisable: 'Não é possível desativar a 2FA',
twoFactorAuthRequired: 'A autenticação de dois fatores (2FA) é necessária para sua conexão com o Xero e não pode ser desativada.',
+ explainProcessToRemoveWithRecovery: 'Para desativar a autenticação de dois fatores (2FA), insira um código de recuperação válido.',
},
recoveryCodeForm: {
error: {
@@ -2013,7 +2014,7 @@ const translations = {
workflowTitle: 'Gastar',
workflowDescription: 'Configurar um fluxo de trabalho desde o momento em que a despesa ocorre, incluindo aprovação e pagamento.',
submissionFrequency: 'Frequência de envio',
- submissionFrequencyDescription: 'Escolha um cronograma personalizado para enviar despesas ou deixe isso desativado para atualizações em tempo real sobre gastos.',
+ submissionFrequencyDescription: 'Escolha um cronograma personalizado para enviar despesas ou deixe desativado para atualizações em tempo real sobre os gastos.',
submissionFrequencyDateOfMonth: 'Data do mês',
addApprovalsTitle: 'Adicionar aprovações',
addApprovalButton: 'Adicionar fluxo de trabalho de aprovação',
@@ -6215,7 +6216,7 @@ const translations = {
groupBy: 'Agrupar por',
moneyRequestReport: {
emptyStateTitle: 'Este relatório não possui despesas.',
- emptyStateSubtitle: 'Você pode adicionar despesas a este relatório\n usando o botão abaixo ou a opção "Adicionar despesa" no menu Mais acima.',
+ emptyStateSubtitle: 'Você pode adicionar despesas a este relatório usando o botão abaixo ou a opção "Adicionar despesa" no menu Mais acima.',
},
noCategory: 'Sem categoria',
noTag: 'Sem etiqueta',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 35a37788..9a8efa31 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -1816,6 +1816,7 @@ const translations = {
twoFactorAuthIsRequiredForAdminsDescription: '您的Xero会计连接需要使用双重身份验证。要继续使用Expensify,请启用它。',
twoFactorAuthCannotDisable: '无法禁用双重身份验证',
twoFactorAuthRequired: '您的Xero连接需要双因素认证(2FA),且无法禁用。',
+ explainProcessToRemoveWithRecovery: '为了禁用双因素认证 (2FA),请输入有效的恢复代码。',
},
recoveryCodeForm: {
error: {
@@ -1986,7 +1987,7 @@ const translations = {
workflowTitle: '花费',
workflowDescription: '配置从支出发生到审批和支付的工作流程。',
submissionFrequency: '提交频率',
- submissionFrequencyDescription: '选择自定义的费用提交时间表,或者关闭此选项以实时更新支出。',
+ submissionFrequencyDescription: '选择自定义提交费用的时间表,或者关闭此选项以实时更新支出。',
submissionFrequencyDateOfMonth: '月份日期',
addApprovalsTitle: '添加审批',
addApprovalButton: '添加审批工作流程',
@@ -6084,10 +6085,7 @@ const translations = {
},
has: '有',
groupBy: '组别',
- moneyRequestReport: {
- emptyStateTitle: '此报告没有费用。',
- emptyStateSubtitle: '您可以使用下方按钮,或上方“更多”菜单中的“添加费用”选项,将费用添加到此报告中。',
- },
+ moneyRequestReport: {emptyStateTitle: '此报告没有费用。', emptyStateSubtitle: '您可以通过下面的按钮或上方“更多”菜单中的“添加费用”选项将费用添加到此报告中。'},
noCategory: '无类别',
noTag: '无标签',
expenseType: '费用类型',
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
|
Thanks @ShridharGoel you can apply the diff to get the translations in the branch and we should be good |
|
Done, thanks. |
|
@madmax330 Can you review when you get a chance? Thanks |
|
✋ 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/madmax330 in version: 9.2.30-0 🚀
|
|
🚀 Deployed to production by https://github.com/mountiny in version: 9.2.30-6 🚀
|

Explanation of Change
Fixed Issues
$ #71812
PROPOSAL: #71812 (comment)
Tests
Offline tests
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
Screen.Recording.2025-10-07.at.8.20.15.PM.mov
Android: mWeb Chrome
Screen.Recording.2025-10-07.at.8.16.28.PM.mov
iOS: Native
Simulator.Screen.Recording.-.iPhone.16.Plus.-.2025-10-07.at.20.14.11.mp4
iOS: mWeb Safari
Simulator.Screen.Recording.-.iPhone.16.Plus.-.2025-10-07.at.20.15.11.mp4
MacOS: Chrome / Safari
TwoFactCode.mov
MacOS: Desktop
TwoFactLatest.mov