Skip to content

Commit

Permalink
Merge pull request Expensify#28999 from dukenv0307/fix/27856
Browse files Browse the repository at this point in the history
The app should take the user back to the profile page when the user clicks the back button in the web browser
  • Loading branch information
johnmlee101 authored Jan 23, 2024
2 parents c69ff56 + ff8e890 commit b31ea3a
Show file tree
Hide file tree
Showing 15 changed files with 339 additions and 81 deletions.
13 changes: 13 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const ROUTES = {
route: 'a/:accountID',
getRoute: (accountID: string | number, backTo?: string) => getUrlWithBackToParam(`a/${accountID}`, backTo),
},
PROFILE_AVATAR: {
route: 'a/:accountID/avatar',
getRoute: (accountID: string) => `a/${accountID}/avatar` as const,
},

TRANSITION_BETWEEN_APPS: 'transition',
VALIDATE_LOGIN: 'v/:accountID/:validateCode',
Expand Down Expand Up @@ -140,6 +144,7 @@ const ROUTES = {
getRoute: (backTo?: string) => getUrlWithBackToParam('settings/security/two-factor-auth', backTo),
},
SETTINGS_STATUS: 'settings/profile/status',

SETTINGS_STATUS_CLEAR_AFTER: 'settings/profile/status/clear-after',
SETTINGS_STATUS_CLEAR_AFTER_DATE: 'settings/profile/status/clear-after/date',
SETTINGS_STATUS_CLEAR_AFTER_TIME: 'settings/profile/status/clear-after/time',
Expand All @@ -155,6 +160,10 @@ const ROUTES = {
route: 'r/:reportID?/:reportActionID?',
getRoute: (reportID: string) => `r/${reportID}` as const,
},
REPORT_AVATAR: {
route: 'r/:reportID/avatar',
getRoute: (reportID: string) => `r/${reportID}/avatar` as const,
},
EDIT_REQUEST: {
route: 'r/:threadReportID/edit/:field',
getRoute: (threadReportID: string, field: ValueOf<typeof CONST.EDIT_REQUEST_FIELD>) => `r/${threadReportID}/edit/${field}` as const,
Expand Down Expand Up @@ -438,6 +447,10 @@ const ROUTES = {
route: 'workspace/:policyID/settings',
getRoute: (policyID: string) => `workspace/${policyID}/settings` as const,
},
WORKSPACE_AVATAR: {
route: 'workspace/:policyID/avatar',
getRoute: (policyID: string) => `workspace/${policyID}/avatar` as const,
},
WORKSPACE_SETTINGS_CURRENCY: {
route: 'workspace/:policyID/settings/currency',
getRoute: (policyID: string) => `workspace/${policyID}/settings/currency` as const,
Expand Down
3 changes: 3 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const PROTECTED_SCREENS = {
const SCREENS = {
...PROTECTED_SCREENS,
REPORT: 'Report',
PROFILE_AVATAR: 'ProfileAvatar',
WORKSPACE_AVATAR: 'WorkspaceAvatar',
REPORT_AVATAR: 'ReportAvatar',
NOT_FOUND: 'not-found',
TRANSITION_BETWEEN_APPS: 'TransitionBetweenApps',
VALIDATE_LOGIN: 'ValidateLogin',
Expand Down
41 changes: 39 additions & 2 deletions src/components/AttachmentModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,21 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import useNativeDriver from '@libs/useNativeDriver';
import reportPropTypes from '@pages/reportPropTypes';
import variables from '@styles/variables';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import AttachmentCarousel from './Attachments/AttachmentCarousel';
import AttachmentView from './Attachments/AttachmentView';
import BlockingView from './BlockingViews/BlockingView';
import Button from './Button';
import ConfirmModal from './ConfirmModal';
import FullScreenLoadingIndicator from './FullscreenLoadingIndicator';
import HeaderGap from './HeaderGap';
import HeaderWithBackButton from './HeaderWithBackButton';
import * as Expensicons from './Icon/Expensicons';
import * as Illustrations from './Icon/Illustrations';
import sourcePropTypes from './Image/sourcePropTypes';
import Modal from './Modal';
import SafeAreaConsumer from './SafeAreaConsumer';
Expand Down Expand Up @@ -61,6 +65,9 @@ const propTypes = {
/** Optional callback to fire when we want to do something after modal hide. */
onModalHide: PropTypes.func,

/** Trigger when we explicity click close button in ProfileAttachment modal */
onModalClose: PropTypes.func,

/** Optional callback to fire when we want to do something after attachment carousel changes. */
onCarouselAttachmentChange: PropTypes.func,

Expand All @@ -85,6 +92,12 @@ const propTypes = {
/** The transaction associated with the receipt attachment, if any */
transaction: transactionPropTypes,

/** The data is loading or not */
isLoading: PropTypes.bool,

/** Should display not found page or not */
shouldShowNotFoundPage: PropTypes.bool,

...withLocalizePropTypes,

...windowDimensionsPropTypes,
Expand Down Expand Up @@ -114,6 +127,9 @@ const defaultProps = {
onModalHide: () => {},
onCarouselAttachmentChange: () => {},
isWorkspaceAvatar: false,
onModalClose: () => {},
isLoading: false,
shouldShowNotFoundPage: false,
isReceiptAttachment: false,
canEditReceipt: false,
};
Expand Down Expand Up @@ -352,7 +368,13 @@ function AttachmentModal(props) {
*/
const closeModal = useCallback(() => {
setIsModalOpen(false);
}, []);

if (typeof props.onModalClose === 'function') {
props.onModalClose();
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.onModalClose]);

/**
* open the modal
Expand Down Expand Up @@ -461,6 +483,19 @@ function AttachmentModal(props) {
shouldOverlayDots
/>
<View style={styles.imageModalImageCenterContainer}>
{props.isLoading && <FullScreenLoadingIndicator />}
{props.shouldShowNotFoundPage && !props.isLoading && (
<BlockingView
icon={Illustrations.ToddBehindCloud}
iconWidth={variables.modalTopIconWidth}
iconHeight={variables.modalTopIconHeight}
title={translate('notFound.notHere')}
subtitle={translate('notFound.pageNotFound')}
linkKey="notFound.goBackHome"
shouldShowLink
onLinkPress={() => Navigation.dismissModal()}
/>
)}
{!_.isEmpty(props.report) && !props.isReceiptAttachment ? (
<AttachmentCarousel
report={props.report}
Expand All @@ -472,7 +507,9 @@ function AttachmentModal(props) {
/>
) : (
Boolean(sourceForAttachmentView) &&
shouldLoadAttachment && (
shouldLoadAttachment &&
!props.isLoading &&
!props.shouldShowNotFoundPage && (
<AttachmentView
containerStyles={[styles.mh5]}
source={sourceForAttachmentView}
Expand Down
13 changes: 12 additions & 1 deletion src/components/AvatarWithImagePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ const propTypes = {
/** Whether navigation is focused */
isFocused: PropTypes.bool.isRequired,

/** Executed once click on view photo option */
onViewPhotoPress: PropTypes.func,

/** Where the popover should be positioned relative to the anchor points. */
anchorAlignment: PropTypes.shape({
horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)),
Expand All @@ -115,6 +118,7 @@ const defaultProps = {
headerTitle: '',
previewSource: '',
originalFileName: '',
onViewPhotoPress: undefined,
anchorAlignment: {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
Expand Down Expand Up @@ -142,6 +146,7 @@ function AvatarWithImagePicker({
anchorAlignment,
onImageSelected,
editorMaskImage,
onViewPhotoPress,
}) {
const theme = useTheme();
const styles = useThemeStyles();
Expand Down Expand Up @@ -344,7 +349,13 @@ function AvatarWithImagePicker({
menuItems.push({
icon: Expensicons.Eye,
text: translate('avatarWithImagePicker.viewPhoto'),
onSelected: show,
onSelected: () => {
if (typeof onViewPhotoPress !== 'function') {
show();
return;
}
onViewPhotoPress();
},
});
}

Expand Down
90 changes: 40 additions & 50 deletions src/components/RoomHeaderAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,33 @@ import {View} from 'react-native';
import _ from 'underscore';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import * as UserUtils from '@libs/UserUtils';
import Navigation from '@libs/Navigation/Navigation';
import CONST from '@src/CONST';
import AttachmentModal from './AttachmentModal';
import ROUTES from '@src/ROUTES';
import Avatar from './Avatar';
import avatarPropTypes from './avatarPropTypes';
import PressableWithoutFocus from './Pressable/PressableWithoutFocus';
import Text from './Text';

const propTypes = {
icons: PropTypes.arrayOf(avatarPropTypes),
reportID: PropTypes.string,
};

const defaultProps = {
icons: [],
reportID: '',
};

function RoomHeaderAvatars(props) {
const navigateToAvatarPage = (icon) => {
if (icon.type === CONST.ICON_TYPE_WORKSPACE) {
Navigation.navigate(ROUTES.REPORT_AVATAR.getRoute(props.reportID));
return;
}
Navigation.navigate(ROUTES.PROFILE_AVATAR.getRoute(icon.id));
};

const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
if (!props.icons.length) {
Expand All @@ -29,31 +39,21 @@ function RoomHeaderAvatars(props) {

if (props.icons.length === 1) {
return (
<AttachmentModal
headerTitle={props.icons[0].name}
source={UserUtils.getFullSizeAvatar(props.icons[0].source, props.icons[0].id)}
isAuthTokenRequired
isWorkspaceAvatar={props.icons[0].type === CONST.ICON_TYPE_WORKSPACE}
originalFileName={props.icons[0].name}
<PressableWithoutFocus
style={[styles.noOutline]}
onPress={() => navigateToAvatarPage(props.icons[0])}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={props.icons[0].name}
>
{({show}) => (
<PressableWithoutFocus
style={[styles.noOutline]}
onPress={show}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={props.icons[0].name}
>
<Avatar
source={props.icons[0].source}
imageStyles={[styles.avatarLarge]}
size={CONST.AVATAR_SIZE.LARGE}
name={props.icons[0].name}
type={props.icons[0].type}
fallbackIcon={props.icons[0].fallbackIcon}
/>
</PressableWithoutFocus>
)}
</AttachmentModal>
<Avatar
source={props.icons[0].source}
imageStyles={[styles.avatarLarge]}
size={CONST.AVATAR_SIZE.LARGE}
name={props.icons[0].name}
type={props.icons[0].type}
fallbackIcon={props.icons[0].fallbackIcon}
/>
</PressableWithoutFocus>
);
}

Expand All @@ -73,31 +73,21 @@ function RoomHeaderAvatars(props) {
key={`${icon.id}${index}`}
style={[styles.justifyContentCenter, styles.alignItemsCenter]}
>
<AttachmentModal
headerTitle={icon.name}
source={UserUtils.getFullSizeAvatar(icon.source, icon.id)}
isAuthTokenRequired
originalFileName={icon.name}
isWorkspaceAvatar={icon.type === CONST.ICON_TYPE_WORKSPACE}
<PressableWithoutFocus
style={[styles.mln4, StyleUtils.getAvatarBorderRadius(CONST.AVATAR_SIZE.LARGE_BORDERED, icon.type)]}
onPress={() => navigateToAvatarPage(icon)}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={icon.name}
>
{({show}) => (
<PressableWithoutFocus
style={[styles.mln4, StyleUtils.getAvatarBorderRadius(CONST.AVATAR_SIZE.LARGE_BORDERED, icon.type)]}
onPress={show}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={icon.name}
>
<Avatar
source={icon.source}
size={CONST.AVATAR_SIZE.LARGE}
containerStyles={[...iconStyle, StyleUtils.getAvatarBorderRadius(CONST.AVATAR_SIZE.LARGE_BORDERED, icon.type)]}
name={icon.name}
type={icon.type}
fallbackIcon={icon.fallbackIcon}
/>
</PressableWithoutFocus>
)}
</AttachmentModal>
<Avatar
source={icon.source}
size={CONST.AVATAR_SIZE.LARGE}
containerStyles={[...iconStyle, StyleUtils.getAvatarBorderRadius(CONST.AVATAR_SIZE.LARGE_BORDERED, icon.type)]}
name={icon.name}
type={icon.type}
fallbackIcon={icon.fallbackIcon}
/>
</PressableWithoutFocus>
{index === CONST.REPORT.MAX_PREVIEW_AVATARS - 1 && props.icons.length - CONST.REPORT.MAX_PREVIEW_AVATARS !== 0 && (
<>
<View
Expand Down
30 changes: 30 additions & 0 deletions src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ const loadSidebarScreen = () => require('../../../pages/home/sidebar/SidebarScre
const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default as React.ComponentType;
const loadLogOutPreviousUserPage = () => require('../../../pages/LogOutPreviousUserPage').default as React.ComponentType;
const loadConciergePage = () => require('../../../pages/ConciergePage').default as React.ComponentType;
const loadProfileAvatar = () => require('../../../pages/settings/Profile/ProfileAvatar').default as React.ComponentType;
const loadWorkspaceAvatar = () => require('../../../pages/workspace/WorkspaceAvatar').default as React.ComponentType;
const loadReportAvatar = () => require('../../../pages/ReportAvatar').default as React.ComponentType;

let timezone: Timezone | null;
let currentAccountID = -1;
Expand Down Expand Up @@ -298,6 +301,33 @@ function AuthScreens({session, lastOpenedPublicRoomID, isUsingMemoryOnlyKeys = f
getComponent={loadReportAttachments}
listeners={modalScreenListeners}
/>
<RootStack.Screen
name={SCREENS.PROFILE_AVATAR}
options={{
headerShown: false,
presentation: 'transparentModal',
}}
getComponent={loadProfileAvatar}
listeners={modalScreenListeners}
/>
<RootStack.Screen
name={SCREENS.WORKSPACE_AVATAR}
options={{
headerShown: false,
presentation: 'transparentModal',
}}
getComponent={loadWorkspaceAvatar}
listeners={modalScreenListeners}
/>
<RootStack.Screen
name={SCREENS.REPORT_AVATAR}
options={{
headerShown: false,
presentation: 'transparentModal',
}}
getComponent={loadReportAvatar}
listeners={modalScreenListeners}
/>
<RootStack.Screen
name={SCREENS.NOT_FOUND}
options={screenOptions.fullScreen}
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/linkingConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ const linkingConfig: LinkingOptions<RootStackParamList> = {
[SCREENS.SAML_SIGN_IN]: ROUTES.SAML_SIGN_IN,
[SCREENS.DESKTOP_SIGN_IN_REDIRECT]: ROUTES.DESKTOP_SIGN_IN_REDIRECT,
[SCREENS.REPORT_ATTACHMENTS]: ROUTES.REPORT_ATTACHMENTS.route,
[SCREENS.PROFILE_AVATAR]: ROUTES.PROFILE_AVATAR.route,
[SCREENS.WORKSPACE_AVATAR]: ROUTES.WORKSPACE_AVATAR.route,
[SCREENS.REPORT_AVATAR]: ROUTES.REPORT_AVATAR.route,

// Sidebar
[SCREENS.HOME]: {
Expand Down
9 changes: 9 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,15 @@ type AuthScreensParamList = {
reportID: string;
source: string;
};
[SCREENS.PROFILE_AVATAR]: {
accountID: string;
};
[SCREENS.WORKSPACE_AVATAR]: {
policyID: string;
};
[SCREENS.REPORT_AVATAR]: {
reportID: string;
};
[SCREENS.NOT_FOUND]: undefined;
[NAVIGATORS.LEFT_MODAL_NAVIGATOR]: NavigatorScreenParams<LeftModalNavigatorParamList>;
[NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: NavigatorScreenParams<RightModalNavigatorParamList>;
Expand Down
Loading

0 comments on commit b31ea3a

Please sign in to comment.