diff --git a/src/CONST/index.ts b/src/CONST/index.ts
index d41a326a1db3..924145528146 100644
--- a/src/CONST/index.ts
+++ b/src/CONST/index.ts
@@ -1212,6 +1212,7 @@ const CONST = {
CUSTOM_REPORT_NAME_HELP_URL: 'https://help.expensify.com/articles/expensify-classic/spending-insights/Export-Expenses-And-Reports#formulas',
CONFIGURE_REIMBURSEMENT_SETTINGS_HELP_URL: 'https://help.expensify.com/articles/expensify-classic/workspaces/Configure-Reimbursement-Settings',
CONFIGURE_EXPENSE_REPORT_RULES_HELP_URL: 'https://help.expensify.com/articles/new-expensify/workspaces/Set-up-rules#configure-expense-report-rules',
+ CONFIGURE_APPROVAL_WORKFLOWS_HELP_URL: 'https://help.expensify.com/articles/new-expensify/workspaces/Configure-approval-workflows',
SELECT_WORKFLOWS_HELP_URL: 'https://help.expensify.com/articles/new-expensify/workspaces/Set-up-workflows#select-workflows',
COPILOT_HELP_URL: 'https://help.expensify.com/articles/new-expensify/settings/Add-or-Act-As-a-Copilot',
BULK_UPLOAD_HELP_URL: 'https://help.expensify.com/articles/new-expensify/reports-and-expenses/Create-an-Expense#option-4-bulk-upload-receipts-desktop-only',
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 4d3c977497dd..14606cf20714 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -2446,6 +2446,15 @@ const ROUTES = {
return `workspaces/${policyID}/hr` as const;
},
},
+ WORKSPACE_HR_GUSTO_APPROVAL_MODE: {
+ route: 'workspaces/:policyID/hr/gusto/approval-mode',
+ getRoute: (policyID: string | undefined) => {
+ if (!policyID) {
+ Log.warn('Invalid policyID is used to build the WORKSPACE_HR_GUSTO_APPROVAL_MODE route');
+ }
+ return `workspaces/${policyID}/hr/gusto/approval-mode` as const;
+ },
+ },
WORKSPACE_TAGS: {
route: 'workspaces/:policyID/tags',
getRoute: (policyID: string | undefined) => {
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index b9289a81f8ed..a06374758505 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -671,6 +671,7 @@ const SCREENS = {
INITIAL: 'Workspace_Initial',
PROFILE: 'Workspace_Overview',
HR: 'Workspace_HR',
+ HR_GUSTO_APPROVAL_MODE: 'Workspace_HR_Gusto_Approval_Mode',
COMPANY_CARDS: 'Workspace_CompanyCards',
COMPANY_CARDS_BROKEN_CARD_FEED_CONNECTION: 'Workspace_CompanyCards_BrokenCardFeedConnection',
COMPANY_CARDS_REFRESH_CARD_FEED_CONNECTION: 'Workspace_CompanyCards_RefreshCardFeedConnection',
diff --git a/src/languages/de.ts b/src/languages/de.ts
index 499db15acc88..25b5434397d4 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -7030,6 +7030,17 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
title: 'Gusto',
approvalMode: 'Genehmigungsmodus',
finalApprover: 'Endgültige:r Genehmiger:in',
+ notSet: 'Nicht festgelegt',
+ approvalModeDescription: 'Mitglieder und Manager sind für die Synchronisation mit Gusto eingerichtet.',
+ approvalModeWarningTitle: 'Genehmigungsmodus ändern?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `Möchten Sie den Genehmigungsmodus für diesen Workspace wirklich ändern? Erfahren Sie mehr über die verschiedenen Gusto-aktivierten Workflow-Modi auf unserer Hilfeseite.`,
+ approvalModeWarningConfirm: 'Genehmigungsmodus ändern',
+ approvalModes: {
+ basic: {label: 'Einfache Genehmigung', description: 'Alle Benutzer reichen zur Bearbeitung und Genehmigung bei einer einzigen Person ein.'},
+ manager: {label: 'Managergenehmigung', description: 'Mitarbeitende reichen Berichte bei ihrer in Gusto hinterlegten direkten Führungskraft ein.'},
+ custom: {label: 'Benutzerdefinierte Genehmigung', description: 'Ich richte Genehmigungs-Workflows in Expensify manuell ein.'},
+ },
connect: 'Verbinden',
connectionDescription: 'Verbinde Gusto, um Mitarbeitergenehmigungen mit deinem Workspace zu synchronisieren.',
syncNow: 'Jetzt synchronisieren',
diff --git a/src/languages/en.ts b/src/languages/en.ts
index db0c869adeb2..c26c3fd0c5b1 100644
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -6384,6 +6384,26 @@ const translations = {
connectionDescription: 'Connect Gusto to keep employee approvals in sync with your workspace.',
approvalMode: 'Approval mode',
finalApprover: 'Final approver',
+ notSet: 'Not set',
+ approvalModeDescription: 'Members and managers are set up to sync with Gusto.',
+ approvalModeWarningTitle: 'Change approval mode?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `Are you sure you would like to change the approval mode for this workspace? Learn more about the different Gusto-enabled workflow modes in our help site.`,
+ approvalModeWarningConfirm: 'Change approval mode',
+ approvalModes: {
+ basic: {
+ label: 'Basic approval',
+ description: 'All users submit to a single person for processing and approval.',
+ },
+ manager: {
+ label: 'Manager approval',
+ description: 'Employees submit reports to their direct manager configured in Gusto.',
+ },
+ custom: {
+ label: 'Custom approval',
+ description: 'I’ll manually setup approval workflows in Expensify.',
+ },
+ },
},
},
export: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 5cf243f95099..7a66d2ac87ea 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -6249,6 +6249,26 @@ ${amount} para ${merchant} - ${date}`,
connectionDescription: 'Conecta Gusto para mantener sincronizadas las aprobaciones de empleados con tu espacio de trabajo.',
approvalMode: 'Modo de aprobación',
finalApprover: 'Aprobador final',
+ notSet: 'No configurado',
+ approvalModeDescription: 'Los miembros y gerentes están configurados para sincronizarse con Gusto.',
+ approvalModeWarningTitle: '¿Cambiar modo de aprobación?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `¿Seguro que quieres cambiar el modo de aprobación de este espacio de trabajo? Obtén más información sobre los diferentes modos de flujo de trabajo con Gusto en nuestro sitio de ayuda.`,
+ approvalModeWarningConfirm: 'Cambiar modo de aprobación',
+ approvalModes: {
+ basic: {
+ label: 'Aprobación básica',
+ description: 'Todos los usuarios envían a una sola persona para su procesamiento y aprobación.',
+ },
+ manager: {
+ label: 'Aprobación del gerente',
+ description: 'Los empleados envían informes a su gerente directo configurado en Gusto.',
+ },
+ custom: {
+ label: 'Aprobación personalizada',
+ description: 'Configuraré manualmente los flujos de aprobación en Expensify.',
+ },
+ },
},
},
export: {
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 1dc26fa7ad1f..f4173899631e 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -7052,6 +7052,17 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
title: 'Gusto',
approvalMode: 'Mode d’approbation',
finalApprover: 'Approbateur final',
+ notSet: 'Non défini',
+ approvalModeDescription: 'Les membres et les responsables sont configurés pour se synchroniser avec Gusto.',
+ approvalModeWarningTitle: 'Changer le mode d’approbation ?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `Êtes-vous sûr·e de vouloir modifier le mode d’approbation de cet espace de travail ? En savoir plus sur les différents modes de workflow compatibles avec Gusto sur notre site d’aide.`,
+ approvalModeWarningConfirm: 'Modifier le mode d’approbation',
+ approvalModes: {
+ basic: {label: 'Approbation simple', description: 'Tous les utilisateurs soumettent à une seule personne pour traitement et approbation.'},
+ manager: {label: 'Approbation du responsable', description: 'Les employé·e·s soumettent leurs rapports à leur responsable direct configuré dans Gusto.'},
+ custom: {label: 'Approbation personnalisée', description: 'Je configurerai manuellement les circuits de validation dans Expensify.'},
+ },
connect: 'Connect',
connectionDescription: 'Connectez Gusto pour synchroniser les validations des employé·e·s avec votre espace de travail.',
syncNow: 'Synchroniser maintenant',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 409eb16ce187..bebaf863bfae 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -7015,6 +7015,17 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
title: 'Gusto',
approvalMode: 'Modalità approvazione',
finalApprover: 'Approvazione finale',
+ notSet: 'Non impostato',
+ approvalModeDescription: 'I membri e i responsabili sono configurati per la sincronizzazione con Gusto.',
+ approvalModeWarningTitle: 'Cambiare modalità di approvazione?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `Sei sicuro di voler cambiare la modalità di approvazione per questo spazio di lavoro? Scopri di più sulle diverse modalità di flusso di lavoro abilitate per Gusto nel nostro sito di assistenza.`,
+ approvalModeWarningConfirm: 'Cambia modalità di approvazione',
+ approvalModes: {
+ basic: {label: 'Approvazione di base', description: 'Tutti gli utenti inviano a una singola persona per l’elaborazione e l’approvazione.'},
+ manager: {label: 'Approvazione del responsabile', description: 'I dipendenti inviano i report al proprio responsabile diretto configurato in Gusto.'},
+ custom: {label: 'Approvazione personalizzata', description: 'Imposterò manualmente i flussi di approvazione in Expensify.'},
+ },
connect: 'Collega',
connectionDescription: 'Collega Gusto per sincronizzare le approvazioni dei dipendenti con il tuo spazio di lavoro.',
syncNow: 'Sincronizza ora',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index f85d3968da21..ceafe94ecf34 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -6938,6 +6938,17 @@ ${reportName}
title: 'Gusto',
approvalMode: '承認モード',
finalApprover: '最終承認者',
+ notSet: '未設定',
+ approvalModeDescription: 'メンバーとマネージャーは Gusto と同期するように設定されています。',
+ approvalModeWarningTitle: '承認モードを変更しますか?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `このワークスペースの承認モードを変更してもよろしいですか?Gusto 対応の各ワークフローモードについては、ヘルプサイトで詳しくご覧いただけます。`,
+ approvalModeWarningConfirm: '承認モードを変更',
+ approvalModes: {
+ basic: {label: '基本承認', description: 'すべてのユーザーは、処理と承認のために 1 人の担当者に提出します。'},
+ manager: {label: 'マネージャー承認', description: '従業員は、Gusto で設定された直属のマネージャーにレポートを提出します。'},
+ custom: {label: 'カスタム承認', description: 'Expensify で承認ワークフローを手動で設定します。'},
+ },
connect: '接続',
connectionDescription: 'Gusto を接続して、従業員の承認をワークスペースと同期させましょう。',
syncNow: '今すぐ同期',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 43637941167e..b7301b1bcbdd 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -6994,6 +6994,17 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
title: 'Gusto',
approvalMode: 'Goedkeuringsmodus',
finalApprover: 'Laatste fiatteur',
+ notSet: 'Niet ingesteld',
+ approvalModeDescription: 'Leden en managers zijn ingesteld om te synchroniseren met Gusto.',
+ approvalModeWarningTitle: 'Goedkeuringsmodus wijzigen?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `Weet je zeker dat je de goedkeuringsmodus voor deze werkruimte wilt wijzigen? Lees meer over de verschillende Gusto-ondersteunde workflowmodi op onze help-site.`,
+ approvalModeWarningConfirm: 'Goedkeuringsmodus wijzigen',
+ approvalModes: {
+ basic: {label: 'Basisgoedkeuring', description: 'Alle gebruikers dienen bij één persoon in voor verwerking en goedkeuring.'},
+ manager: {label: 'Goedkeuring manager', description: 'Werknemers dienen rapporten in bij hun direct leidinggevende die is ingesteld in Gusto.'},
+ custom: {label: 'Aangepaste goedkeuring', description: 'Ik stel goedkeuringsworkflows handmatig in in Expensify.'},
+ },
connect: 'Verbinden',
connectionDescription: 'Verbind Gusto om goedkeuringen van werknemers gesynchroniseerd te houden met je workspace.',
syncNow: 'Nu synchroniseren',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 53263beec1aa..9359cab93104 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -6987,6 +6987,17 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
title: 'Gusto',
approvalMode: 'Tryb zatwierdzania',
finalApprover: 'Ostateczny zatwierdzający',
+ notSet: 'Nie ustawiono',
+ approvalModeDescription: 'Członkowie i menedżerowie są skonfigurowani do synchronizacji z Gusto.',
+ approvalModeWarningTitle: 'Zmienić tryb zatwierdzania?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `Czy na pewno chcesz zmienić tryb zatwierdzania dla tego obszaru roboczego? Dowiedz się więcej o różnych trybach przepływu pracy obsługiwanych przez Gusto w naszej witrynie pomocy.`,
+ approvalModeWarningConfirm: 'Zmień tryb zatwierdzania',
+ approvalModes: {
+ basic: {label: 'Podstawowa akceptacja', description: 'Wszyscy użytkownicy przesyłają wydatki do jednej osoby w celu ich przetworzenia i zatwierdzenia.'},
+ manager: {label: 'Zatwierdzenie przez menedżera', description: 'Pracownicy przesyłają raporty do swojego bezpośredniego menedżera skonfigurowanego w Gusto.'},
+ custom: {label: 'Niestandardowa akceptacja', description: 'Ręcznie skonfiguruję procesy zatwierdzania w Expensify.'},
+ },
connect: 'Połącz',
connectionDescription: 'Połącz Gusto, aby synchronizować akceptacje pracowników z Twoim miejscem pracy.',
syncNow: 'Synchronizuj teraz',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 0e88a1d7dfe5..5da3a7a16e8a 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -6993,6 +6993,17 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
title: 'Gusto',
approvalMode: 'Modo de aprovação',
finalApprover: 'Aprovador final',
+ notSet: 'Não definido',
+ approvalModeDescription: 'Membros e gerentes estão configurados para sincronizar com o Gusto.',
+ approvalModeWarningTitle: 'Alterar modo de aprovação?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `Tem certeza de que deseja alterar o modo de aprovação deste workspace? Saiba mais sobre os diferentes modos de fluxo de trabalho com Gusto em nosso site de ajuda.`,
+ approvalModeWarningConfirm: 'Alterar modo de aprovação',
+ approvalModes: {
+ basic: {label: 'Aprovação básica', description: 'Todos os usuários enviam para uma única pessoa para processamento e aprovação.'},
+ manager: {label: 'Aprovação do gerente', description: 'Os funcionários enviam relatórios ao gestor direto configurado no Gusto.'},
+ custom: {label: 'Aprovação personalizada', description: 'Vou configurar manualmente os fluxos de aprovação no Expensify.'},
+ },
connect: 'Conectar',
connectionDescription: 'Conecte o Gusto para manter as aprovações de funcionários sincronizadas com seu workspace.',
syncNow: 'Sincronizar agora',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 57a033f739b6..c267cc73e21b 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -6820,6 +6820,17 @@ ${reportName}
title: 'Gusto',
approvalMode: '审批模式',
finalApprover: '最终审批人',
+ notSet: '未设置',
+ approvalModeDescription: '成员和管理员已设置为与 Gusto 同步。',
+ approvalModeWarningTitle: '更改审批模式?',
+ approvalModeWarningPrompt: (helpSiteURL: string) =>
+ `您确定要更改此工作区的审批模式吗?在我们的帮助网站中了解更多关于不同 Gusto 启用的工作流模式的信息。`,
+ approvalModeWarningConfirm: '更改审批模式',
+ approvalModes: {
+ basic: {label: '基础审批', description: '所有用户都提交给同一个人进行处理和审批。'},
+ manager: {label: '经理审批', description: '员工会将报销单提交给在 Gusto 中配置的直属经理。'},
+ custom: {label: '自定义审批', description: '我将在 Expensify 中手动设置审批工作流程。'},
+ },
connect: '连接',
connectionDescription: '连接 Gusto,以在您的工作区中同步员工审批。',
syncNow: '立即同步',
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index 080cbb419d16..f4e6191b5a10 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -914,6 +914,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Security/LockAccount/LockAccountPage').default,
[SCREENS.SETTINGS.LOCK.UNLOCK_ACCOUNT]: () => require('../../../../pages/settings/Security/LockAccount/UnlockAccountPage').default,
[SCREENS.SETTINGS.LOCK.FAILED_TO_LOCK_ACCOUNT]: () => require('../../../../pages/settings/Security/LockAccount/FailedToLockAccountPage').default,
+ [SCREENS.WORKSPACE.HR_GUSTO_APPROVAL_MODE]: () => require('../../../../pages/workspace/hr/gusto/GustoApprovalModePage').default,
[SCREENS.WORKSPACE.REPORTS_DEFAULT_TITLE]: () => require('../../../../pages/workspace/reports/ReportsDefaultTitle').default,
[SCREENS.WORKSPACE.RULES_AUTO_APPROVE_REPORTS_UNDER]: () => require('../../../../pages/workspace/rules/RulesAutoApproveReportsUnderPage').default,
[SCREENS.WORKSPACE.RULES_RANDOM_REPORT_AUDIT]: () => require('../../../../pages/workspace/rules/RulesRandomReportAuditPage').default,
diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
index 13256acf6481..f11d61afc7f6 100755
--- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
+++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
@@ -180,6 +180,7 @@ const WORKSPACE_TO_RHP: Partial['config'] = {
[SCREENS.WORKSPACE.RULES_REIMBURSABLE_DEFAULT]: {
path: ROUTES.RULES_REIMBURSABLE_DEFAULT.route,
},
+ [SCREENS.WORKSPACE.HR_GUSTO_APPROVAL_MODE]: {
+ path: ROUTES.WORKSPACE_HR_GUSTO_APPROVAL_MODE.route,
+ },
[SCREENS.WORKSPACE.RULES_CUSTOM]: {
path: ROUTES.RULES_CUSTOM.route,
},
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 57c5dbd085ad..dddf2cde4f73 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -1455,6 +1455,9 @@ type SettingsNavigatorParamList = {
[SCREENS.WORKSPACE.RULES_REIMBURSABLE_DEFAULT]: {
policyID: string;
};
+ [SCREENS.WORKSPACE.HR_GUSTO_APPROVAL_MODE]: {
+ policyID: string;
+ };
[SCREENS.WORKSPACE.RULES_PROHIBITED_DEFAULT]: {
policyID: string;
};
diff --git a/src/libs/actions/connections/Gusto.ts b/src/libs/actions/connections/Gusto.ts
index dab0d99eb924..1c434041ec81 100644
--- a/src/libs/actions/connections/Gusto.ts
+++ b/src/libs/actions/connections/Gusto.ts
@@ -1,6 +1,13 @@
+import type {OnyxUpdate} from 'react-native-onyx';
+import Onyx from 'react-native-onyx';
+import type {ValueOf} from 'type-fest';
+import {write} from '@libs/API';
import type {ConnectPolicyToGustoParams} from '@libs/API/parameters';
-import {READ_COMMANDS} from '@libs/API/types';
+import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import {getCommandURL} from '@libs/ApiUtils';
+import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
function getGustoSetupLink(policyID: string) {
const params: ConnectPolicyToGustoParams = {policyID};
@@ -11,4 +18,70 @@ function getGustoSetupLink(policyID: string) {
return commandURL + new URLSearchParams(params).toString();
}
+function updateGustoApprovalMode(
+ policyID: string | undefined,
+ approvalMode: ValueOf,
+ currentApprovalMode?: ValueOf | null,
+) {
+ if (!policyID) {
+ return;
+ }
+
+ const previousApprovalMode = currentApprovalMode ?? null;
+ const optimisticData: Array> = [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
+ value: {
+ connections: {
+ gusto: {
+ config: {
+ approvalMode,
+ pendingFields: {approvalMode: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
+ errorFields: {approvalMode: null},
+ },
+ },
+ },
+ },
+ },
+ ];
+ const successData: Array> = [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
+ value: {
+ connections: {
+ gusto: {
+ config: {
+ pendingFields: {approvalMode: null},
+ errorFields: {approvalMode: null},
+ },
+ },
+ },
+ },
+ },
+ ];
+ const failureData: Array> = [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
+ value: {
+ connections: {
+ gusto: {
+ config: {
+ approvalMode: previousApprovalMode,
+ pendingFields: {approvalMode: null},
+ errorFields: {approvalMode: getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')},
+ },
+ },
+ },
+ },
+ },
+ ];
+
+ write(WRITE_COMMANDS.UPDATE_GUSTO_APPROVAL_MODE, {policyID, approvalMode}, {optimisticData, successData, failureData});
+}
+
+export {updateGustoApprovalMode};
+
export default getGustoSetupLink;
diff --git a/src/pages/workspace/hr/WorkspaceHRPage.tsx b/src/pages/workspace/hr/WorkspaceHRPage.tsx
index 445c5d210720..d83eb52782ac 100644
--- a/src/pages/workspace/hr/WorkspaceHRPage.tsx
+++ b/src/pages/workspace/hr/WorkspaceHRPage.tsx
@@ -1,11 +1,14 @@
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
+import type {ValueOf} from 'type-fest';
import ActivityIndicator from '@components/ActivityIndicator';
import Button from '@components/Button';
import ConfirmModal from '@components/ConfirmModal';
import ConnectToGustoFlow from '@components/ConnectToGustoFlow';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import Section from '@components/Section';
@@ -30,9 +33,11 @@ import {getIntegrationLastSuccessfulDate, isGustoConnected} from '@libs/PolicyUt
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
type WorkspaceHRPageProps = PlatformStackScreenProps;
+type GustoApprovalMode = ValueOf;
function WorkspaceHRPage({
route: {
@@ -50,6 +55,7 @@ function WorkspaceHRPage({
const icons = useMemoizedLazyExpensifyIcons(['GustoSquare', 'Sync', 'Trashcan']);
const illustrations = useMemoizedLazyIllustrations(['NewUser']);
const gustoConnection = policy?.connections?.gusto;
+ const gustoConfig = gustoConnection?.config;
const isConnected = isGustoConnected(policy);
const isGustoSyncInProgress = connectionSyncProgress?.connectionName === CONST.POLICY.CONNECTIONS.NAME.GUSTO && isConnectionInProgress(connectionSyncProgress, policy);
const stageInProgress = connectionSyncProgress?.stageInProgress;
@@ -101,7 +107,22 @@ function WorkspaceHRPage({
],
[icons.Sync, icons.Trashcan, isOffline, policy, translate],
);
+ const getGustoApprovalModeLabel = (approvalMode?: GustoApprovalMode | null) => {
+ if (!approvalMode) {
+ return translate('workspace.hr.gusto.notSet');
+ }
+ switch (approvalMode) {
+ case CONST.GUSTO.APPROVAL_MODE.BASIC:
+ return translate('workspace.hr.gusto.approvalModes.basic.label');
+ case CONST.GUSTO.APPROVAL_MODE.MANAGER:
+ return translate('workspace.hr.gusto.approvalModes.manager.label');
+ case CONST.GUSTO.APPROVAL_MODE.CUSTOM:
+ return translate('workspace.hr.gusto.approvalModes.custom.label');
+ default:
+ return translate('workspace.hr.gusto.notSet');
+ }
+ };
let gustoRowRightComponent;
if (!isConnected) {
gustoRowRightComponent = (
@@ -178,6 +199,18 @@ function WorkspaceHRPage({
shouldShowRightComponent
rightComponent={gustoRowRightComponent}
/>
+ {isConnected && (
+
+ Navigation.navigate(ROUTES.WORKSPACE_HR_GUSTO_APPROVAL_MODE.getRoute(policyID))}
+ />
+
+ )}
diff --git a/src/pages/workspace/hr/gusto/GustoApprovalModePage.tsx b/src/pages/workspace/hr/gusto/GustoApprovalModePage.tsx
new file mode 100644
index 000000000000..a2b50ffd26a6
--- /dev/null
+++ b/src/pages/workspace/hr/gusto/GustoApprovalModePage.tsx
@@ -0,0 +1,137 @@
+import React, {useState} from 'react';
+import {View} from 'react-native';
+import type {ValueOf} from 'type-fest';
+import Button from '@components/Button';
+import ConfirmModal from '@components/ConfirmModal';
+import FixedFooter from '@components/FixedFooter';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import RenderHTML from '@components/RenderHTML';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import SingleSelectListItem from '@components/SelectionList/ListItem/SingleSelectListItem';
+import type {ListItem} from '@components/SelectionList/types';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import usePermissions from '@hooks/usePermissions';
+import usePolicy from '@hooks/usePolicy';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {updateGustoApprovalMode} from '@libs/actions/connections/Gusto';
+import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
+import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
+import {isGustoConnected} from '@libs/PolicyUtils';
+import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
+import CONST from '@src/CONST';
+import type SCREENS from '@src/SCREENS';
+
+type ApprovalMode = ValueOf;
+type GustoApprovalModePageProps = PlatformStackScreenProps;
+type ApprovalModeListItem = ListItem & {
+ value: ApprovalMode;
+};
+
+function GustoApprovalModePage({
+ route: {
+ params: {policyID},
+ },
+}: GustoApprovalModePageProps) {
+ const {translate} = useLocalize();
+ const styles = useThemeStyles();
+ const {isBetaEnabled} = usePermissions();
+ const policy = usePolicy(policyID);
+ const currentApprovalMode = policy?.connections?.gusto?.config?.approvalMode ?? undefined;
+ const [draftApprovalMode, setDraftApprovalMode] = useState();
+ const [isWarningModalOpen, setIsWarningModalOpen] = useState(false);
+ const selectedApprovalMode = draftApprovalMode ?? currentApprovalMode;
+ const isSaveDisabled = !draftApprovalMode || draftApprovalMode === currentApprovalMode;
+ const approvalModeOptions: ApprovalModeListItem[] = [
+ {
+ text: translate('workspace.hr.gusto.approvalModes.basic.label'),
+ alternateText: translate('workspace.hr.gusto.approvalModes.basic.description'),
+ keyForList: CONST.GUSTO.APPROVAL_MODE.BASIC,
+ value: CONST.GUSTO.APPROVAL_MODE.BASIC,
+ isSelected: selectedApprovalMode === CONST.GUSTO.APPROVAL_MODE.BASIC,
+ },
+ {
+ text: translate('workspace.hr.gusto.approvalModes.manager.label'),
+ alternateText: translate('workspace.hr.gusto.approvalModes.manager.description'),
+ keyForList: CONST.GUSTO.APPROVAL_MODE.MANAGER,
+ value: CONST.GUSTO.APPROVAL_MODE.MANAGER,
+ isSelected: selectedApprovalMode === CONST.GUSTO.APPROVAL_MODE.MANAGER,
+ },
+ {
+ text: translate('workspace.hr.gusto.approvalModes.custom.label'),
+ alternateText: translate('workspace.hr.gusto.approvalModes.custom.description'),
+ keyForList: CONST.GUSTO.APPROVAL_MODE.CUSTOM,
+ value: CONST.GUSTO.APPROVAL_MODE.CUSTOM,
+ isSelected: selectedApprovalMode === CONST.GUSTO.APPROVAL_MODE.CUSTOM,
+ },
+ ];
+ const selectedApprovalModeKey = approvalModeOptions.find((approvalMode) => approvalMode.isSelected)?.keyForList;
+
+ const selectApprovalMode = (approvalMode: ApprovalMode) => {
+ setDraftApprovalMode(approvalMode);
+ };
+
+ const saveApprovalMode = () => {
+ if (!draftApprovalMode) {
+ return;
+ }
+
+ updateGustoApprovalMode(policyID, draftApprovalMode, currentApprovalMode);
+ setIsWarningModalOpen(false);
+ Navigation.goBack();
+ };
+
+ return (
+
+
+ Navigation.goBack()}
+ />
+
+ {translate('workspace.hr.gusto.approvalModeDescription')}
+ selectApprovalMode(option.value)}
+ shouldSingleExecuteRowSelect
+ initiallyFocusedItemKey={selectedApprovalModeKey}
+ alternateNumberOfSupportedLines={3}
+ showScrollIndicator={false}
+ />
+
+
+
+ setIsWarningModalOpen(false)}
+ prompt={}
+ confirmText={translate('workspace.hr.gusto.approvalModeWarningConfirm')}
+ cancelText={translate('common.cancel')}
+ />
+
+
+ );
+}
+
+export default GustoApprovalModePage;