Update /contact/index.html.jst to latest way, no accordion, placeholder company
[ndcode_site.git] / contact / index.html.jst
index fd46d2f..5691020 100644 (file)
@@ -1,7 +1,7 @@
-let XDate = require('xdate')
-
 return async env => {
   let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
+  let fa_envelope = await env.site.get_min_svg('/_svg/fa_envelope.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')
@@ -9,29 +9,23 @@ return async env => {
 
   // preload draft details if any
   let transaction = await env.site.database.Transaction()
-  let draft_details
+  let placeholder
+  let contact_draft
   try {
     let root = await transaction.get({})
     let session = await get_session(env, root)
 
-    let contact_draft = await session.get('contact_draft')
-    draft_details =
-      contact_draft !== undefined &&
-        XDate.now() < await contact_draft.get_json('expires') ?
-        {
-          email: await contact_draft.get_json('email'),
-          given_names: await contact_draft.get_json('given_names'),
-          family_name: await contact_draft.get_json('family_name'),
-          company: await contact_draft.get_json('company'),
-          email: await contact_draft.get_json('email'),
-          message: await contact_draft.get_json('message')
-        } :
-        null
+    placeholder = await get_placeholder(env, session)
+
+    contact_draft = await session.get_json('contact_draft')
+    if (contact_draft === undefined || env.now >= contact_draft.expires)
+      contact_draft = null
+    transaction.commit()
   }
-  finally {
+  catch (error) {
     transaction.rollback()
+    throw error
   }
-  console.log('draft_details', JSON.stringify(draft_details))
 
   await navbar(
     env,
@@ -43,231 +37,215 @@ return async env => {
 
       p {'Do you require more information, or assistance with integrating the projects on this site? We’d love to hear from you.'}
 
-      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)}
-            }
-            //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") {
-              'Enquiry details'
+      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=contact_draft ? contact_draft.given_names : '' placeholder=placeholder.given_names required maxlength=256) {}
+              div.invalid-feedback {'Please enter a name we can address you by.'}
             }
           }
-          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="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) {}
-                  }
-                }
-                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.row {
-                div.col-md-6 {
-                  div.form-group {
-                   label.form-label(for="company") {'Company'}
-                    input.form-control#company(type="company" value=draft_details ? draft_details.company : '' placeholder="Your company" maxlength=256) {}
-                  }
-                }
-                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-12 {
-                  div.form-group {
-                    label.form-label(for="message") {'Message *'}
-                    textarea.form-control#message(placeholder="Your message" required="required" rows=6 maxlength=65536) {
-                      if (draft_details)
-                        `${draft_details.message}`
-                    }
-                  }
-                }
-              }
-
-              button.btn.btn-success#step-1-continue(type="button") {'Continue'}
-              p.'mt-3'.mb-0 {'* These fields are required.'}
+          div.col-md-6 {
+            div.form-group {
+              label.form-label(for="family-name") {'Family name'}
+              input.form-control#family-name(type="text" value=contact_draft ? contact_draft.family_name : '' placeholder=placeholder.family_name maxlength=256) {}
             }
           }
         }
-        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)}
+        div.row {
+          div.col-md-6 {
+            div.form-group {
+             label.form-label(for="company") {'Company'}
+              input.form-control#company(type="company" value=contact_draft ? contact_draft.company : '' placeholder=placeholder.company maxlength=256) {}
             }
-            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") {
-              'Send enquiry'
+          }
+          div.col-md-6 {
+            div.form-group {
+             label.form-label(for="email") {'Email *'}
+              input.form-control#email(type="email" value=contact_draft ? contact_draft.email : '' placeholder=placeholder.email required maxlength=256) {}
+              div.invalid-feedback {'Please enter an email address we can contact you on.'}
             }
           }
-          div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
-            div.card-body {
-              p#step-2-message {'Please enter enquiry details first.'}
-
-              button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
-              button.btn.btn-outline-secondary.ml-3#step-2-resend-enquiry(type="button") {'Re-send enquiry'}
+        }
+        div.row {
+          div.col-md-12 {
+            div.form-group {
+              label.form-label(for="message1") {'Message *'}
+              textarea.form-control#message1(placeholder="I would like to..." required rows=6 maxlength=65536) {
+                if (contact_draft)
+                  `${contact_draft.message}`
+              }
+              div.invalid-feedback {'Please let us know your application or question.'}
             }
           }
         }
       }
-    },
-    // scripts
-    async _out => {
-      //script(src="/js/utils.js") {}
 
-      script {
-        let draft_timeout_running = false
-        let draft_timeout_handler = async () => {
-          draft_timeout_running = false
-          await api_call(
-            '/api/contact/set_draft.json',
-            {
-              given_names: document.getElementById('given-names').value.slice(0, 256),
-              family_name: document.getElementById('family-name').value.slice(0, 256),
-              company: document.getElementById('company').value.slice(0, 256),
-              email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
-              message: document.getElementById('message').value.slice(0, 65536)
+      if (contact_draft !== null)
+        button.btn.btn-success#send-enquiry(type="button") {
+          div.icon24-outer.mr-2#icon {
+            div.icon24-inner {_out.push(fa_envelope)}
+          }
+          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") {}
             }
-          )
-          //console.log('draft', await api_call('/api/contact/get_draft.json'))
-        }
-        let draft_change_handler = () => {
-          if (!draft_timeout_running) {
-            draft_timeout_running = true
-            setTimeout(draft_timeout_handler, 5000)
           }
+          'Send enquiry'
         }
-
-        let details
-        let step_1 = async () => {
-          if (
-            !document.getElementById('given-names').reportValidity() ||
-              !document.getElementById('family-name').reportValidity() ||
-              !document.getElementById('company').reportValidity() ||
-              !document.getElementById('email').reportValidity() ||
-              !document.getElementById('message').reportValidity()
-          ) {
-            $('#step-1-tick').hide()
-            $('#step-1-cross').show()
-            //$('#step-1-spinner').hide()
-            return false
+      else
+        button.btn.btn-success#send-enquiry(type="button" disabled) {
+          div.icon24-outer.mr-2#icon {
+            div.icon24-inner {_out.push(fa_envelope)}
           }
-          $('#step-1-tick').show()
-          $('#step-1-cross').hide()
-          //$('#step-1-spinner').hide()
-
-          details = {
-            given_names: document.getElementById('given-names').value.slice(0, 256),
-            family_name: document.getElementById('family-name').value.slice(0, 256),
-            company: document.getElementById('company').value.slice(0, 256),
-            email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
-            message: document.getElementById('message').value.slice(0, 65536)
+          div.icon24-outer.mr-2#tick(hidden) {
+            div.icon24-inner {_out.push(icon_tick)}
           }
-          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(
-              '/api/contact/send_enquiry.json',
-              details
-            )
+          div.icon24-outer.mr-2#cross(hidden) {
+            div.icon24-inner {_out.push(icon_cross)}
           }
-          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
+          div.icon24-outer.mr-2#spinner(hidden) {
+            div.icon24-inner {
+              div.spinner-border.spinner-border-sm(role="status") {}
+            }
           }
-          $('#step-2-tick').show()
-          $('#step-2-cross').hide()
-          $('#step-2-spinner').hide()
-
-          document.getElementById('step-2-message').textContent = 'We have received your enquiry. We will be in touch as soon as possible.'
-          return true
+          'Send enquiry'
         }
 
+      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 {
         document.addEventListener(
           'DOMContentLoaded',
           () => {
-            document.getElementById('given-names').addEventListener(
-              'change',
-              draft_change_handler
-            )
-            document.getElementById('family-name').addEventListener(
-              'change',
-              draft_change_handler
-            )
-            document.getElementById('company').addEventListener(
-              'change',
-              draft_change_handler
-            )
-            document.getElementById('email').addEventListener(
-              'change',
-              draft_change_handler
-            )
-            document.getElementById('message').addEventListener(
-              'change',
-              draft_change_handler
-            )
+            let id_company = document.getElementById('company')
+            let id_cross = document.getElementById('cross')
+            let id_email = document.getElementById('email')
+            let id_family_name = document.getElementById('family-name')
+            let id_form = document.getElementById('form')
+            let id_given_names = document.getElementById('given-names')
+            let id_icon = document.getElementById('icon')
+            let id_message = document.getElementById('message')
+            let id_message1 = document.getElementById('message1')
+            let id_send_enquiry = document.getElementById('send-enquiry')
+            let id_spinner = document.getElementById('spinner')
+            let id_tick = document.getElementById('tick')
 
-            document.getElementById('step-1-continue').addEventListener(
-              'click',
+            let input_semaphore = new BinarySemaphore(false)
+            ;(
               async () => {
-                if (await step_1() && await step_2())
-                  $('#step-2-collapse').collapse('show')
+                while (true) {
+                  await input_semaphore.acquire()
+                  await new Promise(resolve => setTimeout(resolve, 3000))
+                  input_semaphore.try_acquire()
+                  await api_call(
+                    '/api/contact/set_draft.json',
+                    id_given_names.value.length === 0 &&
+                      id_family_name.value.length === 0 &&
+                      id_company.value.length === 0 &&
+                      id_email.value.length === 0 &&
+                      id_message1.value.length === 0 ?
+                      null :
+                      {
+                        given_names: id_given_names.value.slice(0, 256),
+                        family_name: id_family_name.value.slice(0, 256),
+                        company: id_company.value.slice(0, 256),
+                        email: id_email.value.slice(0, 256).toLowerCase(),
+                        message: id_message1.value.slice(0, 65536)
+                      }
+                  )
+                }
               }
-            )
+            )() // ignore returned promise (start thread)
 
-            document.getElementById('step-2-back').addEventListener(
-              'click',
-              () => {$('#step-1-collapse').collapse('show')}
-            )
+            let edited = () => {
+              input_semaphore.release()
 
-            document.getElementById('step-2-resend-enquiry').addEventListener(
+              id_send_enquiry.disabled =
+                id_given_names.value.length === 0 &&
+                  id_family_name.value.length === 0 &&
+                  id_company.value.length === 0 &&
+                  id_email.value.length === 0 &&
+                  id_message1.value.length === 0
+              id_icon.hidden = false
+              id_tick.hidden = true
+              id_cross.hidden = true
+              id_spinner.hidden = true
+              id_message.hidden = true
+            }
+
+            id_given_names.addEventListener('input', edited)
+            id_family_name.addEventListener('input', edited)
+            id_company.addEventListener('input', edited)
+            id_email.addEventListener('input', edited)
+            id_message1.addEventListener('input', edited)
+
+            id_send_enquiry.addEventListener(
               'click',
               async () => {
-                if (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
+
+                if (!id_form.checkValidity()) {
+                  id_form.classList.add('was-validated');
+
+                  id_icon.hidden = true
+                  id_cross.hidden = false
+                  return
+                }
+                id_form.classList.remove('was-validated');
+
+                let details = {
+                  given_names: id_given_names.value.slice(0, 256),
+                  family_name: id_family_name.value.slice(0, 256),
+                  company: id_company.value.slice(0, 256),
+                  email: id_email.value.slice(0, 256).toLowerCase(),
+                  message: id_message1.value.slice(0, 65536)
+                }
+
+                id_icon.hidden = true
+                id_spinner.hidden = false
+                try {
+                  await api_call(
+                    '/api/contact/send_enquiry.json',
+                    details
+                  )
+                }
+                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 = 'We have received your enquiry. We will be in touch as soon as possible.'
+                //id_message.classList.add('text-success')
+                id_message.classList.remove('text-danger')
+                id_message.hidden = false
               }
             )
           }