9ca59e2ba07c17116aea4ac025b2f22a0aed5f87
[ndcode_site.git] / my_account / sign_up / index.html.jst
1 let XDate = require('xdate')
2
3 return async env => {
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')
9
10   // preload draft details if any
11   let transaction = await env.site.database.Transaction()
12   let draft_details
13   try {
14     let root = await transaction.get({})
15     let session = await get_session(env, root)
16
17     let sign_up_draft = await session.get('sign_up_draft')
18     draft_details =
19       sign_up_draft !== undefined &&
20         XDate.now() < await sign_up_draft.get_json('expires') ?
21         {
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')
26         } :
27         null
28   }
29   finally {
30     transaction.rollback()
31   }
32   console.log('draft_details', JSON.stringify(draft_details))
33
34   await navbar(
35     env,
36     // head
37     async _out => {},
38     // body
39     async _out => {
40       await breadcrumbs(env, _out)
41
42       p {'Signing up allows you to leave comments on our blog and receive communications from us.'}
43
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.'}
45
46       div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
47         div.card#step-1 {
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)}
51             }
52             span#step-1-cross(style="display: none;") {
53               span.icon-color.pr-3 {_out.push(icon_cross)}
54             }
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...'}
59             //    }
60             //  }
61             //}
62             a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
63               'Your details'
64             }
65           }
66           div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
67             div.card-body {
68               div.row {
69                 div.col-md-6 {
70                   div.form-group {
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) {}
73                   }
74                 }
75                 div.col-md-6 {
76                   div.form-group {
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) {}
79                   }
80                 }
81               }
82               div.row {
83                 div.col-md-6 {
84                   div.form-group {
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) {}
87                   }
88                 }
89                 div.col-md-6 {
90                   div.form-group {
91                     label.form-label(for="password") {'Password *'}
92                     input.form-control#password(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
93                   }
94                 }
95               }
96               div.row {
97                 div.col-md-12 {
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") {}
101                     else
102                       input.custom-control-input#contact-me(type="checkbox") {}
103                     ' '
104                     label.custom-control-label(for="contact-me") {
105                       'Contact me by email with updates and special offers'
106                     }
107                   }
108                 }
109               }
110               div.row.align-items-center.mb-3 {
111                 div.'col-md-6' {
112                   div.form-group {
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) {}
115                   }
116                 }
117                 div.'col-md-4' {
118                   img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
119                 }
120                 div.'col-md-2'.my-auto.text-center {
121                   button.btn.btn-outline-secondary#'step-1-new-code'(type="button") {'New code'}
122                 }
123               }
124
125               button.btn.btn-success#step-1-continue(type="button") {'Continue'}
126
127               p.'mt-3'.mb-0 {'* These fields are required.'}
128             }
129           }
130         }
131         div.card#step-2 {
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)}
135             }
136             span#step-2-cross(style="display: none;") {
137               span.icon-color.pr-3 {_out.push(icon_cross)}
138             }
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...'}
143                 }
144               }
145             }
146             a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
147               'Create account'
148             }
149           }
150           div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
151             div.card-body {
152               p#step-2-message {'Please enter your details first.'}
153
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'}
156             }
157           }
158         }
159         div.card#step-3 {
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)}
163             }
164             span#step-3-cross(style="display: none;") {
165               span.icon-color.pr-3 {_out.push(icon_cross)}
166             }
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...'}
171                 }
172               }
173             }
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'
176             }
177           }
178           div#step-3-collapse.collapse(role="tabpanel" aria-labelledby="step-3-heading" data-parent="#accordion") {
179             div.card-body {
180               p#step-3-message {'Please create your account first.'}
181
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'}
184             }
185           }
186         }
187       }
188     },
189     // scripts
190     async _out => {
191       //script(src="/js/api_call.js") {}
192
193       script {
194         let draft_timeout_running = false
195         let draft_timeout_handler = async () => {
196           draft_timeout_running = false
197           await api_call(
198             '/api/account/sign_up/set_draft.json',
199             {
200               email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
201               given_names: document.getElementById('given-names').value.slice(0, 256),
202               family_name: document.getElementById('family-name').value.slice(0, 256),
203               contact_me: document.getElementById('contact-me').checked ? true : false
204             }
205           )
206           //console.log('draft', await api_call('/api/account/sign_up/get_draft.json'))
207         }
208         let draft_change_handler = () => {
209           if (!draft_timeout_running) {
210             draft_timeout_running = true
211             setTimeout(draft_timeout_handler, 5000)
212           }
213         }
214
215         let details
216         let step_1 = async () => {
217           if (
218             !document.getElementById('given-names').reportValidity() ||
219               !document.getElementById('family-name').reportValidity() ||
220               !document.getElementById('email').reportValidity() ||
221               !document.getElementById('password').reportValidity() ||
222               !document.getElementById('verification-code').reportValidity()
223           ) {
224             $('#step-1-tick').hide()
225             $('#step-1-cross').show()
226             //$('#step-1-spinner').hide()
227             return false
228           }
229           $('#step-1-tick').show()
230           $('#step-1-cross').hide()
231           //$('#step-1-spinner').hide()
232
233           details = {
234             email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
235             given_names: document.getElementById('given-names').value.slice(0, 256),
236             family_name: document.getElementById('family-name').value.slice(0, 256),
237             password: document.getElementById('password').value.slice(0, 256),
238             contact_me: document.getElementById('contact-me').checked ? true : false
239           }
240           return true
241         }
242
243         let step_2 = async () => {
244           $('#step-2-tick').hide()
245           $('#step-2-cross').hide()
246           $('#step-2-spinner').show()
247           document.getElementById('step-2').scrollIntoView()
248
249           try {
250             await api_call(
251               '/api/account/sign_up/create_account.json',
252               document.getElementById('verification-code').value.slice(0, 6).toLowerCase(),
253               details
254             )
255           }
256           catch (error) {
257             let problem = Problem.from(error)
258
259             $('#step-2-tick').hide()
260             $('#step-2-cross').show()
261             $('#step-2-spinner').hide()
262
263             document.getElementById('step-2-message').textContent = problem.detail
264             $('#step-2-collapse').collapse('show')
265             return false
266           }
267           $('#step-2-tick').show()
268           $('#step-2-cross').hide()
269           $('#step-2-spinner').hide()
270           document.getElementById('step-2-message').textContent = `Your account with email "${details.email}" has been created.`
271           return true
272         }
273
274         let step_3 = async () => {
275           $('#step-3-tick').hide()
276           $('#step-3-cross').hide()
277           $('#step-3-spinner').show()
278           document.getElementById('step-3').scrollIntoView()
279
280           try {
281             await api_call(
282               '/api/account/sign_up/send_email_verification_link.json',
283               details.email
284             )
285           }
286           catch (error) {
287             let problem = Problem.from(error)
288
289             $('#step-3-tick').hide()
290             $('#step-3-cross').show()
291             $('#step-3-spinner').hide()
292
293             document.getElementById('step-3-message').textContent = problem.detail
294             $('#step-3-collapse').collapse('show')
295             return false
296           }
297           $('#step-3-tick').show()
298           $('#step-3-cross').hide()
299           $('#step-3-spinner').hide()
300
301           document.getElementById('step-3-message').textContent = `Email verification link has been sent to "${details.email}". Please check your email for next steps.`
302           return true
303         }
304
305         document.addEventListener(
306           'DOMContentLoaded',
307           () => {
308             document.getElementById('given-names').addEventListener(
309               'change',
310               draft_change_handler
311             )
312             document.getElementById('family-name').addEventListener(
313               'change',
314               draft_change_handler
315             )
316             document.getElementById('email').addEventListener(
317               'change',
318               draft_change_handler
319             )
320             document.getElementById('password').addEventListener(
321               'change',
322               draft_change_handler
323             )
324             document.getElementById('contact-me').addEventListener(
325               'change',
326               draft_change_handler
327             )
328
329             let image_seq = 1
330             document.getElementById('step-1-new-code').addEventListener(
331               'click',
332               () => {
333                 document.getElementById('verification-image').src = `/api/verification_image.png?seq=${image_seq}`
334                 image_seq += 1
335               }
336             )
337
338             document.getElementById('step-1-continue').addEventListener(
339               'click',
340               async () => {
341                 if (await step_1() && await step_2() && await step_3())
342                   $('#step-3-collapse').collapse('show')
343               }
344             )
345
346             document.getElementById('step-2-back').addEventListener(
347               'click',
348               () => {$('#step-1-collapse').collapse('show')}
349             )
350
351             document.getElementById('step-2-continue').addEventListener(
352               'click',
353               async () => {
354                 if (await step_3())
355                   $('#step-3-collapse').collapse('show')
356               }
357             )
358
359             document.getElementById('step-3-back').addEventListener(
360               'click',
361               () => {$('#step-2-collapse').collapse('show')}
362             )
363
364             document.getElementById('step-3-resend-email').addEventListener(
365               'click',
366               async () => {
367                 if (await step_3())
368                   $('#step-3-collapse').collapse('show')
369               }
370             )
371           }
372         )
373       }
374     }
375   )
376 }