Update /my_account/verify_email/index.html.jst to latest way, no accordion
authorNick Downing <nick@ndcode.org>
Wed, 26 Jan 2022 01:15:58 +0000 (12:15 +1100)
committerNick Downing <nick@ndcode.org>
Wed, 26 Jan 2022 02:56:03 +0000 (13:56 +1100)
_svg/fa_user-check.svg [new file with mode: 0644]
_svg/icon_cross.svg
_svg/icon_tick.svg
api/account/verify_email.json.jst [moved from api/account/sign_up/verify_email.json.jst with 100% similarity]
css/bootstrap/_variables.scss
my_account/sign_up/index.html.jst
my_account/verify_email/index.html.jst

diff --git a/_svg/fa_user-check.svg b/_svg/fa_user-check.svg
new file mode 100644 (file)
index 0000000..5a8f74b
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4zm323-128.4l-27.8-28.1c-4.6-4.7-12.1-4.7-16.8-.1l-104.8 104-45.5-45.8c-4.6-4.7-12.1-4.7-16.8-.1l-28.1 27.9c-4.7 4.6-4.7 12.1-.1 16.8l81.7 82.3c4.6 4.7 12.1 4.7 16.8.1l141.3-140.2c4.6-4.7 4.7-12.2.1-16.8z"/></svg>
\ No newline at end of file
index 6581cb9..3f6165e 100644 (file)
@@ -1,7 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <svg
-   width="32"
-   height="32"
    viewBox="0 0 32 32"
    version="1.1"
    id="svg6"
index 2395b8b..03ddcd3 100644 (file)
@@ -1,7 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <svg
-   width="32"
-   height="32"
    viewBox="0 0 32 32"
    version="1.1"
    id="svg6"
index 095c5bc..5ed78b6 100644 (file)
@@ -1120,10 +1120,10 @@ $carousel-transition:                transform $carousel-transition-duration eas
 
 $spinner-width:           32px !default; //2rem !default;
 $spinner-height:          $spinner-width !default;
-$spinner-vertical-align:  middle !default; //-8px !default; //-.125em !default;
+$spinner-vertical-align:  baseline !default; //-.125em !default;
 $spinner-border-width:    .25em !default;
 
-$spinner-width-sm:        1rem !default;
+$spinner-width-sm:        24px !default; //1rem !default;
 $spinner-height-sm:       $spinner-width-sm !default;
 $spinner-border-width-sm: .2em !default;
 
index 05c6ce9..42681e4 100644 (file)
@@ -187,7 +187,7 @@ return async env => {
         }
       }
 
-      p.mt-3 {'* These fields are required.'}
+      p.text-muted.mt-3 {'* These fields are required.'}
     },
     // scripts
     async _out => {
index e9b335a..23bc712 100644 (file)
@@ -1,24 +1,43 @@
 return async env => {
   let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
+  let fa_user_check = await env.site.get_min_svg('/_svg/fa_user-check.svg')
+  let get_placeholder = await _require('/_lib/get_placeholder.jst')
+  let get_session = await _require('/_lib/get_session.jst')
   let icon_cross = await env.site.get_min_svg('/_svg/icon_cross.svg')
   let icon_tick = await env.site.get_min_svg('/_svg/icon_tick.svg')
   let navbar = await _require('/_lib/navbar.jst')
 
-  // preload draft details if any
-  let details = {}
-  if (Object.prototype.hasOwnProperty.call(env.parsed_url.query, 'email'))
-    details.email = decodeURIComponent(env.parsed_url.query.email)
-  if (
-     Object.prototype.hasOwnProperty.call(
+  // preload placeholder
+  let transaction = await env.site.database.Transaction()
+  let placeholder
+  try {
+    let root = await transaction.get({})
+    let session = await get_session(env, root)
+    placeholder = await get_placeholder(env, session)
+    transaction.commit()
+  }
+  catch (error) {
+    transaction.rollback()
+    throw error
+  }
+
+  // preload URL details if any
+  let email =
+    Object.prototype.hasOwnProperty.call(
+      env.parsed_url.query,
+      'email'
+    ) ?
+      decodeURIComponent(env.parsed_url.query.email) :
+      ''
+  let link_code =
+    Object.prototype.hasOwnProperty.call(
       env.parsed_url.query,
       'link_code'
-    )
-  )
-    details.link_code =
-      decodeURIComponent(env.parsed_url.query.link_code)
-  console.log('details', JSON.stringify(details))
+    ) ?
+      decodeURIComponent(env.parsed_url.query.link_code) :
+      ''
 
-  await navbar(
+   await navbar(
     env,
     // head
     async _out => {},
@@ -28,152 +47,148 @@ return async env => {
 
       p {'You will need to verify your email address via an emailed link before you can sign in to your account.'}
 
-      div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
-        div.card#step-1 {
-          div.card-header#step-1-heading(role="tab") {
-            span#step-1-tick(style="display: none;") {
-              span.icon-color.pr-3 {_out.push(icon_tick)}
-            }
-            span#step-1-cross(style="display: none;") {
-              span.icon-color.pr-3 {_out.push(icon_cross)}
+      form#form {
+        div.row {
+          div.col-md-6 {
+            div.form-group {
+             label.form-label(for="email") {'Email *'}
+              input.form-control#email(type="email" value=email placeholder=placeholder.email required="required" maxlength=256) {}
+              div.invalid-feedback {'Please enter your account\'s email address.'}
             }
-            //span#step-1-spinner(style="display: none;") {
-            //  span.icon-color.pr-3 {
-            //    div.spinner-border(role="status") {
-            //      span.sr-only {'Loading...'}
-            //    }
-            //  }
-            //}
-            a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
-              'Link details'
+          }
+          div.col-md-6 {
+            div.form-group {
+              label.form-label(for="link-code") {'Link code *'}
+              input.form-control#link-code(type="text" value=link_code placeholder="00000000000000000000000000000000" required="required" minlength=32 maxlength=32) {}
+              div.invalid-feedback {'Please enter the 32-character code from the link we have emailed to you.'}
             }
           }
-          div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
-            div.card-body {
-              div.row {
-                div.col-md-6 {
-                  div.form-group {
-                   label.form-label(for="email") {'Email *'}
-                    input.form-control#email(type="email" value=details.email || '' placeholder="Account email address" required="required" maxlength=256) {}
-                  }
-                }
-                div.col-md-6 {
-                  div.form-group {
-                    label.form-label(for="link-code") {'Link code *'}
-                    input.form-control#link-code(type="text" value=details.link_code || '' placeholder="Type the code from the email link" required="required" minlength=32 maxlength=32) {}
-                  }
-                }
-              }
+        }
+      }
 
-              button.btn.btn-success#step-1-continue(type="button") {'Continue'}
-              p.'mt-3'.mb-0 {'* These fields are required.'}
+      if (email.length || details.length)
+        button.btn.btn-success#verify-email(type="button") {
+          div.icon24-outer.mr-2#icon {
+            div.icon24-inner {_out.push(fa_user_check)}
+          }
+          div.icon24-outer.mr-2#tick(hidden) {
+            div.icon24-inner {_out.push(icon_tick)}
+          }
+          div.icon24-outer.mr-2#cross(hidden) {
+            div.icon24-inner {_out.push(icon_cross)}
+          }
+          div.icon24-outer.mr-2#spinner(hidden) {
+            div.icon24-inner {
+              div.spinner-border.spinner-border-sm(role="status") {}
             }
           }
+          'Verify email'
         }
-        div.card#step-2 {
-          div.card-header#step-2-heading(role="tab") {
-            span#step-2-tick(style="display: none;") {
-              span.icon-color.pr-3 {_out.push(icon_tick)}
-            }
-            span#step-2-cross(style="display: none;") {
-              span.icon-color.pr-3 {_out.push(icon_cross)}
-            }
-            span#step-2-spinner(style="display: none;") {
-              span.icon-color.pr-3 {
-                div.spinner-border(role="status") {
-                  span.sr-only {'Loading...'}
-                }
-              }
-            }
-            a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
-              'Verify email'
-            }
+      else
+        button.btn.btn-success#verify-email(type="button" disabled) {
+          div.icon24-outer.mr-2#icon {
+            div.icon24-inner {_out.push(fa_user_check)}
           }
-          div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
-            div.card-body {
-              p#step-2-message {'Please enter link details first.'}
-
-              button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
-              button.btn.btn-outline-secondary.ml-2#step-2-sign-in(type="button") {'Sign in'}
+          div.icon24-outer.mr-2#tick(hidden) {
+            div.icon24-inner {_out.push(icon_tick)}
+          }
+          div.icon24-outer.mr-2#cross(hidden) {
+            div.icon24-inner {_out.push(icon_cross)}
+          }
+          div.icon24-outer.mr-2#spinner(hidden) {
+            div.icon24-inner {
+              div.spinner-border.spinner-border-sm(role="status") {}
             }
           }
+          'Verify email'
         }
-      }
+
+      p.'mt-3'.mb-0#message(hidden) {}
+
+      p.text-muted.mt-3 {'* These fields are required.'}
     },
     // scripts
     async _out => {
       //script(src="/js/utils.js") {}
 
       script {
-        let step_1 = async () => {
-          if (
-            !document.getElementById('email').reportValidity() ||
-              !document.getElementById('link-code').reportValidity()
-          ) {
-            $('#step-1-tick').hide()
-            $('#step-1-cross').show()
-            //$('#step-1-spinner').hide()
-            return false
-          }
-          $('#step-1-tick').show()
-          $('#step-1-cross').hide()
-          //$('#step-1-spinner').hide()
-          return true
-        }
-
-        let step_2 = async () => {
-          $('#step-2-tick').hide()
-          $('#step-2-cross').hide()
-          $('#step-2-spinner').show()
-          document.getElementById('step-1').scrollIntoView()
-
-          let email
-          try {
-            email = document.getElementById('email').value.slice(0, 256).toLowerCase()
-            await api_call(
-              '/api/account/sign_up/verify_email.json',
-              email,
-              document.getElementById('link-code').value.slice(0, 32).toLowerCase()
-            )
-          }
-          catch (error) {
-            let problem = Problem.from(error)
-
-            $('#step-2-tick').hide()
-            $('#step-2-cross').show()
-            $('#step-2-spinner').hide()
-
-            document.getElementById('step-2-message').textContent = problem.detail
-            $('#step-2-collapse').collapse('show')
-            return false
-          }
-          $('#step-2-tick').show()
-          $('#step-2-cross').hide()
-          $('#step-2-spinner').hide()
-
-          document.getElementById('step-2-message').textContent = `Your email "${email}" has been verified. You can now sign in.`
-          return true
-        }
-
         document.addEventListener(
           'DOMContentLoaded',
           () => {
-            document.getElementById('step-1-continue').addEventListener(
+            let id_cross = document.getElementById('cross')
+            let id_email = document.getElementById('email')
+            let id_form = document.getElementById('form')
+            let id_icon = document.getElementById('icon')
+            let id_link_code = document.getElementById('link-code')
+            let id_message = document.getElementById('message')
+            let id_spinner = document.getElementById('spinner')
+            let id_tick = document.getElementById('tick')
+            let id_verify_email = document.getElementById('verify-email')
+
+            let edited = () => {
+              id_verify_email.disabled =
+                id_email.value.length === 0 &&
+                  id_link_code.value.length === 0
+              id_icon.hidden = false
+              id_tick.hidden = true
+              id_cross.hidden = true
+              id_spinner.hidden = true
+              id_message.hidden = true
+            }
+
+            id_email.addEventListener('input', edited)
+            id_link_code.addEventListener('input', edited)
+
+            id_verify_email.addEventListener(
               'click',
               async () => {
-                if (await step_1() && await step_2())
-                  $('#step-2-collapse').collapse('show')
-              }
-            )
+                id_icon.hidden = false
+                id_tick.hidden = true
+                id_cross.hidden = true
+                id_spinner.hidden = true
+                // the below causes an ugly flicker, so just keep the message
+                //id_message.hidden = true
 
-            document.getElementById('step-2-back').addEventListener(
-              'click',
-              () => {$('#step-1-collapse').collapse('show')}
-            )
+                if (!id_form.checkValidity()) {
+                  id_form.classList.add('was-validated');
 
-            document.getElementById('step-2-sign-in').addEventListener(
-              'click',
-              () => {document.getElementById('sign-in').click()}
+                  id_icon.hidden = true
+                  id_cross.hidden = false
+                  return
+                }
+                id_form.classList.remove('was-validated');
+
+                let email = id_email.value.slice(0, 256).toLowerCase()
+                let link_code = id_link_code.value.slice(0, 32)
+
+                id_icon.hidden = true
+                id_spinner.hidden = false
+                try {
+                  await api_call(
+                    '/api/account/verify_email.json',
+                    email,
+                    link_code
+                  )
+                }
+                catch (error) {
+                  let problem = Problem.from(error)
+
+                  id_cross.hidden = false
+                  id_spinner.hidden = true
+
+                  id_message.textContent = problem.detail
+                  //id_message.classList.remove('text-success')
+                  id_message.classList.add('text-danger')
+                  id_message.hidden = false
+                  return
+                }
+                id_tick.hidden = false
+                id_spinner.hidden = true
+                id_message.textContent = `Your email "${email}" has been verified. You can now sign in.`
+                //id_message.classList.add('text-success')
+                id_message.classList.remove('text-danger')
+                id_message.hidden = false
+              }
             )
           }
         )