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