Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add import and export CSV flow for Members #48876

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3165104
Add import flow to Members page
filip-solecki Aug 23, 2024
be229ed
Merge branch 'filip-solecki/import-categories-csv' into filip-solecki…
filip-solecki Aug 30, 2024
f4b6f46
Fix members import
filip-solecki Aug 30, 2024
2c54554
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 10, 2024
93e0e23
ts fix
Guccio163 Sep 10, 2024
8ca6b73
adding fixes after categories
Guccio163 Sep 10, 2024
5f98deb
add members export
Guccio163 Sep 10, 2024
6d0acbb
Update src/libs/actions/Policy/Member.ts
Guccio163 Sep 11, 2024
3b656b9
review fixes
Guccio163 Sep 11, 2024
b375206
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 11, 2024
f9860d0
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 11, 2024
16d3f65
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 11, 2024
77eba31
Merge branch 'main' into Guccio163/import-members-csv
blazejkustra Sep 13, 2024
333a89a
Migrate withOnyx on members page
blazejkustra Sep 13, 2024
dc88ca4
Merge branch 'main' into Guccio163/import-members-csv
blazejkustra Sep 16, 2024
182eb3c
Merge branch 'main' into Guccio163/import-members-csv
blazejkustra Sep 17, 2024
8af21ea
review comments
Guccio163 Sep 17, 2024
5c079e9
fix typo
Guccio163 Sep 17, 2024
5476cd2
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 17, 2024
92e6745
functions moved to utils
Guccio163 Sep 17, 2024
2deb46b
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 18, 2024
38ab688
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 18, 2024
656a3d7
resolve typecheck
Guccio163 Sep 18, 2024
213f5fa
unused translation
Guccio163 Sep 18, 2024
7861f4f
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 18, 2024
a36596b
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 18, 2024
5e25def
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 19, 2024
233388d
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5752,6 +5752,7 @@ const CONST = {
ICON_HEIGHT: 160,

CATEGORIES_ARTICLE_LINK: 'https://help.expensify.com/articles/expensify-classic/workspaces/Create-categories#import-custom-categories',
MEMBERS_ARTICLE_LINK: 'https://help.expensify.com/articles/expensify-classic/workspaces/Invite-members-and-assign-roles#import-a-group-of-members',
},
} as const;

Expand Down
8 changes: 8 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,14 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/members',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/members` as const,
},
WORKSPACE_MEMBERS_IMPORT: {
route: 'settings/workspaces/:policyID/members/import',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/members/import` as const,
},
WORKSPACE_MEMBERS_IMPORTED: {
route: 'settings/workspaces/:policyID/members/imported',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/members/imported` as const,
},
POLICY_ACCOUNTING: {
route: 'settings/workspaces/:policyID/accounting',
getRoute: (policyID: string, newConnectionName?: ConnectionName, integrationToDisconnect?: ConnectionName, shouldDisconnectIntegrationBeforeConnecting?: boolean) => {
Expand Down
2 changes: 2 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ const SCREENS = {
INVOICES_COMPANY_WEBSITE: 'Workspace_Invoices_Company_Website',
TRAVEL: 'Workspace_Travel',
MEMBERS: 'Workspace_Members',
MEMBERS_IMPORT: 'Members_Import',
MEMBERS_IMPORTED: 'Members_Imported',
INVITE: 'Workspace_Invite',
INVITE_MESSAGE: 'Workspace_Invite_Message',
CATEGORIES: 'Workspace_Categories',
Expand Down
4 changes: 4 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ export default {
singleFieldMultipleColumns: (fieldName: string) => `Oops! You've mapped a single field ("${fieldName}") to multiple columns. Please review and try again.`,
importSuccessfullTitle: 'Import successful',
importCategoriesSuccessfullDescription: (categories: number) => (categories > 1 ? `${categories} categories have been added.` : '1 category has been added.'),
importMembersSuccessfullDescription: (members: number) => (members > 1 ? `${members} members have been added.` : '1 member has been added.'),
importFailedTitle: 'Import failed',
importFailedDescription: 'Please ensure all fields are filled out correctly and try again. If the problem persists, please reach out to Concierge.',
sizeNotMet: 'File size must be greater than 0 bytes',
Expand Down Expand Up @@ -3260,6 +3261,9 @@ export default {
addedWithPrimary: 'Some members were added with their primary logins.',
invitedBySecondaryLogin: ({secondaryLogin}) => `Added by secondary login ${secondaryLogin}.`,
membersListTitle: 'Directory of all workspace members.',
importMembers: 'Import members',
importedMembersMessage: (columnCounts: number) =>
`We found *${columnCounts} columns* in your spreadsheet. Select *Email* next to the column that contains emails. You can also select *Role* next to the column that sets users roles.`,
Guccio163 marked this conversation as resolved.
Show resolved Hide resolved
},
card: {
header: 'Unlock free Expensify Cards',
Expand Down
4 changes: 4 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@ export default {
importFailedTitle: 'Fallo en la importación',
importFailedDescription: 'Por favor, asegúrate de que todos los campos estén llenos correctamente e inténtalo de nuevo. Si el problema persiste, por favor contacta a Concierge.',
importCategoriesSuccessfullDescription: (categories: number) => (categories > 1 ? `Se han agregado ${categories} categorías.` : 'Se ha agregado 1 categoría.'),
importMembersSuccessfullDescription: (members: number) => (members > 1 ? `Se han agregado ${members} miembros.` : 'Se ha agregado 1 miembro.'),
Guccio163 marked this conversation as resolved.
Show resolved Hide resolved
importSuccessfullTitle: 'Importar categorías',
sizeNotMet: 'El archivo adjunto debe ser más grande que 0 bytes.',
invalidFileMessage:
Expand Down Expand Up @@ -3309,6 +3310,9 @@ export default {
addedWithPrimary: 'Se agregaron algunos miembros con sus nombres de usuario principales.',
invitedBySecondaryLogin: ({secondaryLogin}) => `Agregado por nombre de usuario secundario ${secondaryLogin}.`,
membersListTitle: 'Directorio de todos los miembros del espacio de trabajo.',
importMembers: 'Importar miembros',
importedMembersMessage: (columnCounts: number) =>
`Hemos encontrado *${columnCounts} columnas* en su hoja de cálculo. Seleccione *Email* junto a la columna que contiene correos electrónicos. También puede seleccionar *Role* junto a la columna que establece los roles de los usuarios.`,
},
accounting: {
settings: 'configuración',
Expand Down
6 changes: 6 additions & 0 deletions src/libs/API/parameters/ExportMembersSpreadsheetParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type ExportMemberssSpreadsheetParams = {
Guccio163 marked this conversation as resolved.
Show resolved Hide resolved
/** ID of the policy */
policyID: string;
};

export default ExportMemberssSpreadsheetParams;
Guccio163 marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 10 additions & 0 deletions src/libs/API/parameters/ImportMembersSpreadsheet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type ImportMembersSpreadsheetParams = {
policyID: string;
/**
* Stringified JSON object with type of following structure:
* Array<{email: string, role: string}>
*/
employees: string;
};

export default ImportMembersSpreadsheetParams;
2 changes: 2 additions & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,9 @@ export type {default as SetPolicyCategoryReceiptsRequiredParams} from './SetPoli
export type {default as RemovePolicyCategoryReceiptsRequiredParams} from './RemovePolicyCategoryReceiptsRequiredParams';
export type {default as UpdateQuickbooksOnlineAutoCreateVendorParams} from './UpdateQuickbooksOnlineAutoCreateVendorParams';
export type {default as ImportCategoriesSpreadsheetParams} from './ImportCategoriesSpreadsheet';
export type {default as ImportMembersSpreadsheetParams} from './ImportMembersSpreadsheet';
export type {default as ExportCategoriesSpreadsheetParams} from './ExportCategoriesSpreadsheet';
export type {default as ExportMembersSpreadsheetParams} from './ExportCategoriesSpreadsheet';
export type {default as UpdateXeroGenericTypeParams} from './UpdateXeroGenericTypeParams';
export type {default as UpdateCardSettlementFrequencyParams} from './UpdateCardSettlementFrequencyParams';
export type {default as UpdateCardSettlementAccountParams} from './UpdateCardSettlementAccountParams';
Expand Down
4 changes: 4 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,10 @@ const WRITE_COMMANDS = {
SET_WORKSPACE_CATEGORIES_ENABLED: 'SetWorkspaceCategoriesEnabled',
SET_POLICY_TAGS_ENABLED: 'SetPolicyTagsEnabled',
CREATE_WORKSPACE_CATEGORIES: 'CreateWorkspaceCategories',
IMPORT_MEMBERS_SPREADSHEET: 'ImportMembersSpreadsheet',
IMPORT_CATEGORIES_SPREADSHEET: 'ImportCategoriesSpreadsheet',
EXPORT_CATEGORIES_CSV: 'ExportCategoriesCSV',
EXPORT_MEMBERS_CSV: 'ExportMembersCSV',
RENAME_WORKSPACE_CATEGORY: 'RenameWorkspaceCategory',
CREATE_POLICY_TAG: 'CreatePolicyTag',
RENAME_POLICY_TAG: 'RenamePolicyTag',
Expand Down Expand Up @@ -524,8 +526,10 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.CREATE_WORKSPACE_FROM_IOU_PAYMENT]: Parameters.CreateWorkspaceFromIOUPaymentParams;
[WRITE_COMMANDS.SET_WORKSPACE_CATEGORIES_ENABLED]: Parameters.SetWorkspaceCategoriesEnabledParams;
[WRITE_COMMANDS.CREATE_WORKSPACE_CATEGORIES]: Parameters.CreateWorkspaceCategoriesParams;
[WRITE_COMMANDS.IMPORT_MEMBERS_SPREADSHEET]: Parameters.ImportMembersSpreadsheetParams;
[WRITE_COMMANDS.IMPORT_CATEGORIES_SPREADSHEET]: Parameters.ImportCategoriesSpreadsheetParams;
[WRITE_COMMANDS.EXPORT_CATEGORIES_CSV]: Parameters.ExportCategoriesSpreadsheetParams;
[WRITE_COMMANDS.EXPORT_MEMBERS_CSV]: Parameters.ExportMembersSpreadsheetParams;
[WRITE_COMMANDS.RENAME_WORKSPACE_CATEGORY]: Parameters.RenameWorkspaceCategoriesParams;
[WRITE_COMMANDS.SET_WORKSPACE_REQUIRES_CATEGORY]: Parameters.SetWorkspaceRequiresCategoryParams;
[WRITE_COMMANDS.DELETE_WORKSPACE_CATEGORIES]: Parameters.DeleteWorkspaceCategoriesParams;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.RATE_AND_UNIT_RATE]: () => require<ReactComponentModule>('../../../../pages/workspace/reimburse/WorkspaceRateAndUnitPage/RatePage').default,
[SCREENS.WORKSPACE.RATE_AND_UNIT_UNIT]: () => require<ReactComponentModule>('../../../../pages/workspace/reimburse/WorkspaceRateAndUnitPage/UnitPage').default,
[SCREENS.WORKSPACE.INVITE]: () => require<ReactComponentModule>('../../../../pages/workspace/WorkspaceInvitePage').default,
[SCREENS.WORKSPACE.MEMBERS_IMPORT]: () => require<ReactComponentModule>('../../../../pages/workspace/members/ImportMembersPage').default,
[SCREENS.WORKSPACE.MEMBERS_IMPORTED]: () => require<ReactComponentModule>('../../../../pages/workspace/members/ImportedMembersPage').default,
[SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW]: () => require<ReactComponentModule>('../../../../pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage').default,
[SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EDIT]: () => require<ReactComponentModule>('../../../../pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage').default,
[SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EXPENSES_FROM]: () =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
SCREENS.WORKSPACE.OWNER_CHANGE_SUCCESS,
SCREENS.WORKSPACE.OWNER_CHANGE_ERROR,
SCREENS.WORKSPACE.OWNER_CHANGE_ERROR,
SCREENS.WORKSPACE.MEMBERS_IMPORT,
SCREENS.WORKSPACE.MEMBERS_IMPORTED,
],
[SCREENS.WORKSPACE.WORKFLOWS]: [
SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW,
Expand Down
6 changes: 6 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,12 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.WORKSPACE.INVITE]: {
path: ROUTES.WORKSPACE_INVITE.route,
},
[SCREENS.WORKSPACE.MEMBERS_IMPORT]: {
path: ROUTES.WORKSPACE_MEMBERS_IMPORT.route,
},
[SCREENS.WORKSPACE.MEMBERS_IMPORTED]: {
path: ROUTES.WORKSPACE_MEMBERS_IMPORTED.route,
},
[SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW]: {
path: ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_NEW.route,
},
Expand Down
6 changes: 6 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ type SettingsNavigatorParamList = {
[SCREENS.WORKSPACE.INVITE]: {
policyID: string;
};
[SCREENS.WORKSPACE.MEMBERS_IMPORT]: {
policyID: string;
};
[SCREENS.WORKSPACE.MEMBERS_IMPORTED]: {
policyID: string;
};
[SCREENS.WORKSPACE.INVITE_MESSAGE]: {
policyID: string;
};
Expand Down
68 changes: 68 additions & 0 deletions src/libs/actions/Policy/Member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ import type {
UpdateWorkspaceMembersRoleParams,
} from '@libs/API/parameters';
import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import * as ApiUtils from '@libs/ApiUtils';
import * as ErrorUtils from '@libs/ErrorUtils';
import fileDownload from '@libs/fileDownload';
import {translateLocal} from '@libs/Localize';
import Log from '@libs/Log';
import enhanceParameters from '@libs/Network/enhanceParameters';
import Parser from '@libs/Parser';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import * as PhoneNumber from '@libs/PhoneNumber';
Expand All @@ -23,6 +27,7 @@ import type {InvitedEmailsToAccountIDs, PersonalDetailsList, Policy, PolicyEmplo
import type {PendingAction} from '@src/types/onyx/OnyxCommon';
import type {JoinWorkspaceResolution} from '@src/types/onyx/OriginalMessage';
import type {Attributes, Rate} from '@src/types/onyx/Policy';
import type {OnyxData} from '@src/types/onyx/Request';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import {createPolicyExpenseChats} from './Policy';

Expand Down Expand Up @@ -167,6 +172,36 @@ function buildAnnounceRoomMembersOnyxData(policyID: string, accountIDs: number[]
});
return announceRoomMembers;
}
/**
* Updates the import spreadsheet data according to the result of the import
*/
function updateImportSpreadsheetData(membersLength: number): OnyxData {
const onyxData: OnyxData = {
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.IMPORTED_SPREADSHEET,
value: {
shouldFinalModalBeOpened: true,
importFinalModal: {title: translateLocal('spreadsheet.importSuccessfullTitle'), prompt: translateLocal('spreadsheet.importMembersSuccessfullDescription', membersLength)},
},
},
],

failureData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.IMPORTED_SPREADSHEET,
value: {
shouldFinalModalBeOpened: true,
importFinalModal: {title: translateLocal('spreadsheet.importFailedTitle'), prompt: translateLocal('spreadsheet.importFailedDescription')},
},
},
],
};

return onyxData;
}

/**
* Build optimistic data for removing users from the announcement room
Expand Down Expand Up @@ -640,6 +675,22 @@ function addMembersToWorkspace(invitedEmailsToAccountIDs: InvitedEmailsToAccount
API.write(WRITE_COMMANDS.ADD_MEMBERS_TO_WORKSPACE, params, {optimisticData, successData, failureData});
}

type PolicyMember = {
email: string;
role: string;
};

function importPolicyMembers(policyID: string, members: PolicyMember[]) {
const onyxData = updateImportSpreadsheetData(members.length);

const parameters = {
policyID,
employees: JSON.stringify(members.map((member) => ({email: member.email, role: member.role}))),
};

API.write(WRITE_COMMANDS.IMPORT_MEMBERS_SPREADSHEET, parameters, onyxData);
}

/**
* Invite member to the specified policyID
* Please see https://github.com/Expensify/App/blob/main/README.md#Security for more details
Expand Down Expand Up @@ -836,6 +887,21 @@ function declineJoinRequest(reportID: string, reportAction: OnyxEntry<ReportActi
API.write(WRITE_COMMANDS.DECLINE_JOIN_REQUEST, parameters, {optimisticData, failureData, successData});
}

function downloadMembersCSV(policyID: string) {
Guccio163 marked this conversation as resolved.
Show resolved Hide resolved
const finalParameters = enhanceParameters(WRITE_COMMANDS.EXPORT_MEMBERS_CSV, {
policyID,
});

const fileName = 'Members.csv';

const formData = new FormData();
Object.entries(finalParameters).forEach(([key, value]) => {
formData.append(key, String(value));
});

fileDownload(ApiUtils.getCommandURL({command: WRITE_COMMANDS.EXPORT_MEMBERS_CSV}), fileName, '', false, formData, CONST.NETWORK.METHOD.POST);
}

export {
removeMembers,
updateWorkspaceMembersRole,
Expand All @@ -850,6 +916,8 @@ export {
acceptJoinRequest,
declineJoinRequest,
isApprover,
importPolicyMembers,
downloadMembersCSV,
};

export type {NewCustomUnit};
47 changes: 46 additions & 1 deletion src/pages/workspace/WorkspaceMembersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import usePrevious from '@hooks/usePrevious';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Log from '@libs/Log';
Expand All @@ -37,6 +38,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import {getDisplayNameForParticipant} from '@libs/ReportUtils';
import * as Modal from '@userActions/Modal';
import * as Member from '@userActions/Policy/Member';
import * as Policy from '@userActions/Policy/Policy';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -70,10 +72,12 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson
const [removeMembersConfirmModalVisible, setRemoveMembersConfirmModalVisible] = useState(false);
const [errors, setErrors] = useState({});
const {isOffline} = useNetwork();
const {windowWidth} = useWindowDimensions();
const prevIsOffline = usePrevious(isOffline);
const accountIDs = useMemo(() => Object.values(policyMemberEmailsToAccountIDs ?? {}).map((accountID) => Number(accountID)), [policyMemberEmailsToAccountIDs]);
const prevAccountIDs = usePrevious(accountIDs);
const textInputRef = useRef<TextInput>(null);
const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false);
const isOfflineAndNoMemberDataAvailable = isEmptyObject(policy?.employeeList) && isOffline;
const prevPersonalDetails = usePrevious(personalDetails);
const {translate, formatPhoneNumber, preferredLocale} = useLocalize();
Expand Down Expand Up @@ -531,7 +535,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson
return null;
}
return (
<View style={styles.w100}>
<View style={[styles.flexRow, styles.gap2, shouldUseNarrowLayout && styles.mb3]}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have caused this: #49749, why did we change the style here? @Guccio163

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it because we needed to acomodate two buttons?

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I see, without this change in desktop the 3-vertical-dots are too far to the right:

image

{(shouldUseNarrowLayout ? canSelectMultiple : selectedEmployees.length > 0) ? (
<ButtonWithDropdownMenu<WorkspaceMemberBulkActionType>
shouldAlwaysShowDropdownMenu
Expand All @@ -558,6 +562,35 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson
);
};

const threeDotsMenuItems = useMemo(() => {
const menuItems = [
{
icon: Expensicons.Table,
text: translate('spreadsheet.importSpreadsheet'),
onSelected: () => {
if (isOffline) {
Modal.close(() => setIsOfflineModalVisible(true));
return;
}
Navigation.navigate(ROUTES.WORKSPACE_MEMBERS_IMPORT.getRoute(policyID));
},
},
{
icon: Expensicons.Download,
text: translate('spreadsheet.downloadCSV'),
onSelected: () => {
if (isOffline) {
Modal.close(() => setIsOfflineModalVisible(true));
return;
}
Member.downloadMembersCSV(policyID);
},
},
];

return menuItems;
}, [policyID, translate, isOffline]);

const selectionModeHeader = selectionMode?.isEnabled && shouldUseNarrowLayout;

return (
Expand All @@ -570,6 +603,9 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson
testID={WorkspaceMembersPage.displayName}
shouldShowLoading={false}
shouldShowOfflineIndicatorInWideScreen
shouldShowThreeDotsButton
threeDotsMenuItems={threeDotsMenuItems}
threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
shouldShowNonAdmin
onBackButtonPress={() => {
if (selectionMode?.isEnabled) {
Expand All @@ -583,6 +619,15 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson
{() => (
<>
{shouldUseNarrowLayout && <View style={[styles.pl5, styles.pr5]}>{getHeaderButtons()}</View>}
<ConfirmModal
isVisible={isOfflineModalVisible}
onConfirm={() => setIsOfflineModalVisible(false)}
title={translate('common.youAppearToBeOffline')}
prompt={translate('common.thisFeatureRequiresInternet')}
confirmText={translate('common.buttonConfirm')}
shouldShowCancelButton={false}
/>

<ConfirmModal
danger
title={translate('workspace.people.removeMembersTitle')}
Expand Down
Loading
Loading