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

[PhoneNumber Verification] Display only valid numbers in user search. #17578

Merged
merged 21 commits into from
Apr 27, 2023
Merged

[PhoneNumber Verification] Display only valid numbers in user search. #17578

merged 21 commits into from
Apr 27, 2023

Conversation

Prince-Mendiratta
Copy link
Contributor

@Prince-Mendiratta Prince-Mendiratta commented Apr 18, 2023

Details

With this PR, we are adding the ability to only show valid phone number users in the search page when a user enters a number.

Fixed Issues

$ #17461
PROPOSAL: #17461 (comment)

Tests

  1. Login to ND
  2. Click on the Search icon
  3. Type an invalid phone number e.g. +444
  4. Verify the Please enter a valid phone number... message is shown below the input
  5. Verify no results are returned
  6. Type a valid phone number e.g. +1 (500) 555-0007
  7. Verify no message is shown below the input
  8. Verify the phone number / user is found

Verify the test steps above for these pages:

  • Search Page

  • New group page

  • New chat page

  • Send Money

  • Request Money

  • Split Bill

  • Workspace - Invite Members

  • Verify that no errors appear in the JS console

Offline tests

Ensure that phone number validation works even when offline.

QA Steps

Same as above.

  • Verify that no errors appear in the JS console

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 the expected offline behavior in the Offline steps 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 tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android / native
    • Android / Chrome
    • iOS / native
    • iOS / Safari
    • MacOS / Chrome / Safari
    • 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 is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I verified the translation was requested/reviewed in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is approved by marketing by adding the Waiting for Copy label for a copy review 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
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • 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 */
    • 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 any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • 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 code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • 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.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR author checklist, including those that don't apply to this PR.

Screenshots/Videos

Web
web.mp4
Mobile Web - Chrome
android-mWeb.mp4
Mobile Web - Safari
iOS-mWeb.mp4
Desktop
desktop.mp4
iOS
iOS.mp4
Android
android.mp4

Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
@Prince-Mendiratta Prince-Mendiratta requested a review from a team as a code owner April 18, 2023 13:50
@melvin-bot melvin-bot bot requested review from s77rt and stitesExpensify and removed request for a team April 18, 2023 13:51
@MelvinBot
Copy link

@stitesExpensify @s77rt One of you needs to copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@Prince-Mendiratta
Copy link
Contributor Author

As raised in this comment here, we should replace all instances of Str.isValidPhone in the App. I have some concerns about this since I feel that in some places, it is more to verify that the input is indeed of the number format and perform operations based on that. Can I please receive some confirmation that we should go ahead with this before proceeding?

There are all the occurrences of the Str.isValidPhone in the App:

@puneetlath
Copy link
Contributor

I have some concerns about this since I feel that in some places, it is more to verify that the input is indeed of the number format and perform operations based on that.

I would think that we do want to replace all uses of isValidPhone, but I don't quite follow what this means? Mind giving an example?

@Prince-Mendiratta
Copy link
Contributor Author

@puneetlath for instance:

In the appendCountryCode function we have:

function appendCountryCode(phone) {
    return (Str.isValidPhone(phone) && !phone.includes('+'))
        ? `+${countryCodeByIP}${phone}`
        : phone;
}

here, if the input is 123, then the Str.isValidPhone(phone) will be true since the regex check will pass and the output of the function would be +1123. If we are to replace it with parseNumber from awesome-phonenumber, the check for 123 would be false, returning 123 only instead.

@Prince-Mendiratta
Copy link
Contributor Author

Prince-Mendiratta commented Apr 18, 2023

This is the regex for the isValidPhone - /^\+?[1-9]\d{1,14}$/. This would be true for any numerical input from 1-15 characters. For the parseNumber to return true, the whole number needs to be passed else the check will fail.

I believe that the function name isValidPhone refers to the format of the number and not if the number itself is a valid number or not. Maybe we can replace it with Str.isSMSLogin where required.

@s77rt
Copy link
Contributor

s77rt commented Apr 18, 2023

@Prince-Mendiratta

  1. Let's use possible instead of valid, just not to block new numbers due to outdated js lib
  2. Apply the suggested changes here [HOLD PR #17578] Feature Request: Search using Formatted phone numbers like (123) 456-7890 #17255 (comment)
  3. Replace every left Str.isValidPhone
  4. Clear a bit (remove unused regex after 2, etc.)
  5. Tag me again

@Prince-Mendiratta
Copy link
Contributor Author

@s77rt Any thoughts on this?

Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
@s77rt
Copy link
Contributor

s77rt commented Apr 18, 2023

@Prince-Mendiratta We can't keep using Str.isValidPhone because it creates inconsistency, if we validate input as a valid number at stage 1 (that uses Str.isValidPhone) then say the number is not correct at stage 2 (using the lib) we will create a confusion.

@Prince-Mendiratta
Copy link
Contributor Author

@s77rt I can notice a slight glitch when the last digit for a valid number is added. The header message changes to No results found before the new result shows up. Is this okay?

2023-04-19.00-12-03.mp4

@s77rt
Copy link
Contributor

s77rt commented Apr 18, 2023

@Prince-Mendiratta I noticed the same bug previously, it should be fixed with the suggested change here #17255 (comment) Or this didn't do it?

Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
@Prince-Mendiratta
Copy link
Contributor Author

@s77rt updated, please have a look!

I noticed the same bug previously, it should be fixed with the suggested change here #17255 (comment) Or this didn't do it?

Nope, it's still pretty noticeable. I think this might be because the header message is updated before we can show the user

@s77rt
Copy link
Contributor

s77rt commented Apr 18, 2023

@Prince-Mendiratta I'm still unable to reproduce the bug, can you please double check?

@Prince-Mendiratta
Copy link
Contributor Author

@s77rt Here's the video and reproduction steps:

  1. Open the search page.
  2. Enter a number +1534543234.
  3. Enter the last digit and notice how the header changes to 'No results found'. Then the results show up and the header goes away.

Realtime

2023-04-19.01-45-29.mp4

Slowed to 0.5x

2023-04-19-01-45-29_q3UUtRsb.mp4

@s77rt
Copy link
Contributor

s77rt commented Apr 18, 2023

Still can't reproduce, can you add a console.log to getHeaderMessage before the not found message, and confirm you get the message logged in the console.

@Prince-Mendiratta
Copy link
Contributor Author

@s77rt
image

@s77rt
Copy link
Contributor

s77rt commented Apr 18, 2023

@Prince-Mendiratta I really can't reproduce that. Sorry if I'm being repetitive but are you sure you are applying the changes exactly as they are in the PR? git checkout then git apply https://github.com/Expensify/App/pull/17578.diff

@Prince-Mendiratta
Copy link
Contributor Author

Prince-Mendiratta commented Apr 18, 2023

@s77rt Yeah, positive. Can you try adding this line after the linked permalink:
console.log(`Input: ${this.state.searchValue} | ${headerMessage}`);

@s77rt
Copy link
Contributor

s77rt commented Apr 18, 2023

Ah okay, I was trying on the New Chat page. I confirm the bug is reproducible on the Search page. Let's fix that

puneetlath
puneetlath previously approved these changes Apr 24, 2023
Copy link
Contributor

@puneetlath puneetlath left a comment

Choose a reason for hiding this comment

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

Looks good to me! You have some merge conflicts though.

Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
@Prince-Mendiratta Prince-Mendiratta dismissed stale reviews from puneetlath and s77rt via e818808 April 24, 2023 23:27
@Prince-Mendiratta
Copy link
Contributor Author

Conflicts resolved, should be good to merge @puneetlath!

Copy link
Contributor

@stitesExpensify stitesExpensify left a comment

Choose a reason for hiding this comment

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

Looking good, loving the clean up! Just a couple of questions

Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
puneetlath
puneetlath previously approved these changes Apr 27, 2023
@puneetlath
Copy link
Contributor

@Prince-Mendiratta sorry, but you've got some conflicts now.

@stitesExpensify let us know if you're good and we can get this merged today!

Signed-off-by: Prince Mendiratta <prince.mendi@gmail.com>
@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.

@s77rt
Copy link
Contributor

s77rt commented Apr 27, 2023

Hey @Prince-Mendiratta Sorry to bother you but the last commit of resolving conflicts undid the fix for the highlighted bug here #17578 (comment)
@puneetlath Should we follow this by another PR?

@Prince-Mendiratta
Copy link
Contributor Author

Ah, woops. I was focused on resolving conflicts and forgot to recheck the commit. I've got the changes ready, let me know when I can put up a follow up PR.

@puneetlath
Copy link
Contributor

Let's revert since we still have the ability. And we can add the fix to an updated PR.

@Prince-Mendiratta please go ahead and open a separate PR with these changes and the fix.

@Prince-Mendiratta
Copy link
Contributor Author

@puneetlath @s77rt Just to confirm, after adding the new changes, I'll have to revert the revert in order to add all the changes, right? I'm not able to see all the changes in any other case. The final commit graph would look like:
image

@puneetlath
Copy link
Contributor

That works

@Prince-Mendiratta
Copy link
Contributor Author

PR is up for review!

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by https://github.com/stitesExpensify in version: 1.3.8-0 🚀

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

@OSBotify
Copy link
Contributor

OSBotify commented May 2, 2023

🚀 Deployed to production by https://github.com/marcaaron in version: 1.3.8-8 🚀

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

@fedirjh
Copy link
Contributor

fedirjh commented Jul 21, 2023

This PR caused a regression in #20233, more context #20233 (comment) , When we have @expensify.sms in the search value, it is not recognized as a phone number.

@s77rt
Copy link
Contributor

s77rt commented Jul 21, 2023

@fedirjh Hmm is this the offending PR? I don't think we changed that behaviour, previously we weren't taking the sms domain in consideration either.

    const isPhoneNumber = CONST.REGEX.PHONE_WITH_SPECIAL_CHARS.test(searchInputValue);
    const searchValue = isPhoneNumber ? searchInputValue.replace(CONST.REGEX.NON_NUMERIC_WITH_PLUS, '') : searchInputValue;

@@ -676,25 +671,21 @@ function getOptions(reports, personalDetails, {
const noOptions = (recentReportOptions.length + personalDetailsOptions.length) === 0;
const noOptionsMatchExactly = !_.find(personalDetailsOptions.concat(recentReportOptions), option => option.login === searchValue.toLowerCase());

// If the phone number doesn't have an international code then let's prefix it with the
// current user's international code based on their IP address.
const login = LoginUtils.appendCountryCode(searchValue);
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm is this the offending PR?

@s77rt Reverting this PR fixes the issue. I believe this line is the root cause, with old code we were appending the country code after we validate the phone number. So if the country code is +1 and we search for valid number with @expensify.sms , for example 5005550006@expensify.sms the old code will return +15005550006@expensify.sms, however with this PR , specifically this line

const searchValue = parsedPhoneNumber.possible ? parsedPhoneNumber.number.e164 : searchInputValue;

parsedPhoneNumber will fail for @expensify.sms and will fallback to the searchInputValue which is 5005550006@expensify.sms.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah so the bug is searching for 5005550006@expensify.sms won't work? I think you are right this is the offending PR. We didn't really check for this case at all 5005550006@expensify.sms does not seem like a valid login.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah so the bug is searching for 5005550006@expensify.sms won't work?

The bug is that when you are logged in using a phone number +15005550006, when inviting a new user to your workspace , without appending the country code , the code will fail to exclude your login and given that 5005550006@expensify.sms is a valid email format, it will give you the possibility to invite that user , later when the backend verify that it will return an error . We fixed that by :

  1. Always removing phone number domain @expensify.sms before validating a phone.
  2. Excluding any email with @expensify.sms domain.

Copy link
Contributor

Choose a reason for hiding this comment

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

@fedirjh Yeah I got it, previously we used to append the country code to every input, but now we only do it for valid numbers. +5005550006@expensify.sms is not considered as a valid number so we end up using 5005550006@expensify.sms. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting case. I would also think that we don't need to support @expensify.sms in search, but I guess there's no downside that we do now. Thanks!

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.

7 participants