1 let logjson = (await import('@ndcode/logjson')).default
2 let XDate = require('xdate')
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 menu = await env.site.get_menu('/my_account/_menu.json')
9 let navbar = await _require('/_lib/navbar.jst')
10 let session_cookie = await _require('/_lib/session_cookie.jst')
12 // see whether signed in, if so preload details, and draft details if any
14 transaction = await env.site.database.Transaction(),
18 // initialize env.session_key, set cookie in env.response
19 let session = await session_cookie(env, transaction)
20 if (env.signed_in_as) {
23 await transaction.get({})
25 ).get(env.signed_in_as)
27 given_names: await logjson.logjson_to_json(
28 await account.get('given_names')
30 family_name: await logjson.logjson_to_json(
31 await account.get('family_name')
33 contact_me: await logjson.logjson_to_json(
34 await account.get('contact_me')
38 let change_details_draft = await session.get('change_details_draft')
40 change_details_draft !== undefined &&
41 XDate.now() < await logjson.logjson_to_json(
42 await change_details_draft.get('expires')
44 given_names: await logjson.logjson_to_json(
45 await change_details_draft.get('given_names')
47 family_name: await logjson.logjson_to_json(
48 await change_details_draft.get('family_name')
50 contact_me: await logjson.logjson_to_json(
51 await change_details_draft.get('contact_me')
55 await transaction.commit()
58 transaction.rollback()
63 JSON.stringify(details),
65 JSON.stringify(draft_details)
74 await breadcrumbs(env, _out)
76 if (env.signed_in_as) {
78 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.'}
80 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
82 div.card-header#step-1-heading(role="tab") {
83 span#step-1-tick(style="display: none;") {
84 span.icon-color.pr-3 {_out.push(icon_tick)}
86 span#step-1-cross(style="display: none;") {
87 span.icon-color.pr-3 {_out.push(icon_cross)}
89 //span#step-1-spinner(style="display: none;") {
90 // span.icon-color.pr-3 {
91 // div.spinner-border(role="status") {
92 // span.sr-only {'Loading...'}
96 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
100 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
105 label.form-label(for="given-names") {'Given names *'}
106 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) {}
111 label.form-label(for="family-name") {'Family name'}
112 input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : details.family_name placeholder="Your family name" maxlength=256) {}
118 div.custom-control.custom-checkbox {
119 if (draft_details ? draft_details.contact_me : details.contact_me)
120 input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
122 input.custom-control-input#contact-me(type="checkbox") {}
124 label.custom-control-label(for="contact-me") {
125 'Contact me by email with updates and special offers'
132 button.btn.btn-outline-secondary#step-1-revert(type="button") {'Revert'}
134 button.btn.btn-outline-secondary#step-1-revert(type="button" disabled="disabled") {'Revert'}
136 button.btn.btn-success.ml-3#step-1-save(type="button") {'Save'}
138 button.btn.btn-success.ml-3#step-1-save(type="button" disabled="disabled") {'Save'}
140 p.'mt-3'.mb-0 {'* These fields are required.'}
145 div.card-header#step-2-heading(role="tab") {
146 span#step-2-tick(style="display: none;") {
147 span.icon-color.pr-3 {_out.push(icon_tick)}
149 span#step-2-cross(style="display: none;") {
150 span.icon-color.pr-3 {_out.push(icon_cross)}
152 span#step-2-spinner(style="display: none;") {
153 span.icon-color.pr-3 {
154 div.spinner-border(role="status") {
155 span.sr-only {'Loading...'}
159 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
163 div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
168 label.form-label(for="old-password") {'Old password *'}
169 input.form-control#old-password(type="password" placeholder="Old password" required="required" minlength=8 maxlength=256) {}
174 label.form-label(for="new-password") {'New password *'}
175 input.form-control#'new-password'(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
180 button.btn.btn-outline-secondary#step-2-clear(type="button" disabled="disabled") {'Clear'}
181 button.btn.btn-success.ml-3#step-2-save(type="button" disabled="disabled") {'Save'}
183 p.'mt-3'.mb-0 {'* These fields are required.'}
191 p {'For account maintenance, please click on one of the options below.'}
194 let entries = menu.entries
195 for (let i = 0; i < entries.length; ++i) {
196 let entry = entries[i]
197 if (Object.prototype.hasOwnProperty.call(entry, 'icon'))
199 a.nav-link(href=`${entry.dir}/index.html`) {
200 table.icon-and-text {
203 _out.push(await env.site.get_min_svg(entry.icon))
206 span.h2{`${entry.name}`}
219 // this will be called by navbar logic after sign in/out
220 function sign_in_out(status) {
221 window.location.reload()
225 if (env.signed_in_as) {
226 //script(src="/js/api_call.js") {}
229 let api_account_change_details_get = async (...args) => api_call(
230 '/api/account/change_details/get.json',
233 let api_account_change_details_set = async (...args) => api_call(
234 '/api/account/change_details/set.json',
237 //let api_account_change_details_get_draft = async (...args) => api_call(
238 // '/api/account/change_details/get_draft.json',
241 let api_account_change_details_set_draft = async (...args) => api_call(
242 '/api/account/change_details/set_draft.json',
245 let api_account_change_password = async (...args) => api_call(
246 '/api/account/change_password.json',
250 let step_1_dirty = ${JSON.stringify(draft_details !== null)}
251 let draft_timeout_running = false
252 let draft_timeout_handler = async () => {
253 draft_timeout_running = false
254 await api_account_change_details_set_draft(
256 given_names: document.getElementById('given-names').value.slice(0, 256),
257 family_name: document.getElementById('family-name').value.slice(0, 256),
258 contact_me: document.getElementById('contact-me').checked ? true : false
261 //console.log('draft', await api_account_change_details_get_draft())
264 document.addEventListener(
267 let step_1_change_handler = () => {
269 document.getElementById('step-1-revert').disabled = false
270 document.getElementById('step-1-save').disabled = false
272 if (!draft_timeout_running) {
273 draft_timeout_running = true
274 setTimeout(draft_timeout_handler, 5000)
277 document.getElementById('given-names').addEventListener(
279 step_1_change_handler
281 document.getElementById('family-name').addEventListener(
283 step_1_change_handler
285 document.getElementById('contact-me').addEventListener(
287 step_1_change_handler
290 document.getElementById('step-1-revert').addEventListener(
293 $('#step-1-tick').hide()
294 $('#step-1-cross').hide()
295 $('#step-1-spinner').show()
299 details = await api_account_change_details_get()
303 error instanceof Problem ?
309 (error.stack || error.message).toString()
313 console.log(problem.detail)
315 $('#step-1-tick').hide()
316 $('#step-1-cross').show()
317 $('#step-1-spinner').hide()
320 $('#step-1-tick').hide()
321 $('#step-1-cross').hide()
322 $('#step-1-spinner').hide()
325 document.getElementById('step-1-revert').disabled = true
326 document.getElementById('step-1-save').disabled = true
328 document.getElementById('given-names').value = details.given_names
329 document.getElementById('family-name').value = details.family_name
330 document.getElementById('contact-me').checked = details.contact_me
332 if (!draft_timeout_running) {
333 draft_timeout_running = true
334 setTimeout(draft_timeout_handler, 5000)
339 document.getElementById('step-1-save').addEventListener(
343 !document.getElementById('given-names').reportValidity() ||
344 !document.getElementById('family-name').reportValidity()
346 $('#step-1-tick').hide()
347 $('#step-1-cross').show()
348 $('#step-1-spinner').hide()
351 $('#step-1-tick').hide()
352 $('#step-1-cross').hide()
353 $('#step-1-spinner').show()
356 await api_account_change_details_set(
358 given_names: document.getElementById('given-names').value.slice(0, 256),
359 family_name: document.getElementById('family-name').value.slice(0, 256),
360 contact_me: document.getElementById('contact-me').checked ? true : false
366 error instanceof Problem ?
372 (error.stack || error.message).toString()
376 console.log(problem.detail)
378 $('#step-1-tick').hide()
379 $('#step-1-cross').show()
380 $('#step-1-spinner').hide()
383 $('#step-1-tick').show()
384 $('#step-1-cross').hide()
385 $('#step-1-spinner').hide()
388 document.getElementById('step-1-revert').disabled = true
389 document.getElementById('step-1-save').disabled = true
391 // SHOULD execute immediately here
392 // (because user is likely to leave the page after save)
393 if (!draft_timeout_running) {
394 draft_timeout_running = true
395 setTimeout(draft_timeout_handler, 5000)
400 let step_2_change_handler = () => {
401 document.getElementById('step-2-clear').disabled = false
402 document.getElementById('step-2-save').disabled = false
404 document.getElementById('old-password').addEventListener(
406 step_2_change_handler
408 document.getElementById('new-password').addEventListener(
410 step_2_change_handler
413 document.getElementById('step-2-clear').addEventListener(
416 document.getElementById('step-2-clear').disabled = true
417 document.getElementById('step-2-save').disabled = true
419 document.getElementById('old-password').value = ''
420 document.getElementById('new-password').value = ''
424 document.getElementById('step-2-save').addEventListener(
428 !document.getElementById('old-password').reportValidity() ||
429 !document.getElementById('new-password').reportValidity()
431 $('#step-2-tick').hide()
432 $('#step-2-cross').show()
433 $('#step-2-spinner').hide()
436 $('#step-2-tick').hide()
437 $('#step-2-cross').hide()
438 $('#step-2-spinner').show()
441 await api_account_change_password(
443 document.getElementById('old-password').value.slice(0, 256),
445 document.getElementById('new-password').value.slice(0, 256)
450 error instanceof Problem ?
456 (error.stack || error.message).toString()
460 console.log(problem.detail)
462 $('#step-2-tick').hide()
463 $('#step-2-cross').show()
464 $('#step-2-spinner').hide()
467 $('#step-2-tick').show()
468 $('#step-2-cross').hide()
469 $('#step-2-spinner').hide()
471 document.getElementById('step-2-clear').disabled = true
472 document.getElementById('step-2-save').disabled = true
474 document.getElementById('old-password').value = ''
475 document.getElementById('new-password').value = ''