Major refactoring of get_session(), get_account(), get_nodemailer(), introduces ...
[ndcode_site.git] / contact / index.html.jst
1 let XDate = require('xdate')
2
3 return async env => {
4   let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
5   let get_session = await _require('/_lib/get_session.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
10   // preload draft details if any
11   let transaction = await env.site.database.Transaction()
12   let draft_details
13   try {
14     let root = await transaction.get({})
15     let session = await get_session(env, root)
16
17     let contact_draft = await session.get('contact_draft')
18     draft_details =
19       contact_draft !== undefined &&
20         XDate.now() < await contact_draft.get_json('expires') ?
21         {
22           email: await contact_draft.get_json('email'),
23           given_names: await contact_draft.get_json('given_names'),
24           family_name: await contact_draft.get_json('family_name'),
25           company: await contact_draft.get_json('company'),
26           email: await contact_draft.get_json('email'),
27           message: await contact_draft.get_json('message')
28         } :
29         null
30   }
31   finally {
32     transaction.rollback()
33   }
34   console.log('draft_details', JSON.stringify(draft_details))
35
36   await navbar(
37     env,
38     // head
39     async _out => {},
40     // body
41     async _out => {
42       await breadcrumbs(env, _out)
43
44       p {'Do you require more information, or assistance with integrating the projects on this site? We’d love to hear from you.'}
45
46       div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
47         div.card#step-1 {
48           div.card-header#step-1-heading(role="tab") {
49             span#step-1-tick(style="display: none;") {
50               span.icon-color.pr-3 {_out.push(icon_tick)}
51             }
52             span#step-1-cross(style="display: none;") {
53               span.icon-color.pr-3 {_out.push(icon_cross)}
54             }
55             //span#step-1-spinner(style="display: none;") {
56             //  span.icon-color.pr-3 {
57             //    div.spinner-border(role="status") {
58             //      span.sr-only {'Loading...'}
59             //    }
60             //  }
61             //}
62             a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
63               'Enquiry details'
64             }
65           }
66           div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
67             div.card-body {
68               div.row {
69                 div.col-md-6 {
70                   div.form-group {
71                     label.form-label(for="given-names") {'Given names *'}
72                     input.form-control#given-names(type="text" value=draft_details ? draft_details.given_names : '' placeholder="Your given names" required="required" maxlength=256) {}
73                   }
74                 }
75                 div.col-md-6 {
76                   div.form-group {
77                     label.form-label(for="family-name") {'Family name'}
78                     input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : '' placeholder="Your family name" maxlength=256) {}
79                   }
80                 }
81               }
82               div.row {
83                 div.col-md-6 {
84                   div.form-group {
85                    label.form-label(for="company") {'Company'}
86                     input.form-control#company(type="company" value=draft_details ? draft_details.company : '' placeholder="Your company" maxlength=256) {}
87                   }
88                 }
89                 div.col-md-6 {
90                   div.form-group {
91                    label.form-label(for="email") {'Email *'}
92                     input.form-control#email(type="email" value=draft_details ? draft_details.email : '' placeholder="Your email address" required="required" maxlength=256) {}
93                   }
94                 }
95               }
96               div.row {
97                 div.col-md-12 {
98                   div.form-group {
99                     label.form-label(for="message") {'Message *'}
100                     textarea.form-control#message(placeholder="Your message" required="required" rows=6 maxlength=65536) {
101                       if (draft_details)
102                         `${draft_details.message}`
103                     }
104                   }
105                 }
106               }
107
108               button.btn.btn-success#step-1-continue(type="button") {'Continue'}
109               p.'mt-3'.mb-0 {'* These fields are required.'}
110             }
111           }
112         }
113         div.card#step-2 {
114           div.card-header#step-2-heading(role="tab") {
115             span#step-2-tick(style="display: none;") {
116               span.icon-color.pr-3 {_out.push(icon_tick)}
117             }
118             span#step-2-cross(style="display: none;") {
119               span.icon-color.pr-3 {_out.push(icon_cross)}
120             }
121             span#step-2-spinner(style="display: none;") {
122               span.icon-color.pr-3 {
123                 div.spinner-border(role="status") {
124                   span.sr-only {'Loading...'}
125                 }
126               }
127             }
128             a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
129               'Send enquiry'
130             }
131           }
132           div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
133             div.card-body {
134               p#step-2-message {'Please enter enquiry details first.'}
135
136               button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
137               button.btn.btn-outline-secondary.ml-3#step-2-resend-enquiry(type="button") {'Re-send enquiry'}
138             }
139           }
140         }
141       }
142     },
143     // scripts
144     async _out => {
145       //script(src="/js/api_call.js") {}
146
147       script {
148         //let api_contact_get_draft = async (...args) => api_call(
149         //  '/api/contact/get_draft.json',
150         //  ...args
151         //)
152         let api_contact_set_draft = async (...args) => api_call(
153           '/api/contact/set_draft.json',
154           ...args
155         )
156         let api_contact_send_enquiry = async (...args) => api_call(
157           '/api/contact/send_enquiry.json',
158           ...args
159         )
160
161         let draft_timeout_running = false
162         let draft_timeout_handler = async () => {
163           draft_timeout_running = false
164           await api_contact_set_draft(
165             {
166               given_names: document.getElementById('given-names').value.slice(0, 256),
167               family_name: document.getElementById('family-name').value.slice(0, 256),
168               company: document.getElementById('company').value.slice(0, 256),
169               email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
170               message: document.getElementById('message').value.slice(0, 65536)
171             }
172           )
173           //console.log('draft', await api_contact_get_draft())
174         }
175         let draft_change_handler = () => {
176           if (!draft_timeout_running) {
177             draft_timeout_running = true
178             setTimeout(draft_timeout_handler, 5000)
179           }
180         }
181
182         let details
183         let step_1 = async () => {
184           if (
185             !document.getElementById('given-names').reportValidity() ||
186               !document.getElementById('family-name').reportValidity() ||
187               !document.getElementById('company').reportValidity() ||
188               !document.getElementById('email').reportValidity() ||
189               !document.getElementById('message').reportValidity()
190           ) {
191             $('#step-1-tick').hide()
192             $('#step-1-cross').show()
193             //$('#step-1-spinner').hide()
194             return false
195           }
196           $('#step-1-tick').show()
197           $('#step-1-cross').hide()
198           //$('#step-1-spinner').hide()
199
200           details = {
201             given_names: document.getElementById('given-names').value.slice(0, 256),
202             family_name: document.getElementById('family-name').value.slice(0, 256),
203             company: document.getElementById('company').value.slice(0, 256),
204             email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
205             message: document.getElementById('message').value.slice(0, 65536)
206           }
207           return true
208         }
209
210         let step_2 = async () => {
211           $('#step-2-tick').hide()
212           $('#step-2-cross').hide()
213           $('#step-2-spinner').show()
214           document.getElementById('step-2').scrollIntoView()
215
216           try {
217             await api_contact_send_enquiry(details)
218           }
219           catch (error) {
220             let problem =
221               error instanceof Problem ?
222                 error :
223                 new Problem(
224                   // title
225                   'Bad request',
226                   // detail
227                   (error.stack || error.message).toString()
228                   // status
229                   400
230                 )
231
232             $('#step-2-tick').hide()
233             $('#step-2-cross').show()
234             $('#step-2-spinner').hide()
235
236             document.getElementById('step-2-message').textContent = problem.detail
237             $('#step-2-collapse').collapse('show')
238             return false
239           }
240           $('#step-2-tick').show()
241           $('#step-2-cross').hide()
242           $('#step-2-spinner').hide()
243
244           document.getElementById('step-2-message').textContent = 'We have received your enquiry. We will be in touch as soon as possible.'
245           return true
246         }
247
248         document.addEventListener(
249           'DOMContentLoaded',
250           () => {
251             document.getElementById('given-names').addEventListener(
252               'change',
253               draft_change_handler
254             )
255             document.getElementById('family-name').addEventListener(
256               'change',
257               draft_change_handler
258             )
259             document.getElementById('company').addEventListener(
260               'change',
261               draft_change_handler
262             )
263             document.getElementById('email').addEventListener(
264               'change',
265               draft_change_handler
266             )
267             document.getElementById('message').addEventListener(
268               'change',
269               draft_change_handler
270             )
271
272             document.getElementById('step-1-continue').addEventListener(
273               'click',
274               async () => {
275                 if (await step_1() && await step_2())
276                   $('#step-2-collapse').collapse('show')
277               }
278             )
279
280             document.getElementById('step-2-back').addEventListener(
281               'click',
282               () => {$('#step-1-collapse').collapse('show')}
283             )
284
285             document.getElementById('step-2-resend-enquiry').addEventListener(
286               'click',
287               async () => {
288                 if (await step_2())
289                   $('#step-2-collapse').collapse('show')
290               }
291             )
292           }
293         )
294       }
295     }
296   )
297 }