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 navbar = await _require('/_lib/navbar.jst')
8 let get_session = await _require('/_lib/get_session.jst')
10 // preload draft details if any
11 let transaction = await env.site.database.Transaction(), draft_details
13 // initialize env.session_key, set cookie in env.response
14 let session = await get_session(env, transaction)
16 let sign_up_draft = await session.get('sign_up_draft')
18 sign_up_draft !== undefined &&
19 XDate.now() < await sign_up_draft.get_json('expires') ?
21 email: await sign_up_draft.get_json('email'),
22 given_names: await sign_up_draft.get_json('given_names'),
23 family_name: await sign_up_draft.get_json('family_name'),
24 contact_me: await sign_up_draft.get_json('contact_me')
28 await transaction.commit()
31 transaction.rollback()
34 console.log('draft_details', JSON.stringify(draft_details))
42 await breadcrumbs(env, _out)
44 p {'Signing up allows you to leave comments on our blog and receive communications from us.'}
46 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.'}
48 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
50 div.card-header#step-1-heading(role="tab") {
51 span#step-1-tick(style="display: none;") {
52 span.icon-color.pr-3 {_out.push(icon_tick)}
54 span#step-1-cross(style="display: none;") {
55 span.icon-color.pr-3 {_out.push(icon_cross)}
57 //span#step-1-spinner(style="display: none;") {
58 // span.icon-color.pr-3 {
59 // div.spinner-border(role="status") {
60 // span.sr-only {'Loading...'}
64 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
68 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
73 label.form-label(for="given-names") {'Given names *'}
74 input.form-control#given-names(type="text" value=draft_details ? draft_details.given_names : '' placeholder="Your given names" required="required" maxlength=256) {}
79 label.form-label(for="family-name") {'Family name'}
80 input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : '' placeholder="Your family name" maxlength=256) {}
87 label.form-label(for="email") {'Email *'}
88 input.form-control#email(type="email" value=draft_details ? draft_details.email : '' placeholder="Your email address" required="required" maxlength=256) {}
93 label.form-label(for="password") {'Password *'}
94 input.form-control#password(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
100 div.custom-control.custom-checkbox {
101 if (!draft_details || draft_details.contact_me)
102 input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
104 input.custom-control-input#contact-me(type="checkbox") {}
106 label.custom-control-label(for="contact-me") {
107 'Contact me by email with updates and special offers'
112 div.row.align-items-center.mb-3 {
115 label.form-label(for="verification-code") {'Verification code *'}
116 input.form-control#verification-code(type="text" placeholder="Type the code shown to the right" required="required" minlength=6 maxlength=6) {}
120 img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
122 div.'col-md-2'.my-auto.text-center {
123 button.btn.btn-outline-secondary#'step-1-new-code'(type="button") {'New code'}
127 button.btn.btn-success#step-1-continue(type="button") {'Continue'}
129 p.'mt-3'.mb-0 {'* These fields are required.'}
134 div.card-header#step-2-heading(role="tab") {
135 span#step-2-tick(style="display: none;") {
136 span.icon-color.pr-3 {_out.push(icon_tick)}
138 span#step-2-cross(style="display: none;") {
139 span.icon-color.pr-3 {_out.push(icon_cross)}
141 span#step-2-spinner(style="display: none;") {
142 span.icon-color.pr-3 {
143 div.spinner-border(role="status") {
144 span.sr-only {'Loading...'}
148 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
152 div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
154 p#step-2-message {'Please enter your details first.'}
156 button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
157 button.btn.btn-outline-secondary.ml-3#step-2-continue(type="button") {'Continue'}
162 div.card-header#step-3-heading(role="tab") {
163 span#step-3-tick(style="display: none;") {
164 span.icon-color.pr-3 {_out.push(icon_tick)}
166 span#step-3-cross(style="display: none;") {
167 span.icon-color.pr-3 {_out.push(icon_cross)}
169 span#step-3-spinner(style="display: none;") {
170 span.icon-color.pr-3 {
171 div.spinner-border(role="status") {
172 span.sr-only {'Loading...'}
176 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-3-collapse" aria-expanded="false" aria-controls="step-3-collapse") {
177 'Send email verification link'
180 div#step-3-collapse.collapse(role="tabpanel" aria-labelledby="step-3-heading" data-parent="#accordion") {
182 p#step-3-message {'Please create your account first.'}
184 button.btn.btn-outline-secondary#step-3-back(type="button") {'Back'}
185 button.btn.btn-outline-secondary.ml-3#step-3-resend-email(type="button") {'Re-send email'}
193 //script(src="/js/api_call.js") {}
196 let api_account_sign_up_create_account = async (...args) => api_call(
197 '/api/account/sign_up/create_account.json',
200 //let api_account_sign_up_get_draft = async (...args) => api_call(
201 // '/api/account/sign_up/get_draft.json',
204 let api_account_sign_up_set_draft = async (...args) => api_call(
205 '/api/account/sign_up/set_draft.json',
208 let api_account_sign_up_send_email_verification_link = async (...args) => api_call(
209 '/api/account/sign_up/send_email_verification_link.json',
213 let draft_timeout_running = false
214 let draft_timeout_handler = async () => {
215 draft_timeout_running = false
216 await api_account_sign_up_set_draft(
218 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
219 given_names: document.getElementById('given-names').value.slice(0, 256),
220 family_name: document.getElementById('family-name').value.slice(0, 256),
221 contact_me: document.getElementById('contact-me').checked ? true : false
224 //console.log('draft', await api_account_sign_up_get_draft())
226 let draft_change_handler = () => {
227 if (!draft_timeout_running) {
228 draft_timeout_running = true
229 setTimeout(draft_timeout_handler, 5000)
234 let step_1 = async () => {
236 !document.getElementById('given-names').reportValidity() ||
237 !document.getElementById('family-name').reportValidity() ||
238 !document.getElementById('email').reportValidity() ||
239 !document.getElementById('password').reportValidity() ||
240 !document.getElementById('verification-code').reportValidity()
242 $('#step-1-tick').hide()
243 $('#step-1-cross').show()
244 //$('#step-1-spinner').hide()
247 $('#step-1-tick').show()
248 $('#step-1-cross').hide()
249 //$('#step-1-spinner').hide()
252 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
253 given_names: document.getElementById('given-names').value.slice(0, 256),
254 family_name: document.getElementById('family-name').value.slice(0, 256),
255 password: document.getElementById('password').value.slice(0, 256),
256 contact_me: document.getElementById('contact-me').checked ? true : false
261 let step_2 = async () => {
262 $('#step-2-tick').hide()
263 $('#step-2-cross').hide()
264 $('#step-2-spinner').show()
265 document.getElementById('step-2').scrollIntoView()
268 await api_account_sign_up_create_account(
270 document.getElementById('verification-code').value.slice(0, 6).toLowerCase(),
277 error instanceof Problem ?
283 (error.stack || error.message).toString()
288 $('#step-2-tick').hide()
289 $('#step-2-cross').show()
290 $('#step-2-spinner').hide()
292 document.getElementById('step-2-message').textContent = problem.detail
293 $('#step-2-collapse').collapse('show')
296 $('#step-2-tick').show()
297 $('#step-2-cross').hide()
298 $('#step-2-spinner').hide()
299 document.getElementById('step-2-message').textContent = `Your account with email "${details.email}" has been created.`
303 let step_3 = async () => {
304 $('#step-3-tick').hide()
305 $('#step-3-cross').hide()
306 $('#step-3-spinner').show()
307 document.getElementById('step-3').scrollIntoView()
310 await api_account_sign_up_send_email_verification_link(details.email)
314 error instanceof Problem ?
320 (error.stack || error.message).toString()
325 $('#step-3-tick').hide()
326 $('#step-3-cross').show()
327 $('#step-3-spinner').hide()
329 document.getElementById('step-3-message').textContent = problem.detail
330 $('#step-3-collapse').collapse('show')
333 $('#step-3-tick').show()
334 $('#step-3-cross').hide()
335 $('#step-3-spinner').hide()
337 document.getElementById('step-3-message').textContent = `Email verification link has been sent to "${details.email}". Please check your email for next steps.`
341 document.addEventListener(
344 document.getElementById('given-names').addEventListener(
348 document.getElementById('family-name').addEventListener(
352 document.getElementById('email').addEventListener(
356 document.getElementById('password').addEventListener(
360 document.getElementById('contact-me').addEventListener(
366 document.getElementById('step-1-new-code').addEventListener(
369 document.getElementById('verification-image').src = `/api/verification_image.png?seq=${image_seq}`
374 document.getElementById('step-1-continue').addEventListener(
377 if (await step_1() && await step_2() && await step_3())
378 $('#step-3-collapse').collapse('show')
382 document.getElementById('step-2-back').addEventListener(
384 () => {$('#step-1-collapse').collapse('show')}
387 document.getElementById('step-2-continue').addEventListener(
391 $('#step-3-collapse').collapse('show')
395 document.getElementById('step-3-back').addEventListener(
397 () => {$('#step-2-collapse').collapse('show')}
400 document.getElementById('step-3-resend-email').addEventListener(
404 $('#step-3-collapse').collapse('show')