Update /contact/index.html.jst to latest way, no accordion, placeholder company
[ndcode_site.git] / contact / index.html.jst
1 return async env => {
2   let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
3   let fa_envelope = await env.site.get_min_svg('/_svg/fa_envelope.svg')
4   let get_placeholder = await _require('/_lib/get_placeholder.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 placeholder
13   let contact_draft
14   try {
15     let root = await transaction.get({})
16     let session = await get_session(env, root)
17
18     placeholder = await get_placeholder(env, session)
19
20     contact_draft = await session.get_json('contact_draft')
21     if (contact_draft === undefined || env.now >= contact_draft.expires)
22       contact_draft = null
23     transaction.commit()
24   }
25   catch (error) {
26     transaction.rollback()
27     throw error
28   }
29
30   await navbar(
31     env,
32     // head
33     async _out => {},
34     // body
35     async _out => {
36       await breadcrumbs(env, _out)
37
38       p {'Do you require more information, or assistance with integrating the projects on this site? We’d love to hear from you.'}
39
40       form#form {
41         div.row {
42           div.col-md-6 {
43             div.form-group {
44               label.form-label(for="given-names") {'Given names *'}
45               input.form-control#given-names(type="text" value=contact_draft ? contact_draft.given_names : '' placeholder=placeholder.given_names required maxlength=256) {}
46               div.invalid-feedback {'Please enter a name we can address you by.'}
47             }
48           }
49           div.col-md-6 {
50             div.form-group {
51               label.form-label(for="family-name") {'Family name'}
52               input.form-control#family-name(type="text" value=contact_draft ? contact_draft.family_name : '' placeholder=placeholder.family_name maxlength=256) {}
53             }
54           }
55         }
56         div.row {
57           div.col-md-6 {
58             div.form-group {
59              label.form-label(for="company") {'Company'}
60               input.form-control#company(type="company" value=contact_draft ? contact_draft.company : '' placeholder=placeholder.company maxlength=256) {}
61             }
62           }
63           div.col-md-6 {
64             div.form-group {
65              label.form-label(for="email") {'Email *'}
66               input.form-control#email(type="email" value=contact_draft ? contact_draft.email : '' placeholder=placeholder.email required maxlength=256) {}
67               div.invalid-feedback {'Please enter an email address we can contact you on.'}
68             }
69           }
70         }
71         div.row {
72           div.col-md-12 {
73             div.form-group {
74               label.form-label(for="message1") {'Message *'}
75               textarea.form-control#message1(placeholder="I would like to..." required rows=6 maxlength=65536) {
76                 if (contact_draft)
77                   `${contact_draft.message}`
78               }
79               div.invalid-feedback {'Please let us know your application or question.'}
80             }
81           }
82         }
83       }
84
85       if (contact_draft !== null)
86         button.btn.btn-success#send-enquiry(type="button") {
87           div.icon24-outer.mr-2#icon {
88             div.icon24-inner {_out.push(fa_envelope)}
89           }
90           div.icon24-outer.mr-2#tick(hidden) {
91             div.icon24-inner {_out.push(icon_tick)}
92           }
93           div.icon24-outer.mr-2#cross(hidden) {
94             div.icon24-inner {_out.push(icon_cross)}
95           }
96           div.icon24-outer.mr-2#spinner(hidden) {
97             div.icon24-inner {
98               div.spinner-border.spinner-border-sm(role="status") {}
99             }
100           }
101           'Send enquiry'
102         }
103       else
104         button.btn.btn-success#send-enquiry(type="button" disabled) {
105           div.icon24-outer.mr-2#icon {
106             div.icon24-inner {_out.push(fa_envelope)}
107           }
108           div.icon24-outer.mr-2#tick(hidden) {
109             div.icon24-inner {_out.push(icon_tick)}
110           }
111           div.icon24-outer.mr-2#cross(hidden) {
112             div.icon24-inner {_out.push(icon_cross)}
113           }
114           div.icon24-outer.mr-2#spinner(hidden) {
115             div.icon24-inner {
116               div.spinner-border.spinner-border-sm(role="status") {}
117             }
118           }
119           'Send enquiry'
120         }
121
122       p.'mt-3'.mb-0#message(hidden) {}
123
124       p.text-muted.mt-3 {'* These fields are required.'}
125     },
126     // scripts
127     async _out => {
128       //script(src="/js/utils.js") {}
129
130       script {
131         document.addEventListener(
132           'DOMContentLoaded',
133           () => {
134             let id_company = document.getElementById('company')
135             let id_cross = document.getElementById('cross')
136             let id_email = document.getElementById('email')
137             let id_family_name = document.getElementById('family-name')
138             let id_form = document.getElementById('form')
139             let id_given_names = document.getElementById('given-names')
140             let id_icon = document.getElementById('icon')
141             let id_message = document.getElementById('message')
142             let id_message1 = document.getElementById('message1')
143             let id_send_enquiry = document.getElementById('send-enquiry')
144             let id_spinner = document.getElementById('spinner')
145             let id_tick = document.getElementById('tick')
146
147             let input_semaphore = new BinarySemaphore(false)
148             ;(
149               async () => {
150                 while (true) {
151                   await input_semaphore.acquire()
152                   await new Promise(resolve => setTimeout(resolve, 3000))
153                   input_semaphore.try_acquire()
154                   await api_call(
155                     '/api/contact/set_draft.json',
156                     id_given_names.value.length === 0 &&
157                       id_family_name.value.length === 0 &&
158                       id_company.value.length === 0 &&
159                       id_email.value.length === 0 &&
160                       id_message1.value.length === 0 ?
161                       null :
162                       {
163                         given_names: id_given_names.value.slice(0, 256),
164                         family_name: id_family_name.value.slice(0, 256),
165                         company: id_company.value.slice(0, 256),
166                         email: id_email.value.slice(0, 256).toLowerCase(),
167                         message: id_message1.value.slice(0, 65536)
168                       }
169                   )
170                 }
171               }
172             )() // ignore returned promise (start thread)
173
174             let edited = () => {
175               input_semaphore.release()
176
177               id_send_enquiry.disabled =
178                 id_given_names.value.length === 0 &&
179                   id_family_name.value.length === 0 &&
180                   id_company.value.length === 0 &&
181                   id_email.value.length === 0 &&
182                   id_message1.value.length === 0
183               id_icon.hidden = false
184               id_tick.hidden = true
185               id_cross.hidden = true
186               id_spinner.hidden = true
187               id_message.hidden = true
188             }
189
190             id_given_names.addEventListener('input', edited)
191             id_family_name.addEventListener('input', edited)
192             id_company.addEventListener('input', edited)
193             id_email.addEventListener('input', edited)
194             id_message1.addEventListener('input', edited)
195
196             id_send_enquiry.addEventListener(
197               'click',
198               async () => {
199                 id_icon.hidden = false
200                 id_tick.hidden = true
201                 id_cross.hidden = true
202                 id_spinner.hidden = true
203                 // the below causes an ugly flicker, so just keep the message
204                 //id_message.hidden = true
205
206                 if (!id_form.checkValidity()) {
207                   id_form.classList.add('was-validated');
208
209                   id_icon.hidden = true
210                   id_cross.hidden = false
211                   return
212                 }
213                 id_form.classList.remove('was-validated');
214
215                 let details = {
216                   given_names: id_given_names.value.slice(0, 256),
217                   family_name: id_family_name.value.slice(0, 256),
218                   company: id_company.value.slice(0, 256),
219                   email: id_email.value.slice(0, 256).toLowerCase(),
220                   message: id_message1.value.slice(0, 65536)
221                 }
222
223                 id_icon.hidden = true
224                 id_spinner.hidden = false
225                 try {
226                   await api_call(
227                     '/api/contact/send_enquiry.json',
228                     details
229                   )
230                 }
231                 catch (error) {
232                   let problem = Problem.from(error)
233
234                   id_cross.hidden = false
235                   id_spinner.hidden = true
236
237                   id_message.textContent = problem.detail
238                   //id_message.classList.remove('text-success')
239                   id_message.classList.add('text-danger')
240                   id_message.hidden = false
241                   return
242                 }
243                 id_tick.hidden = false
244                 id_spinner.hidden = true
245                 id_message.textContent = 'We have received your enquiry. We will be in touch as soon as possible.'
246                 //id_message.classList.add('text-success')
247                 id_message.classList.remove('text-danger')
248                 id_message.hidden = false
249               }
250             )
251           }
252         )
253       }
254     }
255   )
256 }