1 let XDate = require('xdate')
4 let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
5 let get_account = await _require('/_lib/get_account.jst')
6 let get_session = await _require('/_lib/get_session.jst')
7 let icon_cross = await env.site.get_min_svg('/_svg/icon_cross.svg')
8 let icon_tick = await env.site.get_min_svg('/_svg/icon_tick.svg')
9 let menu = await env.site.get_menu('/my_account/_menu.json')
10 let navbar = await _require('/_lib/navbar.jst')
12 // see whether signed in, if so preload details, and draft details if any
13 let transaction = await env.site.database.Transaction()
15 let details, draft_details
17 let root = await transaction.get({})
19 let session = await get_session(env, root)
20 signed_in_as = await session.get_json('signed_in_as')
22 let account = await get_account(root, session)
23 if (account !== undefined) {
25 given_names: await account.get_json('given_names'),
26 family_name: await account.get_json('family_name'),
27 contact_me: await account.get_json('contact_me')
30 let change_details_draft = await session.get('change_details_draft')
32 change_details_draft !== undefined &&
33 XDate.now() < await change_details_draft.get_json('expires') ?
35 given_names: await change_details_draft.get_json('given_names'),
36 family_name: await change_details_draft.get_json('family_name'),
37 contact_me: await change_details_draft.get_json('contact_me')
43 transaction.rollback()
47 JSON.stringify(details),
49 JSON.stringify(draft_details)
58 await breadcrumbs(env, _out)
60 if (signed_in_as !== undefined) {
62 p {'Your given names are visible to other users if you comment on our blog. Your email and family name remain private. If your name is one word or does not fit given names/family name pattern, then please enter given names only.'}
64 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
66 div.card-header#step-1-heading(role="tab") {
67 span#step-1-tick(style="display: none;") {
68 span.icon-color.pr-3 {_out.push(icon_tick)}
70 span#step-1-cross(style="display: none;") {
71 span.icon-color.pr-3 {_out.push(icon_cross)}
73 //span#step-1-spinner(style="display: none;") {
74 // span.icon-color.pr-3 {
75 // div.spinner-border(role="status") {
76 // span.sr-only {'Loading...'}
80 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
84 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
89 label.form-label(for="given-names") {'Given names *'}
90 input.form-control#given-names(type="text" value=draft_details ? draft_details.given_names : details.given_names placeholder="Your given names" required="required" maxlength=256) {}
95 label.form-label(for="family-name") {'Family name'}
96 input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : details.family_name placeholder="Your family name" maxlength=256) {}
102 div.custom-control.custom-checkbox {
103 if (draft_details ? draft_details.contact_me : details.contact_me)
104 input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
106 input.custom-control-input#contact-me(type="checkbox") {}
108 label.custom-control-label(for="contact-me") {
109 'Contact me by email with updates and special offers'
116 button.btn.btn-outline-secondary#step-1-revert(type="button") {'Revert'}
118 button.btn.btn-outline-secondary#step-1-revert(type="button" disabled="disabled") {'Revert'}
120 button.btn.btn-success.ml-3#step-1-save(type="button") {'Save'}
122 button.btn.btn-success.ml-3#step-1-save(type="button" disabled="disabled") {'Save'}
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") {
152 label.form-label(for="old-password") {'Old password *'}
153 input.form-control#old-password(type="password" placeholder="Old password" required="required" minlength=8 maxlength=256) {}
158 label.form-label(for="new-password") {'New password *'}
159 input.form-control#'new-password'(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
164 button.btn.btn-outline-secondary#step-2-clear(type="button" disabled="disabled") {'Clear'}
165 button.btn.btn-success.ml-3#step-2-save(type="button" disabled="disabled") {'Save'}
167 p.'mt-3'.mb-0 {'* These fields are required.'}
175 p {'For account maintenance, please click on one of the options below.'}
178 let entries = menu.entries
179 for (let i = 0; i < entries.length; ++i) {
180 let entry = entries[i]
181 if (Object.prototype.hasOwnProperty.call(entry, 'icon'))
183 a.nav-link(href=`${entry.dir}/index.html`) {
184 table.icon-and-text {
187 _out.push(await env.site.get_min_svg(entry.icon))
190 span.h2{`${entry.name}`}
203 // this will be called by navbar logic after sign in/out
204 function sign_in_out(status) {
205 window.location.reload()
209 if (signed_in_as !== undefined) {
210 //script(src="/js/api_call.js") {}
213 let step_1_dirty = ${JSON.stringify(draft_details !== null)}
214 let draft_timeout_running = false
215 let draft_timeout_handler = async () => {
216 draft_timeout_running = false
218 '/api/account/change_details/set_draft.json',
221 given_names: document.getElementById('given-names').value.slice(0, 256),
222 family_name: document.getElementById('family-name').value.slice(0, 256),
223 contact_me: document.getElementById('contact-me').checked ? true : false
227 //console.log('draft', await api_call('/api/account/change_details/get_draft.json'))
230 document.addEventListener(
233 let step_1_change_handler = () => {
235 document.getElementById('step-1-revert').disabled = false
236 document.getElementById('step-1-save').disabled = false
238 if (!draft_timeout_running) {
239 draft_timeout_running = true
240 setTimeout(draft_timeout_handler, 5000)
243 document.getElementById('given-names').addEventListener(
245 step_1_change_handler
247 document.getElementById('family-name').addEventListener(
249 step_1_change_handler
251 document.getElementById('contact-me').addEventListener(
253 step_1_change_handler
256 document.getElementById('step-1-revert').addEventListener(
259 $('#step-1-tick').hide()
260 $('#step-1-cross').hide()
261 $('#step-1-spinner').show()
265 details = await api_call(
266 '/api/account/change_details/get.json'
270 let problem = Problem.from(error)
271 console.log(problem.detail)
273 $('#step-1-tick').hide()
274 $('#step-1-cross').show()
275 $('#step-1-spinner').hide()
278 $('#step-1-tick').hide()
279 $('#step-1-cross').hide()
280 $('#step-1-spinner').hide()
283 document.getElementById('step-1-revert').disabled = true
284 document.getElementById('step-1-save').disabled = true
286 document.getElementById('given-names').value = details.given_names
287 document.getElementById('family-name').value = details.family_name
288 document.getElementById('contact-me').checked = details.contact_me
290 if (!draft_timeout_running) {
291 draft_timeout_running = true
292 setTimeout(draft_timeout_handler, 5000)
297 document.getElementById('step-1-save').addEventListener(
301 !document.getElementById('given-names').reportValidity() ||
302 !document.getElementById('family-name').reportValidity()
304 $('#step-1-tick').hide()
305 $('#step-1-cross').show()
306 $('#step-1-spinner').hide()
309 $('#step-1-tick').hide()
310 $('#step-1-cross').hide()
311 $('#step-1-spinner').show()
315 '/api/account/change_details/set.json',
317 given_names: document.getElementById('given-names').value.slice(0, 256),
318 family_name: document.getElementById('family-name').value.slice(0, 256),
319 contact_me: document.getElementById('contact-me').checked ? true : false
324 let problem = Problem.from(error)
325 console.log(problem.detail)
327 $('#step-1-tick').hide()
328 $('#step-1-cross').show()
329 $('#step-1-spinner').hide()
332 $('#step-1-tick').show()
333 $('#step-1-cross').hide()
334 $('#step-1-spinner').hide()
337 document.getElementById('step-1-revert').disabled = true
338 document.getElementById('step-1-save').disabled = true
340 // SHOULD execute immediately here
341 // (because user is likely to leave the page after save)
342 if (!draft_timeout_running) {
343 draft_timeout_running = true
344 setTimeout(draft_timeout_handler, 5000)
349 let step_2_change_handler = () => {
350 document.getElementById('step-2-clear').disabled = false
351 document.getElementById('step-2-save').disabled = false
353 document.getElementById('old-password').addEventListener(
355 step_2_change_handler
357 document.getElementById('new-password').addEventListener(
359 step_2_change_handler
362 document.getElementById('step-2-clear').addEventListener(
365 document.getElementById('step-2-clear').disabled = true
366 document.getElementById('step-2-save').disabled = true
368 document.getElementById('old-password').value = ''
369 document.getElementById('new-password').value = ''
373 document.getElementById('step-2-save').addEventListener(
377 !document.getElementById('old-password').reportValidity() ||
378 !document.getElementById('new-password').reportValidity()
380 $('#step-2-tick').hide()
381 $('#step-2-cross').show()
382 $('#step-2-spinner').hide()
385 $('#step-2-tick').hide()
386 $('#step-2-cross').hide()
387 $('#step-2-spinner').show()
391 '/api/account/change_password.json',
392 document.getElementById('old-password').value.slice(0, 256),
393 document.getElementById('new-password').value.slice(0, 256)
397 let problem = Problem.from(error)
398 console.log(problem.detail)
400 $('#step-2-tick').hide()
401 $('#step-2-cross').show()
402 $('#step-2-spinner').hide()
405 $('#step-2-tick').show()
406 $('#step-2-cross').hide()
407 $('#step-2-spinner').hide()
409 document.getElementById('step-2-clear').disabled = true
410 document.getElementById('step-2-save').disabled = true
412 document.getElementById('old-password').value = ''
413 document.getElementById('new-password').value = ''