Skip to content

Commit

Permalink
Merge pull request Expensify#26166 from margelo/feat/#Expensify#23220-…
Browse files Browse the repository at this point in the history
…bidirectional-pagination

Bidirectional pagination
  • Loading branch information
roryabraham authored Oct 24, 2023
2 parents 4a7709f + c9f0620 commit 485a851
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 84 deletions.
7 changes: 7 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2779,13 +2779,20 @@ const CONST = {
SCROLLING: 'scrolling',
},

CHAT_HEADER_LOADER_HEIGHT: 36,

HORIZONTAL_SPACER: {
DEFAULT_BORDER_BOTTOM_WIDTH: 1,
DEFAULT_MARGIN_VERTICAL: 8,
HIDDEN_MARGIN_VERTICAL: 0,
HIDDEN_BORDER_BOTTOM_WIDTH: 0,
},

LIST_COMPONENTS: {
HEADER: 'header',
FOOTER: 'footer',
},

GLOBAL_NAVIGATION_OPTION: {
HOME: 'home',
CHATS: 'chats',
Expand Down
2 changes: 1 addition & 1 deletion src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ const ONYXKEYS = {
POLICY_RECENTLY_USED_TAGS: 'policyRecentlyUsedTags_',
WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_',
REPORT: 'report_',
// REPORT_METADATA is a perf optimization used to hold loading states (isLoadingReportActions, isLoadingMoreReportActions).
// REPORT_METADATA is a perf optimization used to hold loading states (isLoadingInitialReportActions, isLoadingOlderReportActions, isLoadingNewerReportActions).
// A lot of components are connected to the Report entity and do not care about the actions. Setting the loading state
// directly on the report caused a lot of unnecessary re-renders
REPORT_METADATA: 'reportMetadata_',
Expand Down
3 changes: 3 additions & 0 deletions src/components/InvertedFlatList/BaseInvertedFlatList.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ function BaseInvertedFlatList(props) {
// Web requires that items be measured or else crazy things happen when scrolling.
getItemLayout={shouldMeasureItems ? getItemLayout : undefined}
windowSize={15}
maintainVisibleContentPosition={{
minIndexForVisible: 0,
}}
inverted
/>
);
Expand Down
17 changes: 10 additions & 7 deletions src/components/ReportActionsSkeletonView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,26 @@ import CONST from '../../CONST';
const propTypes = {
/** Whether to animate the skeleton view */
shouldAnimate: PropTypes.bool,

/** Number of possible visible content items */
possibleVisibleContentItems: PropTypes.number,
};

const defaultProps = {
shouldAnimate: true,
possibleVisibleContentItems: 0,
};

function ReportActionsSkeletonView(props) {
// Determines the number of content items based on container height
const possibleVisibleContentItems = Math.ceil(Dimensions.get('window').height / CONST.CHAT_SKELETON_VIEW.AVERAGE_ROW_HEIGHT);
function ReportActionsSkeletonView({shouldAnimate, possibleVisibleContentItems}) {
const contentItems = possibleVisibleContentItems || Math.ceil(Dimensions.get('window').height / CONST.CHAT_SKELETON_VIEW.AVERAGE_ROW_HEIGHT);
const skeletonViewLines = [];
for (let index = 0; index < possibleVisibleContentItems; index++) {
for (let index = 0; index < contentItems; index++) {
const iconIndex = (index + 1) % 4;
switch (iconIndex) {
case 2:
skeletonViewLines.push(
<SkeletonViewLines
shouldAnimate={props.shouldAnimate}
shouldAnimate={shouldAnimate}
numberOfRows={2}
key={`skeletonViewLines${index}`}
/>,
Expand All @@ -32,7 +35,7 @@ function ReportActionsSkeletonView(props) {
case 0:
skeletonViewLines.push(
<SkeletonViewLines
shouldAnimate={props.shouldAnimate}
shouldAnimate={shouldAnimate}
numberOfRows={3}
key={`skeletonViewLines${index}`}
/>,
Expand All @@ -41,7 +44,7 @@ function ReportActionsSkeletonView(props) {
default:
skeletonViewLines.push(
<SkeletonViewLines
shouldAnimate={props.shouldAnimate}
shouldAnimate={shouldAnimate}
numberOfRows={1}
key={`skeletonViewLines${index}`}
/>,
Expand Down
2 changes: 1 addition & 1 deletion src/libs/actions/Policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ function createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${optimisticReport.reportID}`,
value: {
isLoadingReportActions: false,
isLoadingInitialReportActions: false,
},
});
});
Expand Down
77 changes: 63 additions & 14 deletions src/libs/actions/Report.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,9 @@ function openReport(reportID, participantLoginList = [], newReportObject = {}, p
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingReportActions: true,
isLoadingMoreReportActions: false,
isLoadingInitialReportActions: true,
isLoadingOlderReportActions: false,
isLoadingNewerReportActions: false,
},
},
];
Expand All @@ -501,7 +502,7 @@ function openReport(reportID, participantLoginList = [], newReportObject = {}, p
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingReportActions: false,
isLoadingInitialReportActions: false,
},
},
];
Expand All @@ -511,7 +512,7 @@ function openReport(reportID, participantLoginList = [], newReportObject = {}, p
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingReportActions: false,
isLoadingInitialReportActions: false,
},
},
];
Expand Down Expand Up @@ -737,8 +738,9 @@ function reconnect(reportID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingReportActions: true,
isLoadingMoreReportActions: false,
isLoadingInitialReportActions: true,
isLoadingNewerReportActions: false,
isLoadingOlderReportActions: false,
},
},
],
Expand All @@ -747,7 +749,7 @@ function reconnect(reportID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingReportActions: false,
isLoadingInitialReportActions: false,
},
},
],
Expand All @@ -756,7 +758,7 @@ function reconnect(reportID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingReportActions: false,
isLoadingInitialReportActions: false,
},
},
],
Expand All @@ -771,9 +773,9 @@ function reconnect(reportID) {
* @param {String} reportID
* @param {String} reportActionID
*/
function readOldestAction(reportID, reportActionID) {
function getOlderActions(reportID, reportActionID) {
API.read(
'ReadOldestAction',
'GetOlderActions',
{
reportID,
reportActionID,
Expand All @@ -784,7 +786,7 @@ function readOldestAction(reportID, reportActionID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingMoreReportActions: true,
isLoadingOlderReportActions: true,
},
},
],
Expand All @@ -793,7 +795,7 @@ function readOldestAction(reportID, reportActionID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingMoreReportActions: false,
isLoadingOlderReportActions: false,
},
},
],
Expand All @@ -802,7 +804,53 @@ function readOldestAction(reportID, reportActionID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingMoreReportActions: false,
isLoadingOlderReportActions: false,
},
},
],
},
);
}

/**
* Gets the newer actions that have not been read yet.
* Normally happens when you are not located at the bottom of the list and scroll down on a chat.
*
* @param {String} reportID
* @param {String} reportActionID
*/
function getNewerActions(reportID, reportActionID) {
API.read(
'GetNewerActions',
{
reportID,
reportActionID,
},
{
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingNewerReportActions: true,
},
},
],
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingNewerReportActions: false,
},
},
],
failureData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isLoadingNewerReportActions: false,
},
},
],
Expand Down Expand Up @@ -2411,7 +2459,6 @@ export {
expandURLPreview,
markCommentAsUnread,
readNewestAction,
readOldestAction,
openReport,
openReportFromDeepLink,
navigateToAndOpenReport,
Expand All @@ -2436,6 +2483,8 @@ export {
getReportPrivateNote,
clearPrivateNotesError,
hasErrorInPrivateNotes,
getOlderActions,
getNewerActions,
openRoomMembersPage,
savePrivateNotesDraft,
getDraftPrivateNote,
Expand Down
26 changes: 18 additions & 8 deletions src/pages/home/ReportScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ const defaultProps = {
hasOutstandingIOU: false,
},
reportMetadata: {
isLoadingReportActions: true,
isLoadingMoreReportActions: false,
isLoadingInitialReportActions: true,
isLoadingOlderReportActions: false,
isLoadingNewerReportActions: false,
},
isComposerFullSize: false,
betas: [],
Expand Down Expand Up @@ -165,7 +166,7 @@ function ReportScreen({
const screenWrapperStyle = [styles.appContent, styles.flex1, {marginTop: viewportOffsetTop}];

// There are no reportActions at all to display and we are still in the process of loading the next set of actions.
const isLoadingInitialReportActions = _.isEmpty(reportActions) && reportMetadata.isLoadingReportActions;
const isLoadingInitialReportActions = _.isEmpty(reportActions) && reportMetadata.isLoadingInitialReportActions;

const isOptimisticDelete = lodashGet(report, 'statusNum') === CONST.REPORT.STATUS.CLOSED;

Expand Down Expand Up @@ -260,6 +261,13 @@ function ReportScreen({
const onSubmitComment = useCallback(
(text) => {
Report.addComment(getReportID(route), text);

// We need to scroll to the bottom of the list after the comment is added
const refID = setTimeout(() => {
flatListRef.current.scrollToOffset({animated: false, offset: 0});
}, 10);

return () => clearTimeout(refID);
},
[route],
);
Expand Down Expand Up @@ -372,7 +380,7 @@ function ReportScreen({

// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundPage = useMemo(
() => (!firstRenderRef.current && !report.reportID && !isOptimisticDelete && !reportMetadata.isLoadingReportActions && !isLoading && !userLeavingStatus) || shouldHideReport,
() => (!firstRenderRef.current && !report.reportID && !isOptimisticDelete && !reportMetadata.isLoadingInitialReportActions && !isLoading && !userLeavingStatus) || shouldHideReport,
[report, reportMetadata, isLoading, shouldHideReport, isOptimisticDelete, userLeavingStatus],
);

Expand Down Expand Up @@ -428,8 +436,9 @@ function ReportScreen({
<ReportActionsView
reportActions={reportActions}
report={report}
isLoadingReportActions={reportMetadata.isLoadingReportActions}
isLoadingMoreReportActions={reportMetadata.isLoadingMoreReportActions}
isLoadingInitialReportActions={reportMetadata.isLoadingInitialReportActions}
isLoadingNewerReportActions={reportMetadata.isLoadingNewerReportActions}
isLoadingOlderReportActions={reportMetadata.isLoadingOlderReportActions}
isComposerFullSize={isComposerFullSize}
policy={policy}
/>
Expand Down Expand Up @@ -488,8 +497,9 @@ export default compose(
reportMetadata: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${getReportID(route)}`,
initialValue: {
isLoadingReportActions: true,
isLoadingMoreReportActions: false,
isLoadingInitialReportActions: true,
isLoadingOlderReportActions: false,
isLoadingNewerReportActions: false,
},
},
isComposerFullSize: {
Expand Down
Loading

0 comments on commit 485a851

Please sign in to comment.