2 let breadcrumbs = await _require('/_lib/breadcrumbs.jst')
3 let get_session = await _require('/_lib/get_session.jst')
4 let icon_cross = await env.site.get_min_svg('/_svg/icon_cross.svg')
5 let icon_tick = await env.site.get_min_svg('/_svg/icon_tick.svg')
6 let navbar = await _require('/_lib/navbar.jst')
8 // preload draft details if any
9 let transaction = await env.site.database.Transaction()
12 let root = await transaction.get({})
13 let session = await get_session(env, root)
14 sign_up_draft = await session.get_json('sign_up_draft')
15 if (sign_up_draft === undefined || env.now >= sign_up_draft.expires)
19 transaction.rollback()
28 await breadcrumbs(env, _out)
30 p {'Signing up allows you to leave comments on our blog and receive communications from us.'}
32 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.'}
34 div.accordion#accordion(role="tablist" aria-multiselectable="true") {
36 div.card-header#card-1-heading(role="tab") {
37 span#card-1-tick(style="display: none;") {
38 span.icon-color.pr-3 {_out.push(icon_tick)}
40 span#card-1-cross(style="display: none;") {
41 span.icon-color.pr-3 {_out.push(icon_cross)}
43 //span#card-1-spinner(style="display: none;") {
44 // span.icon-color.pr-3 {
45 // div.spinner-border(role="status") {
46 // span.sr-only {'Loading...'}
50 a.h5(data-toggle="collapse" data-parent="#accordion" href="#card-1-collapse" aria-expanded="true" aria-controls="card-1-collapse") {
54 div#card-1-collapse.collapse.show(role="tabpanel" aria-labelledby="card-1-heading" data-parent="#accordion") {
60 label.form-label(for="given-names") {'Given names *'}
61 input.form-control#given-names(type="text" value=sign_up_draft.given_names || '' placeholder="Miley" required maxlength=256) {}
62 div.invalid-feedback {'Please enter a name we can address you by.'}
67 label.form-label(for="family-name") {'Family name'}
68 input.form-control#family-name(type="text" value=sign_up_draft.family_name || '' placeholder="Chapman" maxlength=256) {}
75 label.form-label(for="email") {'Email *'}
76 input.form-control#email(type="email" value=sign_up_draft.email || '' placeholder="mileychapman@email.com" required maxlength=256) {}
77 div.invalid-feedback {'Please enter an email address we can contact you on.'}
82 label.form-label(for="password") {'Password *'}
83 input.form-control#password(type="password" placeholder="Choose" required minlength=8 maxlength=256) {}
84 div.invalid-feedback {'Please choose a secure password of at least 8 characters.'}
90 div.custom-control.custom-checkbox {
91 if (sign_up_draft === undefined || sign_up_draft.contact_me)
92 input.custom-control-input#contact-me(type="checkbox" checked) {}
94 input.custom-control-input#contact-me(type="checkbox") {}
96 label.custom-control-label(for="contact-me") {
97 'Contact me by email with updates and special offers'
102 div.row.align-items-center {
105 label.form-label(for="verification-code") {'Verification code *'}
106 input.form-control#verification-code(type="text" placeholder="ad7jb3" required minlength=6 maxlength=6) {}
107 div.invalid-feedback {'Please enter the 6 characters from the verification image to right or below. We need this to protect us from spam and bots.'}
110 div.'col-md-6'.my-3 {
111 img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
116 button.btn.btn-outline-secondary#'card-1-new-code'(type="button") {'New code'}
117 button.btn.btn-success.ml-3#card-1-create-account(type="button") {'Create account'}
119 p.'mt-3'.mb-0#card-1-message(style="display: none;") {}
124 div.card-header#card-2-heading(role="tab") {
125 span#card-2-tick(style="display: none;") {
126 span.icon-color.pr-3 {_out.push(icon_tick)}
128 span#card-2-cross(style="display: none;") {
129 span.icon-color.pr-3 {_out.push(icon_cross)}
131 span#card-2-spinner(style="display: none;") {
132 span.icon-color.pr-3 {
133 div.spinner-border(role="status") {
134 span.sr-only {'Loading...'}
138 a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#card-2-collapse" aria-expanded="false" aria-controls="card-2-collapse") {
139 'Send email verification link'
142 div#card-2-collapse.collapse(role="tabpanel" aria-labelledby="card-2-heading" data-parent="#accordion") {
144 button.btn.btn-outline-secondary#card-2-back(type="button") {'Back'}
145 button.btn.btn-outline-secondary.ml-3#card-2-resend-email(type="button") {'Re-send email'}
147 p.'mt-3'.mb-0#card-2-message(style="display: none;") {}
153 p.mt-3 {'* These fields are required.'}
157 //script(src="/js/utils.js") {}
160 let input_semaphore = new BinarySemaphore(false)
164 await input_semaphore.acquire()
165 await new Promise(resolve => setTimeout(resolve, 3000))
166 input_semaphore.try_acquire()
168 '/api/account/sign_up/set_draft.json',
170 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
171 given_names: document.getElementById('given-names').value.slice(0, 256),
172 family_name: document.getElementById('family-name').value.slice(0, 256),
173 contact_me: document.getElementById('contact-me').checked ? true : false
178 )() // ignore returned promise (start thread)
181 let card_1 = async () => {
182 if (!document.getElementById('form').checkValidity()) {
183 document.getElementById('form').classList.add('was-validated');
184 $('#card-1-tick').hide()
185 $('#card-1-cross').show()
186 //$('#card-1-spinner').hide()
189 document.getElementById('form').classList.remove('was-validated');
192 email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
193 given_names: document.getElementById('given-names').value.slice(0, 256),
194 family_name: document.getElementById('family-name').value.slice(0, 256),
195 password: document.getElementById('password').value.slice(0, 256),
196 contact_me: document.getElementById('contact-me').checked ? true : false
201 '/api/account/sign_up/create_account.json',
202 document.getElementById('verification-code').value.slice(0, 6).toLowerCase(),
207 let problem = Problem.from(error)
209 $('#card-1-tick').hide()
210 $('#card-1-cross').show()
211 $('#card-1-spinner').hide()
213 document.getElementById('card-1-message').textContent = problem.detail
214 //document.getElementById('card-1-message').classList.remove('text-success')
215 document.getElementById('card-1-message').classList.add('text-danger')
216 $('#card-1-message').show()
218 $('#card-1-collapse').collapse('show')
221 $('#card-1-tick').show()
222 $('#card-1-cross').hide()
223 $('#card-1-spinner').hide()
224 document.getElementById('card-1-message').textContent = `Your account with email "${details.email}" has been created.`
225 //document.getElementById('card-1-message').classList.add('text-success')
226 document.getElementById('card-1-message').classList.remove('text-danger')
227 $('#card-1-message').show()
231 let card_2 = async () => {
232 $('#card-2-tick').hide()
233 $('#card-2-cross').hide()
234 $('#card-2-spinner').show()
235 document.getElementById('card-2').scrollIntoView()
239 '/api/account/sign_up/send_email_verification_link.json',
244 let problem = Problem.from(error)
246 $('#card-2-tick').hide()
247 $('#card-2-cross').show()
248 $('#card-2-spinner').hide()
250 document.getElementById('card-2-message').textContent = problem.detail
251 //document.getElementById('card-2-message').classList.remove('text-success')
252 document.getElementById('card-2-message').classList.add('text-danger')
253 $('#card-2-message').show()
255 $('#card-2-collapse').collapse('show')
258 $('#card-2-tick').show()
259 $('#card-2-cross').hide()
260 $('#card-2-spinner').hide()
262 document.getElementById('card-2-message').textContent = `Email verification link has been sent to "${details.email}". Please check your email for next steps.`
263 //document.getElementById('card-2-message').classList.add('text-success')
264 document.getElementById('card-2-message').classList.remove('text-danger')
265 $('#card-2-message').show()
269 document.addEventListener(
272 document.getElementById('given-names').addEventListener(
274 () => {input_semaphore.release()}
276 document.getElementById('family-name').addEventListener(
278 () => {input_semaphore.release()}
280 document.getElementById('email').addEventListener(
282 () => {input_semaphore.release()}
284 //document.getElementById('password').addEventListener(
286 // () => {input_semaphore.release()}
288 document.getElementById('contact-me').addEventListener(
290 () => {input_semaphore.release()}
292 //document.getElementById('verification-code').addEventListener(
294 // () => {input_semaphore.release()}
298 document.getElementById('card-1-new-code').addEventListener(
301 document.getElementById('verification-image').src = `/api/verification_image.png?seq=${image_seq}`
306 document.getElementById('card-1-create-account').addEventListener(
309 if (await card_1() && await card_2())
310 $('#card-2-collapse').collapse('show')
314 document.getElementById('card-2-back').addEventListener(
316 () => {$('#card-1-collapse').collapse('show')}
319 document.getElementById('card-2-resend-email').addEventListener(
323 $('#card-2-collapse').collapse('show')