From e8a2b770ecf7c0d2b398de9c59069ae90db65522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Mon, 18 May 2026 22:49:58 +0200 Subject: [PATCH 01/19] Render per page providers on HR page POC --- src/CONST/index.ts | 3 + src/languages/de.ts | 16 ++ src/languages/en.ts | 22 ++ src/languages/es.ts | 22 ++ src/languages/fr.ts | 16 ++ src/languages/it.ts | 16 ++ src/languages/ja.ts | 16 ++ src/languages/nl.ts | 16 ++ src/languages/pl.ts | 16 ++ src/languages/pt-BR.ts | 16 ++ src/languages/zh-hans.ts | 16 ++ .../parameters/SyncPolicyToMergeHRParams.ts | 6 + src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + src/libs/PolicyUtils.ts | 2 +- src/libs/actions/connections/index.ts | 3 + src/pages/workspace/WorkspaceInitialPage.tsx | 2 +- .../WorkspaceMoreFeaturesPage/index.tsx | 2 +- src/pages/workspace/hr/HRProviderCard.tsx | 151 +++++++++++ src/pages/workspace/hr/WorkspaceHRPage.tsx | 254 ++++++------------ src/pages/workspace/hr/utils.ts | 245 +++++++++++++++++ 21 files changed, 672 insertions(+), 171 deletions(-) create mode 100644 src/libs/API/parameters/SyncPolicyToMergeHRParams.ts create mode 100644 src/pages/workspace/hr/HRProviderCard.tsx create mode 100644 src/pages/workspace/hr/utils.ts diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 586e997b41b7..6a6ba75e68f1 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -3958,6 +3958,9 @@ const CONST = { ZENEFITS_SYNC_TITLE: 'zenefitsSyncTitle', ZENEFITS_SYNC_LOAD_DATA: 'zenefitsSyncLoadData', ZENEFITS_SYNC_PROVISIONING: 'zenefitsSyncProvisioning', + MERGE_HR_SYNC_TITLE: 'mergeHRSyncTitle', + MERGE_HR_SYNC_LOAD_DATA: 'mergeHRSyncLoadData', + MERGE_HR_SYNC_PROVISIONING: 'mergeHRSyncProvisioning', FINANCIAL_FORCE_SYNC_CONNECTION: 'financialForceSyncConnection', }, SYNC_STAGE_TIMEOUT_MINUTES: 20, diff --git a/src/languages/de.ts b/src/languages/de.ts index f53de4ba4fc4..9689bfc511a9 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -261,6 +261,7 @@ const translations: TranslationDeepObject = { reset: 'Zurücksetzen', done: 'Fertig', more: 'Mehr', + other: 'Andere', debitCard: 'Debitkarte', bankAccount: 'Bankkonto', personalBankAccount: 'Persönliches Bankkonto', @@ -7068,6 +7069,21 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc title: 'Personalwesen', subtitle: 'HR-Tools verbinden und Mitarbeitergenehmigungen synchron halten.', settingsTitle: 'Gusto-Einstellungen', + connect: 'Verbinden', + syncNow: 'Jetzt synchronisieren', + disconnect: 'Trennen', + disconnectTitle: (providerName: string) => `${providerName} trennen`, + disconnectPrompt: (providerName: string) => `Möchten Sie ${providerName} wirklich trennen?`, + lastSync: (relativeDate: string) => `Zuletzt synchronisiert ${relativeDate}`, + syncError: (providerName: string) => `Verbindung zu ${providerName} nicht möglich`, + approvalMode: 'Genehmigungsmodus', + finalApprover: 'Endgültiger Genehmiger', + notSet: 'Nicht festgelegt', + approvalModes: { + basic: {label: 'Einfache Genehmigung'}, + manager: {label: 'Manager-Genehmigung'}, + custom: {label: 'Benutzerdefinierte Genehmigung'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': diff --git a/src/languages/en.ts b/src/languages/en.ts index 33ccd870dd9d..22542a914178 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -270,6 +270,7 @@ const translations = { // @context Status or button indicating that an action or process has been completed. Should reflect completion. done: 'Done', more: 'More', + other: 'Other', debitCard: 'Debit card', bankAccount: 'Bank account', personalBankAccount: 'Personal bank account', @@ -6421,6 +6422,21 @@ const translations = { title: 'HR', subtitle: 'Connect HR tools and keep employee approvals in sync.', settingsTitle: 'Gusto settings', + connect: 'Connect', + syncNow: 'Sync now', + disconnect: 'Disconnect', + disconnectTitle: (providerName: string) => `Disconnect ${providerName}`, + disconnectPrompt: (providerName: string) => `Are you sure you want to disconnect ${providerName}?`, + lastSync: (relativeDate: string) => `Last synced ${relativeDate}`, + syncError: (providerName: string) => `Can't connect to ${providerName}`, + approvalMode: 'Approval mode', + finalApprover: 'Final approver', + notSet: 'Not set', + approvalModes: { + basic: {label: 'Basic approval'}, + manager: {label: 'Manager approval'}, + custom: {label: 'Custom approval'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': @@ -6435,6 +6451,12 @@ const translations = { return 'Loading data from TriNet'; case 'zenefitsSyncProvisioning': return 'Provisioning employees in policy'; + case 'mergeHRSyncTitle': + return 'Synchronizing HR Employees'; + case 'mergeHRSyncLoadData': + return 'Loading data from HR provider'; + case 'mergeHRSyncProvisioning': + return 'Provisioning employees in policy'; case 'jobDone': return 'Waiting for imported data to load'; default: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 1ec062081842..3837b990158e 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -217,6 +217,7 @@ const translations: TranslationDeepObject = { reset: 'Restablecer', done: 'Listo', more: 'Más', + other: 'Otro', debitCard: 'Tarjeta de débito', bankAccount: 'Cuenta bancaria', personalBankAccount: 'Cuenta bancaria personal', @@ -6233,6 +6234,21 @@ ${amount} para ${merchant} - ${date}`, title: 'HR', subtitle: 'Conecta herramientas de HR y mantén sincronizadas las aprobaciones de empleados.', settingsTitle: 'Configuración de Gusto', + connect: 'Conectar', + syncNow: 'Sincronizar ahora', + disconnect: 'Desconectar', + disconnectTitle: (providerName: string) => `Desconectar ${providerName}`, + disconnectPrompt: (providerName: string) => `¿Seguro que quieres desconectar ${providerName}?`, + lastSync: (relativeDate: string) => `Última sincronización ${relativeDate}`, + syncError: (providerName: string) => `No se puede conectar con ${providerName}`, + approvalMode: 'Modo de aprobación', + finalApprover: 'Aprobador final', + notSet: 'No configurado', + approvalModes: { + basic: {label: 'Aprobación básica'}, + manager: {label: 'Aprobación del gerente'}, + custom: {label: 'Aprobación personalizada'}, + }, syncStageName: ({stage}) => { switch (stage) { case 'gustoSyncTitle': @@ -6247,6 +6263,12 @@ ${amount} para ${merchant} - ${date}`, return 'Cargando datos desde TriNet'; case 'zenefitsSyncProvisioning': return 'Aprovisionar empleados en la política'; + case 'mergeHRSyncTitle': + return 'Sincronización de empleados de HR'; + case 'mergeHRSyncLoadData': + return 'Cargando datos del proveedor de HR'; + case 'mergeHRSyncProvisioning': + return 'Aprovisionar empleados en la política'; case 'jobDone': return 'Esperando a que se carguen los datos importados'; default: { diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 9520cff2236c..d76e0b647672 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -261,6 +261,7 @@ const translations: TranslationDeepObject = { reset: 'Réinitialiser', done: 'Terminé', more: 'Plus', + other: 'Autre', debitCard: 'Carte de débit', bankAccount: 'Compte bancaire', personalBankAccount: 'Compte bancaire personnel', @@ -7090,6 +7091,21 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e title: 'RH', subtitle: 'Connectez vos outils RH et gardez les approbations des employés synchronisées.', settingsTitle: 'Paramètres Gusto', + connect: 'Connecter', + syncNow: 'Synchroniser maintenant', + disconnect: 'Déconnecter', + disconnectTitle: (providerName: string) => `Déconnecter ${providerName}`, + disconnectPrompt: (providerName: string) => `Êtes-vous sûr de vouloir déconnecter ${providerName} ?`, + lastSync: (relativeDate: string) => `Dernière synchronisation ${relativeDate}`, + syncError: (providerName: string) => `Impossible de se connecter à ${providerName}`, + approvalMode: "Mode d'approbation", + finalApprover: 'Approbateur final', + notSet: 'Non défini', + approvalModes: { + basic: {label: 'Approbation basique'}, + manager: {label: 'Approbation du manager'}, + custom: {label: 'Approbation personnalisée'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': diff --git a/src/languages/it.ts b/src/languages/it.ts index 3a5a35b0c5a6..a6d6f4402c2e 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -261,6 +261,7 @@ const translations: TranslationDeepObject = { reset: 'Reimposta', done: 'Completato', more: 'Altro', + other: 'Altro', debitCard: 'Carta di debito', bankAccount: 'Conto bancario', personalBankAccount: 'Conto bancario personale', @@ -7054,6 +7055,21 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`, title: 'Risorse umane', subtitle: 'Collega gli strumenti HR e mantieni sincronizzate le approvazioni dei dipendenti.', settingsTitle: 'Impostazioni Gusto', + connect: 'Connetti', + syncNow: 'Sincronizza ora', + disconnect: 'Disconnetti', + disconnectTitle: (providerName: string) => `Disconnetti ${providerName}`, + disconnectPrompt: (providerName: string) => `Sei sicuro di voler disconnettere ${providerName}?`, + lastSync: (relativeDate: string) => `Ultima sincronizzazione ${relativeDate}`, + syncError: (providerName: string) => `Impossibile connettersi a ${providerName}`, + approvalMode: 'Modalità di approvazione', + finalApprover: 'Approvatore finale', + notSet: 'Non impostato', + approvalModes: { + basic: {label: 'Approvazione base'}, + manager: {label: 'Approvazione del manager'}, + custom: {label: 'Approvazione personalizzata'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 505b040300a3..9a7043f36db2 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -261,6 +261,7 @@ const translations: TranslationDeepObject = { reset: 'リセット', done: '完了', more: 'その他', + other: 'その他', debitCard: 'デビットカード', bankAccount: '銀行口座', personalBankAccount: '個人銀行口座', @@ -6976,6 +6977,21 @@ ${reportName} title: '人事', subtitle: '人事ツールを連携して、従業員の承認を常に同期させます。', settingsTitle: 'Gusto 設定', + connect: '接続', + syncNow: '今すぐ同期', + disconnect: '切断', + disconnectTitle: (providerName: string) => `${providerName}を切断`, + disconnectPrompt: (providerName: string) => `${providerName}を切断してもよろしいですか?`, + lastSync: (relativeDate: string) => `最終同期: ${relativeDate}`, + syncError: (providerName: string) => `${providerName}に接続できません`, + approvalMode: '承認モード', + finalApprover: '最終承認者', + notSet: '未設定', + approvalModes: { + basic: {label: '基本承認'}, + manager: {label: 'マネージャー承認'}, + custom: {label: 'カスタム承認'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': diff --git a/src/languages/nl.ts b/src/languages/nl.ts index ff5e1f6e449a..30c16fe3fa56 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -261,6 +261,7 @@ const translations: TranslationDeepObject = { reset: 'Opnieuw instellen', done: 'Klaar', more: 'Meer', + other: 'Overig', debitCard: 'Debetkaart', bankAccount: 'Bankrekening', personalBankAccount: 'Persoonlijke bankrekening', @@ -7031,6 +7032,21 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`, title: 'HR', subtitle: 'Koppel HR-tools en houd goedkeuringen van medewerkers gesynchroniseerd.', settingsTitle: 'Gusto-instellingen', + connect: 'Verbinden', + syncNow: 'Nu synchroniseren', + disconnect: 'Ontkoppelen', + disconnectTitle: (providerName: string) => `${providerName} ontkoppelen`, + disconnectPrompt: (providerName: string) => `Weet je zeker dat je ${providerName} wilt ontkoppelen?`, + lastSync: (relativeDate: string) => `Laatst gesynchroniseerd ${relativeDate}`, + syncError: (providerName: string) => `Kan geen verbinding maken met ${providerName}`, + approvalMode: 'Goedkeuringsmodus', + finalApprover: 'Eindgoedkeurder', + notSet: 'Niet ingesteld', + approvalModes: { + basic: {label: 'Basisgoedkeuring'}, + manager: {label: 'Managergoedkeuring'}, + custom: {label: 'Aangepaste goedkeuring'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': diff --git a/src/languages/pl.ts b/src/languages/pl.ts index ed8a163d51c7..a59d32b5f313 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -261,6 +261,7 @@ const translations: TranslationDeepObject = { reset: 'Reset', done: 'Gotowe', more: 'Więcej', + other: 'Inne', debitCard: 'Karta debetowa', bankAccount: 'Konto bankowe', personalBankAccount: 'Prywatne konto bankowe', @@ -7025,6 +7026,21 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`, title: 'HR', subtitle: 'Połącz narzędzia HR i utrzymuj zgody pracowników w synchronizacji.', settingsTitle: 'Ustawienia Gusto', + connect: 'Połącz', + syncNow: 'Synchronizuj teraz', + disconnect: 'Odłącz', + disconnectTitle: (providerName: string) => `Odłącz ${providerName}`, + disconnectPrompt: (providerName: string) => `Czy na pewno chcesz odłączyć ${providerName}?`, + lastSync: (relativeDate: string) => `Ostatnia synchronizacja ${relativeDate}`, + syncError: (providerName: string) => `Nie można połączyć z ${providerName}`, + approvalMode: 'Tryb zatwierdzania', + finalApprover: 'Ostateczny zatwierdzający', + notSet: 'Nie ustawiono', + approvalModes: { + basic: {label: 'Podstawowe zatwierdzanie'}, + manager: {label: 'Zatwierdzanie przez menedżera'}, + custom: {label: 'Niestandardowe zatwierdzanie'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index a991ab46d5c3..138c22b03007 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -261,6 +261,7 @@ const translations: TranslationDeepObject = { reset: 'Redefinir', done: 'Concluído', more: 'Mais', + other: 'Outro', debitCard: 'Cartão de débito', bankAccount: 'Conta bancária', personalBankAccount: 'Conta bancária pessoal', @@ -7031,6 +7032,21 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, title: 'RH', subtitle: 'Conecte ferramentas de RH e mantenha as aprovações de funcionários em sincronia.', settingsTitle: 'Configurações do Gusto', + connect: 'Conectar', + syncNow: 'Sincronizar agora', + disconnect: 'Desconectar', + disconnectTitle: (providerName: string) => `Desconectar ${providerName}`, + disconnectPrompt: (providerName: string) => `Tem certeza de que deseja desconectar ${providerName}?`, + lastSync: (relativeDate: string) => `Última sincronização ${relativeDate}`, + syncError: (providerName: string) => `Não é possível conectar ao ${providerName}`, + approvalMode: 'Modo de aprovação', + finalApprover: 'Aprovador final', + notSet: 'Não definido', + approvalModes: { + basic: {label: 'Aprovação básica'}, + manager: {label: 'Aprovação do gerente'}, + custom: {label: 'Aprovação personalizada'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 39b09da95659..d179bc7bba3d 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -261,6 +261,7 @@ const translations: TranslationDeepObject = { reset: '重置', done: '完成', more: '更多', + other: '其他', debitCard: '借记卡', bankAccount: '银行账户', personalBankAccount: '个人银行账户', @@ -6856,6 +6857,21 @@ ${reportName} title: '人力资源', subtitle: '连接人力资源工具,保持员工审批同步。', settingsTitle: 'Gusto 设置', + connect: '连接', + syncNow: '立即同步', + disconnect: '断开连接', + disconnectTitle: (providerName: string) => `断开 ${providerName}`, + disconnectPrompt: (providerName: string) => `确定要断开 ${providerName} 吗?`, + lastSync: (relativeDate: string) => `上次同步 ${relativeDate}`, + syncError: (providerName: string) => `无法连接到 ${providerName}`, + approvalMode: '审批模式', + finalApprover: '最终审批人', + notSet: '未设置', + approvalModes: { + basic: {label: '基本审批'}, + manager: {label: '经理审批'}, + custom: {label: '自定义审批'}, + }, syncStageName: ({stage}: SyncStageNameConnectionsParams) => { switch (stage) { case 'gustoSyncTitle': diff --git a/src/libs/API/parameters/SyncPolicyToMergeHRParams.ts b/src/libs/API/parameters/SyncPolicyToMergeHRParams.ts new file mode 100644 index 000000000000..81e18bcebd3e --- /dev/null +++ b/src/libs/API/parameters/SyncPolicyToMergeHRParams.ts @@ -0,0 +1,6 @@ +type SyncPolicyToMergeHRParams = { + policyID: string; + idempotencyKey: string; +}; + +export default SyncPolicyToMergeHRParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 722e597f8b05..8596dbfc1ee3 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -28,6 +28,7 @@ export type {default as OpenPolicyProfilePageParams} from './OpenPolicyProfilePa export type {default as OpenPolicyInitialPageParams} from './OpenPolicyInitialPageParams'; export type {default as SyncPolicyToGustoParams} from './SyncPolicyToGustoParams'; export type {default as SyncPolicyToZenefitsParams} from './SyncPolicyToZenefitsParams'; +export type {default as SyncPolicyToMergeHRParams} from './SyncPolicyToMergeHRParams'; export type {default as SyncPolicyToQuickbooksOnlineParams} from './SyncPolicyToQuickbooksOnlineParams'; export type {default as SyncPolicyToXeroParams} from './SyncPolicyToXeroParams'; export type {default as SyncPolicyToNetSuiteParams} from './SyncPolicyToNetSuiteParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 7a8d9a7ddb3f..7f2b47aace1d 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -1271,6 +1271,7 @@ const READ_COMMANDS = { SYNC_POLICY_TO_QUICKBOOKS_DESKTOP: 'SyncPolicyToQuickbooksDesktop', SYNC_POLICY_TO_GUSTO: 'SyncPolicyToGusto', SYNC_POLICY_TO_ZENEFITS: 'SyncPolicyToZenefits', + SYNC_POLICY_TO_MERGE_HR: 'SyncPolicyToMergeHR', SYNC_POLICY_TO_FINANCIAL_FORCE: 'SyncPolicyToFinancialForce', CONNECT_POLICY_TO_FINANCIAL_FORCE: 'ConnectPolicyToFinancialForce', OPEN_REIMBURSEMENT_ACCOUNT_PAGE: 'OpenReimbursementAccountPage', @@ -1373,6 +1374,7 @@ type ReadCommandParameters = { [READ_COMMANDS.SYNC_POLICY_TO_QUICKBOOKS_DESKTOP]: Parameters.SyncPolicyToQuickbooksDesktopParams; [READ_COMMANDS.SYNC_POLICY_TO_GUSTO]: Parameters.SyncPolicyToGustoParams; [READ_COMMANDS.SYNC_POLICY_TO_ZENEFITS]: Parameters.SyncPolicyToZenefitsParams; + [READ_COMMANDS.SYNC_POLICY_TO_MERGE_HR]: Parameters.SyncPolicyToMergeHRParams; [READ_COMMANDS.SYNC_POLICY_TO_FINANCIAL_FORCE]: {policyID: string}; [READ_COMMANDS.OPEN_REIMBURSEMENT_ACCOUNT_PAGE]: Parameters.OpenReimbursementAccountPageParams; [READ_COMMANDS.OPEN_WORKSPACE_VIEW]: Parameters.OpenWorkspaceViewParams; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 5333d97e4c5c..c4b98c74d49f 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -2456,4 +2456,4 @@ export { isPolicyEditor, }; -export type {MemberEmailsToAccountIDs, HRProviderInfo}; +export type {MemberEmailsToAccountIDs, HRProviderInfo, HRConnectionName}; diff --git a/src/libs/actions/connections/index.ts b/src/libs/actions/connections/index.ts index b81904a4f3fb..17d468a017ad 100644 --- a/src/libs/actions/connections/index.ts +++ b/src/libs/actions/connections/index.ts @@ -135,6 +135,9 @@ function getSyncConnectionParameters(connectionName: PolicyConnectionName) { case CONST.POLICY.CONNECTIONS.NAME.ZENEFITS: { return {readCommand: READ_COMMANDS.SYNC_POLICY_TO_ZENEFITS, stageInProgress: CONST.POLICY.CONNECTIONS.SYNC_STAGE_NAME.ZENEFITS_SYNC_TITLE}; } + case CONST.POLICY.CONNECTIONS.NAME.MERGE_HR: { + return {readCommand: READ_COMMANDS.SYNC_POLICY_TO_MERGE_HR, stageInProgress: CONST.POLICY.CONNECTIONS.SYNC_STAGE_NAME.MERGE_HR_SYNC_TITLE}; + } case CONST.POLICY.CONNECTIONS.NAME.CERTINIA: { return {readCommand: READ_COMMANDS.SYNC_POLICY_TO_FINANCIAL_FORCE, stageInProgress: CONST.POLICY.CONNECTIONS.SYNC_STAGE_NAME.FINANCIAL_FORCE_SYNC_CONNECTION}; } diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 761c67a7cf46..2b9c5e9eb8f0 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -166,7 +166,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac [CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED]: policy?.areCompanyCardsEnabled, [CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED]: !!policy?.areConnectionsEnabled || hasAccountingFeatureConnection(policy), [CONST.POLICY.MORE_FEATURES.IS_HR_ENABLED]: - (isBetaEnabled(CONST.BETAS.GUSTO) || isBetaEnabled(CONST.BETAS.ZENEFITS)) && + (isBetaEnabled(CONST.BETAS.GUSTO) || isBetaEnabled(CONST.BETAS.ZENEFITS) || isBetaEnabled(CONST.BETAS.MERGE_HR)) && (policy?.isHREnabled === true || isAnyHRConnected(policy)) && canPolicyAccessFeature(policy, CONST.POLICY.MORE_FEATURES.IS_HR_ENABLED), [CONST.POLICY.MORE_FEATURES.ARE_EXPENSIFY_CARDS_ENABLED]: policy?.areExpensifyCardsEnabled, diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage/index.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage/index.tsx index dbb530c5cdc0..47737384de90 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage/index.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage/index.tsx @@ -322,7 +322,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro Navigation.navigate(ROUTES.WORKSPACE_RECEIPT_PARTNERS.getRoute(policyID)); }} /> - {(isBetaEnabled(CONST.BETAS.GUSTO) || isBetaEnabled(CONST.BETAS.ZENEFITS)) && ( + {(isBetaEnabled(CONST.BETAS.GUSTO) || isBetaEnabled(CONST.BETAS.ZENEFITS) || isBetaEnabled(CONST.BETAS.MERGE_HR)) && ( void; +}; + +function HRProviderCard({card, policy, isFirst, onConnect}: HRProviderCardProps) { + const {translate, datetimeToRelative} = useLocalize(); + const styles = useThemeStyles(); + const {isOffline} = useNetwork(); + const icons = useMemoizedLazyExpensifyIcons(['Sync', 'Trashcan', 'Building']); + const {showConfirmModal} = useConfirmModal(); + + const fallbackIcon: IconAsset = icons[getFallbackHRIcon() as 'Building']; + const cardIcon = typeof card.icon === 'string' && card.icon.startsWith('http') ? card.icon : (card.icon as IconAsset) || fallbackIcon; + + let connectionDescription: string | undefined; + if (!card.isSyncInProgress && card.successfulDate && !card.hasError) { + connectionDescription = translate('workspace.hr.lastSync', datetimeToRelative(String(card.successfulDate))); + } + + const lastSyncErrorMessage = card.hasError ? translate('workspace.hr.syncError', card.displayName) : undefined; + + const overflowMenu: ThreeDotsMenuProps['menuItems'] = [ + { + icon: icons.Sync, + text: translate('workspace.hr.syncNow'), + onSelected: () => syncConnection(policy, card.connectionName), + disabled: isOffline, + }, + { + icon: icons.Trashcan, + text: translate('workspace.hr.disconnect'), + onSelected: () => { + showConfirmModal({ + title: translate('workspace.hr.disconnectTitle', card.displayName), + prompt: translate('workspace.hr.disconnectPrompt', card.displayName), + confirmText: translate('workspace.hr.disconnect'), + cancelText: translate('common.cancel'), + danger: true, + }).then((result) => { + if (!result) { + return; + } + if (policy) { + removePolicyConnection(policy, card.connectionName); + } + }); + }, + shouldCallAfterModalHide: true, + }, + ]; + + let rightComponent; + if (!card.isConnected) { + rightComponent = ( +