1 let XDate = require('xdate')
4 let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
5 let get_session = await _require('/_lib/get_session.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')
10 // preload draft details if any
11 let transaction = await env.site.database.Transaction()
14 let root = await transaction.get({})
15 let session = await get_session(env, root)
17 let sign_up_draft = await session.get('sign_up_draft')
19 sign_up_draft !== undefined &&
20 XDate.now() < await sign_up_draft.get_json('expires') ?
22 email: await sign_up_draft.get_json('email'),
23 given_names: await sign_up_draft.get_json('given_names'),
24 family_name: await sign_up_draft.get_json('family_name'),
25 contact_me: await sign_up_draft.get_json('contact_me')
30 transaction.rollback()
32 console.log('draft_details', JSON.stringify(draft_details))
40 await breadcrumbs(env, _out)
42 p {'Signing up allows you to leave comments on our blog and receive communications from us.'}
44 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.'}
46 div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
48 div.card-header#step-1-heading(role="tab") {
49 span#step-1-tick(style="display: none;") {
50 span.icon-color.pr-3 {_out.push(icon_tick)}
52 span#step-1-cross(style="display: none;") {
53 span.icon-color.pr-3 {_out.push(icon_cross)}
55 //span#step-1-spinner(style="display: none;") {
56 // span.icon-color.pr-3 {
57 // div.spinner-border(role="status") {
58 // span.sr-only {'Loading...'}
62 a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
66 div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
71 label.form-label(for="given-names") {'Given names *'}
72 input.form-control#given-names(type="text" value=draft_details ? draft_details.given_names : '' placeholder="Your given names" required="required" maxlength=256) {}
77 label.form-label(for="family-name") {'Family name'}
78 input.form-control#family-name(type="text" value=draft_details ? draft_details.family_name : '' placeholder="Your family name" maxlength=256) {}
85 label.form-label(for="email") {'Email *'}
86 input.form-control#email(type="email" value=draft_details ? draft_details.email : '' placeholder="Your email address" required="required" maxlength=256) {}
91 label.form-label(for="password") {'Password *'}
92 input.form-control#password(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
98 div.custom-control.custom-checkbox {
99 if (!draft_details || draft_details.contact_me)
100 input.custom-control-input#contact-me(type="checkbox" checked="checked") {}
102 input.custom-control-input#contact-me(type="checkbox") {}
104 label.custom-control-label(for="contact-me") {
105 'Contact me by email with updates and special offers'
110 div.row.align-items-center.mb-3 {
113 label.form-label(for="verification-code") {'Verification code *'}
114 input.form-control#verification-code(type="text" placeholder="Type the code shown to the right" required="required" minlength=6 maxlength=6) {}
118 img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
120 div.'col-md-2'.my-auto.text-center {
121 button.btn.btn-outline-secondary#'step-1-new-code'(type="button") {'New code'}
125 button.btn.btn-success#step-1-continue(type="button") {'Continue'}
127 p.'mt-3'.mb-0 {'* These fields are required.'}
132 div.card-header#step-2-heading(role="tab") {
133 span#step-2-tick(style="display: none;") {
134 span.icon-color.pr-3 {_out.push(icon_tick)}
136 span#step-2-cross(style="display: none;") {
137 span.icon-color.pr-3 {_out.push(icon_cross)}
139 span#step-2-spinner(style="display: none;") {
140 span.icon-color.pr-3 {
141 div.spinner-border(role="status") {
142 span.sr-only {'Loading...'}
146 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
150 div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
152 p#step-2-message {'Please enter your details first.'}
154 button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
155 button.btn.btn-outline-secondary.ml-3#step-2-continue(type="button") {'Continue'}
160 div.card-header#step-3-heading(role="tab") {
161 span#step-3-tick(style="display: none;") {
162 span.icon-color.pr-3 {_out.push(icon_tick)}
164 span#step-3-cross(style="display: none;") {
165 span.icon-color.pr-3 {_out.push(icon_cross)}
167 span#step-3-spinner(style="display: none;") {
168 span.icon-color.pr-3 {
169 div.spinner-border(role="status") {
170 span.sr-only {'Loading...'}
174 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-3-collapse" aria-expanded="false" aria-controls="step-3-collapse") {
175 'Send email verification link'
178 div#step-3-collapse.collapse(role="tabpanel" aria-labelledby="step-3-heading" data-parent="#accordion") {
180 p#step-3-message {'Please create your account first.'}
182 button.btn.btn-outline-secondary#step-3-back(type="button") {'Back'}
183 button.btn.btn-outline-secondary.ml-3#step-3-resend-email(type="button") {'Re-send email'}
191 //script(src="/js/api_call.js") {}
194 let api_account_sign_up_create_account = async (...args) => api_call(
195 '/api/account/sign_up/create_account.json',
198 //let api_account_sign_up_get_draft = async (...args) => api_call(
199 // '/api/account/sign_up/get_draft.json',
202 let api_account_sign_up_set_draft = async (...args) => api_call(
203 '/api/account/sign_up/set_draft.json',
206 let api_account_sign_up_send_email_verification_link = async (...args) => api_call(
207 '/api/account/sign_up/send_email_verification_link.json',
211 let draft_timeout_running = false
212 let draft_timeout_handler = async () => {
213 draft_timeout_running = false
214 await api_account_sign_up_set_draft(
216 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
217 given_names: document.getElementById('given-names').value.slice(0, 256),
218 family_name: document.getElementById('family-name').value.slice(0, 256),
219 contact_me: document.getElementById('contact-me').checked ? true : false
222 //console.log('draft', await api_account_sign_up_get_draft())
224 let draft_change_handler = () => {
225 if (!draft_timeout_running) {
226 draft_timeout_running = true
227 setTimeout(draft_timeout_handler, 5000)
232 let step_1 = async () => {
234 !document.getElementById('given-names').reportValidity() ||
235 !document.getElementById('family-name').reportValidity() ||
236 !document.getElementById('email').reportValidity() ||
237 !document.getElementById('password').reportValidity() ||
238 !document.getElementById('verification-code').reportValidity()
240 $('#step-1-tick').hide()
241 $('#step-1-cross').show()
242 //$('#step-1-spinner').hide()
245 $('#step-1-tick').show()
246 $('#step-1-cross').hide()
247 //$('#step-1-spinner').hide()
250 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
251 given_names: document.getElementById('given-names').value.slice(0, 256),
252 family_name: document.getElementById('family-name').value.slice(0, 256),
253 password: document.getElementById('password').value.slice(0, 256),
254 contact_me: document.getElementById('contact-me').checked ? true : false
259 let step_2 = async () => {
260 $('#step-2-tick').hide()
261 $('#step-2-cross').hide()
262 $('#step-2-spinner').show()
263 document.getElementById('step-2').scrollIntoView()
266 await api_account_sign_up_create_account(
268 document.getElementById('verification-code').value.slice(0, 6).toLowerCase(),
275 error instanceof Problem ?
281 (error.stack || error.message).toString()
286 $('#step-2-tick').hide()
287 $('#step-2-cross').show()
288 $('#step-2-spinner').hide()
290 document.getElementById('step-2-message').textContent = problem.detail
291 $('#step-2-collapse').collapse('show')
294 $('#step-2-tick').show()
295 $('#step-2-cross').hide()
296 $('#step-2-spinner').hide()
297 document.getElementById('step-2-message').textContent = `Your account with email "${details.email}" has been created.`
301 let step_3 = async () => {
302 $('#step-3-tick').hide()
303 $('#step-3-cross').hide()
304 $('#step-3-spinner').show()
305 document.getElementById('step-3').scrollIntoView()
308 await api_account_sign_up_send_email_verification_link(details.email)
312 error instanceof Problem ?
318 (error.stack || error.message).toString()
323 $('#step-3-tick').hide()
324 $('#step-3-cross').show()
325 $('#step-3-spinner').hide()
327 document.getElementById('step-3-message').textContent = problem.detail
328 $('#step-3-collapse').collapse('show')
331 $('#step-3-tick').show()
332 $('#step-3-cross').hide()
333 $('#step-3-spinner').hide()
335 document.getElementById('step-3-message').textContent = `Email verification link has been sent to "${details.email}". Please check your email for next steps.`
339 document.addEventListener(
342 document.getElementById('given-names').addEventListener(
346 document.getElementById('family-name').addEventListener(
350 document.getElementById('email').addEventListener(
354 document.getElementById('password').addEventListener(
358 document.getElementById('contact-me').addEventListener(
364 document.getElementById('step-1-new-code').addEventListener(
367 document.getElementById('verification-image').src = `/api/verification_image.png?seq=${image_seq}`
372 document.getElementById('step-1-continue').addEventListener(
375 if (await step_1() && await step_2() && await step_3())
376 $('#step-3-collapse').collapse('show')
380 document.getElementById('step-2-back').addEventListener(
382 () => {$('#step-1-collapse').collapse('show')}
385 document.getElementById('step-2-continue').addEventListener(
389 $('#step-3-collapse').collapse('show')
393 document.getElementById('step-3-back').addEventListener(
395 () => {$('#step-2-collapse').collapse('show')}
398 document.getElementById('step-3-resend-email').addEventListener(
402 $('#step-3-collapse').collapse('show')