From 90cde72d6a77f307e8264875adb7f762fbb3dd6a Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Tue, 19 May 2026 06:36:54 +0530 Subject: [PATCH 1/4] Build ZenefitsApprovalModePage and ZenefitsFinalApproverPage mirroring Gusto Signed-off-by: krishna2323 --- src/libs/actions/connections/Zenefits.ts | 46 +++++- .../hr/zenefits/ZenefitsApprovalModePage.tsx | 137 +++++++++++++++++- .../hr/zenefits/ZenefitsFinalApproverPage.tsx | 59 +++++++- 3 files changed, 221 insertions(+), 21 deletions(-) diff --git a/src/libs/actions/connections/Zenefits.ts b/src/libs/actions/connections/Zenefits.ts index d027e4eb30aa..409353741346 100644 --- a/src/libs/actions/connections/Zenefits.ts +++ b/src/libs/actions/connections/Zenefits.ts @@ -1,4 +1,4 @@ -import type {OnyxUpdate} from 'react-native-onyx'; +import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import {write} from '@libs/API'; @@ -8,6 +8,7 @@ import {getCommandURL} from '@libs/ApiUtils'; import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {PolicyConnectionSyncProgress} from '@src/types/onyx/Policy'; function getZenefitsSetupLink(policyID: string) { const params: ConnectPolicyToZenefitsParams = {policyID}; @@ -18,17 +19,41 @@ function getZenefitsSetupLink(policyID: string) { return commandURL + new URLSearchParams(params).toString(); } +function getZenefitsSyncProgressOptimisticData(policyID: string): OnyxUpdate { + return { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID}`, + value: { + stageInProgress: CONST.POLICY.CONNECTIONS.SYNC_STAGE_NAME.ZENEFITS_SYNC_TITLE, + connectionName: CONST.POLICY.CONNECTIONS.NAME.ZENEFITS, + timestamp: new Date().toISOString(), + }, + }; +} + +function getZenefitsSyncProgressFailureData( + policyID: string, + currentConnectionSyncProgress: OnyxEntry, +): OnyxUpdate { + return { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID}`, + value: currentConnectionSyncProgress ?? null, + }; +} + function updateZenefitsApprovalMode( policyID: string | undefined, approvalMode: ValueOf, currentApprovalMode?: ValueOf | null, + currentConnectionSyncProgress?: OnyxEntry, ) { if (!policyID) { return; } const previousApprovalMode = currentApprovalMode ?? null; - const optimisticData: Array> = [ + const optimisticData: Array> = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, @@ -44,6 +69,7 @@ function updateZenefitsApprovalMode( }, }, }, + getZenefitsSyncProgressOptimisticData(policyID), ]; const successData: Array> = [ { @@ -61,7 +87,7 @@ function updateZenefitsApprovalMode( }, }, ]; - const failureData: Array> = [ + const failureData: Array> = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, @@ -77,18 +103,24 @@ function updateZenefitsApprovalMode( }, }, }, + getZenefitsSyncProgressFailureData(policyID, currentConnectionSyncProgress), ]; write(WRITE_COMMANDS.UPDATE_ZENEFITS_APPROVAL_MODE, {policyID, approvalMode}, {optimisticData, successData, failureData}); } -function updateZenefitsFinalApprover(policyID: string | undefined, finalApprover: string | null, currentFinalApprover?: string | null) { +function updateZenefitsFinalApprover( + policyID: string | undefined, + finalApprover: string | null, + currentFinalApprover?: string | null, + currentConnectionSyncProgress?: OnyxEntry, +) { if (!policyID) { return; } const previousFinalApprover = currentFinalApprover ?? null; - const optimisticData: Array> = [ + const optimisticData: Array> = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, @@ -104,6 +136,7 @@ function updateZenefitsFinalApprover(policyID: string | undefined, finalApprover }, }, }, + getZenefitsSyncProgressOptimisticData(policyID), ]; const successData: Array> = [ { @@ -121,7 +154,7 @@ function updateZenefitsFinalApprover(policyID: string | undefined, finalApprover }, }, ]; - const failureData: Array> = [ + const failureData: Array> = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, @@ -137,6 +170,7 @@ function updateZenefitsFinalApprover(policyID: string | undefined, finalApprover }, }, }, + getZenefitsSyncProgressFailureData(policyID, currentConnectionSyncProgress), ]; write(WRITE_COMMANDS.UPDATE_ZENEFITS_FINAL_APPROVER, {policyID, finalApprover}, {optimisticData, successData, failureData}); diff --git a/src/pages/workspace/hr/zenefits/ZenefitsApprovalModePage.tsx b/src/pages/workspace/hr/zenefits/ZenefitsApprovalModePage.tsx index 094ba48a9fbd..0d1948add22e 100644 --- a/src/pages/workspace/hr/zenefits/ZenefitsApprovalModePage.tsx +++ b/src/pages/workspace/hr/zenefits/ZenefitsApprovalModePage.tsx @@ -1,19 +1,140 @@ -import React from 'react'; +import React, {useState} from 'react'; +import {View} from 'react-native'; +import type {ValueOf} from 'type-fest'; +import Button from '@components/Button'; +import FixedFooter from '@components/FixedFooter'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import {ModalActions} from '@components/Modal/Global/ModalContext'; +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 useConfirmModal from '@hooks/useConfirmModal'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import usePermissions from '@hooks/usePermissions'; +import usePolicy from '@hooks/usePolicy'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {updateZenefitsApprovalMode} from '@libs/actions/connections/Zenefits'; import Navigation from '@libs/Navigation/Navigation'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import {isZenefitsConnected} from '@libs/PolicyUtils'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; -function ZenefitsApprovalModePage() { +type ApprovalMode = ValueOf; +type ZenefitsApprovalModePageProps = PlatformStackScreenProps; +type ApprovalModeListItem = ListItem & { + value: ApprovalMode; +}; + +function ZenefitsApprovalModePage({ + route: { + params: {policyID}, + }, +}: ZenefitsApprovalModePageProps) { const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {isBetaEnabled} = usePermissions(); + const {showConfirmModal} = useConfirmModal(); + const policy = usePolicy(policyID); + const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID}`); + const currentApprovalMode = policy?.connections?.zenefits?.config?.approvalMode ?? undefined; + const [draftApprovalMode, setDraftApprovalMode] = useState(); + const selectedApprovalMode = draftApprovalMode ?? currentApprovalMode; + const isSaveDisabled = !draftApprovalMode || draftApprovalMode === currentApprovalMode; + const approvalModeOptions: ApprovalModeListItem[] = [ + { + text: translate('workspace.hr.zenefits.approvalModes.basic.label'), + alternateText: translate('workspace.hr.zenefits.approvalModes.basic.description'), + keyForList: CONST.ZENEFITS.APPROVAL_MODE.BASIC, + value: CONST.ZENEFITS.APPROVAL_MODE.BASIC, + isSelected: selectedApprovalMode === CONST.ZENEFITS.APPROVAL_MODE.BASIC, + }, + { + text: translate('workspace.hr.zenefits.approvalModes.manager.label'), + alternateText: translate('workspace.hr.zenefits.approvalModes.manager.description'), + keyForList: CONST.ZENEFITS.APPROVAL_MODE.MANAGER, + value: CONST.ZENEFITS.APPROVAL_MODE.MANAGER, + isSelected: selectedApprovalMode === CONST.ZENEFITS.APPROVAL_MODE.MANAGER, + }, + { + text: translate('workspace.hr.zenefits.approvalModes.custom.label'), + alternateText: translate('workspace.hr.zenefits.approvalModes.custom.description'), + keyForList: CONST.ZENEFITS.APPROVAL_MODE.CUSTOM, + value: CONST.ZENEFITS.APPROVAL_MODE.CUSTOM, + isSelected: selectedApprovalMode === CONST.ZENEFITS.APPROVAL_MODE.CUSTOM, + }, + ]; + const selectedApprovalModeKey = approvalModeOptions.find((approvalMode) => approvalMode.isSelected)?.keyForList; + + const selectApprovalMode = (approvalMode: ApprovalMode) => { + setDraftApprovalMode(approvalMode); + }; + + const confirmAndSave = () => { + if (!draftApprovalMode) { + return; + } + + showConfirmModal({ + title: translate('workspace.hr.zenefits.approvalModeWarningTitle'), + prompt: , + confirmText: translate('workspace.hr.zenefits.approvalModeWarningConfirm'), + cancelText: translate('common.cancel'), + }).then(({action}) => { + if (action !== ModalActions.CONFIRM) { + return; + } + updateZenefitsApprovalMode(policyID, draftApprovalMode, currentApprovalMode, connectionSyncProgress); + Navigation.goBack(); + }); + }; return ( - - Navigation.goBack()} - /> - + + + Navigation.goBack()} + /> + + {translate('workspace.hr.zenefits.approvalModeDescription')} + selectApprovalMode(option.value)} + shouldSingleExecuteRowSelect + initiallyFocusedItemKey={selectedApprovalModeKey} + alternateNumberOfSupportedLines={3} + showScrollIndicator={false} + /> + +