1 let logjson = (await import('@ndcode/logjson')).default
2 let XDate = require('xdate')
5 let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
6 let icon_cross = await env.site.get_min_svg('/_svg/icon_cross.svg')
7 let icon_tick = await env.site.get_min_svg('/_svg/icon_tick.svg')
8 let navbar = await _require('/_lib/navbar.jst')
9 let session_cookie = await _require('/_lib/session_cookie.jst')
11 // preload draft details if any
12 let transaction = await env.site.database.Transaction(), draft_details
14 // initialize env.session_key, set cookie in env.response
15 let session = await session_cookie(env, transaction)
17 let contact_draft = await session.get('contact_draft')
19 contact_draft !== undefined &&
20 XDate.now() < await logjson.logjson_to_json(
21 await contact_draft.get('expires')
23 email: await logjson.logjson_to_json(
24 await contact_draft.get('email')
26 given_names: await logjson.logjson_to_json(
27 await contact_draft.get('given_names')
29 family_name: await logjson.logjson_to_json(
30 await contact_draft.get('family_name')
32 company: await logjson.logjson_to_json(
33 await contact_draft.get('company')
35 email: await logjson.logjson_to_json(
36 await contact_draft.get('email')
38 message: await logjson.logjson_to_json(
39 await contact_draft.get('message')
43 await transaction.commit()
46 transaction.rollback()
49 console.log('draft_details', JSON.stringify(draft_details))
57 await breadcrumbs(env, _out)
59 p {'Do you require more information, or assistance with integrating the projects on this site? We’d love to hear from you.'}
61 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
63 div.card-header#step-1-heading(role="tab") {
64 span#step-1-tick(style="display: none;") {
65 span.icon-color.pr-3 {_out.push(icon_tick)}
67 span#step-1-cross(style="display: none;") {
68 span.icon-color.pr-3 {_out.push(icon_cross)}
70 //span#step-1-spinner(style="display: none;") {
71 // span.icon-color.pr-3 {
72 // div.spinner-border(role="status") {
73 // span.sr-only {'Loading...'}
77 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
81 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
86 label.form-label(for="given-names") {'Given names *'}
87 input.form-control#given-names(type="text" value=draft_details ? draft_details.given_names : '' placeholder="Your given names" required="required" maxlength=256) {}
92 label.form-label(for="family-name") {'Family name'}
93 input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : '' placeholder="Your family name" maxlength=256) {}
100 label.form-label(for="company") {'Company'}
101 input.form-control#company(type="company" value=draft_details ? draft_details.company : '' placeholder="Your company" maxlength=256) {}
106 label.form-label(for="email") {'Email *'}
107 input.form-control#email(type="email" value=draft_details ? draft_details.email : '' placeholder="Your email address" required="required" maxlength=256) {}
114 label.form-label(for="message") {'Message *'}
115 textarea.form-control#message(placeholder="Your message" required="required" rows=6 maxlength=65536) {
117 `${draft_details.message}`
123 button.btn.btn-success#step-1-continue(type="button") {'Continue'}
124 p.'mt-3'.mb-0 {'* These fields are required.'}
129 div.card-header#step-2-heading(role="tab") {
130 span#step-2-tick(style="display: none;") {
131 span.icon-color.pr-3 {_out.push(icon_tick)}
133 span#step-2-cross(style="display: none;") {
134 span.icon-color.pr-3 {_out.push(icon_cross)}
136 span#step-2-spinner(style="display: none;") {
137 span.icon-color.pr-3 {
138 div.spinner-border(role="status") {
139 span.sr-only {'Loading...'}
143 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
147 div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
149 p#step-2-message {'Please enter enquiry details first.'}
151 button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
152 button.btn.btn-outline-secondary.ml-3#step-2-resend-enquiry(type="button") {'Re-send enquiry'}
160 //script(src="/js/api_call.js") {}
163 //let api_contact_get_draft = async (...args) => api_call(
164 // '/api/contact/get_draft.json',
167 let api_contact_set_draft = async (...args) => api_call(
168 '/api/contact/set_draft.json',
171 let api_contact_send_enquiry = async (...args) => api_call(
172 '/api/contact/send_enquiry.json',
176 let draft_timeout_running = false
177 let draft_timeout_handler = async () => {
178 draft_timeout_running = false
179 await api_contact_set_draft(
181 given_names: document.getElementById('given-names').value.slice(0, 256),
182 family_name: document.getElementById('family-name').value.slice(0, 256),
183 company: document.getElementById('company').value.slice(0, 256),
184 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
185 message: document.getElementById('message').value.slice(0, 65536)
188 //console.log('draft', await api_contact_get_draft())
190 let draft_change_handler = () => {
191 if (!draft_timeout_running) {
192 draft_timeout_running = true
193 setTimeout(draft_timeout_handler, 5000)
198 let step_1 = async () => {
200 !document.getElementById('given-names').reportValidity() ||
201 !document.getElementById('family-name').reportValidity() ||
202 !document.getElementById('company').reportValidity() ||
203 !document.getElementById('email').reportValidity() ||
204 !document.getElementById('message').reportValidity()
206 $('#step-1-tick').hide()
207 $('#step-1-cross').show()
208 //$('#step-1-spinner').hide()
211 $('#step-1-tick').show()
212 $('#step-1-cross').hide()
213 //$('#step-1-spinner').hide()
216 given_names: document.getElementById('given-names').value.slice(0, 256),
217 family_name: document.getElementById('family-name').value.slice(0, 256),
218 company: document.getElementById('company').value.slice(0, 256),
219 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
220 message: document.getElementById('message').value.slice(0, 65536)
225 let step_2 = async () => {
226 $('#step-2-tick').hide()
227 $('#step-2-cross').hide()
228 $('#step-2-spinner').show()
229 document.getElementById('step-2').scrollIntoView()
232 await api_contact_send_enquiry(details)
236 error instanceof Problem ?
242 (error.stack || error.message).toString()
247 $('#step-2-tick').hide()
248 $('#step-2-cross').show()
249 $('#step-2-spinner').hide()
251 document.getElementById('step-2-message').textContent = problem.detail
252 $('#step-2-collapse').collapse('show')
255 $('#step-2-tick').show()
256 $('#step-2-cross').hide()
257 $('#step-2-spinner').hide()
259 document.getElementById('step-2-message').textContent = 'We have received your enquiry. We will be in touch as soon as possible.'
263 document.addEventListener(
266 document.getElementById('given-names').addEventListener(
270 document.getElementById('family-name').addEventListener(
274 document.getElementById('company').addEventListener(
278 document.getElementById('email').addEventListener(
282 document.getElementById('message').addEventListener(
287 document.getElementById('step-1-continue').addEventListener(
290 if (await step_1() && await step_2())
291 $('#step-2-collapse').collapse('show')
295 document.getElementById('step-2-back').addEventListener(
297 () => {$('#step-1-collapse').collapse('show')}
300 document.getElementById('step-2-resend-enquiry').addEventListener(
304 $('#step-2-collapse').collapse('show')