Skip to content

Commit 8d483f7

Browse files
committed
Add Gusto sync to members page
1 parent 1311ebf commit 8d483f7

4 files changed

Lines changed: 62 additions & 6 deletions

File tree

src/CONST/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3656,6 +3656,7 @@ const CONST = {
36563656
DOWNLOAD_CSV: 'downloadCSV',
36573657
SETTINGS: 'settings',
36583658
EXPORT: 'export',
3659+
SYNC_WITH_GUSTO: 'syncWithGusto',
36593660
},
36603661
MEMBERS_BULK_ACTION_TYPES: {
36613662
REMOVE: 'remove',

src/languages/en.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6026,6 +6026,8 @@ const translations = {
60266026
addedWithPrimary: 'Some members were added with their primary logins.',
60276027
invitedBySecondaryLogin: (secondaryLogin: string) => `Added by secondary login ${secondaryLogin}.`,
60286028
workspaceMembersCount: (count: number) => `Total workspace members: ${count}`,
6029+
configureGustoSync: 'Configure Gusto sync.',
6030+
syncWithGusto: 'Sync with Gusto',
60296031
allMembers: 'All members',
60306032
admins: 'Admins',
60316033
approvers: 'Approvers',

src/languages/es.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5890,6 +5890,8 @@ ${amount} para ${merchant} - ${date}`,
58905890
addedWithPrimary: 'Se agregaron algunos miembros con sus nombres de usuario principales.',
58915891
invitedBySecondaryLogin: (secondaryLogin) => `Agregado por nombre de usuario secundario ${secondaryLogin}.`,
58925892
workspaceMembersCount: (count) => `Total de miembros del espacio de trabajo: ${count}`,
5893+
configureGustoSync: 'Configurar sincronización de Gusto.',
5894+
syncWithGusto: 'Sincronizar con Gusto',
58935895
allMembers: 'Todos los miembros',
58945896
admins: 'Administradores',
58955897
approvers: 'Aprobadores',

src/pages/workspace/WorkspaceMembersPage.tsx

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
33
// eslint-disable-next-line no-restricted-imports
44
import {InteractionManager, View} from 'react-native';
55
import type {ValueOf} from 'type-fest';
6+
import ActivityIndicator from '@components/ActivityIndicator';
67
import Button from '@components/Button';
78
import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu';
89
import type {DropdownOption, WorkspaceMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types';
@@ -21,6 +22,7 @@ import type {ListItem, SelectionListHandle} from '@components/SelectionList/type
2122
import SelectionListWithModal from '@components/SelectionListWithModal';
2223
import CustomListHeader from '@components/SelectionListWithModal/CustomListHeader';
2324
import Text from '@components/Text';
25+
import TextLink from '@components/TextLink';
2426
import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';
2527
import useConfirmModal from '@hooks/useConfirmModal';
2628
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
@@ -39,6 +41,7 @@ import useSearchResults from '@hooks/useSearchResults';
3941
import useStyleUtils from '@hooks/useStyleUtils';
4042
import useThemeStyles from '@hooks/useThemeStyles';
4143
import useWorkspaceDocumentTitle from '@hooks/useWorkspaceDocumentTitle';
44+
import {isConnectionInProgress, syncConnection} from '@libs/actions/connections';
4245
import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode';
4346
import {
4447
clearAddMemberError,
@@ -118,7 +121,7 @@ type WorkspaceMemberFilterOption = SingleSelectItem<WorkspaceMemberFilterValue>;
118121

119122
function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembersPageProps) {
120123
useWorkspaceDocumentTitle(policy?.name, 'common.members');
121-
const icons = useMemoizedLazyExpensifyIcons(['Download', 'FallbackAvatar', 'MakeAdmin', 'Plus', 'RemoveMembers', 'Table', 'User', 'UserEye']);
124+
const icons = useMemoizedLazyExpensifyIcons(['Download', 'FallbackAvatar', 'MakeAdmin', 'Plus', 'RemoveMembers', 'Sync', 'Table', 'User', 'UserEye']);
122125
const policyMemberEmailsToAccountIDs = useMemo(() => getMemberAccountIDsForWorkspace(policy?.employeeList, true), [policy?.employeeList]);
123126
const employeeListDetails = useMemo(() => policy?.employeeList ?? ({} as PolicyEmployeeList), [policy?.employeeList]);
124127
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
@@ -168,6 +171,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers
168171
const selectionListRef = useRef<SelectionListHandle<MemberOption>>(null);
169172
const isFocused = useIsFocused();
170173
const policyID = route.params.policyID;
174+
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID}`);
171175
const illustrations = useMemoizedLazyIllustrations(['ReceiptWrangler', 'EmptyShelves']);
172176

173177
const ownerDetails = personalDetails?.[policy?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? ({} as PersonalDetails);
@@ -623,6 +627,10 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers
623627
}, [isLoading, policy?.employeeList, translate, isOfflineAndNoMemberDataAvailable]);
624628

625629
const memberCount = data.filter((member) => member.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length;
630+
const hasGustoConnection = !!policy?.connections?.gusto;
631+
const shouldShowGustoSyncLink = isPolicyAdmin && hasGustoConnection;
632+
const isGustoSyncInProgress =
633+
hasGustoConnection && connectionSyncProgress?.connectionName === CONST.POLICY.CONNECTIONS.NAME.GUSTO && isConnectionInProgress(connectionSyncProgress, policy);
626634
const isPendingAddOrDelete =
627635
isOffline && data?.some((member) => member.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || member.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
628636
const shouldShowSearchBar = data.length > CONST.SEARCH_ITEM_LIMIT;
@@ -667,9 +675,21 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers
667675

668676
const getHeaderContent = () => (
669677
<View style={shouldUseNarrowLayout ? styles.workspaceSectionMobile : styles.workspaceSection}>
670-
<Text style={[styles.pl5, styles.mb5, styles.mt3, styles.textSupporting, isPendingAddOrDelete && styles.offlineFeedbackPending]}>
671-
{translate('workspace.people.workspaceMembersCount', memberCount)}
672-
</Text>
678+
<View style={[styles.pl5, styles.mb5, styles.mt3, styles.flexRow, styles.alignItemsCenter]}>
679+
<Text style={[styles.textSupporting, styles.flexShrink1, isPendingAddOrDelete && styles.offlineFeedbackPending]}>
680+
{translate('workspace.people.workspaceMembersCount', memberCount)}
681+
{shouldShowGustoSyncLink && ' '}
682+
{shouldShowGustoSyncLink && (
683+
<TextLink onPress={() => Navigation.navigate(ROUTES.WORKSPACE_HR.getRoute(policyID))}>{translate('workspace.people.configureGustoSync')}</TextLink>
684+
)}
685+
</Text>
686+
{shouldShowGustoSyncLink && isGustoSyncInProgress && (
687+
<ActivityIndicator
688+
size="small"
689+
style={styles.ml2}
690+
/>
691+
)}
692+
</View>
673693
{!isEmptyObject(invitedPrimaryToSecondaryLogins) && (
674694
<MessagesRow
675695
type="success"
@@ -825,7 +845,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers
825845
return [];
826846
}
827847

828-
const menuItems = [
848+
const menuItems: Array<DropdownOption<ValueOf<typeof CONST.POLICY.SECONDARY_ACTIONS>>> = [
829849
{
830850
icon: icons.Table,
831851
text: translate('spreadsheet.importSpreadsheet'),
@@ -865,8 +885,39 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers
865885
},
866886
];
867887

888+
if (hasGustoConnection) {
889+
menuItems.push({
890+
icon: icons.Sync,
891+
text: translate('workspace.people.syncWithGusto'),
892+
onSelected: () => {
893+
if (isOffline) {
894+
close(showRequiresInternetModal);
895+
return;
896+
}
897+
898+
close(() => syncConnection(policy, CONST.POLICY.CONNECTIONS.NAME.GUSTO));
899+
},
900+
value: CONST.POLICY.SECONDARY_ACTIONS.SYNC_WITH_GUSTO,
901+
disabled: isGustoSyncInProgress,
902+
});
903+
}
904+
868905
return menuItems;
869-
}, [isPolicyAdmin, icons.Table, icons.Download, translate, isAccountLocked, isOffline, policyID, showLockedAccountModal, showRequiresInternetModal]);
906+
}, [
907+
isPolicyAdmin,
908+
icons.Table,
909+
icons.Download,
910+
icons.Sync,
911+
translate,
912+
isAccountLocked,
913+
isOffline,
914+
policyID,
915+
showLockedAccountModal,
916+
showRequiresInternetModal,
917+
hasGustoConnection,
918+
isGustoSyncInProgress,
919+
policy,
920+
]);
870921

871922
const getHeaderButtons = () => {
872923
if (!isPolicyAdmin) {

0 commit comments

Comments
 (0)