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()
14 let signed_in_as, details, draft_details
16 let root = await transaction.get({})
18 let session = await get_session(env, root)
19 signed_in_as = await session.get_json('signed_in_as', null)
21 let account = await get_account(root, session)
22 if (account !== undefined) {
24 given_names: await account.get_json('given_names'),
25 family_name: await account.get_json('family_name'),
26 contact_me: await account.get_json('contact_me')
29 let change_details_draft = await session.get('change_details_draft')
31 change_details_draft !== undefined &&
32 XDate.now() < await change_details_draft.get_json('expires') ?
34 given_names: await change_details_draft.get_json('given_names'),
35 family_name: await change_details_draft.get_json('family_name'),
36 contact_me: await change_details_draft.get_json('contact_me')
42 transaction.rollback()
46 JSON.stringify(details),
48 JSON.stringify(draft_details)
57 await breadcrumbs(env, _out)
59 if (signed_in_as !== null) {
61 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.'}
63 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
65 div.card-header#step-1-heading(role="tab") {
66 span#step-1-tick(style="display: none;") {
67 span.icon-color.pr-3 {_out.push(icon_tick)}
69 span#step-1-cross(style="display: none;") {
70 span.icon-color.pr-3 {_out.push(icon_cross)}
72 //span#step-1-spinner(style="display: none;") {
73 // span.icon-color.pr-3 {
74 // div.spinner-border(role="status") {
75 // span.sr-only {'Loading...'}
79 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
83 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
88 label.form-label(for="given-names") {'Given names *'}
89 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) {}
94 label.form-label(for="family-name") {'Family name'}
95 input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : details.family_name placeholder="Your family name" maxlength=256) {}
101 div.custom-control.custom-checkbox {
102 if (draft_details ? draft_details.contact_me : details.contact_me)
103 input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
105 input.custom-control-input#contact-me(type="checkbox") {}
107 label.custom-control-label(for="contact-me") {
108 'Contact me by email with updates and special offers'
115 button.btn.btn-outline-secondary#step-1-revert(type="button") {'Revert'}
117 button.btn.btn-outline-secondary#step-1-revert(type="button" disabled="disabled") {'Revert'}
119 button.btn.btn-success.ml-3#step-1-save(type="button") {'Save'}
121 button.btn.btn-success.ml-3#step-1-save(type="button" disabled="disabled") {'Save'}
123 p.'mt-3'.mb-0 {'* These fields are required.'}
128 div.card-header#step-2-heading(role="tab") {
129 span#step-2-tick(style="display: none;") {
130 span.icon-color.pr-3 {_out.push(icon_tick)}
132 span#step-2-cross(style="display: none;") {
133 span.icon-color.pr-3 {_out.push(icon_cross)}
135 span#step-2-spinner(style="display: none;") {
136 span.icon-color.pr-3 {
137 div.spinner-border(role="status") {
138 span.sr-only {'Loading...'}
142 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
146 div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
151 label.form-label(for="old-password") {'Old password *'}
152 input.form-control#old-password(type="password" placeholder="Old password" required="required" minlength=8 maxlength=256) {}
157 label.form-label(for="new-password") {'New password *'}
158 input.form-control#'new-password'(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
163 button.btn.btn-outline-secondary#step-2-clear(type="button" disabled="disabled") {'Clear'}
164 button.btn.btn-success.ml-3#step-2-save(type="button" disabled="disabled") {'Save'}
166 p.'mt-3'.mb-0 {'* These fields are required.'}
174 p {'For account maintenance, please click on one of the options below.'}
177 let entries = menu.entries
178 for (let i = 0; i < entries.length; ++i) {
179 let entry = entries[i]
180 if (Object.prototype.hasOwnProperty.call(entry, 'icon'))
182 a.nav-link(href=`${entry.dir}/index.html`) {
183 table.icon-and-text {
186 _out.push(await env.site.get_min_svg(entry.icon))
189 span.h2{`${entry.name}`}
202 // this will be called by navbar logic after sign in/out
203 function sign_in_out(status) {
204 window.location.reload()
208 if (signed_in_as !== null) {
209 //script(src="/js/api_call.js") {}
212 let api_account_change_details_get = async (...args) => api_call(
213 '/api/account/change_details/get.json',
216 let api_account_change_details_set = async (...args) => api_call(
217 '/api/account/change_details/set.json',
220 //let api_account_change_details_get_draft = async (...args) => api_call(
221 // '/api/account/change_details/get_draft.json',
224 let api_account_change_details_set_draft = async (...args) => api_call(
225 '/api/account/change_details/set_draft.json',
228 let api_account_change_password = async (...args) => api_call(
229 '/api/account/change_password.json',
233 let step_1_dirty = ${JSON.stringify(draft_details !== null)}
234 let draft_timeout_running = false
235 let draft_timeout_handler = async () => {
236 draft_timeout_running = false
237 await api_account_change_details_set_draft(
240 given_names: document.getElementById('given-names').value.slice(0, 256),
241 family_name: document.getElementById('family-name').value.slice(0, 256),
242 contact_me: document.getElementById('contact-me').checked ? true : false
246 //console.log('draft', await api_account_change_details_get_draft())
249 document.addEventListener(
252 let step_1_change_handler = () => {
254 document.getElementById('step-1-revert').disabled = false
255 document.getElementById('step-1-save').disabled = false
257 if (!draft_timeout_running) {
258 draft_timeout_running = true
259 setTimeout(draft_timeout_handler, 5000)
262 document.getElementById('given-names').addEventListener(
264 step_1_change_handler
266 document.getElementById('family-name').addEventListener(
268 step_1_change_handler
270 document.getElementById('contact-me').addEventListener(
272 step_1_change_handler
275 document.getElementById('step-1-revert').addEventListener(
278 $('#step-1-tick').hide()
279 $('#step-1-cross').hide()
280 $('#step-1-spinner').show()
284 details = await api_account_change_details_get()
288 error instanceof Problem ?
294 (error.stack || error.message).toString()
298 console.log(problem.detail)
300 $('#step-1-tick').hide()
301 $('#step-1-cross').show()
302 $('#step-1-spinner').hide()
305 $('#step-1-tick').hide()
306 $('#step-1-cross').hide()
307 $('#step-1-spinner').hide()
310 document.getElementById('step-1-revert').disabled = true
311 document.getElementById('step-1-save').disabled = true
313 document.getElementById('given-names').value = details.given_names
314 document.getElementById('family-name').value = details.family_name
315 document.getElementById('contact-me').checked = details.contact_me
317 if (!draft_timeout_running) {
318 draft_timeout_running = true
319 setTimeout(draft_timeout_handler, 5000)
324 document.getElementById('step-1-save').addEventListener(
328 !document.getElementById('given-names').reportValidity() ||
329 !document.getElementById('family-name').reportValidity()
331 $('#step-1-tick').hide()
332 $('#step-1-cross').show()
333 $('#step-1-spinner').hide()
336 $('#step-1-tick').hide()
337 $('#step-1-cross').hide()
338 $('#step-1-spinner').show()
341 await api_account_change_details_set(
343 given_names: document.getElementById('given-names').value.slice(0, 256),
344 family_name: document.getElementById('family-name').value.slice(0, 256),
345 contact_me: document.getElementById('contact-me').checked ? true : false
351 error instanceof Problem ?
357 (error.stack || error.message).toString()
361 console.log(problem.detail)
363 $('#step-1-tick').hide()
364 $('#step-1-cross').show()
365 $('#step-1-spinner').hide()
368 $('#step-1-tick').show()
369 $('#step-1-cross').hide()
370 $('#step-1-spinner').hide()
373 document.getElementById('step-1-revert').disabled = true
374 document.getElementById('step-1-save').disabled = true
376 // SHOULD execute immediately here
377 // (because user is likely to leave the page after save)
378 if (!draft_timeout_running) {
379 draft_timeout_running = true
380 setTimeout(draft_timeout_handler, 5000)
385 let step_2_change_handler = () => {
386 document.getElementById('step-2-clear').disabled = false
387 document.getElementById('step-2-save').disabled = false
389 document.getElementById('old-password').addEventListener(
391 step_2_change_handler
393 document.getElementById('new-password').addEventListener(
395 step_2_change_handler
398 document.getElementById('step-2-clear').addEventListener(
401 document.getElementById('step-2-clear').disabled = true
402 document.getElementById('step-2-save').disabled = true
404 document.getElementById('old-password').value = ''
405 document.getElementById('new-password').value = ''
409 document.getElementById('step-2-save').addEventListener(
413 !document.getElementById('old-password').reportValidity() ||
414 !document.getElementById('new-password').reportValidity()
416 $('#step-2-tick').hide()
417 $('#step-2-cross').show()
418 $('#step-2-spinner').hide()
421 $('#step-2-tick').hide()
422 $('#step-2-cross').hide()
423 $('#step-2-spinner').show()
426 await api_account_change_password(
428 document.getElementById('old-password').value.slice(0, 256),
430 document.getElementById('new-password').value.slice(0, 256)
435 error instanceof Problem ?
441 (error.stack || error.message).toString()
445 console.log(problem.detail)
447 $('#step-2-tick').hide()
448 $('#step-2-cross').show()
449 $('#step-2-spinner').hide()
452 $('#step-2-tick').show()
453 $('#step-2-cross').hide()
454 $('#step-2-spinner').hide()
456 document.getElementById('step-2-clear').disabled = true
457 document.getElementById('step-2-save').disabled = true
459 document.getElementById('old-password').value = ''
460 document.getElementById('new-password').value = ''