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: Request money - Five most recent chats aren't shown correctly #8549

Merged
merged 16 commits into from
Jun 24, 2022

Conversation

metehanozyurt
Copy link
Contributor

@metehanozyurt metehanozyurt commented Apr 7, 2022

Details

getNewChatOptions and getSearchOptions functions changed for passing sortByLastMessageTimestamp parameter. NewChatPage.js , OUParticipantsRequest.js , IOUParticipantsSplit.js files changed. "New chat" , "New group" , "Send money" , "Request money" , "Split bill" pages recents chat areas fixed.

Fixed Issues

$ #8220

Tests

  1. Open Expensify App.
  2. Click left side chat area randomly
  3. Click plus button and click "Request money". Fill number area then click "next"
  4. Request money page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  5. Click plus button and click "New chat".
  6. New chat page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  7. Click plus button and click "Send money". Fill number area then click "next"
  8. Send money page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  9. Click plus button and click "Split bill". Fill number area then click "next"
  10. Split bill page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  11. Click plus button and click "New group".
  12. New group page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  13. Click profile button, Click workspaces, click manage members, click invite button. verify persons not sorted by alphabetical order

example reproduce issue video before fix:

20220408_003702.mp4

test video:

20220408_003925.1.mp4
  • Verify that no errors appear in the JS console

PR Review Checklist

Contributor (PR Author) Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • iOS / native
    • Android / native
    • iOS / Safari
    • Android / Chrome
    • MacOS / Chrome
    • MacOS / Desktop
  • I verified there are no console errors (if there’s a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained “why” the code was doing something instead of only explaining “what” the code was doing.
    • I verified any copy / text shown in the product was added in all src/languages/* files
    • I verified any copy / text that was added to the app is correct English and approved by marketing by tagging the marketing team on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named “index.js”. All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • Any functional components have the displayName property
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose and it is
  • If a new CSS style is added I verified that:
    • A similar style doesn’t already exist
    • The style can’t be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.

PR Reviewer Checklist

  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I verified tests pass on all platforms & I tested again on:
    • iOS / native
    • Android / native
    • iOS / Safari
    • Android / Chrome
    • MacOS / Chrome
    • MacOS / Desktop
  • I verified there are no console errors (if there’s a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained “why” the code was doing something instead of only explaining “what” the code was doing.
    • I verified any copy / text shown in the product was added in all src/languages/* files
    • I verified any copy / text that was added to the app is correct English and approved by marketing by tagging the marketing team on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named “index.js”. All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • Any functional components have the displayName property
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose and it is broken down into smaller components in order to separate concerns and functions
  • If a new CSS style is added I verified that:
    • A similar style doesn’t already exist
    • The style can’t be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.

QA Steps

  1. Open Expensify App.
  2. Click left side chat area randomly
  3. Click plus button and click "Request money". Fill number area then click "next"
  4. Request money page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  5. Click plus button and click "New chat".
  6. New chat page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  7. Click plus button and click "Send money". Fill number area then click "next"
  8. Send money page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  9. Click plus button and click "Split bill". Fill number area then click "next"
  10. Split bill page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  11. Click plus button and click "New group".
  12. New group page Recents section should be ordered last message time ,Contacts section should be sorted by alphabetical order
  13. Click profile button, Click workspaces, click manage members, click invite button. verify persons not sorted by alphabetical order
  • Pages that changes recents order (sort by last message time):

    • New chat page (Recents section)
    • New group page (Recents section)
    • Send money page (Recents section)
    • Request money page (Recents section)
    • Split bill page (Recents section)
  • Pages that changes contacts order (sort by alphabetically order):

    • New chat page (Contacts section)
    • New group page (Contacts section)
    • Send money page (Contacts section)
    • Request money page (Contacts section)
    • Split bill page (Contacts section)
  • Verify that no errors appear in the JS console

Screenshots

Web

five-recent-Web-Screen-Recording-2022-06-12-at-13.04.21.mp4

Mobile Web

five-recent-ios-web-Screen-Recording-2022-06-12-at-13.27.27.mp4
five-recent-android-web-Screen-Recording-2022-06-12-at-13.37.41.mp4

Desktop

five-recent-desktop-Screen-Recording-2022-06-12-at-13.20.30.mp4

iOS

five-recent-ios-native-Screen-Recording-2022-06-12-at-13.24.52.mp4

Android

five-recent-android-native-Screen-Recording-2022-06-12-at-13.33.16.mp4

@metehanozyurt metehanozyurt requested review from marcaaron and a team as code owners April 7, 2022 22:22
@melvin-bot melvin-bot bot requested review from parasharrajat and roryabraham and removed request for a team April 7, 2022 22:22
@marcaaron
Copy link
Contributor

Just leaving a quick comment, but I think it would be easier to default sortByLastMessageTimestamp to true for getNewChatOptions() and then specifically pass false for the "workspace members" usages if we want those not to be sorted.

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have to pass the config options from the callable location. The whole purpose of creating getNewChatOptions, getSearchOptions functions was to encapsulate the configuration and use it as it is.

Secondly, it seems every function is setting that option to true. SO set it to true by default value and then should be enough. Then explicitly set it false where needed.

@metehanozyurt
Copy link
Contributor Author

metehanozyurt commented Apr 9, 2022

Thank you so much @parasharrajat , @marcaaron . I will immediately update commit and test file for changes 🙏.

@parasharrajat
Copy link
Member

Need to confirm the sort order for various pages. Thanks for the patience.

@parasharrajat
Copy link
Member

@metehanozyurt Could you please merge the main so that I can test it?

@metehanozyurt
Copy link
Contributor Author

Now I merged the conflict problem solved. So Sorry for falling behind the main.

@parasharrajat
Copy link
Member

I will review this in some time.

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me know when ready so that I can test.

@@ -65,6 +65,7 @@ class SearchPage extends Component {
props.personalDetails,
'',
props.betas,
true,
Copy link
Member

@parasharrajat parasharrajat Apr 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As pointed earlier, we should not expose the config option outside. Instead of doing this create another wrapper method like OptionsListUtils#getSearchOptions which sets this flag to true and then use that method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After new updates all places using functions started sending true by default (getSearchOptions & getNewChatOptions). Now we dont need wrapper method. Because If I write a new function, the old one will not be used this time. I'm making the changes now as you said. I'm removing the parameter pass support. Thank you.
After this i will update PR videos immediately.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, But I didn't understand. Could you please rephrase this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSearchOptions function only used on SearchPage. That's why I fixed the mistake I made by getting extra config. if i wrote another function the old function would be un used.

@@ -295,12 +295,44 @@ describe('OptionsListUtils', () => {
expect(results.recentReports[0].text).toBe('The Flash');
});

it('getNewChatOptions()', () => {
it('getSearchOptions() with message timeStampOrder', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you will do the above change, here new test will be created for each function including that new function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will update OptionsListUtilsTest test and removing condition timeStampOrder (true-false). Thank you.

@metehanozyurt
Copy link
Contributor Author

#8549 (comment)
I did not write a new wrapper method for the reason I mentioned here. I reverted the parameters it received.
I updated PR videos and checked results. I added lines to check the alphabet to the steps in the test file. I hope I succeeded this time.

There is one last thing I want to say @parasharrajat . When I examined the PR files, I realized that it is more beautiful now. Thank you very much for your guidance and help. Sorry for not being able to do it earlier. I hope I didn't seem too emotional, but I really thank you 🙏 .

@marcaaron marcaaron removed their request for review May 6, 2022 19:46
@stitesExpensify
Copy link
Contributor

Bumping this to keep the issue moving forward @parasharrajat @roryabraham 😄

@parasharrajat
Copy link
Member

I will review this today. Apologies for the delay. It just got out of sync.

createOption([personalDetail.login], personalDetails, reportMapForLogins[personalDetail.login], {
showChatPreviewLine,
forcePolicyNamePreview,
})
));

// PersonalDetails should be ordered Alphabetically by default acording to issue #8220
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the issue link to the comment that exactly asks for it.

@@ -641,7 +643,7 @@ function getSearchOptions(
showChatPreviewLine: true,
showReportsWithNoComments: true,
includePersonalDetails: true,
sortByLastMessageTimestamp: false,
sortByLastMessageTimestamp: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set the default value for this true in getOptions definition as I can see that is always true for all methods.


// Then several options will be returned and they will be each have the search string in their email or name
// even though the currently logged in user matches they should not show.
expect(results.personalDetails.length).toBe(1);
expect(results.recentReports.length).toBe(2);
// should be ordered by lastMessageTimestamp values
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// should be ordered by lastMessageTimestamp values
// Should be ordered by lastMessageTimestamp values.

@@ -283,9 +283,10 @@ describe('OptionsListUtils', () => {
// When we filter again but provide a searchValue that should match multiple times
results = OptionsListUtils.getSearchOptions(REPORTS, PERSONAL_DETAILS, 'fantastic');

// Then we get both values with the pinned value still on top
// lastMessageTimestamp value should be top
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// lastMessageTimestamp value should be top
// Value with latestd lastMessageTimestamp should be at the top.

// Then the result which has an existing report should also have the reportID attached
const personalDetailWithExistingReport = _.find(
results.personalDetails,
personalDetail => personalDetail.login === 'peterparker@expensify.com',
);
expect(personalDetailWithExistingReport.reportID).toBe(2);

// When we call only pass personal details
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// When we call only pass personal details
// When we only pass personal details

expect(results.recentReports.length).toBe(2);
expect(results.recentReports[0].text).toBe('Invisible Woman');
expect(results.recentReports[1].text).toBe('Spider-Man');
// Then all single participant reports that match will show up in the recentReports array, Recent used person should be top
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Then all single participant reports that match will show up in the recentReports array, Recent used person should be top
// Then all single participant reports that match will show up in the recentReports array, Recently used contact should be at the top

@parasharrajat
Copy link
Member

No, reports are not supposed to be part of this list. Only contacts.

@metehanozyurt
Copy link
Contributor Author

Ok , We want to list of contacts like LHN but only contacts. Recents on the top am i right? We need reports to sort contacts because it contains the lastMessageTimestamp information. If we do not give this, we cannot make a sort.

For Example New Chat Page;
This page give us 5 recent contacts.
recentReports represent 5 recent contacts.

const {
recentReports,
personalDetails,
userToInvite,
} = OptionsListUtils.getNewChatOptions(
props.reports,
props.personalDetails,
props.betas,
'',
[],
this.props.isGroupChat ? this.excludedGroupEmails : [],
);

If we don't give the reports and only empty array(line 70), it will only give us the contact list(alphabeticly ordered). The recentReports information will never come.

@parasharrajat
Copy link
Member

Ok, I would say just leave the contacts in A-Z order.

@roryabraham Do you think the A-Z order is fine for contacts on the Workspace member invite page?

@roryabraham
Copy link
Contributor

Do you think the A-Z order is fine for contacts on the Workspace member invite page?

Yes I think that would be fine in isolation – but for search, new chat, and request pages we'll want to sort results by most recent timestamp. Given that, I would say let's be consistent for the workspace member invite page.

@parasharrajat
Copy link
Member

parasharrajat commented May 26, 2022

Ok so @metehanozyurt we can just keep the workspace behavior the same as it was before. The only change would be that it will now be sorted using sortByLastMessageTimestamp.

@metehanozyurt
Copy link
Contributor Author

Thank you @parasharrajat . I updated the QA steps and created a checklist. I hope it was in the requested format and descriptive.

@parasharrajat
Copy link
Member

Thanks for doing that. Do you have an update for #8549 (comment)?

@metehanozyurt
Copy link
Contributor Author

I thought the current version covers this. I thought you wanted it like the contact list on other pages.
Workspace invite page : order by A-Z (like other pages contacts sections)

New chat , New group , Request money , Send money, Split bill pages :
Recent sections : sorted using sortByLastMessageTimestamp
Contacts sections : order by A-Z

Workspace invite page before no ordered just The last user added was the last person on list . I can make the workspace page no sorting at all. But now it's beautiful 🥰. Don't you think it's more beautiful like this on phones like a contact list?

My humble opinion is that it looks really beautiful now. But of course, you are the decision makers. If you want the old version, I can get it right back no problem @parasharrajat .

@parasharrajat
Copy link
Member

I am following this #8549 (comment). Please feel free to open this on Slack to get consensus.

@parasharrajat
Copy link
Member

Did you get a chance to ask this on slack?

@metehanozyurt
Copy link
Contributor Author

Thanks @parasharrajat for chance to do this. I asked a question, I hope I did it right. I was a little nervous as this was my first time doing something like this.
https://expensify.slack.com/archives/C01GTK53T8Q/p1654330306672439

@metehanozyurt
Copy link
Contributor Author

I'm a little sorry that my question didn't get much attention 😢.
Would you like me to leave the Workspace invite page as it is currently live version on web?

I can't sort by last message time information because it will only be a list of people messaged before.
A-Z order was also not considered appropriate.
The only option I have left is to write a new wrapper method and show it without A-Z sorting contacts.

@parasharrajat
Copy link
Member

I have bumped the thread.

@parasharrajat
Copy link
Member

There is consensus to leave the page as it is for Workspace Invite page. So you can do the following.

  1. Check staging app. Observe the order on the Workspace Invite page.
  2. Keep the same order with one exception that now contacts will be A-Z by default.

Any questions?

@metehanozyurt
Copy link
Contributor Author

Thank you for helping me on Slack @parasharrajat .
For this i need to one parameter for this so i add sortPersonalDetailsByAlphaAsc in getOptions params its default true . And write new wrapper method getMemberInviteOptions.
I couldn't use the sortByAlphaAsc parameter because it was used to sort reports. Reports are not sent on our page (Workspace Invite Page).

function getMemberInviteOptions(
    reports,
    personalDetails,
    betas = [],
    searchValue = '',
    selectedOptions = [],
    excludeLogins = [],
) {
    return getOptions(reports, personalDetails, 0, {
        betas,
        searchValue: searchValue.trim(),
        selectedOptions,
        excludeDefaultRooms: true,
        includePersonalDetails: true,
        excludeLogins,
        sortPersonalDetailsByAlphaAsc: false,
    });
}

I am currently updating the test document for this new method.
I'll update the videos once I'm done with my work. Thank you again about the Slack topic 🙏 .

@metehanozyurt
Copy link
Contributor Author

Hi @parasharrajat , I merged it with main branch. I updated test file , PR steps and videos. Thanks for your time 🙏 .

@@ -607,7 +613,6 @@ function getOptions(reports, personalDetails, activeReportID, {
return 0;
}], ['asc']);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB: unnecessary change.

* @returns {Object}
*/
function getMemberInviteOptions(
reports,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this argument? We can just remove it and refactor all the usages of this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @parasharrajat . I removed report parameter and updated all functions. Also removed selectedOptions.

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Good work @metehanozyurt. Appreciate your patience.

cc: @roryabraham

🎀 👀 🎀 C+ reviewed

@roryabraham roryabraham merged commit 960982d into Expensify:main Jun 24, 2022
@roryabraham
Copy link
Contributor

@Expensify/applauseleads can we be sure to update the regression test suite to account for the new sorting orders on these pages, and ensure that as part of the TC's we're verifying that these list pages are correctly sorted? Thanks 🙇

@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by @roryabraham in version: 1.1.79-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

OSBotify commented Jul 8, 2022

🚀 Deployed to production by @roryabraham in version: 1.1.79-17 🚀

platform result
🤖 android 🤖 failure ❌
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants