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 navbar = await _require('/_lib/navbar.jst')
9 let session_cookie = await _require('/_lib/session_cookie.jst')
11 // preload draft details if any
12 let transaction = await env.site.database.Transaction(), draft_details
14 // initialize env.session_key, set cookie in env.response
15 let session = await session_cookie(env, transaction)
17 let sign_up_draft = await session.get('sign_up_draft')
19 sign_up_draft !== undefined &&
20 XDate.now() < await logjson.logjson_to_json(
21 await sign_up_draft.get('expires')
23 email: await logjson.logjson_to_json(
24 await sign_up_draft.get('email')
26 given_names: await logjson.logjson_to_json(
27 await sign_up_draft.get('given_names')
29 family_name: await logjson.logjson_to_json(
30 await sign_up_draft.get('family_name')
32 contact_me: await logjson.logjson_to_json(
33 await sign_up_draft.get('contact_me')
37 await transaction.commit()
40 transaction.rollback()
43 console.log('draft_details', JSON.stringify(draft_details))
51 await breadcrumbs(env, _out)
53 p {'Signing up allows you to leave comments on our blog and receive communications from us.'}
55 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.'}
57 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
59 div.card-header#step-1-heading(role="tab") {
60 span#step-1-tick(style="display: none;") {
61 span.icon-color.pr-3 {_out.push(icon_tick)}
63 span#step-1-cross(style="display: none;") {
64 span.icon-color.pr-3 {_out.push(icon_cross)}
66 //span#step-1-spinner(style="display: none;") {
67 // span.icon-color.pr-3 {
68 // div.spinner-border(role="status") {
69 // span.sr-only {'Loading...'}
73 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
77 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
82 label.form-label(for="given-names") {'Given names *'}
83 input.form-control#given-names(type="text" value=draft_details ? draft_details.given_names : '' placeholder="Your given names" required="required" maxlength=256) {}
88 label.form-label(for="family-name") {'Family name'}
89 input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : '' placeholder="Your family name" maxlength=256) {}
96 label.form-label(for="email") {'Email *'}
97 input.form-control#email(type="email" value=draft_details ? draft_details.email : '' placeholder="Your email address" required="required" maxlength=256) {}
102 label.form-label(for="password") {'Password *'}
103 input.form-control#password(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
109 div.custom-control.custom-checkbox {
110 if (!draft_details || draft_details.contact_me)
111 input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
113 input.custom-control-input#contact-me(type="checkbox") {}
115 label.custom-control-label(for="contact-me") {
116 'Contact me by email with updates and special offers'
121 div.row.align-items-center.mb-3 {
124 label.form-label(for="verification-code") {'Verification code *'}
125 input.form-control#verification-code(type="text" placeholder="Type the code shown to the right" required="required" minlength=6 maxlength=6) {}
129 img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
131 div.'col-md-2'.my-auto.text-center {
132 button.btn.btn-outline-secondary#'step-1-new-code'(type="button") {'New code'}
136 button.btn.btn-success#step-1-continue(type="button") {'Continue'}
138 p.'mt-3'.mb-0 {'* These fields are required.'}
143 div.card-header#step-2-heading(role="tab") {
144 span#step-2-tick(style="display: none;") {
145 span.icon-color.pr-3 {_out.push(icon_tick)}
147 span#step-2-cross(style="display: none;") {
148 span.icon-color.pr-3 {_out.push(icon_cross)}
150 span#step-2-spinner(style="display: none;") {
151 span.icon-color.pr-3 {
152 div.spinner-border(role="status") {
153 span.sr-only {'Loading...'}
157 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
161 div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
163 p#step-2-message {'Please enter your details first.'}
165 button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
166 button.btn.btn-outline-secondary.ml-3#step-2-continue(type="button") {'Continue'}
171 div.card-header#step-3-heading(role="tab") {
172 span#step-3-tick(style="display: none;") {
173 span.icon-color.pr-3 {_out.push(icon_tick)}
175 span#step-3-cross(style="display: none;") {
176 span.icon-color.pr-3 {_out.push(icon_cross)}
178 span#step-3-spinner(style="display: none;") {
179 span.icon-color.pr-3 {
180 div.spinner-border(role="status") {
181 span.sr-only {'Loading...'}
185 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-3-collapse" aria-expanded="false" aria-controls="step-3-collapse") {
186 'Send email verification link'
189 div#step-3-collapse.collapse(role="tabpanel" aria-labelledby="step-3-heading" data-parent="#accordion") {
191 p#step-3-message {'Please create your account first.'}
193 button.btn.btn-outline-secondary#step-3-back(type="button") {'Back'}
194 button.btn.btn-outline-secondary.ml-3#step-3-resend-email(type="button") {'Re-send email'}
202 script(src="/js/api_call.js") {}
205 let sign_up_create_account = async (...arguments) => api_call(
206 '/api/account/sign_up/create_account.json',
209 //let sign_up_get_draft = async (...arguments) => api_call(
210 // '/api/account/sign_up/get_draft.json',
213 let sign_up_set_draft = async (...arguments) => api_call(
214 '/api/account/sign_up/set_draft.json',
217 let sign_up_send_email_verification_link = async (...arguments) => api_call(
218 '/api/account/sign_up/send_email_verification_link.json',
222 let draft_timeout_running = false
223 let draft_timeout_handler = async () => {
224 draft_timeout_running = false
225 await sign_up_set_draft(
227 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
228 given_names: document.getElementById('given-names').value.slice(0, 256),
229 family_name: document.getElementById('family-name').value.slice(0, 256),
230 contact_me: document.getElementById('contact-me').checked ? true : false
233 //console.log('draft', await sign_up_get_draft())
235 let draft_change_handler = () => {
236 if (!draft_timeout_running) {
237 draft_timeout_running = true
238 setTimeout(draft_timeout_handler, 5000)
243 let step_1 = async () => {
245 !document.getElementById('given-names').reportValidity() ||
246 !document.getElementById('family-name').reportValidity() ||
247 !document.getElementById('email').reportValidity() ||
248 !document.getElementById('password').reportValidity() ||
249 !document.getElementById('verification-code').reportValidity()
251 $('#step-1-tick').hide()
252 $('#step-1-cross').show()
253 //$('#step-1-spinner').hide()
256 $('#step-1-tick').show()
257 $('#step-1-cross').hide()
258 //$('#step-1-spinner').hide()
261 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
262 given_names: document.getElementById('given-names').value.slice(0, 256),
263 family_name: document.getElementById('family-name').value.slice(0, 256),
264 password: document.getElementById('password').value.slice(0, 256),
265 contact_me: document.getElementById('contact-me').checked ? true : false
270 let step_2 = async () => {
271 $('#step-2-tick').hide()
272 $('#step-2-cross').hide()
273 $('#step-2-spinner').show()
274 document.getElementById('step-2').scrollIntoView()
277 await sign_up_create_account(
279 document.getElementById('verification-code').value.slice(0, 6).toLowerCase(),
286 error instanceof Problem ?
292 (error.stack || error.message).toString()
297 $('#step-2-tick').hide()
298 $('#step-2-cross').show()
299 $('#step-2-spinner').hide()
301 document.getElementById('step-2-message').textContent = problem.detail
302 $('#step-2-collapse').collapse('show')
305 $('#step-2-tick').show()
306 $('#step-2-cross').hide()
307 $('#step-2-spinner').hide()
308 document.getElementById('step-2-message').textContent = `Your account with email "${details.email}" has been created.`
312 let step_3 = async () => {
313 $('#step-3-tick').hide()
314 $('#step-3-cross').hide()
315 $('#step-3-spinner').show()
316 document.getElementById('step-3').scrollIntoView()
319 await sign_up_send_email_verification_link(details.email)
323 error instanceof Problem ?
329 (error.stack || error.message).toString()
334 $('#step-3-tick').hide()
335 $('#step-3-cross').show()
336 $('#step-3-spinner').hide()
338 document.getElementById('step-3-message').textContent = problem.detail
339 $('#step-3-collapse').collapse('show')
342 $('#step-3-tick').show()
343 $('#step-3-cross').hide()
344 $('#step-3-spinner').hide()
346 document.getElementById('step-3-message').textContent = `Email verification link has been sent to "${details.email}". Please check your email for next steps.`
350 document.addEventListener(
353 document.getElementById('given-names').addEventListener(
357 document.getElementById('family-name').addEventListener(
361 document.getElementById('email').addEventListener(
365 document.getElementById('password').addEventListener(
369 document.getElementById('contact-me').addEventListener(
375 document.getElementById('step-1-new-code').addEventListener(
378 document.getElementById('verification-image').src = `/api/verification_image.png?seq=${image_seq}`
383 document.getElementById('step-1-continue').addEventListener(
386 if (await step_1() && await step_2() && await step_3())
387 $('#step-3-collapse').collapse('show')
391 document.getElementById('step-2-back').addEventListener(
393 () => {$('#step-1-collapse').collapse('show')}
396 document.getElementById('step-2-continue').addEventListener(
400 $('#step-3-collapse').collapse('show')
404 document.getElementById('step-3-back').addEventListener(
406 () => {$('#step-2-collapse').collapse('show')}
409 document.getElementById('step-3-resend-email').addEventListener(
413 $('#step-3-collapse').collapse('show')