-
Notifications
You must be signed in to change notification settings - Fork 21
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
Support paste verification #1106
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I haven't looked at the .test.js part. This review only comments on the implementation first.
js/src/components/contact-information/phone-number-card/verification-code-control.js
Outdated
Show resolved
Hide resolved
js/src/components/contact-information/phone-number-card/verification-code-control.js
Outdated
Show resolved
Hide resolved
js/src/components/contact-information/phone-number-card/verification-code-control.js
Outdated
Show resolved
Hide resolved
const handlePaste = ( e ) => { | ||
const { idx, value } = getEventData( e ); | ||
|
||
onCodeChange( toCallbackData( nextDigits ) ); | ||
} | ||
// only allow n digits, from the current idx position until the end | ||
const newDigits = [ | ||
...value.replace( /\D/g, '' ).substr( 0, DIGIT_LENGTH - idx ), | ||
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓
We don't need to handle content other than plain text. Not sure why it needs to use onPaste
event? The same newDigits
value could be got in the original onInput
handler by
const handleInput = ( e ) => {
const { value, dataset } = e.target;
const newDigits = value
.replace( /\D/g, '' )
.substr( cursorRef.current, DIGIT_LENGTH - idx );
// ...omitted
};
I think this could simplify the processing of getting content from onPaste
, and even further simplify other changes by using the original handleInput
to handle a 1 to DIGIT_LENGTH
length array of digits.
FYI - If need to get more context from the previous relevant discussions, you can find them in these PRs: |
Agree! 👍 Fixed in e37f3b7 |
This is definitely working for me. 😕 Could you double-check? Note: At some point in the dev process, it wasn't working, that is why I added the statement |
Tried with |
First of all, thanks for catching this @eason9487! 🙏 My manual test was wrong cos my counter was off due request limit. Now I was able to reproduce and fix the error.
Bug causes: Testing deeper I can confirm the problem is related to the way On single-digit insertion, we don't have that problem since we move the focus to the next input box. Hence, the previous one is updated correctly after losing focus. Solution: I replaced now the Besides that, I refactored a bit the Let me know if it works now :) Tested:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There're two new critical issues after adding new commits.
js/src/components/contact-information/phone-number-card/verification-code-control.js
Outdated
Show resolved
Hide resolved
js/src/components/contact-information/phone-number-card/verification-code-control.js
Outdated
Show resolved
Hide resolved
No sorry, thanks to you for checking this! Better you than the users :) Thank you for being so thorough in the reviews!
Fixed here d20faae
Fixed here d20faae
Fixed here d20faae |
Restored! |
💅
Added toString() strategy. Other alternatives are... _.isEqual (lodash) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📜
Due to the internal state management of <InputControl>
, the implementation of this component has to use some workaround for the focus controlling of input cursor. But the fixing result after several rounds of code review makes the implementation start to become too complex. Even more, workarounds have to be used at more places because of other side effects caused by the added workarounds.
The key problem is when a <InputControl>
has the focus, updating the value
prop would not affect the actually displaying content on the <input>
, and even update via the value property of the real <input>
DOM node could temporarily show the wanted content, it will be still recovered back to the content of passing value
prop after any re-render occurs.
When we want to set the focus on an unfocused <InputControl>
, which is also updating its display content, this state conflict happened. To deal with this, it could be resolved by updating the value
prop and yielding the focus move to the next tick of re-render.
And this case will only happen in the first (when reset) and the last (when pasted) <InputControl>
. Moving the workaround into the maybeMoveFocus
function with a bit of magic could make the implementation simpler and clearer.
const maybeMoveFocus = ( targetIdx ) => {
const validIdx = Math.max( Math.min( targetIdx, DIGIT_LENGTH - 1 ), 0 );
const node = inputsRef.current[ validIdx ];
if ( targetIdx === validIdx ) {
node.focus();
} else {
setTimeout( () => node.focus() );
}
};
Then we could call maybeMoveFocus( -1 );
when resetting, and maybeMoveFocus( DIGIT_LENGTH );
when moving focus to the last. With this method, it will need to change most other implementations. I made the alternative with code comments here 8db0834...707e15b. Probably we could consider this solution.
? handlePaste( e ) | ||
: handleInput( e ); | ||
|
||
setFocus( nextFocusIdx ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚧
The focus
state may be out of sync with the actual focusing index of <input>
nodes, and further causes the input to get stuck due to all deps
have not been changed here:
Lines 198 to 200 in d20faae
useEffect( () => { | |
maybeMoveFocus( focus ); | |
}, [ digits, resetNeedle, focus ] ); |
Steps:
- Enter a number in the first
<input>
- Move back to the first
<input>
by the ← key or mouse - Enter the same number as step 1
- I expect it would move to the next input but it gets stuck
const digit = value.substr( cursorRef.current, 1 ).replace( /\D/, '' ); | ||
|
||
// If that char is not a digit, then clear the input to empty. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓
The meaning of this code comment is different from the if ( digit !== value )
condition and its processing below.
@@ -135,13 +185,19 @@ export default function VerificationCodeControl( { | |||
* So here we await the `digits` is reset back to `initDigits` by above useEffect and sync to internal value, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💅
The code comments are outdated after changing the position and implementation of the original useEffect
.
// edge case: blur when pasting on last item | ||
if ( | ||
newDigits.length === 1 && | ||
newDigits[ 0 ] !== digits[ idx ] && | ||
idx === DIGIT_LENGTH - 1 | ||
) { | ||
e.target.blur(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📜
I think we don't really need this. I will propose an alternative that simplifies overall implementations by the new submitting code review.
Changes proposed in this Pull Request:
Closes #1001 .
Added functionality in order to allow the user to paste the code inside the verification code control inputs.
Screenshots:
Screen.Recording.2021-11-23.at.10.33.53.mov
Changes
handlePaste
function to handle the input in the case is a paste eventDetailed test instructions:
Changelog entry