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

Fix: three not found view v2 #41665

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a29d34e
Revert "[Revert] #36409 "Fix: three not found view""
kosmydel Apr 22, 2024
a535acb
fix #40509
kosmydel May 6, 2024
adf1ca4
fix one more issue on android
kosmydel May 6, 2024
c034221
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel May 8, 2024
b513239
fix comment
kosmydel May 8, 2024
ce12e86
change type
kosmydel May 8, 2024
d175fb5
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel May 15, 2024
4a9a77c
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel May 28, 2024
16ca1c0
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel May 29, 2024
35f21ea
Merge branch 'Expensify:main' into @kosmydel/not-found-view-v2
kosmydel Jun 13, 2024
92015a6
fix: empty ProfilePage
kosmydel Jun 14, 2024
54f1cff
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel Jun 18, 2024
fcbe4ff
Merge branch 'Expensify:main' into @kosmydel/not-found-view-v2
kosmydel Jun 20, 2024
ffa8cf7
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel Jun 26, 2024
145513d
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel Jun 27, 2024
001a36b
fix: add concurrent mode support
kosmydel Jun 27, 2024
e76dd16
fix: double navigation
kosmydel Jun 27, 2024
04c420b
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel Jul 2, 2024
6cca6df
fix: double navigation when selecting workspace in settings
kosmydel Jul 2, 2024
9487f61
continue previous commit
kosmydel Jul 2, 2024
9ec0333
refactor: WorkspaceMoreFeaturesPage and WorkspaceReportFieldsPage
kosmydel Jul 2, 2024
ad96e9e
fix
kosmydel Jul 3, 2024
37fc8c7
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel Jul 3, 2024
6d269c3
modify AccessOrNotFoundWrapper
kosmydel Jul 3, 2024
4c50c13
small fix
kosmydel Jul 3, 2024
e8c80a3
Merge branch 'Expensify:main' into @kosmydel/not-found-view-v2
kosmydel Jul 4, 2024
ebfd706
Merge branch 'main' into @kosmydel/not-found-view-v2
kosmydel Jul 9, 2024
2a00bb9
remove flag
BrtqKr Jul 16, 2024
1488a51
Merge remote-tracking branch 'origin/main' into @kosmydel/not-found-v…
BrtqKr Jul 16, 2024
e60668b
prettier
kosmydel Jul 17, 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
7 changes: 7 additions & 0 deletions src/libs/Navigation/Navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {EmptyObject} from '@src/types/utils/EmptyObject';
import originalCloseRHPFlow from './closeRHPFlow';
import originalDismissModal from './dismissModal';
import originalDismissModalWithReport from './dismissModalWithReport';
import originalDismissRHP from './dismissRHP';
import originalGetTopmostReportActionId from './getTopmostReportActionID';
import originalGetTopmostReportId from './getTopmostReportId';
import linkingConfig from './linkingConfig';
Expand Down Expand Up @@ -64,6 +65,11 @@ const dismissModal = (reportID?: string, ref = navigationRef) => {
// Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies.
const closeRHPFlow = (ref = navigationRef) => originalCloseRHPFlow(ref);

// Re-exporting the dismissRHP here to fill in default value for navigationRef. The dismissRHP isn't defined in this file to avoid cyclic dependencies.
const dismissRHP = (ref = navigationRef) => {
originalDismissRHP(ref);
};

// Re-exporting the dismissModalWithReport here to fill in default value for navigationRef. The dismissModalWithReport isn't defined in this file to avoid cyclic dependencies.
// This method is needed because it allows to dismiss the modal and then open the report. Within this method is checked whether the report belongs to a specific workspace. Sometimes the report we want to check, hasn't been added to the Onyx yet.
// Then we can pass the report as a param without getting it from the Onyx.
Expand Down Expand Up @@ -367,6 +373,7 @@ export default {
setShouldPopAllStateOnUP,
navigate,
setParams,
dismissRHP,
dismissModal,
dismissModalWithReport,
isActiveRoute,
Expand Down
25 changes: 25 additions & 0 deletions src/libs/Navigation/dismissRHP.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type {NavigationContainerRef} from '@react-navigation/native';
import {StackActions} from '@react-navigation/native';
import NAVIGATORS from '@src/NAVIGATORS';
import type {RootStackParamList} from './types';

// This function is in a separate file than Navigation.ts to avoid cyclic dependency.

/**
* Dismisses the RHP modal stack if there is any
*
* @param targetReportID - The reportID to navigate to after dismissing the modal
kosmydel marked this conversation as resolved.
Show resolved Hide resolved
*/
function dismissRHP(navigationRef: NavigationContainerRef<RootStackParamList>) {
if (!navigationRef.isReady()) {
return;
}

const state = navigationRef.getState();
const lastRoute = state.routes.at(-1);
if (lastRoute?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR) {
navigationRef.dispatch({...StackActions.pop(), target: state.key});
}
}

export default dismissRHP;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import getTopmostNestedRHPRoute from '@libs/Navigation/getTopmostNestedRHPRoute'
import type {BottomTabName, CentralPaneName, FullScreenName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types';
import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils';
import NAVIGATORS from '@src/NAVIGATORS';
import type {Screen} from '@src/SCREENS';
import SCREENS from '@src/SCREENS';
import CENTRAL_PANE_TO_RHP_MAPPING from './CENTRAL_PANE_TO_RHP_MAPPING';
import config from './config';
Expand All @@ -14,7 +15,7 @@ import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForSta
import getMatchingCentralPaneRouteForState from './getMatchingCentralPaneRouteForState';
import replacePathInNestedState from './replacePathInNestedState';

const RHP_SCREENS_OPENED_FROM_LHN = [SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS] as const;
const RHP_SCREENS_OPENED_FROM_LHN: Screen[] = [SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS, SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE];
kosmydel marked this conversation as resolved.
Show resolved Hide resolved

type RHPScreenOpenedFromLHN = (typeof RHP_SCREENS_OPENED_FROM_LHN)[number];

Expand Down Expand Up @@ -166,11 +167,6 @@ function getAdaptedState(state: PartialState<NavigationState<RootStackParamList>
const featureTrainingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR);
const reportAttachmentsScreen = state.routes.find((route) => route.name === SCREENS.REPORT_ATTACHMENTS);

if (isNarrowLayout) {
metainfo.isFullScreenNavigatorMandatory = false;
metainfo.isCentralPaneAndBottomTabMandatory = false;
}
kosmydel marked this conversation as resolved.
Show resolved Hide resolved

if (rhpNavigator) {
// Routes
// - matching bottom tab
Expand Down
14 changes: 14 additions & 0 deletions src/pages/workspace/WorkspaceInitialPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,20 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, reimbursementAcc
PolicyUtils.goBackFromInvalidPolicy();
}, [policy, prevPolicy]);

// We are checking if the user can access the route.
// If user can't access the route, we are dismissing any modals that are open when the NotFound view is shown
const canAccessRoute = activeRoute && menuItems.some((item) => item.routeName === activeRoute);

useEffect(() => {
if (!shouldShowNotFoundPage && canAccessRoute) {
return;
}
// We are dismissing any modals that are open when the NotFound view is shown
Navigation.isNavigationReady().then(() => {
Navigation.dismissRHP();
});
}, [canAccessRoute, shouldShowNotFoundPage]);

const policyAvatar = useMemo(() => {
if (!policy) {
return {source: Expensicons.ExpensifyAppIcon, name: CONST.WORKSPACE_SWITCHER.NAME, type: CONST.ICON_TYPE_AVATAR};
Expand Down
3 changes: 3 additions & 0 deletions src/pages/workspace/WorkspaceInviteMessagePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ function WorkspaceInviteMessagePage({
setWelcomeNote(parser.htmlToMarkdown(getDefaultWelcomeNote()));
return;
}
if (isEmptyObject(policy)) {
return;
}
Navigation.goBack(ROUTES.WORKSPACE_INVITE.getRoute(route.params.policyID), true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
Expand Down
123 changes: 56 additions & 67 deletions src/pages/workspace/WorkspaceMembersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ import {InteractionManager, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import Badge from '@components/Badge';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import Button from '@components/Button';
import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu';
import type {DropdownOption, WorkspaceMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types';
import ConfirmModal from '@components/ConfirmModal';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Expensicons from '@components/Icon/Expensicons';
import * as Illustrations from '@components/Icon/Illustrations';
import MessagesRow from '@components/MessagesRow';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import TableListItem from '@components/SelectionList/TableListItem';
import type {ListItem, SelectionListHandle} from '@components/SelectionList/types';
Expand Down Expand Up @@ -47,6 +44,7 @@ import type {Errors, PendingAction} from '@src/types/onyx/OnyxCommon';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscreenLoading';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
import WorkspacePageWithSections from './WorkspacePageWithSections';

type WorkspaceMembersPageOnyxProps = {
/** Session info for the currently logged in user. */
Expand All @@ -59,7 +57,6 @@ type WorkspaceMembersPageProps = WithPolicyAndFullscreenLoadingProps &
WithCurrentUserPersonalDetailsProps &
WorkspaceMembersPageOnyxProps &
StackScreenProps<WorkspacesCentralPaneNavigatorParamList, typeof SCREENS.WORKSPACE.MEMBERS>;

/**
* Inverts an object, equivalent of _.invert
*/
Expand All @@ -71,8 +68,8 @@ function invertObject(object: Record<string, string>): Record<string, string> {

type MemberOption = Omit<ListItem, 'accountID'> & {accountID: number};

function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft, route, policy, session, currentUserPersonalDetails, isLoadingReportData = true}: WorkspaceMembersPageProps) {
const policyMemberEmailsToAccountIDs = useMemo(() => PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList, true), [policy?.employeeList]);
function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft, route, policy, session, currentUserPersonalDetails}: WorkspaceMembersPageProps) {
const policyMemberEmailsToAccountIDs = useMemo(() => PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList), [policy?.employeeList]);
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const [selectedEmployees, setSelectedEmployees] = useState<number[]>([]);
Expand Down Expand Up @@ -522,71 +519,63 @@ function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft,
};

return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
style={[styles.defaultModalContainer]}
<WorkspacePageWithSections
headerText={translate('workspace.common.members')}
route={route}
guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_MEMBERS}
headerContent={!isSmallScreenWidth && getHeaderButtons()}
icon={Illustrations.ReceiptWrangler}
testID={WorkspaceMembersPage.displayName}
shouldShowLoading={false}
shouldShowOfflineIndicatorInWideScreen
shouldShowNonAdmin
>
<FullPageNotFoundView
shouldShow={(isEmptyObject(policy) && !isLoadingReportData) || PolicyUtils.isPendingDeletePolicy(policy)}
subtitleKey={isEmptyObject(policy) ? undefined : 'workspace.common.notAuthorized'}
onBackButtonPress={PolicyUtils.goBackFromInvalidPolicy}
onLinkPress={PolicyUtils.goBackFromInvalidPolicy}
>
<HeaderWithBackButton
title={translate('workspace.common.members')}
icon={Illustrations.ReceiptWrangler}
onBackButtonPress={() => {
Navigation.goBack();
}}
shouldShowBackButton={isSmallScreenWidth}
guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_MEMBERS}
>
{!isSmallScreenWidth && getHeaderButtons()}
</HeaderWithBackButton>
{isSmallScreenWidth && <View style={[styles.pl5, styles.pr5]}>{getHeaderButtons()}</View>}
<ConfirmModal
danger
title={translate('workspace.people.removeMembersTitle')}
isVisible={removeMembersConfirmModalVisible}
onConfirm={removeUsers}
onCancel={() => setRemoveMembersConfirmModalVisible(false)}
prompt={translate('workspace.people.removeMembersPrompt')}
confirmText={translate('common.remove')}
cancelText={translate('common.cancel')}
onModalHide={() => {
InteractionManager.runAfterInteractions(() => {
if (!textInputRef.current) {
return;
}
textInputRef.current.focus();
});
}}
/>
<View style={[styles.w100, styles.flex1]}>
<SelectionList
ref={selectionListRef}
canSelectMultiple={isPolicyAdmin}
sections={[{data, isDisabled: false}]}
ListItem={TableListItem}
disableKeyboardShortcuts={removeMembersConfirmModalVisible}
headerMessage={getHeaderMessage()}
headerContent={getHeaderContent()}
onSelectRow={openMemberDetails}
onCheckboxPress={(item) => toggleUser(item.accountID)}
onSelectAll={() => toggleAllUsers(data)}
onDismissError={dismissError}
showLoadingPlaceholder={isLoading}
showScrollIndicator
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
textInputRef={textInputRef}
customListHeader={getCustomListHeader()}
listHeaderWrapperStyle={[styles.ph9, styles.pv3, styles.pb5]}
{() => (
<>
{isSmallScreenWidth && <View style={[styles.pl5, styles.pr5]}>{getHeaderButtons()}</View>}
<ConfirmModal
danger
title={translate('workspace.people.removeMembersTitle')}
isVisible={removeMembersConfirmModalVisible}
onConfirm={removeUsers}
onCancel={() => setRemoveMembersConfirmModalVisible(false)}
prompt={translate('workspace.people.removeMembersPrompt')}
confirmText={translate('common.remove')}
cancelText={translate('common.cancel')}
onModalHide={() => {
InteractionManager.runAfterInteractions(() => {
if (!textInputRef.current) {
return;
}
textInputRef.current.focus();
});
}}
/>
</View>
</FullPageNotFoundView>
</ScreenWrapper>

<View style={[styles.w100, styles.flex1]}>
<SelectionList
ref={selectionListRef}
canSelectMultiple={isPolicyAdmin}
sections={[{data, isDisabled: false}]}
ListItem={TableListItem}
disableKeyboardShortcuts={removeMembersConfirmModalVisible}
headerMessage={getHeaderMessage()}
headerContent={getHeaderContent()}
onSelectRow={openMemberDetails}
onCheckboxPress={(item) => toggleUser(item.accountID)}
onSelectAll={() => toggleAllUsers(data)}
onDismissError={dismissError}
showLoadingPlaceholder={isLoading}
showScrollIndicator
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
textInputRef={textInputRef}
customListHeader={getCustomListHeader()}
listHeaderWrapperStyle={[styles.ph9, styles.pv3, styles.pb5]}
/>
</View>
</>
)}
</WorkspacePageWithSections>
);
}

Expand Down
14 changes: 12 additions & 2 deletions src/pages/workspace/WorkspacePageWithSections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ type WorkspacePageWithSectionsProps = WithPolicyAndFullscreenLoadingProps &
* */
icon?: IconAsset;

/** Content to be added to the header */
headerContent?: ReactNode;

/** TestID of the component */
testID?: string;

/** Whether the page is loading, example any other API call in progres */
isLoading?: boolean;
};
Expand Down Expand Up @@ -112,6 +118,8 @@ function WorkspacePageWithSections({
shouldShowLoading = true,
shouldShowOfflineIndicatorInWideScreen = false,
shouldShowNonAdmin = false,
headerContent,
testID,
shouldShowNotFoundPage = false,
isLoading: isPageLoading = false,
}: WorkspacePageWithSectionsProps) {
Expand Down Expand Up @@ -160,7 +168,7 @@ function WorkspacePageWithSections({
includeSafeAreaPaddingBottom={false}
shouldEnablePickerAvoiding={false}
shouldEnableMaxHeight
testID={WorkspacePageWithSections.displayName}
testID={testID ?? WorkspacePageWithSections.displayName}
shouldShowOfflineIndicatorInWideScreen={shouldShowOfflineIndicatorInWideScreen && !shouldShow}
>
<FullPageNotFoundView
Expand All @@ -177,7 +185,9 @@ function WorkspacePageWithSections({
onBackButtonPress={() => Navigation.goBack(backButtonRoute)}
icon={icon ?? undefined}
style={styles.headerBarDesktopHeight}
/>
>
{headerContent}
</HeaderWithBackButton>
{(isLoading || firstRender.current) && shouldShowLoading && isFocused ? (
<FullScreenLoadingIndicator style={[styles.flex1, styles.pRelative]} />
) : (
Expand Down
Loading