[NoQA] Show Gusto sync results#90526
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 |
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
@shubham1206agra 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] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2ced94da5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Video above looks good to me 👍 |
|
Same! |
trjExpensify
left a comment
There was a problem hiding this comment.
Core PR for a WN project. 👍
🦜 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 633d39c6..2bc1424e 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -7079,6 +7079,14 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
syncError: 'Verbindung zu Gusto nicht möglich',
disconnectTitle: 'Gusto trennen',
disconnectPrompt: 'Bist du sicher, dass du Gusto trennen möchtest?',
+ syncResults: {
+ title: 'Gusto-Synchronisierungsergebnisse',
+ successTitle: 'Ihre Gusto-Verbindung wurde erfolgreich synchronisiert!',
+ added: 'Hinzugefügt',
+ removed: 'Entfernt',
+ skipped: 'Übersprungen',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? 'Mitarbeiter' : 'Mitarbeitende'}`,
+ },
},
},
},
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 3f8b9216..6e4a4128 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1687,10 +1687,8 @@ const translations: TranslationDeepObject<typeof en> = {
backdropLabel: 'Fondo del Modal',
},
nextStep: {
- /* eslint-disable @typescript-eslint/no-unused-vars */
message: {
[CONST.NEXT_STEP.MESSAGE_KEY.WAITING_TO_ADD_TRANSACTIONS]: (actor, actorType, _eta, _etaType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que <strong>tú</strong> añadas gastos.`;
@@ -1701,7 +1699,6 @@ const translations: TranslationDeepObject<typeof en> = {
}
},
[CONST.NEXT_STEP.MESSAGE_KEY.WAITING_TO_SUBMIT]: (actor, actorType, _eta, _etaType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que <strong>tú</strong> envíes los gastos.`;
@@ -1713,7 +1710,6 @@ const translations: TranslationDeepObject<typeof en> = {
},
[CONST.NEXT_STEP.MESSAGE_KEY.NO_FURTHER_ACTION]: (_actor, _actorType, _eta, _etaType) => `¡No se requiere ninguna acción adicional!`,
[CONST.NEXT_STEP.MESSAGE_KEY.WAITING_FOR_SUBMITTER_ACCOUNT]: (actor, actorType, _eta, _etaType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que <strong>tú</strong> añadas una cuenta bancaria.`;
@@ -1728,7 +1724,6 @@ const translations: TranslationDeepObject<typeof en> = {
if (eta) {
formattedETA = etaType === CONST.NEXT_STEP.ETA_TYPE.DATE_TIME ? ` el ${eta} de cada mes` : ` ${eta}`;
}
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que tus gastos se envíen automáticamente${formattedETA}.`;
@@ -1739,7 +1734,6 @@ const translations: TranslationDeepObject<typeof en> = {
}
},
[CONST.NEXT_STEP.MESSAGE_KEY.WAITING_TO_FIX_ISSUES]: (actor, actorType, _eta, _etaType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que <strong>tú</strong> soluciones ellos problemas.`;
@@ -1750,7 +1744,6 @@ const translations: TranslationDeepObject<typeof en> = {
}
},
[CONST.NEXT_STEP.MESSAGE_KEY.WAITING_TO_APPROVE]: (actor, actorType, _eta, _etaType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que <strong>tú</strong> apruebes los gastos.`;
@@ -1761,7 +1754,6 @@ const translations: TranslationDeepObject<typeof en> = {
}
},
[CONST.NEXT_STEP.MESSAGE_KEY.WAITING_TO_EXPORT]: (actor, actorType, _eta, _etaType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que <strong>tú</strong> exportes este informe.`;
@@ -1772,7 +1764,6 @@ const translations: TranslationDeepObject<typeof en> = {
}
},
[CONST.NEXT_STEP.MESSAGE_KEY.WAITING_TO_PAY]: (actor, actorType, _eta, _etaType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que <strong>tú</strong> pagues los gastos.`;
@@ -1783,7 +1774,6 @@ const translations: TranslationDeepObject<typeof en> = {
}
},
[CONST.NEXT_STEP.MESSAGE_KEY.WAITING_FOR_POLICY_BANK_ACCOUNT]: (actor, actorType, _eta, _etaType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Esperando a que <strong>tú</strong> termines de configurar una cuenta bancaria de empresa.`;
@@ -1803,7 +1793,6 @@ const translations: TranslationDeepObject<typeof en> = {
[CONST.NEXT_STEP.MESSAGE_KEY.SUBMITTING_TO_SELF]: (_actor, _actorType, _eta, _etaType) =>
`¡Ups! Parece que estás enviando el informe a <strong>ti mismo</strong>. Aprobar tus propios informes está <strong>prohibido</strong> por tu espacio de trabajo. Por favor, envía este informe a otra persona o contacta a tu administrador para cambiar la persona a la que lo envías.`,
[CONST.NEXT_STEP.MESSAGE_KEY.REJECTED_REPORT]: (actor, actorType) => {
- // eslint-disable-next-line default-case
switch (actorType) {
case CONST.NEXT_STEP.ACTOR_TYPE.CURRENT_USER:
return `Este informe fue rechazado. Esperando a que <strong>tú</strong> corrijas los problemas y lo vuelvas a enviar manualmente.`;
@@ -2458,7 +2447,6 @@ ${amount} para ${merchant} - ${date}`,
two: 'º',
few: 'º',
other: 'º',
- /* eslint-disable @typescript-eslint/naming-convention */
'1': 'Primero',
'2': 'Segundo',
'3': 'Tercero',
@@ -2469,7 +2457,6 @@ ${amount} para ${merchant} - ${date}`,
'8': 'Octavo',
'9': 'Noveno',
'10': 'Décimo',
- /* eslint-enable @typescript-eslint/naming-convention */
},
},
approverInMultipleWorkflows: 'Este miembro ya pertenece a otro flujo de aprobación. Cualquier actualización aquí se reflejará allí también.',
@@ -6269,12 +6256,12 @@ ${amount} para ${merchant} - ${date}`,
},
},
syncResults: {
- title: 'Resultados de sincronización de Gusto',
- successTitle: '¡Tu conexión de Gusto se sincronizó correctamente!',
- added: 'Añadidos',
- removed: 'Eliminados',
- skipped: 'Omitidos',
- employeeCount: ({count}) => `${count} ${count === 1 ? 'empleado' : 'empleados'}`,
+ title: 'Resultados de la sincronización de Gusto',
+ successTitle: '¡Se sincronizó correctamente tu conexión con Gusto!',
+ added: 'Añadido',
+ removed: 'Eliminado',
+ skipped: 'Omitido',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? 'empleado' : 'empleados'}`,
},
},
},
@@ -6941,7 +6928,6 @@ ${amount} para ${merchant} - ${date}`,
restrictedDescription: 'Sólo las personas en tu espacio de trabajo pueden encontrar esta sala',
privateDescription: 'Sólo las personas que están invitadas a esta sala pueden encontrarla',
publicDescription: 'Cualquier persona puede unirse a esta sala',
- // eslint-disable-next-line @typescript-eslint/naming-convention
public_announceDescription: 'Cualquier persona puede unirse a esta sala',
createRoom: 'Crea una sala de chat',
roomAlreadyExistsError: 'Ya existe una sala con este nombre',
@@ -6961,7 +6947,6 @@ ${amount} para ${merchant} - ${date}`,
restricted: 'Espacio de trabajo',
private: 'Privada',
public: 'Público',
- // eslint-disable-next-line @typescript-eslint/naming-convention
public_announce: 'Anuncio Público',
},
},
@@ -7276,7 +7261,6 @@ ${amount} para ${merchant} - ${date}`,
updatedDefaultTitle: (newDefaultTitle, oldDefaultTitle) => `cambió la fórmula personalizada del nombre del informe a "${newDefaultTitle}" (previamente "${oldDefaultTitle}")`,
updatedOwnership: (oldOwnerEmail, oldOwnerName, policyName) => `asumió la propiedad del espacio de trabajo ${policyName} de ${oldOwnerName} (${oldOwnerEmail})`,
updatedAutoHarvesting: (enabled) => `${enabled ? 'habilitó' : 'deshabilitó'} el envío programado`,
- // eslint-disable-next-line @typescript-eslint/max-params
updatedIndividualBudgetNotification: (
budgetAmount,
budgetFrequency,
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index d0551c1b..1149d818 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -7101,6 +7101,14 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
syncError: 'Impossible de se connecter à Gusto',
disconnectTitle: 'Déconnecter Gusto',
disconnectPrompt: 'Voulez-vous vraiment déconnecter Gusto ?',
+ syncResults: {
+ title: 'Résultats de la synchronisation Gusto',
+ successTitle: 'Connexion Gusto synchronisée avec succès !',
+ added: 'Ajouté',
+ removed: 'Supprimé',
+ skipped: 'Ignoré',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? 'employé' : 'employés'}`,
+ },
},
},
},
@@ -9306,7 +9314,6 @@ Voici un *reçu test* pour vous montrer comment ça fonctionne :`,
restrictDefaultLoginSelection: 'Restreindre la sélection de connexion par défaut',
restrictDefaultLoginSelectionDescription:
'Empêche les membres de modifier leur e-mail de connexion en dehors du domaine de leur entreprise afin d’éviter les restrictions de politique.',
-
expensifyCardPreferredWorkspaceDisabledMessage:
'Pour activer ce paramètre, veuillez d’abord activer un espace de travail préféré et configurer les cartes Expensify sur votre domaine.',
findGroup: 'Trouver un groupe',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 2af8ca2f..e6ed044e 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -7065,6 +7065,14 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
syncError: 'Impossibile connettersi a Gusto',
disconnectTitle: 'Disconnetti Gusto',
disconnectPrompt: 'Sei sicuro di voler disconnettere Gusto?',
+ syncResults: {
+ title: 'Risultati sincronizzazione Gusto',
+ successTitle: 'Connessione a Gusto sincronizzata con successo!',
+ added: 'Aggiunto',
+ removed: 'Rimosso',
+ skipped: 'Saltato',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? 'dipendente' : 'dipendenti'}`,
+ },
},
},
},
@@ -9273,7 +9281,6 @@ Ecco una *ricevuta di prova* per mostrarti come funziona:`,
noWorkspacesMessage: 'Non ci sono spazi di lavoro su questo dominio. È necessario uno spazio di lavoro per abilitare questa restrizione.',
restrictDefaultLoginSelection: 'Limita la selezione di accesso predefinita',
restrictDefaultLoginSelectionDescription: 'Impedisce ai membri di modificare l’email di accesso al di fuori del dominio aziendale per eludere le restrizioni delle policy.',
-
expensifyCardPreferredWorkspaceDisabledMessage:
'Per abilitare questa impostazione, abilita prima uno spazio di lavoro preferito e configura le Expensify Card per il tuo dominio.',
findGroup: 'Trova gruppo',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 352e35d6..af012e6b 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -6986,6 +6986,14 @@ ${reportName}
syncError: 'Gusto に接続できません',
disconnectTitle: 'Gusto の接続を解除',
disconnectPrompt: 'Gusto との接続を本当に解除しますか?',
+ syncResults: {
+ title: 'Gusto 同期結果',
+ successTitle: 'Gusto との連携が正常に同期されました!',
+ added: '追加済み',
+ removed: '削除済み',
+ skipped: 'スキップ済み',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? '従業員' : '従業員'}`,
+ },
},
},
},
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index eb071e01..3234e7ed 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -7041,6 +7041,14 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
syncError: 'Kan geen verbinding maken met Gusto',
disconnectTitle: 'Verbinding met Gusto verbreken',
disconnectPrompt: 'Weet je zeker dat je de verbinding met Gusto wilt verbreken?',
+ syncResults: {
+ title: 'Gusto-synchronisatieresultaten',
+ successTitle: 'Je Gusto-verbinding is succesvol gesynchroniseerd!',
+ added: 'Toegevoegd',
+ removed: 'Verwijderd',
+ skipped: 'Overgeslagen',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? 'werknemer' : 'medewerkers'}`,
+ },
},
},
},
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 9d574d27..5fe63a58 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -7036,6 +7036,14 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
syncError: 'Nie można połączyć się z Gusto',
disconnectTitle: 'Odłącz Gusto',
disconnectPrompt: 'Czy na pewno chcesz odłączyć Gusto?',
+ syncResults: {
+ title: 'Wyniki synchronizacji Gusto',
+ successTitle: 'Pomyślnie zsynchronizowano Twoje połączenie z Gusto!',
+ added: 'Dodano',
+ removed: 'Usunięto',
+ skipped: 'Pominięto',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? 'pracownik' : 'pracownicy'}`,
+ },
},
},
},
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 33fb094d..4f18f6e4 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -7042,6 +7042,14 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
syncError: 'Não é possível conectar ao Gusto',
disconnectTitle: 'Desconectar Gusto',
disconnectPrompt: 'Tem certeza de que deseja desconectar o Gusto?',
+ syncResults: {
+ title: 'Resultados da sincronização com Gusto',
+ successTitle: 'Sua conexão com o Gusto foi sincronizada com sucesso!',
+ added: 'Adicionado',
+ removed: 'Removido',
+ skipped: 'Ignorado',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? 'funcionário' : 'funcionários'}`,
+ },
},
},
},
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 708c543c..990776c0 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -6868,6 +6868,14 @@ ${reportName}
syncError: '无法连接到 Gusto',
disconnectTitle: '断开 Gusto',
disconnectPrompt: '确定要断开与 Gusto 的连接吗?',
+ syncResults: {
+ title: 'Gusto 同步结果',
+ successTitle: '已成功同步你的 Gusto 连接!',
+ added: '已添加',
+ removed: '已移除',
+ skipped: '已跳过',
+ employeeCount: ({count}: {count: number}) => `${count} ${count === 1 ? '员工' : '员工'}`,
+ },
},
},
},
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
Screen.Recording.2026-05-16.at.1.08.46.AM.mov@yuwenmemon Click on Sync again does not work Edit - One off bug. The sync is working now. |
Reviewer Checklist
Screenshots/VideosScreen.Recording.2026-05-16.at.1.10.33.AM.mov |
|
🚧 @yuwenmemon has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
✋ 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/yuwenmemon in version: 9.3.76-0 🚀
|
|
🚀 Deployed to production by https://github.com/roryabraham in version: 9.3.77-3 🚀
|
Explanation of Change
Adds a reusable Gusto sync results modal and opens it from the HR and Members pages when a focused page receives a completed Gusto sync progress update with a result payload. The modal shows added, removed, and skipped employee counts, with skipped details expandable.
Fixed Issues
$ #87010, #90573
PROPOSAL:
Tests
Offline tests
Same as tests.
QA Steps
Same as tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand 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: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-05-15.at.2.20.54.PM.mov