diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index bcba8774f96b..884451d168f5 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -541,6 +541,7 @@ const ONYXKEYS = { POLICY_CONNECTION_SYNC_PROGRESS: 'policyConnectionSyncProgress_', WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_', WORKSPACE_INVITE_MESSAGE_DRAFT: 'workspaceInviteMessageDraft_', + WORKSPACE_INVITE_ROLE_DRAFT: 'workspaceInviteRoleDraft_', REPORT: 'report_', REPORT_NAME_VALUE_PAIRS: 'reportNameValuePairs_', REPORT_DRAFT: 'reportDraft_', @@ -932,6 +933,7 @@ type OnyxCollectionValuesMapping = { [ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyEmployeeList; [ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT]: OnyxTypes.InvitedEmailsToAccountIDs; [ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MESSAGE_DRAFT]: string; + [ONYXKEYS.COLLECTION.WORKSPACE_INVITE_ROLE_DRAFT]: string; [ONYXKEYS.COLLECTION.REPORT]: OnyxTypes.Report; [ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS]: OnyxTypes.ReportNameValuePairs; [ONYXKEYS.COLLECTION.REPORT_DRAFT]: OnyxTypes.Report; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 80d934b74f2e..b6b9513c1997 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -943,6 +943,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/invite-message', getRoute: (policyID: string, backTo?: string) => `${getUrlWithBackToParam(`settings/workspaces/${policyID}/invite-message`, backTo)}` as const, }, + WORKSPACE_INVITE_MESSAGE_ROLE: { + route: 'settings/workspaces/:policyID/invite-message/role', + getRoute: (policyID: string, backTo?: string) => `${getUrlWithBackToParam(`settings/workspaces/${policyID}/invite-message/role`, backTo)}` as const, + }, WORKSPACE_OVERVIEW: { route: 'settings/workspaces/:policyID/overview', getRoute: (policyID: string | undefined, backTo?: string) => { diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 6e12ea0af4ae..cbd597ff8d3b 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -521,6 +521,7 @@ const SCREENS = { MEMBERS_IMPORTED: 'Members_Imported', INVITE: 'Workspace_Invite', INVITE_MESSAGE: 'Workspace_Invite_Message', + INVITE_MESSAGE_ROLE: 'Workspace_Invite_Message_Role', CATEGORIES: 'Workspace_Categories', TAGS: 'Workspace_Tags', TAGS_SETTINGS: 'Tags_Settings', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 80befb6ccfad..0e7e759b1e54 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -297,6 +297,7 @@ const SettingsModalStackNavigator = createModalStackNavigator('../../../../pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage').default, [SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER]: () => require('../../../../pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage').default, [SCREENS.WORKSPACE.INVITE_MESSAGE]: () => require('../../../../pages/workspace/WorkspaceInviteMessagePage').default, + [SCREENS.WORKSPACE.INVITE_MESSAGE_ROLE]: () => require('../../../../pages/workspace/WorkspaceInviteMessageRolePage').default, [SCREENS.WORKSPACE.WORKFLOWS_PAYER]: () => require('../../../../pages/workspace/workflows/WorkspaceWorkflowsPayerPage').default, [SCREENS.WORKSPACE.NAME]: () => require('../../../../pages/workspace/WorkspaceNamePage').default, [SCREENS.WORKSPACE.DESCRIPTION]: () => require('../../../../pages/workspace/WorkspaceOverviewDescriptionPage').default, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 88ff8b743943..6b5effd6e0e3 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -693,6 +693,9 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.INVITE_MESSAGE]: { path: ROUTES.WORKSPACE_INVITE_MESSAGE.route, }, + [SCREENS.WORKSPACE.INVITE_MESSAGE_ROLE]: { + path: ROUTES.WORKSPACE_INVITE_MESSAGE_ROLE.route, + }, [SCREENS.WORKSPACE.CATEGORY_SETTINGS]: { path: ROUTES.WORKSPACE_CATEGORY_SETTINGS.route, parse: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 9d97fe7a43c3..24da906bb20b 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -184,6 +184,10 @@ type SettingsNavigatorParamList = { policyID: string; backTo?: Routes; }; + [SCREENS.WORKSPACE.INVITE_MESSAGE_ROLE]: { + policyID: string; + backTo?: Routes; + }; [SCREENS.WORKSPACE.CATEGORY_CREATE]: { policyID: string; backTo?: Routes; diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index 91348f7dac5b..207f8d8973aa 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -1105,6 +1105,14 @@ function setWorkspaceInviteMembersDraft(policyID: string, invitedEmailsToAccount Onyx.set(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${policyID}`, invitedEmailsToAccountIDs); } +function setWorkspaceInviteRoleDraft(policyID: string, role: ValueOf) { + Onyx.set(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_ROLE_DRAFT}${policyID}`, role); +} + +function clearWorkspaceInviteRoleDraft(policyID: string) { + Onyx.set(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_ROLE_DRAFT}${policyID}`, null); +} + /** * Accept user join request to a workspace */ @@ -1269,4 +1277,6 @@ export { clearInviteDraft, buildRoomMembersOnyxData, openPolicyMemberProfilePage, + setWorkspaceInviteRoleDraft, + clearWorkspaceInviteRoleDraft, }; diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.tsx b/src/pages/workspace/WorkspaceInviteMessagePage.tsx index 59eceb2cb454..c1f8b36eaf12 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.tsx +++ b/src/pages/workspace/WorkspaceInviteMessagePage.tsx @@ -2,7 +2,6 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {InteractionManager, Keyboard, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {GestureResponderEvent} from 'react-native/Libraries/Types/CoreEventTypes'; -import type {ValueOf} from 'type-fest'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors} from '@components/Form/types'; @@ -22,7 +21,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useViewportOffsetTop from '@hooks/useViewportOffsetTop'; import {clearDraftValues} from '@libs/actions/FormActions'; import {openExternalLink} from '@libs/actions/Link'; -import {addMembersToWorkspace} from '@libs/actions/Policy/Member'; +import {addMembersToWorkspace, clearWorkspaceInviteRoleDraft} from '@libs/actions/Policy/Member'; import {setWorkspaceInviteMessageDraft} from '@libs/actions/Policy/Policy'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Navigation from '@libs/Navigation/Navigation'; @@ -39,12 +38,9 @@ import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/WorkspaceInviteMessageForm'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; -import KeyboardUtils from '@src/utils/keyboard'; import AccessOrNotFoundWrapper from './AccessOrNotFoundWrapper'; import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading'; import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscreenLoading'; -import WorkspaceMemberDetailsRoleSelectionModal from './WorkspaceMemberRoleSelectionModal'; -import type {ListItemType} from './WorkspaceMemberRoleSelectionModal'; type WorkspaceInviteMessagePageProps = WithPolicyAndFullscreenLoadingProps & WithCurrentUserPersonalDetailsProps & @@ -54,7 +50,6 @@ function WorkspaceInviteMessagePage({policy, route, currentUserPersonalDetails}: const styles = useThemeStyles(); const {translate} = useLocalize(); const [formData, formDataResult] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM_DRAFT, {canBeMissing: true}); - const [role, setRole] = useState>(CONST.POLICY.ROLE.USER); const viewportOffsetTop = useViewportOffsetTop(); const [welcomeNote, setWelcomeNote] = useState(); @@ -67,22 +62,15 @@ function WorkspaceInviteMessagePage({policy, route, currentUserPersonalDetails}: const [workspaceInviteMessageDraft, workspaceInviteMessageDraftResult] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MESSAGE_DRAFT}${route.params.policyID.toString()}`, { canBeMissing: true, }); - const [allPersonalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: true}); + const [workspaceInviteRoleDraft = CONST.POLICY.ROLE.USER] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_ROLE_DRAFT}${route.params.policyID.toString()}`, {canBeMissing: true}); + const [allPersonalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false}); const isOnyxLoading = isLoadingOnyxValue(workspaceInviteMessageDraftResult, invitedEmailsToAccountIDsDraftResult, formDataResult); - const [isRoleSelectionModalVisible, setIsRoleSelectionModalVisible] = useState(false); - const welcomeNoteSubject = useMemo( () => `# ${currentUserPersonalDetails?.displayName ?? ''} invited you to ${policy?.name ?? 'a workspace'}`, [policy?.name, currentUserPersonalDetails?.displayName], ); - const openRoleSelectionModal = useCallback(() => { - KeyboardUtils.dismiss().then(() => { - setIsRoleSelectionModalVisible(true); - }); - }, []); - const getDefaultWelcomeNote = useCallback(() => { return ( // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -113,7 +101,7 @@ function WorkspaceInviteMessagePage({policy, route, currentUserPersonalDetails}: Keyboard.dismiss(); const policyMemberAccountIDs = Object.values(getMemberAccountIDsForWorkspace(policy?.employeeList, false, false)); // Please see https://github.com/Expensify/App/blob/main/README.md#Security for more details - addMembersToWorkspace(invitedEmailsToAccountIDsDraft ?? {}, `${welcomeNoteSubject}\n\n${welcomeNote}`, route.params.policyID, policyMemberAccountIDs, role); + addMembersToWorkspace(invitedEmailsToAccountIDsDraft ?? {}, `${welcomeNoteSubject}\n\n${welcomeNote}`, route.params.policyID, policyMemberAccountIDs, workspaceInviteRoleDraft); setWorkspaceInviteMessageDraft(route.params.policyID, welcomeNote ?? null); clearDraftValues(ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM); if ((route.params?.backTo as string)?.endsWith('members')) { @@ -150,37 +138,11 @@ function WorkspaceInviteMessagePage({policy, route, currentUserPersonalDetails}: const policyName = policy?.name; - const roleItems: ListItemType[] = useMemo( - () => [ - { - value: CONST.POLICY.ROLE.ADMIN, - text: translate('common.admin'), - alternateText: translate('workspace.common.adminAlternateText'), - isSelected: role === CONST.POLICY.ROLE.ADMIN, - keyForList: CONST.POLICY.ROLE.ADMIN, - }, - { - value: CONST.POLICY.ROLE.AUDITOR, - text: translate('common.auditor'), - alternateText: translate('workspace.common.auditorAlternateText'), - isSelected: role === CONST.POLICY.ROLE.AUDITOR, - keyForList: CONST.POLICY.ROLE.AUDITOR, - }, - { - value: CONST.POLICY.ROLE.USER, - text: translate('common.member'), - alternateText: translate('workspace.common.memberAlternateText'), - isSelected: role === CONST.POLICY.ROLE.USER, - keyForList: CONST.POLICY.ROLE.USER, - }, - ], - [role, translate], - ); - - const changeRole = useCallback(({value}: ListItemType) => { - setIsRoleSelectionModalVisible(false); - setRole(value); - }, []); + useEffect(() => { + return () => { + clearWorkspaceInviteRoleDraft(route.params.policyID); + }; + }, [route.params.policyID]); return ( - setIsRoleSelectionModalVisible(false)} + onPress={() => { + Navigation.navigate(ROUTES.WORKSPACE_INVITE_MESSAGE_ROLE.getRoute(route.params.policyID, Navigation.getActiveRoute())); + }} /> ; + text: string; + alternateText: string; + isSelected: boolean; + keyForList: ValueOf; +}; + +type WorkspaceInviteMessageRolePageProps = WithPolicyAndFullscreenLoadingProps & PlatformStackScreenProps; + +function WorkspaceInviteMessageRolePage({policy, route}: WorkspaceInviteMessageRolePageProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const [role = CONST.POLICY.ROLE.USER, roleResult] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_ROLE_DRAFT}${route.params.policyID}`, { + canBeMissing: true, + }); + const viewportOffsetTop = useViewportOffsetTop(); + const isOnyxLoading = isLoadingOnyxValue(roleResult); + + const roleItems: ListItemType[] = useMemo( + () => [ + { + value: CONST.POLICY.ROLE.ADMIN, + text: translate('common.admin'), + alternateText: translate('workspace.common.adminAlternateText'), + isSelected: role === CONST.POLICY.ROLE.ADMIN, + keyForList: CONST.POLICY.ROLE.ADMIN, + }, + { + value: CONST.POLICY.ROLE.AUDITOR, + text: translate('common.auditor'), + alternateText: translate('workspace.common.auditorAlternateText'), + isSelected: role === CONST.POLICY.ROLE.AUDITOR, + keyForList: CONST.POLICY.ROLE.AUDITOR, + }, + { + value: CONST.POLICY.ROLE.USER, + text: translate('common.member'), + alternateText: translate('workspace.common.memberAlternateText'), + isSelected: role === CONST.POLICY.ROLE.USER, + keyForList: CONST.POLICY.ROLE.USER, + }, + ], + [role, translate], + ); + + return ( + + + Navigation.goBack(route.params.backTo)} + /> + {!isOnyxLoading && ( + + { + setWorkspaceInviteRoleDraft(route.params.policyID, value); + Navigation.setNavigationActionToMicrotaskQueue(() => { + Navigation.goBack(route.params.backTo); + }); + }} + isAlternateTextMultilineSupported + shouldSingleExecuteRowSelect + initiallyFocusedOptionKey={roleItems.find((item) => item.isSelected)?.keyForList} + addBottomSafeAreaPadding + /> + + )} + + + ); +} + +WorkspaceInviteMessageRolePage.displayName = 'WorkspaceInviteMessageRolePage'; +export default withPolicyAndFullscreenLoading(WorkspaceInviteMessageRolePage); diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index b2e7dd9b98fc..b849c31d4ec4 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -22,6 +22,7 @@ type PolicyRouteName = | typeof SCREENS.WORKSPACE.COMPANY_CARDS | typeof SCREENS.WORKSPACE.INVITE | typeof SCREENS.WORKSPACE.INVITE_MESSAGE + | typeof SCREENS.WORKSPACE.INVITE_MESSAGE_ROLE | typeof SCREENS.WORKSPACE.WORKFLOWS_PAYER | typeof SCREENS.WORKSPACE.WORKFLOWS | typeof SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW