-let querystring = require('querystring')
-let stream_buffers = require('stream-buffers')
+let logjson = (await import('@ndcode/logjson')).default
let XDate = require('xdate')
return async env => {
let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
- let globals = await env.site.get_json('/_config/globals.json')
+ 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')
+ let session_cookie = await _require('/_lib/session_cookie.jst')
+
+ // preload draft details if any
+ let transaction = await env.site.database.Transaction(), draft_details
+ try {
+ // initialize env.session_key, set cookie in env.response
+ let session = await session_cookie(env, transaction)
+
+ let contact_draft = await session.get('contact_draft')
+ draft_details =
+ contact_draft !== undefined &&
+ XDate.now() < await logjson.logjson_to_json(
+ await contact_draft.get('expires')
+ ) ? {
+ email: await logjson.logjson_to_json(
+ await contact_draft.get('email')
+ ),
+ given_names: await logjson.logjson_to_json(
+ await contact_draft.get('given_names')
+ ),
+ family_name: await logjson.logjson_to_json(
+ await contact_draft.get('family_name')
+ ),
+ company: await logjson.logjson_to_json(
+ await contact_draft.get('company')
+ ),
+ email: await logjson.logjson_to_json(
+ await contact_draft.get('email')
+ ),
+ message: await logjson.logjson_to_json(
+ await contact_draft.get('message')
+ )
+ } : null
+
+ await transaction.commit()
+ }
+ catch (error) {
+ transaction.rollback()
+ throw error
+ }
+ console.log('draft_details', JSON.stringify(draft_details))
await navbar(
env,
+ // head
async _out => {},
+ // body
async _out => {
await breadcrumbs(env, _out)
- if (env.request.method == 'POST') {
- let write_stream = new stream_buffers.WritableStreamBuffer()
- let data = new Promise(
- (resolve, reject) => {
- write_stream.
- on('finish', () => {resolve(write_stream.getContents())}).
- on('error', () => {reject()})
- }
- )
- env.request.pipe(write_stream)
- let query = querystring.parse((await data).toString())
- console.log('received contact form:', query.email)
-
- // save the form contents in a dated logfile, so that we can
- // recover manually if the email doesn't send for some reason
- date = new XDate()
- query.date = date.toUTCString()
-
- let transaction = await env.site.database.Transaction()
- ;(
- await (
- await (
- await (
- await transaction.get({})
- ).get('logs', {})
- ).get(date.toUTCString('yyyyMMdd'), {})
- ).get('contact', [])
- ).push(transaction.json_to_logjson(query))
- transaction.commit()
-
- // send email (asynchronously)
- let emailjs_contact = await env.site.get_emailjs(
- '/_config/email_contact.json'
- )
- emailjs_contact.send(
- {
- from: globals.contact_from,
- 'reply-to':
- `${query.first_name} ${query.last_name} <${query.email}>`,
- to: globals.contact_to,
- subject:
- Object.prototype.hasOwnProperty.call(query, 'company') ?
- 'Enquiry: ' + query.company :
- 'Enquiry',
- text: query.message
- },
- (err, message) => {
- if (err)
- console.error(err.stack || err.message)
- else
- console.log('sent contact email:', query.email)
- }
- ) // ignore returned promise
+ p {'Do you require more information, or assistance with integrating the projects on this site? We’d love to hear from you.'}
- p {'Thanks! We\'ll be in touch as soon as we can.'}
- }
- else {
- p {'Do you require more information or consulting assistance with integrating the projects on this site? We\'d love to hear from you.'}
-
- form#contact-form(method="post" action="index.html" role="form") {
- div.row {
- div.col-md-6 {
- div.form-group {
- label(for="contact_form_first_name") {'First name *'}
- input.form-control#contact_form_first_name(type="text" name="first_name" placeholder="Please enter your first name" required="required" data-error="First name is required.") {}
- div.help-block.with-errors {}
- }
+ 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)}
}
- div.col-md-6 {
- div.form-group {
- label(for="contact_form_last_name") {'Last name *'}
- input.form-control#contact_form_last_name(type="text" name="last_name" placeholder="Please enter your last name" required="required" data-error="Last name is required.") {}
- div.help-block.with-errors {}
- }
+ 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'
}
}
- div.row {
- div.col-md-6 {
- div.form-group {
- label(for="contact_form_company") {'Company'}
- input.form-control#contact_form_company(type="text" name="company" placeholder="Please enter your company") {}
- div.help-block.with-errors {}
+ 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.col-md-6 {
- div.form-group {
- label(for="contact_form_email") {'Email *'}
- input.form-control#contact_form_email(type="email" name="email" placeholder="Please enter your email" required="required" data-error="Valid email is required.") {}
- div.help-block.with-errors {}
+ 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.row {
- div.col-md-12 {
- div.form-group {
- label(for="contact_form_message") {'Message *'}
- textarea.form-control#contact_form_message(name="message" placeholder="Please explain your application" rows="4" required="required" data-error="Please, leave us a message.") {}
- div.help-block.with-errors {}
+ }
+ 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...'}
+ }
}
}
- }
- p {} // fix this later
- div.row {
- div.col-md-12 {
- button.btn.btn-success.btn-send(type="submit") {'Send message'}
+ a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
+ 'Send enquiry'
}
}
- p {} // fix this later
- div.row {
- div.col-md-12 {
- p.text-muted {
- strong {'*'}
- 'These fields are required.'
- //'Contact form template by '
- //a(href="https://bootstrapious.com/p/how-to-build-a-working-bootstrap-contact-form" target="_blank") {'Bootstrapious'}
- //'.'
- }
+ 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'}
}
}
}
}
},
- async _out => {}
+ // scripts
+ async _out => {
+ //script(src="/js/api_call.js") {}
+
+ script {
+ //let api_contact_get_draft = async (...arguments) => api_call(
+ // '/api/contact/get_draft.json',
+ // ...arguments
+ //)
+ let api_contact_set_draft = async (...arguments) => api_call(
+ '/api/contact/set_draft.json',
+ ...arguments
+ )
+ let api_contact_send_enquiry = async (...arguments) => api_call(
+ '/api/contact/send_enquiry.json',
+ ...arguments
+ )
+
+ let draft_timeout_running = false
+ let draft_timeout_handler = async () => {
+ draft_timeout_running = false
+ await api_contact_set_draft(
+ {
+ 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)
+ }
+ )
+ //console.log('draft', await api_contact_get_draft())
+ }
+ let draft_change_handler = () => {
+ if (!draft_timeout_running) {
+ draft_timeout_running = true
+ setTimeout(draft_timeout_handler, 5000)
+ }
+ }
+
+ 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
+ }
+ $('#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)
+ }
+ 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_contact_send_enquiry(details)
+ }
+ catch (error) {
+ let problem =
+ error instanceof Problem ?
+ error :
+ new Problem(
+ // title
+ 'Bad request',
+ // detail
+ (error.stack || error.message).toString()
+ // status
+ 400
+ )
+
+ $('#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 = 'We have received your enquiry. We will be in touch as soon as possible.'
+ return true
+ }
+
+ 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
+ )
+
+ document.getElementById('step-1-continue').addEventListener(
+ 'click',
+ async () => {
+ if (await step_1() && await step_2())
+ $('#step-2-collapse').collapse('show')
+ }
+ )
+
+ document.getElementById('step-2-back').addEventListener(
+ 'click',
+ () => {$('#step-1-collapse').collapse('show')}
+ )
+
+ document.getElementById('step-2-resend-enquiry').addEventListener(
+ 'click',
+ async () => {
+ if (await step_2())
+ $('#step-2-collapse').collapse('show')
+ }
+ )
+ }
+ )
+ }
+ }
)
}