1 let XDate = require('xdate')
4 let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
5 let icon_cross = await env.site.get_min_svg('/_svg/icon_cross.svg')
6 let icon_tick = await env.site.get_min_svg('/_svg/icon_tick.svg')
7 let menu = await env.site.get_menu('/my_account/_menu.json')
8 let navbar = await _require('/_lib/navbar.jst')
9 let get_session = await _require('/_lib/get_session.jst')
11 // see whether signed in, if so preload details, and draft details if any
13 transaction = await env.site.database.Transaction(),
17 // initialize env.session_key, set cookie in env.response
18 let session = await get_session(env, transaction)
19 if (env.signed_in_as) {
22 await transaction.get({})
24 ).get(env.signed_in_as)
26 given_names: await account.get_json('given_names'),
27 family_name: await account.get_json('family_name'),
28 contact_me: await account.get_json('contact_me')
31 let change_details_draft = await session.get('change_details_draft')
33 change_details_draft !== undefined &&
34 XDate.now() < await change_details_draft.get_json('expires') ?
36 given_names: await change_details_draft.get_json('given_names'),
37 family_name: await change_details_draft.get_json('family_name'),
38 contact_me: await change_details_draft.get_json('contact_me')
42 await transaction.commit()
45 transaction.rollback()
50 JSON.stringify(details),
52 JSON.stringify(draft_details)
61 await breadcrumbs(env, _out)
63 if (env.signed_in_as) {
65 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.'}
67 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
69 div.card-header#step-1-heading(role="tab") {
70 span#step-1-tick(style="display: none;") {
71 span.icon-color.pr-3 {_out.push(icon_tick)}
73 span#step-1-cross(style="display: none;") {
74 span.icon-color.pr-3 {_out.push(icon_cross)}
76 //span#step-1-spinner(style="display: none;") {
77 // span.icon-color.pr-3 {
78 // div.spinner-border(role="status") {
79 // span.sr-only {'Loading...'}
83 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
87 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
92 label.form-label(for="given-names") {'Given names *'}
93 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) {}
98 label.form-label(for="family-name") {'Family name'}
99 input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : details.family_name placeholder="Your family name" maxlength=256) {}
105 div.custom-control.custom-checkbox {
106 if (draft_details ? draft_details.contact_me : details.contact_me)
107 input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
109 input.custom-control-input#contact-me(type="checkbox") {}
111 label.custom-control-label(for="contact-me") {
112 'Contact me by email with updates and special offers'
119 button.btn.btn-outline-secondary#step-1-revert(type="button") {'Revert'}
121 button.btn.btn-outline-secondary#step-1-revert(type="button" disabled="disabled") {'Revert'}
123 button.btn.btn-success.ml-3#step-1-save(type="button") {'Save'}
125 button.btn.btn-success.ml-3#step-1-save(type="button" disabled="disabled") {'Save'}
127 p.'mt-3'.mb-0 {'* These fields are required.'}
132 div.card-header#step-2-heading(role="tab") {
133 span#step-2-tick(style="display: none;") {
134 span.icon-color.pr-3 {_out.push(icon_tick)}
136 span#step-2-cross(style="display: none;") {
137 span.icon-color.pr-3 {_out.push(icon_cross)}
139 span#step-2-spinner(style="display: none;") {
140 span.icon-color.pr-3 {
141 div.spinner-border(role="status") {
142 span.sr-only {'Loading...'}
146 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
150 div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
155 label.form-label(for="old-password") {'Old password *'}
156 input.form-control#old-password(type="password" placeholder="Old password" required="required" minlength=8 maxlength=256) {}
161 label.form-label(for="new-password") {'New password *'}
162 input.form-control#'new-password'(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
167 button.btn.btn-outline-secondary#step-2-clear(type="button" disabled="disabled") {'Clear'}
168 button.btn.btn-success.ml-3#step-2-save(type="button" disabled="disabled") {'Save'}
170 p.'mt-3'.mb-0 {'* These fields are required.'}
178 p {'For account maintenance, please click on one of the options below.'}
181 let entries = menu.entries
182 for (let i = 0; i < entries.length; ++i) {
183 let entry = entries[i]
184 if (Object.prototype.hasOwnProperty.call(entry, 'icon'))
186 a.nav-link(href=`${entry.dir}/index.html`) {
187 table.icon-and-text {
190 _out.push(await env.site.get_min_svg(entry.icon))
193 span.h2{`${entry.name}`}
206 // this will be called by navbar logic after sign in/out
207 function sign_in_out(status) {
208 window.location.reload()
212 if (env.signed_in_as) {
213 //script(src="/js/api_call.js") {}
216 let api_account_change_details_get = async (...args) => api_call(
217 '/api/account/change_details/get.json',
220 let api_account_change_details_set = async (...args) => api_call(
221 '/api/account/change_details/set.json',
224 //let api_account_change_details_get_draft = async (...args) => api_call(
225 // '/api/account/change_details/get_draft.json',
228 let api_account_change_details_set_draft = async (...args) => api_call(
229 '/api/account/change_details/set_draft.json',
232 let api_account_change_password = async (...args) => api_call(
233 '/api/account/change_password.json',
237 let step_1_dirty = ${JSON.stringify(draft_details !== null)}
238 let draft_timeout_running = false
239 let draft_timeout_handler = async () => {
240 draft_timeout_running = false
241 await api_account_change_details_set_draft(
244 given_names: document.getElementById('given-names').value.slice(0, 256),
245 family_name: document.getElementById('family-name').value.slice(0, 256),
246 contact_me: document.getElementById('contact-me').checked ? true : false
250 //console.log('draft', await api_account_change_details_get_draft())
253 document.addEventListener(
256 let step_1_change_handler = () => {
258 document.getElementById('step-1-revert').disabled = false
259 document.getElementById('step-1-save').disabled = false
261 if (!draft_timeout_running) {
262 draft_timeout_running = true
263 setTimeout(draft_timeout_handler, 5000)
266 document.getElementById('given-names').addEventListener(
268 step_1_change_handler
270 document.getElementById('family-name').addEventListener(
272 step_1_change_handler
274 document.getElementById('contact-me').addEventListener(
276 step_1_change_handler
279 document.getElementById('step-1-revert').addEventListener(
282 $('#step-1-tick').hide()
283 $('#step-1-cross').hide()
284 $('#step-1-spinner').show()
288 details = await api_account_change_details_get()
292 error instanceof Problem ?
298 (error.stack || error.message).toString()
302 console.log(problem.detail)
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').hide()
314 document.getElementById('step-1-revert').disabled = true
315 document.getElementById('step-1-save').disabled = true
317 document.getElementById('given-names').value = details.given_names
318 document.getElementById('family-name').value = details.family_name
319 document.getElementById('contact-me').checked = details.contact_me
321 if (!draft_timeout_running) {
322 draft_timeout_running = true
323 setTimeout(draft_timeout_handler, 5000)
328 document.getElementById('step-1-save').addEventListener(
332 !document.getElementById('given-names').reportValidity() ||
333 !document.getElementById('family-name').reportValidity()
335 $('#step-1-tick').hide()
336 $('#step-1-cross').show()
337 $('#step-1-spinner').hide()
340 $('#step-1-tick').hide()
341 $('#step-1-cross').hide()
342 $('#step-1-spinner').show()
345 await api_account_change_details_set(
347 given_names: document.getElementById('given-names').value.slice(0, 256),
348 family_name: document.getElementById('family-name').value.slice(0, 256),
349 contact_me: document.getElementById('contact-me').checked ? true : false
355 error instanceof Problem ?
361 (error.stack || error.message).toString()
365 console.log(problem.detail)
367 $('#step-1-tick').hide()
368 $('#step-1-cross').show()
369 $('#step-1-spinner').hide()
372 $('#step-1-tick').show()
373 $('#step-1-cross').hide()
374 $('#step-1-spinner').hide()
377 document.getElementById('step-1-revert').disabled = true
378 document.getElementById('step-1-save').disabled = true
380 // SHOULD execute immediately here
381 // (because user is likely to leave the page after save)
382 if (!draft_timeout_running) {
383 draft_timeout_running = true
384 setTimeout(draft_timeout_handler, 5000)
389 let step_2_change_handler = () => {
390 document.getElementById('step-2-clear').disabled = false
391 document.getElementById('step-2-save').disabled = false
393 document.getElementById('old-password').addEventListener(
395 step_2_change_handler
397 document.getElementById('new-password').addEventListener(
399 step_2_change_handler
402 document.getElementById('step-2-clear').addEventListener(
405 document.getElementById('step-2-clear').disabled = true
406 document.getElementById('step-2-save').disabled = true
408 document.getElementById('old-password').value = ''
409 document.getElementById('new-password').value = ''
413 document.getElementById('step-2-save').addEventListener(
417 !document.getElementById('old-password').reportValidity() ||
418 !document.getElementById('new-password').reportValidity()
420 $('#step-2-tick').hide()
421 $('#step-2-cross').show()
422 $('#step-2-spinner').hide()
425 $('#step-2-tick').hide()
426 $('#step-2-cross').hide()
427 $('#step-2-spinner').show()
430 await api_account_change_password(
432 document.getElementById('old-password').value.slice(0, 256),
434 document.getElementById('new-password').value.slice(0, 256)
439 error instanceof Problem ?
445 (error.stack || error.message).toString()
449 console.log(problem.detail)
451 $('#step-2-tick').hide()
452 $('#step-2-cross').show()
453 $('#step-2-spinner').hide()
456 $('#step-2-tick').show()
457 $('#step-2-cross').hide()
458 $('#step-2-spinner').hide()
460 document.getElementById('step-2-clear').disabled = true
461 document.getElementById('step-2-save').disabled = true
463 document.getElementById('old-password').value = ''
464 document.getElementById('new-password').value = ''