diff --git a/src/languages/en.ts b/src/languages/en.ts
index c186a1fffedf..8ce15d16f4fe 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -811,7 +811,6 @@ export default {
title: 'Private notes',
personalNoteMessage: 'Keep notes about this chat here. You are the only person who can add, edit or view these notes.',
sharedNoteMessage: 'Keep notes about this chat here. Expensify employees and other users on the team.expensify.com domain can view these notes.',
- notesUnavailable: 'No notes found for the user',
composerLabel: 'Notes',
myNote: 'My note',
},
diff --git a/src/languages/es.ts b/src/languages/es.ts
index a0a30bcf4141..9d0184ffff30 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -806,7 +806,6 @@ export default {
title: 'Notas privadas',
personalNoteMessage: 'Guarda notas sobre este chat aquí. Usted es la única persona que puede añadir, editar o ver estas notas.',
sharedNoteMessage: 'Guarda notas sobre este chat aquí. Los empleados de Expensify y otros usuarios del dominio team.expensify.com pueden ver estas notas.',
- notesUnavailable: 'No se han encontrado notas para el usuario',
composerLabel: 'Notas',
myNote: 'Mi nota',
},
diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.js b/src/pages/PrivateNotes/PrivateNotesEditPage.js
index 7c8aec8d12de..78e6929121ae 100644
--- a/src/pages/PrivateNotes/PrivateNotesEditPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesEditPage.js
@@ -7,7 +7,6 @@ import React, {useCallback, useMemo, useRef, useState} from 'react';
import {Keyboard} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
@@ -19,8 +18,8 @@ import withLocalize from '@components/withLocalize';
import useLocalize from '@hooks/useLocalize';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
-import * as ReportUtils from '@libs/ReportUtils';
import updateMultilineInputRange from '@libs/UpdateMultilineInputRange';
+import withReportAndPrivateNotesOrNotFound from '@pages/home/report/withReportAndPrivateNotesOrNotFound';
import personalDetailsPropType from '@pages/personalDetailsPropType';
import reportPropTypes from '@pages/reportPropTypes';
import styles from '@styles/styles';
@@ -43,23 +42,14 @@ const propTypes = {
accountID: PropTypes.string,
}),
}).isRequired,
-
- /** Session of currently logged in user */
- session: PropTypes.shape({
- /** Currently logged in user accountID */
- accountID: PropTypes.number,
- }),
};
const defaultProps = {
report: {},
- session: {
- accountID: null,
- },
personalDetailsList: {},
};
-function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
+function PrivateNotesEditPage({route, personalDetailsList, report}) {
const {translate} = useLocalize();
// We need to edit the note in markdown format, but display it in HTML format
@@ -81,8 +71,6 @@ function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
[report.reportID],
);
- const isCurrentUserNote = Number(session.accountID) === Number(route.params.accountID);
-
// To focus on the input field when the page loads
const privateNotesInput = useRef(null);
const focusTimeoutRef = useRef(null);
@@ -119,73 +107,62 @@ function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
includeSafeAreaPaddingBottom={false}
testID={PrivateNotesEditPage.displayName}
>
- Navigation.goBack(ROUTES.PRIVATE_NOTES_VIEW.getRoute(report.reportID, route.params.accountID))}
+ shouldShowBackButton
+ onCloseButtonPress={() => Navigation.dismissModal()}
+ />
+
- Navigation.goBack(ROUTES.PRIVATE_NOTES_VIEW.getRoute(report.reportID, route.params.accountID))}
- shouldShowBackButton
- onCloseButtonPress={() => Navigation.dismissModal()}
- />
-
+ {translate(
+ Str.extractEmailDomain(lodashGet(personalDetailsList, [route.params.accountID, 'login'], '')) === CONST.EMAIL.GUIDES_DOMAIN
+ ? 'privateNotes.sharedNoteMessage'
+ : 'privateNotes.personalNoteMessage',
+ )}
+
+ Report.clearPrivateNotesError(report.reportID, route.params.accountID)}
+ style={[styles.mb3]}
>
-
- {translate(
- Str.extractEmailDomain(lodashGet(personalDetailsList, [route.params.accountID, 'login'], '')) === CONST.EMAIL.GUIDES_DOMAIN
- ? 'privateNotes.sharedNoteMessage'
- : 'privateNotes.personalNoteMessage',
- )}
-
- {
+ debouncedSavePrivateNote(text);
+ setPrivateNote(text);
}}
- onClose={() => Report.clearPrivateNotesError(report.reportID, route.params.accountID)}
- style={[styles.mb3]}
- >
- {
- debouncedSavePrivateNote(text);
- setPrivateNote(text);
- }}
- ref={(el) => {
- if (!el) {
- return;
- }
- privateNotesInput.current = el;
- updateMultilineInputRange(privateNotesInput.current);
- }}
- />
-
-
-
+ ref={(el) => {
+ if (!el) {
+ return;
+ }
+ privateNotesInput.current = el;
+ updateMultilineInputRange(privateNotesInput.current);
+ }}
+ />
+
+
);
}
@@ -196,13 +173,8 @@ PrivateNotesEditPage.defaultProps = defaultProps;
export default compose(
withLocalize,
+ withReportAndPrivateNotesOrNotFound,
withOnyx({
- report: {
- key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`,
- },
- session: {
- key: ONYXKEYS.SESSION,
- },
personalDetailsList: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.js b/src/pages/PrivateNotes/PrivateNotesListPage.js
index ec3905db349e..4d5b348c4b9f 100644
--- a/src/pages/PrivateNotes/PrivateNotesListPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesListPage.js
@@ -1,14 +1,11 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import React, {useEffect, useMemo} from 'react';
+import React, {useMemo} from 'react';
import {ScrollView} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
-import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import MenuItem from '@components/MenuItem';
-import networkPropTypes from '@components/networkPropTypes';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {withNetwork} from '@components/OnyxProvider';
import ScreenWrapper from '@components/ScreenWrapper';
@@ -16,12 +13,11 @@ import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import useLocalize from '@hooks/useLocalize';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
-import * as ReportUtils from '@libs/ReportUtils';
import * as UserUtils from '@libs/UserUtils';
+import withReportAndPrivateNotesOrNotFound from '@pages/home/report/withReportAndPrivateNotesOrNotFound';
import personalDetailsPropType from '@pages/personalDetailsPropType';
import reportPropTypes from '@pages/reportPropTypes';
import styles from '@styles/styles';
-import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
@@ -47,8 +43,6 @@ const propTypes = {
/** All of the personal details for everyone */
personalDetailsList: PropTypes.objectOf(personalDetailsPropType),
- /** Information about the network */
- network: networkPropTypes.isRequired,
...withLocalizePropTypes,
};
@@ -60,17 +54,9 @@ const defaultProps = {
personalDetailsList: {},
};
-function PrivateNotesListPage({report, personalDetailsList, network, session}) {
+function PrivateNotesListPage({report, personalDetailsList, session}) {
const {translate} = useLocalize();
- useEffect(() => {
- if (network.isOffline && report.isLoadingPrivateNotes) {
- return;
- }
- Report.getReportPrivateNote(report.reportID);
- // eslint-disable-next-line react-hooks/exhaustive-deps -- do not add isLoadingPrivateNotes to dependencies
- }, [report.reportID, network.isOffline]);
-
/**
* Gets the menu item for each workspace
*
@@ -124,26 +110,12 @@ function PrivateNotesListPage({report, personalDetailsList, network, session}) {
includeSafeAreaPaddingBottom={false}
testID={PrivateNotesListPage.displayName}
>
-
- Navigation.dismissModal()}
- />
-
- {report.isLoadingPrivateNotes && _.isEmpty(lodashGet(report, 'privateNotes', {})) ? (
-
- ) : (
- _.map(privateNotes, (item, index) => getMenuItem(item, index))
- )}
-
-
+ Navigation.dismissModal()}
+ />
+ {_.map(privateNotes, (item, index) => getMenuItem(item, index))}
);
}
@@ -154,13 +126,8 @@ PrivateNotesListPage.displayName = 'PrivateNotesListPage';
export default compose(
withLocalize,
+ withReportAndPrivateNotesOrNotFound,
withOnyx({
- report: {
- key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`,
- },
- session: {
- key: ONYXKEYS.SESSION,
- },
personalDetailsList: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
diff --git a/src/pages/PrivateNotes/PrivateNotesViewPage.js b/src/pages/PrivateNotes/PrivateNotesViewPage.js
index bb9d96516437..2b836036448d 100644
--- a/src/pages/PrivateNotes/PrivateNotesViewPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesViewPage.js
@@ -4,7 +4,6 @@ import React from 'react';
import {ScrollView} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
@@ -13,7 +12,7 @@ import withLocalize from '@components/withLocalize';
import useLocalize from '@hooks/useLocalize';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
-import * as ReportUtils from '@libs/ReportUtils';
+import withReportAndPrivateNotesOrNotFound from '@pages/home/report/withReportAndPrivateNotesOrNotFound';
import personalDetailsPropType from '@pages/personalDetailsPropType';
import reportPropTypes from '@pages/reportPropTypes';
import styles from '@styles/styles';
@@ -71,33 +70,28 @@ function PrivateNotesViewPage({route, personalDetailsList, session, report}) {
includeSafeAreaPaddingBottom={false}
testID={PrivateNotesViewPage.displayName}
>
-
- Navigation.goBack(getFallbackRoute())}
- subtitle={isCurrentUserNote ? translate('privateNotes.myNote') : `${lodashGet(personalDetailsList, [route.params.accountID, 'login'], '')} note`}
- shouldShowBackButton
- onCloseButtonPress={() => Navigation.dismissModal()}
- />
-
-
- isCurrentUserNote && Navigation.navigate(ROUTES.PRIVATE_NOTES_EDIT.getRoute(report.reportID, route.params.accountID))}
- shouldShowRightIcon={isCurrentUserNote}
- numberOfLinesTitle={0}
- shouldRenderAsHTML
- brickRoadIndicator={!_.isEmpty(lodashGet(report, ['privateNotes', route.params.accountID, 'errors'], '')) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
- disabled={!isCurrentUserNote}
- shouldGreyOutWhenDisabled={false}
- />
-
-
-
+ Navigation.goBack(getFallbackRoute())}
+ subtitle={isCurrentUserNote ? translate('privateNotes.myNote') : `${lodashGet(personalDetailsList, [route.params.accountID, 'login'], '')} note`}
+ shouldShowBackButton
+ onCloseButtonPress={() => Navigation.dismissModal()}
+ />
+
+
+ isCurrentUserNote && Navigation.navigate(ROUTES.PRIVATE_NOTES_EDIT.getRoute(report.reportID, route.params.accountID))}
+ shouldShowRightIcon={isCurrentUserNote}
+ numberOfLinesTitle={0}
+ shouldRenderAsHTML
+ brickRoadIndicator={!_.isEmpty(lodashGet(report, ['privateNotes', route.params.accountID, 'errors'], '')) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
+ disabled={!isCurrentUserNote}
+ shouldGreyOutWhenDisabled={false}
+ />
+
+
);
}
@@ -108,13 +102,8 @@ PrivateNotesViewPage.defaultProps = defaultProps;
export default compose(
withLocalize,
+ withReportAndPrivateNotesOrNotFound,
withOnyx({
- report: {
- key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`,
- },
- session: {
- key: ONYXKEYS.SESSION,
- },
personalDetailsList: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
diff --git a/src/pages/home/report/withReportAndPrivateNotesOrNotFound.js b/src/pages/home/report/withReportAndPrivateNotesOrNotFound.js
new file mode 100644
index 000000000000..3982dd5ab542
--- /dev/null
+++ b/src/pages/home/report/withReportAndPrivateNotesOrNotFound.js
@@ -0,0 +1,130 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useEffect, useMemo} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import * as Report from '@libs/actions/Report';
+import compose from '@libs/compose';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import * as ReportUtils from '@libs/ReportUtils';
+import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import reportPropTypes from '@pages/reportPropTypes';
+import ONYXKEYS from '@src/ONYXKEYS';
+import withReportOrNotFound from './withReportOrNotFound';
+
+const propTypes = {
+ /** The HOC takes an optional ref as a prop and passes it as a ref to the wrapped component.
+ * That way, if a ref is passed to a component wrapped in the HOC, the ref is a reference to the wrapped component, not the HOC. */
+ forwardedRef: PropTypes.func,
+
+ /** The report currently being looked at */
+ report: reportPropTypes,
+
+ /** Information about the network */
+ network: networkPropTypes.isRequired,
+
+ /** Session of currently logged in user */
+ session: PropTypes.shape({
+ /** accountID of currently logged in user */
+ accountID: PropTypes.number,
+ }),
+
+ route: PropTypes.shape({
+ /** Params from the URL path */
+ params: PropTypes.shape({
+ /** reportID and accountID passed via route: /r/:reportID/notes/:accountID */
+ reportID: PropTypes.string,
+ accountID: PropTypes.string,
+ }),
+ }).isRequired,
+};
+
+const defaultProps = {
+ forwardedRef: () => {},
+ report: {},
+ session: {
+ accountID: null,
+ },
+};
+
+export default function (WrappedComponent) {
+ // eslint-disable-next-line rulesdir/no-negated-variables
+ function WithReportAndPrivateNotesOrNotFound({forwardedRef, ...props}) {
+ const {route, report, network, session} = props;
+ const accountID = route.params.accountID;
+ const isPrivateNotesFetchTriggered = !_.isUndefined(report.isLoadingPrivateNotes);
+
+ useEffect(() => {
+ // Do not fetch private notes if isLoadingPrivateNotes is already defined, or if network is offline.
+ if (isPrivateNotesFetchTriggered || network.isOffline) {
+ return;
+ }
+
+ Report.getReportPrivateNote(report.reportID);
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- do not add report.isLoadingPrivateNotes to dependencies
+ }, [report.reportID, network.isOffline, isPrivateNotesFetchTriggered]);
+
+ const isPrivateNotesEmpty = accountID ? _.isEmpty(lodashGet(report, ['privateNotes', accountID, 'note'], '')) : _.isEmpty(report.privateNotes);
+ const shouldShowFullScreenLoadingIndicator = !isPrivateNotesFetchTriggered || (isPrivateNotesEmpty && report.isLoadingPrivateNotes);
+
+ // eslint-disable-next-line rulesdir/no-negated-variables
+ const shouldShowNotFoundPage = useMemo(() => {
+ // Show not found view if the report is archived, or if the note is not of current user.
+ if (ReportUtils.isArchivedRoom(report) || (accountID && Number(session.accountID) !== Number(accountID))) {
+ return true;
+ }
+
+ // Don't show not found view if the notes are still loading, or if the notes are non-empty.
+ if (shouldShowFullScreenLoadingIndicator || !isPrivateNotesEmpty) {
+ return false;
+ }
+
+ // As notes being empty and not loading is a valid case, show not found view only in offline mode.
+ return network.isOffline;
+ }, [report, network.isOffline, accountID, session.accountID, isPrivateNotesEmpty, shouldShowFullScreenLoadingIndicator]);
+
+ if (shouldShowFullScreenLoadingIndicator) {
+ return ;
+ }
+
+ if (shouldShowNotFoundPage) {
+ return ;
+ }
+
+ return (
+
+ );
+ }
+
+ WithReportAndPrivateNotesOrNotFound.propTypes = propTypes;
+ WithReportAndPrivateNotesOrNotFound.defaultProps = defaultProps;
+ WithReportAndPrivateNotesOrNotFound.displayName = `withReportAndPrivateNotesOrNotFound(${getComponentDisplayName(WrappedComponent)})`;
+
+ // eslint-disable-next-line rulesdir/no-negated-variables
+ const WithReportAndPrivateNotesOrNotFoundWithRef = React.forwardRef((props, ref) => (
+
+ ));
+
+ WithReportAndPrivateNotesOrNotFoundWithRef.displayName = 'WithReportAndPrivateNotesOrNotFoundWithRef';
+
+ return compose(
+ withReportOrNotFound(),
+ withOnyx({
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ }),
+ withNetwork(),
+ )(WithReportAndPrivateNotesOrNotFoundWithRef);
+}
diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx
index 81d1376abd37..95997da71a2d 100644
--- a/src/pages/home/report/withReportOrNotFound.tsx
+++ b/src/pages/home/report/withReportOrNotFound.tsx
@@ -36,7 +36,7 @@ export default function (
const isReportIdInRoute = props.route.params.reportID?.length;
if (shouldRequireReportID || isReportIdInRoute) {
- const shouldShowFullScreenLoadingIndicator = props.isLoadingReportData && (!Object.entries(props.report ?? {}).length || !props.report?.reportID);
+ const shouldShowFullScreenLoadingIndicator = props.isLoadingReportData !== false && (!Object.entries(props.report ?? {}).length || !props.report?.reportID);
const shouldShowNotFoundPage =
!Object.entries(props.report ?? {}).length || !props.report?.reportID || !ReportUtils.canAccessReport(props.report, props.policies, props.betas, {});