Skip to content

Commit

Permalink
Merge pull request #34290 from Krishna2323/krishna2323/issue/30999
Browse files Browse the repository at this point in the history
fix: Workspace - User is scrolled down in Workspace invite page
  • Loading branch information
rlinoz authored Jan 24, 2024
2 parents edf0fd0 + de51e08 commit 6cfdd6f
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 107 deletions.
113 changes: 63 additions & 50 deletions src/pages/RoomInvitePage.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {useNavigation} from '@react-navigation/native';
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
Expand Down Expand Up @@ -71,6 +72,8 @@ function RoomInvitePage(props) {
const [selectedOptions, setSelectedOptions] = useState([]);
const [personalDetails, setPersonalDetails] = useState([]);
const [userToInvite, setUserToInvite] = useState(null);
const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false);
const navigation = useNavigation();

// Any existing participants and Expensify emails should not be eligible for invitation
const excludedUsers = useMemo(
Expand All @@ -95,10 +98,26 @@ function RoomInvitePage(props) {
// eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to recalculate when selectedOptions change
}, [props.personalDetails, props.betas, searchTerm, excludedUsers]);

const getSections = () => {
const sections = [];
useEffect(() => {
const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', () => {
setDidScreenTransitionEnd(true);
});

return () => {
unsubscribeTransitionEnd();
};
// Rule disabled because this effect is only for component did mount & will component unmount lifecycle event
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const sections = useMemo(() => {
const sectionsArr = [];
let indexOffset = 0;

if (!didScreenTransitionEnd) {
return [];
}

// Filter all options that is a part of the search term or in the personal details
let filterSelectedOptions = selectedOptions;
if (searchTerm !== '') {
Expand All @@ -112,7 +131,7 @@ function RoomInvitePage(props) {
});
}

sections.push({
sectionsArr.push({
title: undefined,
data: filterSelectedOptions,
shouldShow: true,
Expand All @@ -126,7 +145,7 @@ function RoomInvitePage(props) {
const personalDetailsFormatted = _.map(personalDetailsWithoutSelected, (personalDetail) => OptionsListUtils.formatMemberForList(personalDetail, false));
const hasUnselectedUserToInvite = userToInvite && !_.contains(selectedLogins, userToInvite.login);

sections.push({
sectionsArr.push({
title: translate('common.contacts'),
data: personalDetailsFormatted,
shouldShow: !_.isEmpty(personalDetailsFormatted),
Expand All @@ -135,16 +154,16 @@ function RoomInvitePage(props) {
indexOffset += personalDetailsFormatted.length;

if (hasUnselectedUserToInvite) {
sections.push({
sectionsArr.push({
title: undefined,
data: [OptionsListUtils.formatMemberForList(userToInvite, false)],
shouldShow: true,
indexOffset,
});
}

return sections;
};
return sectionsArr;
}, [personalDetails, searchTerm, selectedOptions, translate, userToInvite, didScreenTransitionEnd]);

const toggleOption = useCallback(
(option) => {
Expand Down Expand Up @@ -213,49 +232,43 @@ function RoomInvitePage(props) {
shouldEnableMaxHeight
testID={RoomInvitePage.displayName}
>
{({didScreenTransitionEnd}) => {
const sections = didScreenTransitionEnd ? getSections() : [];

return (
<FullPageNotFoundView
shouldShow={_.isEmpty(props.report)}
subtitleKey={_.isEmpty(props.report) ? undefined : 'roomMembersPage.notAuthorized'}
onBackButtonPress={() => Navigation.goBack(backRoute)}
>
<HeaderWithBackButton
title={translate('workspace.invite.invitePeople')}
subtitle={reportName}
onBackButtonPress={() => {
Navigation.goBack(backRoute);
}}
/>
<SelectionList
canSelectMultiple
sections={sections}
textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')}
textInputValue={searchTerm}
onChangeText={setSearchTerm}
headerMessage={headerMessage}
onSelectRow={toggleOption}
onConfirm={inviteUsers}
showScrollIndicator
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
showLoadingPlaceholder={!didScreenTransitionEnd || !OptionsListUtils.isPersonalDetailsReady(props.personalDetails)}
/>
<View style={[styles.flexShrink0]}>
<FormAlertWithSubmitButton
isDisabled={!selectedOptions.length}
buttonText={translate('common.invite')}
onSubmit={inviteUsers}
containerStyles={[styles.flexReset, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto, styles.mb5]}
enabledWhenOffline
disablePressOnEnter
isAlertVisible={false}
/>
</View>
</FullPageNotFoundView>
);
}}
<FullPageNotFoundView
shouldShow={_.isEmpty(props.report)}
subtitleKey={_.isEmpty(props.report) ? undefined : 'roomMembersPage.notAuthorized'}
onBackButtonPress={() => Navigation.goBack(backRoute)}
>
<HeaderWithBackButton
title={translate('workspace.invite.invitePeople')}
subtitle={reportName}
onBackButtonPress={() => {
Navigation.goBack(backRoute);
}}
/>
<SelectionList
canSelectMultiple
sections={sections}
textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')}
textInputValue={searchTerm}
onChangeText={setSearchTerm}
headerMessage={headerMessage}
onSelectRow={toggleOption}
onConfirm={inviteUsers}
showScrollIndicator
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
showLoadingPlaceholder={!didScreenTransitionEnd || !OptionsListUtils.isPersonalDetailsReady(props.personalDetails)}
/>
<View style={[styles.flexShrink0]}>
<FormAlertWithSubmitButton
isDisabled={!selectedOptions.length}
buttonText={translate('common.invite')}
onSubmit={inviteUsers}
containerStyles={[styles.flexReset, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto, styles.mb5]}
enabledWhenOffline
disablePressOnEnter
isAlertVisible={false}
/>
</View>
</FullPageNotFoundView>
</ScreenWrapper>
);
}
Expand Down
127 changes: 70 additions & 57 deletions src/pages/workspace/WorkspaceInvitePage.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {useNavigation} from '@react-navigation/native';
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
Expand Down Expand Up @@ -76,6 +77,8 @@ function WorkspaceInvitePage(props) {
const [selectedOptions, setSelectedOptions] = useState([]);
const [personalDetails, setPersonalDetails] = useState([]);
const [usersToInvite, setUsersToInvite] = useState([]);
const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false);
const navigation = useNavigation();
const openWorkspaceInvitePage = () => {
const policyMemberEmailsToAccountIDs = PolicyUtils.getMemberAccountIDsForWorkspace(props.policyMembers, props.personalDetails);
Policy.openWorkspaceInvitePage(props.route.params.policyID, _.keys(policyMemberEmailsToAccountIDs));
Expand All @@ -94,6 +97,18 @@ function WorkspaceInvitePage(props) {
// eslint-disable-next-line react-hooks/exhaustive-deps -- policyID changes remount the component
}, []);

useEffect(() => {
const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', () => {
setDidScreenTransitionEnd(true);
});

return () => {
unsubscribeTransitionEnd();
};
// Rule disabled because this effect is only for component did mount & will component unmount lifecycle event
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useNetwork({onReconnect: openWorkspaceInvitePage});

const excludedUsers = useMemo(() => PolicyUtils.getIneligibleInvitees(props.policyMembers, props.personalDetails), [props.policyMembers, props.personalDetails]);
Expand Down Expand Up @@ -145,10 +160,14 @@ function WorkspaceInvitePage(props) {
// eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to recalculate when selectedOptions change
}, [props.personalDetails, props.policyMembers, props.betas, searchTerm, excludedUsers]);

const getSections = () => {
const sections = [];
const sections = useMemo(() => {
const sectionsArr = [];
let indexOffset = 0;

if (!didScreenTransitionEnd) {
return [];
}

// Filter all options that is a part of the search term or in the personal details
let filterSelectedOptions = selectedOptions;
if (searchTerm !== '') {
Expand All @@ -163,7 +182,7 @@ function WorkspaceInvitePage(props) {
});
}

sections.push({
sectionsArr.push({
title: undefined,
data: filterSelectedOptions,
shouldShow: true,
Expand All @@ -176,7 +195,7 @@ function WorkspaceInvitePage(props) {
const personalDetailsWithoutSelected = _.filter(personalDetails, ({login}) => !_.contains(selectedLogins, login));
const personalDetailsFormatted = _.map(personalDetailsWithoutSelected, OptionsListUtils.formatMemberForList);

sections.push({
sectionsArr.push({
title: translate('common.contacts'),
data: personalDetailsFormatted,
shouldShow: !_.isEmpty(personalDetailsFormatted),
Expand All @@ -188,7 +207,7 @@ function WorkspaceInvitePage(props) {
const hasUnselectedUserToInvite = !_.contains(selectedLogins, userToInvite.login);

if (hasUnselectedUserToInvite) {
sections.push({
sectionsArr.push({
title: undefined,
data: [OptionsListUtils.formatMemberForList(userToInvite)],
shouldShow: true,
Expand All @@ -197,8 +216,8 @@ function WorkspaceInvitePage(props) {
}
});

return sections;
};
return sectionsArr;
}, [personalDetails, searchTerm, selectedOptions, usersToInvite, translate, didScreenTransitionEnd]);

const toggleOption = (option) => {
Policy.clearErrors(props.route.params.policyID);
Expand Down Expand Up @@ -269,56 +288,50 @@ function WorkspaceInvitePage(props) {
shouldEnableMaxHeight
testID={WorkspaceInvitePage.displayName}
>
{({didScreenTransitionEnd}) => {
const sections = didScreenTransitionEnd ? getSections() : [];

return (
<FullPageNotFoundView
shouldShow={(_.isEmpty(props.policy) && !props.isLoadingReportData) || !PolicyUtils.isPolicyAdmin(props.policy) || PolicyUtils.isPendingDeletePolicy(props.policy)}
subtitleKey={_.isEmpty(props.policy) ? undefined : 'workspace.common.notAuthorized'}
onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_WORKSPACES)}
>
<HeaderWithBackButton
title={translate('workspace.invite.invitePeople')}
subtitle={policyName}
shouldShowGetAssistanceButton
guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_MEMBERS}
onBackButtonPress={() => {
Policy.clearErrors(props.route.params.policyID);
Navigation.goBack(ROUTES.WORKSPACE_MEMBERS.getRoute(props.route.params.policyID));
}}
/>
<SelectionList
canSelectMultiple
sections={sections}
textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')}
textInputValue={searchTerm}
onChangeText={(value) => {
SearchInputManager.searchInput = value;
setSearchTerm(value);
}}
headerMessage={headerMessage}
onSelectRow={toggleOption}
onConfirm={inviteUser}
showScrollIndicator
showLoadingPlaceholder={!didScreenTransitionEnd || !OptionsListUtils.isPersonalDetailsReady(props.personalDetails)}
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
/>
<View style={[styles.flexShrink0]}>
<FormAlertWithSubmitButton
isDisabled={!selectedOptions.length}
isAlertVisible={shouldShowAlertPrompt}
buttonText={translate('common.next')}
onSubmit={inviteUser}
message={props.policy.alertMessage}
containerStyles={[styles.flexReset, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto, styles.mb5]}
enabledWhenOffline
disablePressOnEnter
/>
</View>
</FullPageNotFoundView>
);
}}
<FullPageNotFoundView
shouldShow={(_.isEmpty(props.policy) && !props.isLoadingReportData) || !PolicyUtils.isPolicyAdmin(props.policy) || PolicyUtils.isPendingDeletePolicy(props.policy)}
subtitleKey={_.isEmpty(props.policy) ? undefined : 'workspace.common.notAuthorized'}
onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_WORKSPACES)}
>
<HeaderWithBackButton
title={translate('workspace.invite.invitePeople')}
subtitle={policyName}
shouldShowGetAssistanceButton
guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_MEMBERS}
onBackButtonPress={() => {
Policy.clearErrors(props.route.params.policyID);
Navigation.goBack(ROUTES.WORKSPACE_MEMBERS.getRoute(props.route.params.policyID));
}}
/>
<SelectionList
canSelectMultiple
sections={sections}
textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')}
textInputValue={searchTerm}
onChangeText={(value) => {
SearchInputManager.searchInput = value;
setSearchTerm(value);
}}
headerMessage={headerMessage}
onSelectRow={toggleOption}
onConfirm={inviteUser}
showScrollIndicator
showLoadingPlaceholder={!didScreenTransitionEnd || !OptionsListUtils.isPersonalDetailsReady(props.personalDetails)}
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
/>
<View style={[styles.flexShrink0]}>
<FormAlertWithSubmitButton
isDisabled={!selectedOptions.length}
isAlertVisible={shouldShowAlertPrompt}
buttonText={translate('common.next')}
onSubmit={inviteUser}
message={props.policy.alertMessage}
containerStyles={[styles.flexReset, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto, styles.mb5]}
enabledWhenOffline
disablePressOnEnter
/>
</View>
</FullPageNotFoundView>
</ScreenWrapper>
);
}
Expand Down

0 comments on commit 6cfdd6f

Please sign in to comment.