1 let logjson = (await import('@ndcode/logjson')).default
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 navbar = await _require('/_lib/navbar.jst')
8 let session_cookie = await _require('/_lib/session_cookie.jst')
10 // preload draft details if any
11 let transaction = await env.site.database.Transaction(), details
13 // initialize env.session_key, set cookie in env.response
14 let session = await session_cookie(env, transaction)
16 details = await logjson.logjson_to_json(
17 await session.get('sign_up_draft', {})
21 transaction.rollback()
23 console.log('details', JSON.stringify(details))
31 await breadcrumbs(env, _out)
33 p {'Signing up allows you to leave comments on our blog and receive communications from us.'}
35 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
37 div.card-header#step-1-heading(role="tab") {
38 span#step-1-tick(style="display: none;") {
39 span.icon-color.pr-3 {_out.push(icon_tick)}
41 span#step-1-cross(style="display: none;") {
42 span.icon-color.pr-3 {_out.push(icon_cross)}
44 //span#step-1-spinner(style="display: none;") {
45 // span.icon-color.pr-3 {
46 // div.spinner-border(role="status") {
47 // span.sr-only {'Loading...'}
51 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
55 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
60 label.form-label(for="given-names") {'Given names *'}
61 input.form-control#given-names(type="text" value=details.given_names || '' placeholder="Your given names" required="required" maxlength=256) {}
66 label.form-label(for="family-name") {'Family name'}
67 input.form-control#family-name(type="text" value=details.family_name || '' placeholder="Your family name" maxlength=256) {}
74 label.form-label(for="email") {'Email *'}
75 input.form-control#email(type="email" value=details.email || '' placeholder="Your email address" required="required" maxlength=256) {}
80 label.form-label(for="password") {'Password *'}
81 input.form-control#password(type="password" value=details.password || '' placeholder="New password" required="required" minlength=8 maxlength=256) {}
87 div.custom-control.custom-checkbox {
88 if (details.contact_me === undefined || details.contact_me)
89 input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
91 input.custom-control-input#contact-me(type="checkbox") {}
93 label.custom-control-label(for="contact-me") {
94 'Contact me by email with updates and special offers'
99 div.row.align-items-center {
102 label.form-label(for="verification-code") {'Verification code *'}
103 input.form-control#verification-code(type="text" placeholder="Type the code shown to the right" required="required" minlength=6 maxlength=6) {}
107 img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
109 div.'col-md-2'.my-auto.text-center {
110 button.btn.btn-outline-secondary#'step-1-new-code'(type="button") {'New code'}
114 p.mt-3 {'Note: If your name is one word or does not fit given names/family name pattern, then please enter given names only. Your given names are visible to other users if you comment on our blog. Your email and family name remain private.'}
116 button.btn.btn-success#step-1-continue(type="button") {'Continue'}
117 p.'mt-3'.mb-0 {'* These fields are required.'}
122 div.card-header#step-2-heading(role="tab") {
123 span#step-2-tick(style="display: none;") {
124 span.icon-color.pr-3 {_out.push(icon_tick)}
126 span#step-2-cross(style="display: none;") {
127 span.icon-color.pr-3 {_out.push(icon_cross)}
129 span#step-2-spinner(style="display: none;") {
130 span.icon-color.pr-3 {
131 div.spinner-border(role="status") {
132 span.sr-only {'Loading...'}
136 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
140 div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
142 p#step-2-message {'Please enter your details first.'}
144 button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
145 button.btn.btn-outline-secondary.ml-3#step-2-continue(type="button") {'Continue'}
150 div.card-header#step-3-heading(role="tab") {
151 span#step-3-tick(style="display: none;") {
152 span.icon-color.pr-3 {_out.push(icon_tick)}
154 span#step-3-cross(style="display: none;") {
155 span.icon-color.pr-3 {_out.push(icon_cross)}
157 span#step-3-spinner(style="display: none;") {
158 span.icon-color.pr-3 {
159 div.spinner-border(role="status") {
160 span.sr-only {'Loading...'}
164 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-3-collapse" aria-expanded="false" aria-controls="step-3-collapse") {
165 'Send email verification link'
168 div#step-3-collapse.collapse(role="tabpanel" aria-labelledby="step-3-heading" data-parent="#accordion") {
170 p#step-3-message {'Please create your account first.'}
172 button.btn.btn-outline-secondary#step-3-back(type="button") {'Back'}
173 button.btn.btn-outline-secondary.ml-3#step-3-resend-email(type="button") {'Re-send email'}
181 script(src="/js/api_call.js") {}
184 let sign_up_create_account = async (...arguments) => api_call(
185 '/api/sign_up/create_account.json',
188 //let sign_up_get_draft = async (...arguments) => api_call(
189 // '/api/sign_up/get_draft.json',
192 let sign_up_set_draft = async (...arguments) => api_call(
193 '/api/sign_up/set_draft.json',
196 let sign_up_send_email_verification_link = async (...arguments) => api_call(
197 '/api/sign_up/send_email_verification_link.json',
201 let coerce_details = () => {
203 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
204 given_names: document.getElementById('given-names').value.slice(0, 256),
205 family_name: document.getElementById('family-name').value.slice(0, 256),
206 password: document.getElementById('password').value.slice(0, 256),
207 contact_me: document.getElementById('contact-me').checked ? true : false
211 let draft_timeout_running = false
212 let draft_timeout_handler = async () => {
213 draft_timeout_running = false
214 await sign_up_set_draft(coerce_details())
215 //console.log('draft', await sign_up_get_draft())
217 let draft_change_handler = () => {
218 if (!draft_timeout_running) {
219 draft_timeout_running = true
220 setTimeout(draft_timeout_handler, 5000)
224 let step_1 = async () => {
226 !document.getElementById('given-names').reportValidity() ||
227 !document.getElementById('family-name').reportValidity() ||
228 !document.getElementById('email').reportValidity() ||
229 !document.getElementById('password').reportValidity() ||
230 !document.getElementById('verification-code').reportValidity()
232 $('#step-1-tick').hide()
233 $('#step-1-cross').show()
234 //$('#step-1-spinner').hide()
237 $('#step-1-tick').show()
238 $('#step-1-cross').hide()
239 //$('#step-1-spinner').hide()
243 let step_2_details = ''
244 let step_2 = async () => {
245 $('#step-2-tick').hide()
246 $('#step-2-cross').hide()
247 $('#step-2-spinner').show()
248 document.getElementById('step-2').scrollIntoView()
251 step_2_details = coerce_details()
252 await sign_up_create_account(
254 document.getElementById('verification-code').value.slice(0, 6).toLowerCase(),
261 error instanceof Problem ?
267 (error.stack || error.message).toString()
272 $('#step-2-tick').hide()
273 $('#step-2-cross').show()
274 $('#step-2-spinner').hide()
276 document.getElementById('step-2-message').textContent = problem.detail
277 $('#step-2-collapse').collapse('show')
280 $('#step-2-tick').show()
281 $('#step-2-cross').hide()
282 $('#step-2-spinner').hide()
283 document.getElementById('step-2-message').textContent = `Your account with email "${step_2_details.email}" has been created.`
287 let step_3 = async () => {
288 $('#step-3-tick').hide()
289 $('#step-3-cross').hide()
290 $('#step-3-spinner').show()
291 document.getElementById('step-3').scrollIntoView()
294 await sign_up_send_email_verification_link(step_2_details.email)
298 error instanceof Problem ?
304 (error.stack || error.message).toString()
309 $('#step-3-tick').hide()
310 $('#step-3-cross').show()
311 $('#step-3-spinner').hide()
313 document.getElementById('step-3-message').textContent = problem.detail
314 $('#step-3-collapse').collapse('show')
317 $('#step-3-tick').show()
318 $('#step-3-cross').hide()
319 $('#step-3-spinner').hide()
321 document.getElementById('step-3-message').textContent = `Email verification link has been sent to "${step_2_details.email}". Please check your email for next steps.`
325 document.addEventListener(
328 document.getElementById('given-names').addEventListener(
332 document.getElementById('family-name').addEventListener(
336 document.getElementById('email').addEventListener(
340 document.getElementById('password').addEventListener(
344 document.getElementById('contact-me').addEventListener(
350 document.getElementById('step-1-new-code').addEventListener(
353 document.getElementById('verification-image').src = `/api/verification_image.png?seq=${image_seq}`
358 document.getElementById('step-1-continue').addEventListener(
361 if (await step_1() && await step_2() && await step_3())
362 $('#step-3-collapse').collapse('show')
366 document.getElementById('step-2-back').addEventListener(
368 () => {$('#step-1-collapse').collapse('show')}
371 document.getElementById('step-2-continue').addEventListener(
375 $('#step-3-collapse').collapse('show')
379 document.getElementById('step-3-back').addEventListener(
381 () => {$('#step-2-collapse').collapse('show')}
384 document.getElementById('step-3-resend-email').addEventListener(
388 $('#step-3-collapse').collapse('show')