Rework /my_account/sign_up/index.html.jst to use custom validation style, reduce...
authorNick Downing <nick@ndcode.org>
Mon, 24 Jan 2022 06:15:32 +0000 (17:15 +1100)
committerNick Downing <nick@ndcode.org>
Mon, 24 Jan 2022 06:17:04 +0000 (17:17 +1100)
css/bootstrap/_card.scss
css/bootstrap/_variables.scss
my_account/sign_up/index.html.jst

index a974163..6affdf6 100644 (file)
@@ -81,7 +81,8 @@
 //
 
 .card-header {
-  padding: $card-spacer-y $card-spacer-x;
+  //padding: $card-spacer-y $card-spacer-x;
+  padding: $card-spacer-yt $card-spacer-x $card-spacer-yb $card-spacer-x; // Nick
   margin-bottom: 0; // Removes the default margin-bottom of <hN>
   color: $card-cap-color;
   background-color: $card-cap-bg;
@@ -93,7 +94,8 @@
 }
 
 .card-footer {
-  padding: $card-spacer-y $card-spacer-x;
+  //padding: $card-spacer-y $card-spacer-x;
+  padding: $card-spacer-yt $card-spacer-x $card-spacer-yb $card-spacer-x; // Nick
   color: $card-cap-color;
   background-color: $card-cap-bg;
   border-top: $card-border-width solid $card-border-color;
index a162bd0..a6ba2ed 100644 (file)
@@ -491,7 +491,7 @@ $input-focus-color:                     $input-color !default;
 $input-focus-width:                     $input-btn-focus-width !default;
 $input-focus-box-shadow:                $input-btn-focus-box-shadow !default;
 
-$input-placeholder-color:               $gray-600 !default;
+$input-placeholder-color:               $gray-500 !default; //$gray-600 !default;
 $input-plaintext-color:                 $body-color !default;
 
 $input-height-border:                   $input-border-width * 2 !default;
@@ -840,6 +840,14 @@ $jumbotron-bg:                      $gray-200 !default;
 
 // Cards
 
+// Nick
+// the card header/footer looks slightly wonky because the centring is
+// applied after room for ascender and descender, but don't want room
+// for descender, therefore set the bottom spacing to be slightly less;
+// try to allow enough room overall for a 32px icon to show and hide
+$card-spacer-yt:                    .8rem !default;
+$card-spacer-yb:                    .7rem !default;
+
 $card-spacer-y:                     .75rem !default;
 $card-spacer-x:                     1.25rem !default;
 $card-border-width:                 $border-width !default;
index 9ca59e2..339458e 100644 (file)
@@ -1,5 +1,3 @@
-let XDate = require('xdate')
-
 return async env => {
   let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
   let get_session = await _require('/_lib/get_session.jst')
@@ -9,27 +7,17 @@ return async env => {
 
   // preload draft details if any
   let transaction = await env.site.database.Transaction()
-  let draft_details
+  let sign_up_draft
   try {
     let root = await transaction.get({})
     let session = await get_session(env, root)
-
-    let sign_up_draft = await session.get('sign_up_draft')
-    draft_details =
-      sign_up_draft !== undefined &&
-        XDate.now() < await sign_up_draft.get_json('expires') ?
-        {
-          email: await sign_up_draft.get_json('email'),
-          given_names: await sign_up_draft.get_json('given_names'),
-          family_name: await sign_up_draft.get_json('family_name'),
-          contact_me: await sign_up_draft.get_json('contact_me')
-        } :
-        null
+    sign_up_draft = await session.get_json('sign_up_draft')
+    if (sign_up_draft === undefined || env.now >= sign_up_draft.expires)
+      sign_up_draft = {}
   }
   finally {
     transaction.rollback()
   }
-  console.log('draft_details', JSON.stringify(draft_details))
 
   await navbar(
     env,
@@ -43,148 +31,126 @@ return async env => {
 
       p {'Your given names are visible to other users if you comment on our blog. Your email and family name remain private. If your name is one word or does not fit given names/family name pattern, then please enter given names only.'}
 
-      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;") {
+      div.accordion#accordion(role="tablist" aria-multiselectable="true") {
+        div.card#card-1 {
+          div.card-header#card-1-heading(role="tab") {
+            span#card-1-tick(style="display: none;") {
               span.icon-color.pr-3 {_out.push(icon_tick)}
             }
-            span#step-1-cross(style="display: none;") {
+            span#card-1-cross(style="display: none;") {
               span.icon-color.pr-3 {_out.push(icon_cross)}
             }
-            //span#step-1-spinner(style="display: none;") {
+            //span#card-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") {
-              'Your details'
+            a.h5(data-toggle="collapse" data-parent="#accordion" href="#card-1-collapse" aria-expanded="true" aria-controls="card-1-collapse") {
+              'Create account'
             }
           }
-          div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
+          div#card-1-collapse.collapse.show(role="tabpanel" aria-labelledby="card-1-heading" data-parent="#accordion") {
             div.card-body {
-              div.row {
-                div.col-md-6 {
-                  div.form-group {
-                    label.form-label(for="given-names") {'Given names *'}
-                    input.form-control#given-names(type="text" value=draft_details ? draft_details.given_names : '' placeholder="Your given names" required="required" maxlength=256) {}
+              form#form {
+                div.row {
+                  div.col-md-6 {
+                    div.form-group {
+                      label.form-label(for="given-names") {'Given names *'}
+                      input.form-control#given-names(type="text" value=sign_up_draft.given_names || '' placeholder="Miley" required maxlength=256) {}
+                      div.invalid-feedback {'Please enter a name we can address you by.'}
+                    }
                   }
-                }
-                div.col-md-6 {
-                  div.form-group {
-                    label.form-label(for="family-name") {'Family name'}
-                    input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : '' placeholder="Your family name" maxlength=256) {}
+                  div.col-md-6 {
+                    div.form-group {
+                      label.form-label(for="family-name") {'Family name'}
+                      input.form-control#family-name(type="text" value=sign_up_draft.family_name || '' placeholder="Chapman" maxlength=256) {}
+                    }
                   }
                 }
-              }
-              div.row {
-                div.col-md-6 {
-                  div.form-group {
-                    label.form-label(for="email") {'Email *'}
-                    input.form-control#email(type="email" value=draft_details ? draft_details.email : '' placeholder="Your email address" required="required" maxlength=256) {}
+                div.row {
+                  div.col-md-6 {
+                    div.form-group {
+                      label.form-label(for="email") {'Email *'}
+                      input.form-control#email(type="email" value=sign_up_draft.email || '' placeholder="mileychapman@email.com" required maxlength=256) {}
+                      div.invalid-feedback {'Please enter an email address we can contact you on.'}
+                    }
                   }
-                }
-                div.col-md-6 {
-                  div.form-group {
-                    label.form-label(for="password") {'Password *'}
-                    input.form-control#password(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
+                  div.col-md-6 {
+                    div.form-group {
+                      label.form-label(for="password") {'Password *'}
+                      input.form-control#password(type="password" placeholder="Choose" required minlength=8 maxlength=256) {}
+                      div.invalid-feedback {'Please choose a secure password of at least 8 characters.'}
+                    }
                   }
                 }
-              }
-              div.row {
-                div.col-md-12 {
-                  div.custom-control.custom-checkbox {
-                    if (!draft_details || draft_details.contact_me)
-                      input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
-                    else
-                      input.custom-control-input#contact-me(type="checkbox") {}
-                    ' '
-                    label.custom-control-label(for="contact-me") {
-                      'Contact me by email with updates and special offers'
+                div.row {
+                  div.col-md-12 {
+                    div.custom-control.custom-checkbox {
+                      if (sign_up_draft === undefined || sign_up_draft.contact_me)
+                        input.custom-control-input#contact-me(type="checkbox" checked) {}
+                      else
+                        input.custom-control-input#contact-me(type="checkbox") {}
+                      ' '
+                      label.custom-control-label(for="contact-me") {
+                        'Contact me by email with updates and special offers'
+                      }
                     }
                   }
                 }
-              }
-              div.row.align-items-center.mb-3 {
-                div.'col-md-6' {
-                  div.form-group {
-                    label.form-label(for="verification-code") {'Verification code *'}
-                    input.form-control#verification-code(type="text" placeholder="Type the code shown to the right" required="required" minlength=6 maxlength=6) {}
+                div.row.align-items-center {
+                  div.col-md-6 {
+                    div.form-group {
+                      label.form-label(for="verification-code") {'Verification code *'}
+                      input.form-control#verification-code(type="text" placeholder="ad7jb3" required minlength=6 maxlength=6) {}
+                      div.invalid-feedback {'Please enter the 6 characters from the verification image to right or below. We need this to protect us from spam and bots.'}
+                    }
+                  }
+                  div.'col-md-6'.my-3 {
+                    img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
                   }
-                }
-                div.'col-md-4' {
-                  img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
-                }
-                div.'col-md-2'.my-auto.text-center {
-                  button.btn.btn-outline-secondary#'step-1-new-code'(type="button") {'New code'}
                 }
               }
 
-              button.btn.btn-success#step-1-continue(type="button") {'Continue'}
-
-              p.'mt-3'.mb-0 {'* These fields are required.'}
-            }
-          }
-        }
-        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") {
-              'Create account'
-            }
-          }
-          div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
-            div.card-body {
-              p#step-2-message {'Please enter your details first.'}
+              button.btn.btn-outline-secondary#'card-1-new-code'(type="button") {'New code'}
+              button.btn.btn-success.ml-3#card-1-create-account(type="button") {'Create account'}
 
-              button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
-              button.btn.btn-outline-secondary.ml-3#step-2-continue(type="button") {'Continue'}
+              p.'mt-3'.mb-0#card-1-message(style="display: none;") {}
             }
           }
         }
-        div.card#step-3 {
-          div.card-header#step-3-heading(role="tab") {
-            span#step-3-tick(style="display: none;") {
+        div.card#card-2 {
+          div.card-header#card-2-heading(role="tab") {
+            span#card-2-tick(style="display: none;") {
               span.icon-color.pr-3 {_out.push(icon_tick)}
             }
-            span#step-3-cross(style="display: none;") {
+            span#card-2-cross(style="display: none;") {
               span.icon-color.pr-3 {_out.push(icon_cross)}
             }
-            span#step-3-spinner(style="display: none;") {
+            span#card-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-3-collapse" aria-expanded="false" aria-controls="step-3-collapse") {
+            a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#card-2-collapse" aria-expanded="false" aria-controls="card-2-collapse") {
               'Send email verification link'
             }
           }
-          div#step-3-collapse.collapse(role="tabpanel" aria-labelledby="step-3-heading" data-parent="#accordion") {
+          div#card-2-collapse.collapse(role="tabpanel" aria-labelledby="card-2-heading" data-parent="#accordion") {
             div.card-body {
-              p#step-3-message {'Please create your account first.'}
+              button.btn.btn-outline-secondary#card-2-back(type="button") {'Back'}
+              button.btn.btn-outline-secondary.ml-3#card-2-resend-email(type="button") {'Re-send email'}
 
-              button.btn.btn-outline-secondary#step-3-back(type="button") {'Back'}
-              button.btn.btn-outline-secondary.ml-3#step-3-resend-email(type="button") {'Re-send email'}
+              p.'mt-3'.mb-0#card-2-message(style="display: none;") {}
             }
           }
         }
       }
+
+      p.mt-3 {'* These fields are required.'}
     },
     // scripts
     async _out => {
@@ -213,22 +179,15 @@ return async env => {
         }
 
         let details
-        let step_1 = async () => {
-          if (
-            !document.getElementById('given-names').reportValidity() ||
-              !document.getElementById('family-name').reportValidity() ||
-              !document.getElementById('email').reportValidity() ||
-              !document.getElementById('password').reportValidity() ||
-              !document.getElementById('verification-code').reportValidity()
-          ) {
-            $('#step-1-tick').hide()
-            $('#step-1-cross').show()
-            //$('#step-1-spinner').hide()
+        let card_1 = async () => {
+          if (!document.getElementById('form').checkValidity()) {
+            document.getElementById('form').classList.add('was-validated');
+            $('#card-1-tick').hide()
+            $('#card-1-cross').show()
+            //$('#card-1-spinner').hide()
             return false
           }
-          $('#step-1-tick').show()
-          $('#step-1-cross').hide()
-          //$('#step-1-spinner').hide()
+          document.getElementById('form').classList.remove('was-validated');
 
           details = {
             email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
@@ -237,14 +196,6 @@ return async env => {
             password: document.getElementById('password').value.slice(0, 256),
             contact_me: document.getElementById('contact-me').checked ? true : false
           }
-          return true
-        }
-
-        let step_2 = async () => {
-          $('#step-2-tick').hide()
-          $('#step-2-cross').hide()
-          $('#step-2-spinner').show()
-          document.getElementById('step-2').scrollIntoView()
 
           try {
             await api_call(
@@ -256,26 +207,33 @@ return async env => {
           catch (error) {
             let problem = Problem.from(error)
 
-            $('#step-2-tick').hide()
-            $('#step-2-cross').show()
-            $('#step-2-spinner').hide()
+            $('#card-1-tick').hide()
+            $('#card-1-cross').show()
+            $('#card-1-spinner').hide()
+
+            document.getElementById('card-1-message').textContent = problem.detail
+            //document.getElementById('card-1-message').classList.remove('text-success')
+            document.getElementById('card-1-message').classList.add('text-danger')
+            $('#card-1-message').show()
 
-            document.getElementById('step-2-message').textContent = problem.detail
-            $('#step-2-collapse').collapse('show')
+            $('#card-1-collapse').collapse('show')
             return false
           }
-          $('#step-2-tick').show()
-          $('#step-2-cross').hide()
-          $('#step-2-spinner').hide()
-          document.getElementById('step-2-message').textContent = `Your account with email "${details.email}" has been created.`
+          $('#card-1-tick').show()
+          $('#card-1-cross').hide()
+          $('#card-1-spinner').hide()
+          document.getElementById('card-1-message').textContent = `Your account with email "${details.email}" has been created.`
+          //document.getElementById('card-1-message').classList.add('text-success')
+          document.getElementById('card-1-message').classList.remove('text-danger')
+          $('#card-1-message').show()
           return true
         }
 
-        let step_3 = async () => {
-          $('#step-3-tick').hide()
-          $('#step-3-cross').hide()
-          $('#step-3-spinner').show()
-          document.getElementById('step-3').scrollIntoView()
+        let card_2 = async () => {
+          $('#card-2-tick').hide()
+          $('#card-2-cross').hide()
+          $('#card-2-spinner').show()
+          document.getElementById('card-2').scrollIntoView()
 
           try {
             await api_call(
@@ -286,19 +244,26 @@ return async env => {
           catch (error) {
             let problem = Problem.from(error)
 
-            $('#step-3-tick').hide()
-            $('#step-3-cross').show()
-            $('#step-3-spinner').hide()
+            $('#card-2-tick').hide()
+            $('#card-2-cross').show()
+            $('#card-2-spinner').hide()
 
-            document.getElementById('step-3-message').textContent = problem.detail
-            $('#step-3-collapse').collapse('show')
+            document.getElementById('card-2-message').textContent = problem.detail
+            //document.getElementById('card-2-message').classList.remove('text-success')
+            document.getElementById('card-2-message').classList.add('text-danger')
+            $('#card-2-message').show()
+
+            $('#card-2-collapse').collapse('show')
             return false
           }
-          $('#step-3-tick').show()
-          $('#step-3-cross').hide()
-          $('#step-3-spinner').hide()
+          $('#card-2-tick').show()
+          $('#card-2-cross').hide()
+          $('#card-2-spinner').hide()
 
-          document.getElementById('step-3-message').textContent = `Email verification link has been sent to "${details.email}". Please check your email for next steps.`
+          document.getElementById('card-2-message').textContent = `Email verification link has been sent to "${details.email}". Please check your email for next steps.`
+          //document.getElementById('card-2-message').classList.add('text-success')
+          document.getElementById('card-2-message').classList.remove('text-danger')
+          $('#card-2-message').show()
           return true
         }
 
@@ -327,7 +292,7 @@ return async env => {
             )
 
             let image_seq = 1
-            document.getElementById('step-1-new-code').addEventListener(
+            document.getElementById('card-1-new-code').addEventListener(
               'click',
               () => {
                 document.getElementById('verification-image').src = `/api/verification_image.png?seq=${image_seq}`
@@ -335,37 +300,24 @@ return async env => {
               }
             )
 
-            document.getElementById('step-1-continue').addEventListener(
-              'click',
-              async () => {
-                if (await step_1() && await step_2() && await step_3())
-                  $('#step-3-collapse').collapse('show')
-              }
-            )
-
-            document.getElementById('step-2-back').addEventListener(
-              'click',
-              () => {$('#step-1-collapse').collapse('show')}
-            )
-
-            document.getElementById('step-2-continue').addEventListener(
+            document.getElementById('card-1-create-account').addEventListener(
               'click',
               async () => {
-                if (await step_3())
-                  $('#step-3-collapse').collapse('show')
+                if (await card_1() && await card_2())
+                  $('#card-2-collapse').collapse('show')
               }
             )
 
-            document.getElementById('step-3-back').addEventListener(
+            document.getElementById('card-2-back').addEventListener(
               'click',
-              () => {$('#step-2-collapse').collapse('show')}
+              () => {$('#card-1-collapse').collapse('show')}
             )
 
-            document.getElementById('step-3-resend-email').addEventListener(
+            document.getElementById('card-2-resend-email').addEventListener(
               'click',
               async () => {
-                if (await step_3())
-                  $('#step-3-collapse').collapse('show')
+                if (await card_2())
+                  $('#card-2-collapse').collapse('show')
               }
             )
           }