Add sign up draft facility (avoids having to re-enter data if you refresh page)
[ndcode_site.git] / my_account / sign_up / index.html.jst
1 let logjson = (await import('@ndcode/logjson')).default
2
3 return async env => {
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')
9
10   // preload draft details if any
11   let transaction = await env.site.database.Transaction(), details
12   try {
13     // initialize env.session_key, set cookie in env.response
14     let session = await session_cookie(env, transaction)
15
16     details = await logjson.logjson_to_json(
17       await session.get('sign_up_draft', {})
18     )
19   }
20   finally {
21     transaction.rollback()
22   }
23   console.log('details', JSON.stringify(details))
24
25   await navbar(
26     env,
27     // head
28     async _out => {},
29     // body
30     async _out => {
31       await breadcrumbs(env, _out)
32
33       p {'Signing up allows you to leave comments on our blog and receive communications from us.'}
34
35       div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
36         div.card {
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)}
40             }
41             span#step-1-cross(style="display: none;") {
42               span.icon-color.pr-3 {_out.push(icon_cross)}
43             }
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...'}
48             //    }
49             //  }
50             //}
51             a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
52               'Your details'
53             }
54           }
55           div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
56             div.card-body {
57               div.row {
58                 div.col-md-6 {
59                   div.form-group {
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) {}
62                   }
63                 }
64                 div.col-md-6 {
65                   div.form-group {
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) {}
68                   }
69                 }
70               }
71               div.row {
72                 div.col-md-6 {
73                   div.form-group {
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) {}
76                   }
77                 }
78                 div.col-md-6 {
79                   div.form-group {
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) {}
82                   }
83                 }
84               }
85               div.row {
86                 div.col-md-12 {
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") {}
90                     else
91                       input.custom-control-input#contact-me(type="checkbox") {}
92                     ' '
93                     label.custom-control-label(for="contact-me") {
94                       'Contact me by email with updates and special offers'
95                     }
96                   }
97                 }
98               }
99               div.row.align-items-center {
100                 div.'col-md-6' {
101                   div.form-group {
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) {}
104                   }
105                 }
106                 div.'col-md-4' {
107                   img#verification-image(src="/api/verification_image.png?seq=0" width=300 height=150) {}
108                 }
109                 div.'col-md-2'.my-auto.text-center {
110                   input.btn.btn-outline-secondary#'new-code'(type="button" value="New code") {}
111                 }
112               }
113
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.'}
115
116               input.btn.btn-success#step-1-continue(type="button" value="Continue") {}
117               p.'mt-3'.mb-0 {'* These fields are required.'}
118             }
119           }
120         }
121         div.card {
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)}
125             }
126             span#step-2-cross(style="display: none;") {
127               span.icon-color.pr-3 {_out.push(icon_cross)}
128             }
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...'}
133                 }
134               }
135             }
136             a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
137               'Create account'
138             }
139           }
140           div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
141             div.card-body {
142               p#step-2-message {'Please enter your details first.'}
143
144               input.btn.btn-outline-secondary#step-2-back(type="button" value="Back") {}
145             }
146           }
147         }
148         div.card {
149           div.card-header#step-3-heading(role="tab") {
150             span#step-3-tick(style="display: none;") {
151               span.icon-color.pr-3 {_out.push(icon_tick)}
152             }
153             span#step-3-cross(style="display: none;") {
154               span.icon-color.pr-3 {_out.push(icon_cross)}
155             }
156             span#step-3-spinner(style="display: none;") {
157               span.icon-color.pr-3 {
158                 div.spinner-border(role="status") {
159                   span.sr-only {'Loading...'}
160                 }
161               }
162             }
163             a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-3-collapse" aria-expanded="false" aria-controls="step-3-collapse") {
164               'Send verification email'
165             }
166           }
167           div#step-3-collapse.collapse(role="tabpanel" aria-labelledby="step-3-heading" data-parent="#accordion") {
168             div.card-body {
169               p#step-3-message {'Please create your account first.'}
170
171               input.btn.btn-outline-secondary#step-3-back(type="button" value="Back") {}
172             }
173           }
174         }
175       }
176     },
177     // scripts
178     async _out => {
179       script(src="/js/api_call.js") {}
180
181       script {
182         let sign_up_create_account = async (...arguments) => api_call(
183           '/api/sign_up/create_account.json',
184           ...arguments
185         )
186         //let sign_up_get_draft = async (...arguments) => api_call(
187         //  '/api/sign_up/get_draft.json',
188         //  ...arguments
189         //)
190         let sign_up_set_draft = async (...arguments) => api_call(
191           '/api/sign_up/set_draft.json',
192           ...arguments
193         )
194
195         let details = () => {
196           return {
197             email: document.getElementById('email').value.slice(0, 256).toLowerCase(),
198             given_names: document.getElementById('given-names').value.slice(0, 256),
199             family_name: document.getElementById('family-name').value.slice(0, 256),
200             password: document.getElementById('password').value.slice(0, 256),
201             contact_me: document.getElementById('contact-me').checked ? true : false
202           }
203         }
204
205         let draft_timeout_running = false
206         let draft_timeout_handler = async () => {
207           draft_timeout_running = false
208           await sign_up_set_draft(details())
209           //console.log('draft', await sign_up_get_draft())
210         }
211         let draft_change_handler = () => {
212           if (!draft_timeout_running) {
213             draft_timeout_running = true
214             setTimeout(draft_timeout_handler, 5000)
215           }
216         }
217
218         document.addEventListener(
219           'DOMContentLoaded', 
220           () => {
221             document.getElementById('given-names').addEventListener(
222               'change',
223               draft_change_handler
224             )
225             document.getElementById('family-name').addEventListener(
226               'change',
227               draft_change_handler
228             )
229             document.getElementById('email').addEventListener(
230               'change',
231               draft_change_handler
232             )
233             document.getElementById('password').addEventListener(
234               'change',
235               draft_change_handler
236             )
237             document.getElementById('contact-me').addEventListener(
238               'change',
239               draft_change_handler
240             )
241
242             document.getElementById('step-1-continue').addEventListener(
243               'click',
244               async () => {
245                 if (
246                   !document.getElementById('given-names').reportValidity() ||
247                     !document.getElementById('family-name').reportValidity() ||
248                     !document.getElementById('email').reportValidity() ||
249                     !document.getElementById('password').reportValidity() ||
250                     !document.getElementById('verification-code').reportValidity()
251                 ) {
252                   $('#step-1-tick').hide()
253                   $('#step-1-cross').show()
254                   //$('#step-1-spinner').hide()
255                   return
256                 }
257                 $('#step-1-tick').show()
258                 $('#step-1-cross').hide()
259                 //$('#step-1-spinner').hide()
260
261                 $('#step-2-tick').hide()
262                 $('#step-2-cross').hide()
263                 $('#step-2-spinner').show()
264                 try {
265                   await sign_up_create_account(
266                     // verification_code
267                     document.getElementById('verification-code').value.slice(0, 6).toLowerCase(),
268                     // details
269                     details()
270                   )
271                 }
272                 catch (e) {
273                   $('#step-2-tick').hide()
274                   $('#step-2-cross').show()
275                   $('#step-2-spinner').hide()
276
277                   document.getElementById('step-2-message').textContent = e.message
278                   $('#step-2-collapse').collapse('show')
279                   return
280                 }
281                 $('#step-2-tick').show()
282                 $('#step-2-cross').hide()
283                 $('#step-2-spinner').hide()
284
285                 document.getElementById('step-2-message').textContent = `Your account with email "${document.getElementById('email').value}" has been created.`
286                 $('#step-2-collapse').collapse('show')
287               }
288             )
289
290             $('#step-2-back').click(
291               () => {$('#step-1-collapse').collapse('show')}
292             )
293
294             $('#step-3-back').click(
295               () => {$('#step-2-collapse').collapse('show')}
296             )
297
298             let image_seq = 1
299             $('#new-code').click(
300               () => {
301                 document.getElementById('verification-image').src = `/api/verification_image.png?seq=${image_seq}`
302                 image_seq += 1
303               }
304             ) 
305           }
306         )
307       }
308     }
309   )
310 }