Skip to content

Commit

Permalink
feat: redesign password authentication flow (#2826)
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelpeixe authored Jan 12, 2024
1 parent e134422 commit c5190be
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 254 deletions.
187 changes: 89 additions & 98 deletions assets/reader-activation/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ window.newspackRAS.push( function ( readerActivation ) {
try {
const labels = JSON.parse( link.getAttribute( 'data-labels' ) );
link.querySelector( '.newspack-reader__account-link__label' ).textContent =
reader?.email ? labels.signedin : labels.signedout;
reader?.authenticated ? labels.signedin : labels.signedout;
} catch {}
} );
}
Expand Down Expand Up @@ -228,89 +228,90 @@ window.newspackRAS.push( function ( readerActivation ) {
const submitButtons = form.querySelectorAll( '[type="submit"]' );
const closeButton = container.querySelector( 'button[data-close]' );
const backButtons = container.querySelectorAll( '[data-back]' );
const resendCodeButton = container.querySelector( '[data-resend-code]' );
const sendCodeButtons = container.querySelectorAll( '[data-send-code]' );

backButtons.forEach( backButton => {
backButton.addEventListener( 'click', function ( ev ) {
ev.preventDefault();
setFormAction( 'link', true );
setFormAction( 'signin', true );
} );
} );

let otpTimerInterval;
let otpOriginalButtonText;
function handleOTPTimer() {
if ( otpTimerInterval ) {
clearInterval( otpTimerInterval );
}
if ( ! resendCodeButton ) {
if ( ! sendCodeButtons.length ) {
return;
}
otpOriginalButtonText = resendCodeButton.textContent;
const updateButton = () => {
sendCodeButtons.forEach( button => {
button.originalButtonText = button.textContent;
if ( button.otpTimerInterval ) {
clearInterval( button.otpTimerInterval );
}
const updateButton = () => {
const remaining = readerActivation.getOTPTimeRemaining();
if ( remaining ) {
button.textContent = `${ button.originalButtonText } (${ formatTime( remaining ) })`;
button.disabled = true;
} else {
button.textContent = button.originalButtonText;
button.disabled = false;
clearInterval( button.otpTimerInterval );
}
};
const remaining = readerActivation.getOTPTimeRemaining();
if ( remaining ) {
resendCodeButton.textContent = `${ otpOriginalButtonText } (${ formatTime(
remaining
) })`;
resendCodeButton.disabled = true;
} else {
resendCodeButton.textContent = otpOriginalButtonText;
resendCodeButton.disabled = false;
clearInterval( otpTimerInterval );
button.otpTimerInterval = setInterval( updateButton, 1000 );
updateButton();
}
};
const remaining = readerActivation.getOTPTimeRemaining();
if ( remaining ) {
otpTimerInterval = setInterval( updateButton, 1000 );
updateButton();
}
} );
}

if ( resendCodeButton ) {
if ( sendCodeButtons.length ) {
handleOTPTimer();
resendCodeButton.addEventListener( 'click', function ( ev ) {
messageContentElement.innerHTML = '';
ev.preventDefault();
form.startLoginFlow();
const body = new FormData();
body.set( 'reader-activation-auth-form', 1 );
body.set( 'npe', emailInput.value );
body.set( 'action', 'link' );
readerActivation
.getCaptchaToken()
.then( captchaToken => {
if ( ! captchaToken ) {
return;
}
body.set( 'captcha_token', captchaToken );
} )
.catch( e => {
console.log( { e } );
} )
.finally( () => {
fetch( form.getAttribute( 'action' ) || window.location.pathname, {
method: 'POST',
headers: {
Accept: 'application/json',
},
body,
sendCodeButtons.forEach( button => {
button.addEventListener( 'click', function ( ev ) {
messageContentElement.innerHTML = '';
ev.preventDefault();
form.startLoginFlow();
const body = new FormData();
body.set( 'reader-activation-auth-form', 1 );
body.set( 'npe', emailInput.value );
body.set( 'action', 'link' );
readerActivation
.getCaptchaToken()
.then( captchaToken => {
if ( ! captchaToken ) {
return;
}
body.set( 'captcha_token', captchaToken );
} )
.then( () => {
messageContentElement.innerHTML = newspack_reader_auth_labels.code_resent;
readerActivation.setOTPTimer();
} )
.catch( e => {
console.log( e );
.catch( e => {
console.log( { e } );
} )
.finally( () => {
fetch( form.getAttribute( 'action' ) || window.location.pathname, {
method: 'POST',
headers: {
Accept: 'application/json',
},
body,
} )
.finally( () => {
handleOTPTimer();
form.style.opacity = 1;
submitButtons.forEach( button => {
button.disabled = false;
.then( () => {
messageContentElement.innerHTML = newspack_reader_auth_labels.code_resent;
setFormAction( 'otp' );
readerActivation.setOTPTimer();
} )
.catch( e => {
console.log( e );
} )
.finally( () => {
handleOTPTimer();
form.style.opacity = 1;
submitButtons.forEach( submitButton => {
submitButton.disabled = false;
} );
} );
} );
} );
} );
} );
} );
}

Expand Down Expand Up @@ -344,6 +345,9 @@ window.newspackRAS.push( function ( readerActivation ) {
* Handle auth form action selection.
*/
function setFormAction( action, shouldFocus = false ) {
if ( ! [ 'register', 'signin', 'pwd', 'otp' ].includes( action ) ) {
action = 'signin';
}
if ( 'otp' === action ) {
if ( ! readerActivation.getOTPHash() ) {
return;
Expand All @@ -358,9 +362,6 @@ window.newspackRAS.push( function ( readerActivation ) {
firstInput.focus();
}
}
if ( [ 'link', 'pwd' ].includes( action ) ) {
readerActivation.setAuthStrategy( action );
}
actionInput.value = action;
container.removeAttribute( 'data-form-status' );
messageContentElement.innerHTML = '';
Expand Down Expand Up @@ -388,16 +389,10 @@ window.newspackRAS.push( function ( readerActivation ) {
}
}
}
setFormAction(
currentHash === 'register_modal' ? 'register' : readerActivation.getAuthStrategy() || 'link'
);
setFormAction( currentHash === 'register_modal' ? 'register' : 'signin' );
window.addEventListener( 'hashchange', () => {
if ( SIGN_IN_MODAL_HASHES.includes( currentHash ) ) {
setFormAction(
currentHash === 'register_modal'
? 'register'
: readerActivation.getAuthStrategy() || 'link'
);
setFormAction( currentHash === 'register_modal' ? 'register' : 'signin' );
}
} );
readerActivation.on( 'reader', () => {
Expand Down Expand Up @@ -438,12 +433,8 @@ window.newspackRAS.push( function ( readerActivation ) {
} else {
form.replaceWith( messageContentElement.parentNode );
}
container.setAttribute( 'data-form-status', status );
}
container.setAttribute( 'data-form-status', status );
form.style.opacity = 1;
submitButtons.forEach( button => {
button.disabled = false;
} );
};

/**
Expand Down Expand Up @@ -504,7 +495,7 @@ window.newspackRAS.push( function ( readerActivation ) {
} )
.catch( data => {
if ( data.expired ) {
setFormAction( 'link' );
setFormAction( 'signin' );
}
form.endLoginFlow( data.message, 400 );
} );
Expand All @@ -521,37 +512,37 @@ window.newspackRAS.push( function ( readerActivation ) {
res
.json()
.then( ( { message, data } ) => {
let status = res.status;
const status = res.status;
let redirect = body.get( 'redirect' );
if ( status === 200 ) {
readerActivation.setReaderEmail( body.get( 'npe' ) );
}
/** Redirect every registration to the account page for verification if not coming from a hash link */
if ( action === 'register' ) {
redirect = newspack_ras_config.account_url;
}
// Never redirect from hash links.
/** Never redirect from hash links. */
if ( currentHash ) {
redirect = '';
}
if ( status === 200 ) {
readerActivation.setReaderEmail( body.get( 'npe' ) );
}
const otpHash = readerActivation.getOTPHash();
if ( otpHash && [ 'register', 'link' ].includes( action ) ) {
if ( status === 200 ) {
// Set OTP rate-limit timer
if ( data.action ) {
setFormAction( data.action );
if ( data.action === 'otp' ) {
readerActivation.setOTPTimer();
handleOTPTimer();
setFormAction( 'otp' );
}
/** If action is link, suppress message and status so the OTP handles it. */
if ( status === 200 && action === 'link' ) {
status = null;
message = null;
}
} else {
form.endLoginFlow( message, status, data, redirect );
}
form.endLoginFlow( message, status, data, redirect );
} )
.catch( () => {
form.endLoginFlow();
} )
.finally( () => {
form.style.opacity = 1;
submitButtons.forEach( button => {
button.disabled = false;
} );
} );
} )
.catch( () => {
Expand Down
76 changes: 44 additions & 32 deletions assets/reader-activation/auth.scss
Original file line number Diff line number Diff line change
Expand Up @@ -153,22 +153,6 @@
}
}

button[type='button'] {
display: block;
background: transparent;
border: 1px solid wp-colors.$gray-200;
color: wp-colors.$gray-700;
margin-bottom: 0.8rem;
&:disabled {
background-color: wp-colors.$gray-100;
color: wp-colors.$gray-600;
}
&.back-button {
border: 0;
margin: 0;
}
}

.components-form {
&__field {
font-size: 1rem;
Expand All @@ -179,19 +163,6 @@
flex: 1 1 100%;
font-size: 1rem;
margin: 0;

button[type='submit'] {
background-color: var( --newspack-cta-color );
color: var( --newspack-cta-contrast-color );
transition: background-color 150ms ease-in-out;
margin-bottom: 0.8rem;

&:hover,
&:focus {
background-color: #111;
color: white;
}
}
}

&__help {
Expand Down Expand Up @@ -337,9 +308,50 @@
display: flex;
justify-content: space-between;
flex-wrap: wrap;
button {
display: block;

button,
.button,
a.button {
width: 100%;
display: block;
text-align: center;
text-decoration: none;
background: transparent;
border: 1px solid wp-colors.$gray-200;
color: wp-colors.$gray-700;
margin-bottom: 0.4rem;
&:disabled {
background-color: wp-colors.$gray-100;
color: wp-colors.$gray-600;
}
&.secondary {
color: wp-colors.$gray-700;
&:hover,
&:focus {
background-color: wp-colors.$gray-100;
color: wp-colors.$gray-700;
}
}
&.tertiary {
border: 0;
margin: 0;
&:hover,
&:focus {
background-color: transparent;
color: wp-colors.$gray-900;
}
}
&[type='submit'] {
background-color: var( --newspack-cta-color );
color: var( --newspack-cta-contrast-color );
transition: background-color 150ms ease-in-out;
border: 0;
&:hover,
&:focus {
background-color: #111;
color: white;
}
}
}
}

Expand Down Expand Up @@ -467,7 +479,7 @@
&__separator {
align-items: center;
display: flex;
margin-bottom: 0.8rem;
margin: 0.8rem 0;
div {
text-align: center;
&:nth-child( 2 ) {
Expand Down
Loading

0 comments on commit c5190be

Please sign in to comment.