Skip to content

Updated Amount validation conditions to not allow indefinite zeroes at the start.#7104

Merged
Julesssss merged 21 commits into
Expensify:mainfrom
sig5:fix-issue#7068
Jan 17, 2022
Merged

Updated Amount validation conditions to not allow indefinite zeroes at the start.#7104
Julesssss merged 21 commits into
Expensify:mainfrom
sig5:fix-issue#7068

Conversation

@sig5

@sig5 sig5 commented Jan 10, 2022

Copy link
Copy Markdown
Contributor

Details

The IOU Amount page didn't impose limits on the length of the string if zeroes are appended to the string. Hence the string can be indefinitely long if zeroes are used at the start.

Fixed Issues

$ #7068

Tests

  1. Open IOU Amount Page(Send/Receive).
  2. Enter amounts starting with zeroes.
  3. Test edge cases such as 0's at end and fractional values.
  • Verify that no errors appear in the JS console

QA Steps

  1. Try entering a string of consecutive zeroes.
  2. Test if fractional values appear as expected.
  • Verify that no errors appear in the JS console

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Screenshots

Web

Screencast.from.10-01-22.11-39-07.PM.IST.mov

Mobile Web

WhatsApp.Video.2022-01-10.at.11.41.38.PM.mp4

Desktop

iOS

Android

WhatsApp.Video.2022-01-11.at.12.52.15.AM.mp4

@sig5 sig5 requested a review from a team as a code owner January 10, 2022 18:18
@MelvinBot MelvinBot requested review from Julesssss and parasharrajat and removed request for a team January 10, 2022 18:18
@github-actions

github-actions Bot commented Jan 10, 2022

Copy link
Copy Markdown
Contributor

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@sig5

sig5 commented Jan 10, 2022

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

@parasharrajat

Copy link
Copy Markdown
Member

@sig5 Please add videos for the rest of the platforms.

@sig5

sig5 commented Jan 10, 2022

Copy link
Copy Markdown
Contributor Author

@parasharrajat I don't have access to a Macbook at the moment. But since this is just a regex change, this should work just fine. Can we do without the Mac/iOS videos?

@parasharrajat

Copy link
Copy Markdown
Member

That's fine.

@sig5

sig5 commented Jan 10, 2022

Copy link
Copy Markdown
Contributor Author

@parasharrajat Thanks :D ! Added for Android.

@parasharrajat parasharrajat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM.. Found an issue below.

@parasharrajat parasharrajat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Found an issue
Enter this value => 2000222

Now place the cursor after 2 and try to delete the preceding 2. We can't delete it.

@sig5

sig5 commented Jan 10, 2022

Copy link
Copy Markdown
Contributor Author

Ah, I missed that! As a user, he/she might want to change 5001 to 1001, So we should allow trailing zeroes at the beginning.
Now what we can do is:
I can revert the regex change and modify the validation condition.
The issue comes due to the fact that the last length checking condition parses the string as a number and compares the length.

validateAmount(amount) {
const decimalNumberRegex = new RegExp(/^\d+(,\d+)*(\.\d{0,2})?$/, 'i');
return amount === '' || (decimalNumberRegex.test(amount) && (parseFloat((amount * 100).toFixed(2)).toString().length <= CONST.IOU.AMOUNT_MAX_LENGTH));
}

We can instead parse the string directly after removing the Commas.
this.stripCommaFromAmount(amount).length <= CONST.IOU.AMOUNT_MAX_LENGTH;

And this should take care of all the values.

cc: @parasharrajat

@parasharrajat

Copy link
Copy Markdown
Member

Sound like a plan...

@sig5

sig5 commented Jan 10, 2022

Copy link
Copy Markdown
Contributor Author

I have modified the conditions to work with all strings. I have also modified the value of Constant AMOUNT_MAX_LENGTH because only the length of part before decimal matters, and the value after the decimal is limited to two places.

@sig5 sig5 requested a review from parasharrajat January 11, 2022 07:35
Comment thread src/pages/iou/steps/IOUAmountPage.js Outdated
Comment on lines +143 to +144
const lengthBeforeDecimal = this.stripCommaFromAmount(amount.split('.')[0]).length;
return amount === '' || (decimalNumberRegex.test(amount) && decimalNumberRegex.test(amount) && lengthBeforeDecimal <= (CONST.IOU.AMOUNT_MAX_LENGTH);

@parasharrajat parasharrajat Jan 11, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do need to check the decimal part only? It seems to be that we just need to strip , and . from the number and check the length.

@sig5 sig5 Jan 11, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because the regex enforces the number of values after the decimal to <= 2. If the condition is imposed on the whole string instead, the user can have 500000 and 50000.0 in his valid range but not 50000.24 if IOU.AMOUNT_MAX_LENGTH =6. Applying check on the only part before decimal will ensure a uniform range for the user.
In essence: The sufficient condition to ensure the range of values stays under the max limit is to ensure the length of the decimal part.

Also commas were handled because they were expected to be handled in the existing code. The appropriate use case must be : We might be inserting commas if we are copy-pasting the amount!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, commas are added. Missed that upper line. On Backend, we check the whole number via converting the floats to integer (amount * 100) is used.
If we try the logic from the previous code.

  1. 5000.24 => 500024
  2. 5000.0 => 500000

I will try to stick to the old code. and we can just prevent zeros.

Let me know if I am missing something.

@sig5 sig5 Jan 11, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The logic that was previously provided works well for a processed string (as we get in backend ) since we can be happy without caring about zeroes in the beginning. In this case, we will need to add an additional condition that essentially checks if (length of stripped portion as a parsedFloat + length of trailing zeroes ) doesn't exceed the limit.

Previous Code:
00500.23 => disregards the initial two zeroes, applies the older condition, and checks from the amount string if the number of zeroes in the beginning, invalidates the amount string.

Newer Logic
00500.23 => takes care of the length of the string directly. The two conditions: (1) fractional part upto 2 decimal places[ Regex takes care] (2) Length of string before decimal should be bounded by Amount_Length, are handled appropriately this way.

In my humble opinion, this condition will ensure a lesser overhead, cleaner, and more generally applicable too! Do let me know your thoughts on it :D .

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

disregards the initial two zeroes, applies the older condition, and checks from the amount string if the number of zeroes in the beginning, invalidates the amount string.

Hmm. Still, I am not sure of what you explained above but I got the idea.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since we essentially cast strings as integers, we lose the zeroes in the beginning of the number that causes the referenced issue ( Since parseFloat("00000005")=5 ).
I am suggesting that if we directly use the string for validation, we won't be losing the zeroes in the beginning.

Comment thread src/pages/iou/steps/IOUAmountPage.js Outdated
Comment thread src/CONST.js Outdated
REQUEST: 'request',
},
AMOUNT_MAX_LENGTH: 10,
AMOUNT_MAX_LENGTH: 7,

@parasharrajat parasharrajat Jan 11, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
AMOUNT_MAX_LENGTH: 7,
AMOUNT_WHOLE_MAX_LENGTH: 7,

Can you think of a better name to denote the part correctly? I can't think any..

@sig5 sig5 Jan 11, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We can probably do something like AMOUNT_INTEGER_PART_MAX_LEN

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm, did I miss the reasoning behind this change? We want to support large IOU amounts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you revert the value to 10 please

sig5 and others added 3 commits January 11, 2022 14:22
Co-authored-by: Rajat Parashar <parasharrajat@users.noreply.github.com>
parasharrajat
parasharrajat previously approved these changes Jan 11, 2022

@parasharrajat parasharrajat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM.

cc: @Julesssss

🎀 👀 🎀 C+ reviewed

@sig5 sig5 changed the title Updated regex to not allow more than one trailing zero at start. Updated Amount validation conditions to not allow more than one trailing zero at start. Jan 11, 2022
@sig5 sig5 changed the title Updated Amount validation conditions to not allow more than one trailing zero at start. Updated Amount validation conditions to not allow indefinite zeroes at the start. Jan 11, 2022
@Julesssss

Copy link
Copy Markdown
Contributor

Hi @sig5. please merge main to resolve the failing test.

@sig5

sig5 commented Jan 11, 2022

Copy link
Copy Markdown
Contributor Author

Done. Thanks!

@Julesssss Julesssss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yep, that has fixed the lag on my size. Thanks.

It looks like there's a trailing space lint failure to fix, but other than that the PR looks good.

@parasharrajat

Copy link
Copy Markdown
Member

Seems, PR is changed completely. I will do the review shortly...

@parasharrajat parasharrajat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good work. Loved the math.

Comment thread src/pages/iou/steps/IOUAmountPage.js Outdated
Comment thread src/pages/iou/steps/IOUAmountPage.js Outdated
* @returns {Number}
*/
amountLength(amount) {
const trailingZeroes = amount.match(/^0+/);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be leadingZeroes ? if so, please replace all the trailing to leading.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah my bad!

Comment thread src/pages/iou/steps/IOUAmountPage.js Outdated
Comment on lines +148 to +152
We return sum of trailing zeroes length and absAmount length( which has value of the all digits after the decimal).
In case of zeroes, we add the trailing zeroes length to 2, which
represent places reserved for digits after decimal.
*/
return trailingZeroesLength + (absAmount === '0' ? 2 : absAmount.length);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
We return sum of trailing zeroes length and absAmount length( which has value of the all digits after the decimal).
In case of zeroes, we add the trailing zeroes length to 2, which
represent places reserved for digits after decimal.
*/
return trailingZeroesLength + (absAmount === '0' ? 2 : absAmount.length);
Return the sum of leading zeroes length and absolute amount length(including fraction digits).
When the absolute amount is 0, add 2 to the leading zeroes length to represent fraction digits.
*/
return trailingZeroesLength + absAmount === '0' ? 2 : absAmount.length;

@sig5 sig5 Jan 14, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I addressed the comments, but am doing away with parentheses change since === and ?: has lower precedence than +, it will break the code to put w/o it both at beginning and end.

Comment thread src/pages/iou/steps/IOUAmountPage.js Outdated
Comment thread src/pages/iou/steps/IOUAmountPage.js Outdated
@sig5

sig5 commented Jan 14, 2022

Copy link
Copy Markdown
Contributor Author

Thanks, @parasharrajat :D! I addressed the suggestions.

@parasharrajat parasharrajat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@sig5 Could you please do a final checkout on performance? just to make sure lodashGet is not slow... 😄

@sig5

sig5 commented Jan 15, 2022

Copy link
Copy Markdown
Contributor Author

Hey @parasharrajat , the runtimes of both the methods seem pretty much equal on my system!

@parasharrajat

Copy link
Copy Markdown
Member

https://measurethat.net/Benchmarks/Show/16725/0/lodashget-vs-property-df

Native code is 1.5 times faster than lodashGet. But I am fine as far as it does not affect the UX. I leave this to @Julesssss to check. For me, both are the same and I don't see a recognizable delay.

@parasharrajat parasharrajat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM.

cc: @Julesssss

@Julesssss

Copy link
Copy Markdown
Contributor

Hi @sig5, with the latest changes I'm once again able to add multiple zeros prior to the decimal place.

Screenshot 2022-01-17 at 14 42 36

@Julesssss Julesssss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Requesting further changes.

@sig5

sig5 commented Jan 17, 2022

Copy link
Copy Markdown
Contributor Author

Hi @Julesssss this is expected since we decided to only limit the number of zeroes rather than limiting the zeroes to one since it will pose issues while editing the number. (Eg: 50001->00001-> 10001).
The initial issue was the addition of unlimited zeroes in the number which has been resolved, So you cannot add more zeroes indefinitely but up to 8 0's are allowed as per the constant length criterion.
#7104 (review)

Ah, I missed that! As a user, he/she might want to change 5001 to 1001, So we should allow trailing zeroes at the beginning.

@Julesssss

Copy link
Copy Markdown
Contributor

Ah, that makes sense. Thanks for pointing out the comment.

@Julesssss Julesssss merged commit eaa09e7 into Expensify:main Jan 17, 2022
@OSBotify

Copy link
Copy Markdown
Contributor

@sig5, Great job getting your first Expensify/App pull request over the finish line! 🎉

I know there's a lot of information in our contributing guidelines, so here are some points to take note of 📝:

  1. Now that your first PR has been merged, you can be hired for another issue. Once you've completed a few issues, you may be eligible to work on more than one job at a time.
  2. Once your PR is deployed to our staging servers, it will undergo quality assurance (QA) testing. If we find that it doesn't work as expected or causes a regression, you'll be responsible for fixing it. Typically, we would revert this PR and give you another chance to create a similar PR without causing a regression.
  3. Once your PR is deployed to production, we start a 7-day timer ⏰. After it has been on production for 7 days without causing any regressions, then we pay out the Upwork job. 💰

So it might take a while before you're paid for your work, but we typically post multiple new jobs every day, so there's plenty of opportunity. I hope you've had a positive experience contributing to this repo! 😊

@OSBotify

Copy link
Copy Markdown
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
Copy Markdown
Contributor

🚀 Deployed to staging by @Julesssss in version: 1.1.30-4 🚀

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

@mvtglobally

Copy link
Copy Markdown

@marcaaron @chiragsalian @mallenexpensify When we have a single zero upfront, it is not being stripped. Can you please confirm its expected?

@sig5

sig5 commented Jan 20, 2022

Copy link
Copy Markdown
Contributor Author

Hi @mvtglobally I feel like I should mention here that this was discussed here:#7104 (review),
We concluded that, in case the user just missed adding a number before the zeroes, he might want to go back and edit it with the zeroes .

Example:

  • User wants to type 60001
  • User types 50001 by mistake
  • User clears the 5, and 0001 gets stripped to 1
  • So it can pose issues while editing the number.

@chiragsalian

Copy link
Copy Markdown
Contributor

Hi @mvtglobally, yes i believe this is fine. From my understanding the code here does not allow indefinite 0's. i.e., you can't enter more than 8 0's to destroy the UI. You can enter 00012345 and its totally fine. Its just that you cannot enter like 30 0's to break the UI (which currently happens on production). Can you retest and let us know if its a pass or if you have any more questions?

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to production by @chiragsalian in version: 1.1.31-1 🚀

platform result
🤖 android 🤖 success ✅
🖥 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