ffae545cdb4300cf379cbc20ca0c9965a06144b5
[ndcode_site.git] / my_account / password_reset / 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 details = {}
12   if (Object.prototype.hasOwnProperty.call(env.parsed_url.query, 'email'))
13     details.email = decodeURIComponent(env.parsed_url.query.email)
14   console.log('details', JSON.stringify(details))
15
16   await navbar(
17     env,
18     // head
19     async _out => {},
20     // body
21     async _out => {
22       await breadcrumbs(env, _out)
23
24       p {'To reset your password, please enter new details below and we will send you a password reset link.'}
25
26       div.accordion#accordion.mb-5(role="tablist" aria-multiselectable="true") {
27         div.card#step-1 {
28           div.card-header#step-1-heading(role="tab") {
29             span#step-1-tick(style="display: none;") {
30               span.icon-color.pr-3 {_out.push(icon_tick)}
31             }
32             span#step-1-cross(style="display: none;") {
33               span.icon-color.pr-3 {_out.push(icon_cross)}
34             }
35             //span#step-1-spinner(style="display: none;") {
36             //  span.icon-color.pr-3 {
37             //    div.spinner-border(role="status") {
38             //      span.sr-only {'Loading...'}
39             //    }
40             //  }
41             //}
42             a.h5(data-toggle="collapse" data-parent="#accordion" href="#step-1-collapse" aria-expanded="true" aria-controls="step-1-collapse") {
43               'Account details'
44             }
45           }
46           div#step-1-collapse.collapse.show(role="tabpanel" aria-labelledby="step-1-heading" data-parent="#accordion") {
47             div.card-body {
48               div.row {
49                 div.col-md-6 {
50                   div.form-group {
51                    label.form-label(for="email") {'Email *'}
52                     input.form-control#email(type="email" value=details.email || '' placeholder="Account email address" required="required" maxlength=256) {}
53                   }
54                 }
55                 div.col-md-6 {
56                   div.form-group {
57                    label.form-label(for="password") {'Password *'}
58                     input.form-control#password(type="password" placeholder="New password" required="required" minlength=8 maxlength=256) {}
59                   }
60                 }
61               }
62
63               button.btn.btn-success#step-1-continue(type="button") {'Continue'}
64               p.'mt-3'.mb-0 {'* This field is required.'}
65             }
66           }
67         }
68         div.card#step-2 {
69           div.card-header#step-2-heading(role="tab") {
70             span#step-2-tick(style="display: none;") {
71               span.icon-color.pr-3 {_out.push(icon_tick)}
72             }
73             span#step-2-cross(style="display: none;") {
74               span.icon-color.pr-3 {_out.push(icon_cross)}
75             }
76             span#step-2-spinner(style="display: none;") {
77               span.icon-color.pr-3 {
78                 div.spinner-border(role="status") {
79                   span.sr-only {'Loading...'}
80                 }
81               }
82             }
83             a.h5.collapsed(data-toggle="collapse" data-parent="#accordion" href="#step-2-collapse" aria-expanded="false" aria-controls="step-2-collapse") {
84               'Send password reset link'
85             }
86           }
87           div#step-2-collapse.collapse(role="tabpanel" aria-labelledby="step-2-heading" data-parent="#accordion") {
88             div.card-body {
89               p#step-2-message {'Please enter account details first.'}
90
91               button.btn.btn-outline-secondary#step-2-back(type="button") {'Back'}
92               button.btn.btn-outline-secondary.ml-3#step-2-resend-email(type="button") {'Re-send email'}
93             }
94           }
95         }
96       }
97     },
98     // scripts
99     async _out => {
100       script(src="/js/api_call.js") {}
101
102       script {
103         let password_reset = async (...arguments) => api_call(
104           '/api/account/password_reset.json',
105           ...arguments
106         )
107
108         let step_1 = async () => {
109           if (
110             !document.getElementById('email').reportValidity() || 
111               !document.getElementById('password').reportValidity()
112           ) {
113             $('#step-1-tick').hide()
114             $('#step-1-cross').show()
115             //$('#step-1-spinner').hide()
116             return false
117           }
118           $('#step-1-tick').show()
119           $('#step-1-cross').hide()
120           //$('#step-1-spinner').hide()
121           return true
122         }
123
124         let step_2 = async () => {
125           $('#step-2-tick').hide()
126           $('#step-2-cross').hide()
127           $('#step-2-spinner').show()
128           document.getElementById('step-1').scrollIntoView()
129
130           let email
131           try {
132             email = document.getElementById('email').value.slice(0, 256).toLowerCase()
133             await password_reset(
134               email,
135               document.getElementById('password').value.slice(0, 256)
136             )
137           }
138           catch (error) {
139             let problem =
140               error instanceof Problem ?
141                 error :
142                 new Problem(
143                   // title
144                   'Bad request',
145                   // details
146                   (error.stack || error.message).toString()
147                   // status
148                   400
149                 )
150
151             $('#step-2-tick').hide()
152             $('#step-2-cross').show()
153             $('#step-2-spinner').hide()
154
155             document.getElementById('step-2-message').textContent = problem.detail
156             $('#step-2-collapse').collapse('show')
157             return false
158           }
159           $('#step-2-tick').show()
160           $('#step-2-cross').hide()
161           $('#step-2-spinner').hide()
162
163           document.getElementById('step-2-message').textContent = `Password reset link has been sent to "${email}". Please check your email for next steps.`
164           return true
165         }
166
167         document.addEventListener(
168           'DOMContentLoaded',
169           () => {
170             document.getElementById('step-1-continue').addEventListener(
171               'click',
172               async () => {
173                 if (await step_1() && await step_2())
174                   $('#step-2-collapse').collapse('show')
175               }
176             )
177
178             document.getElementById('step-2-back').addEventListener(
179               'click',
180               () => {$('#step-1-collapse').collapse('show')}
181             )
182
183             document.getElementById('step-2-resend-email').addEventListener(
184               'click',
185               async () => {
186                 if (await step_2())
187                   $('#step-3-collapse').collapse('show')
188               }
189             )
190           }
191         )
192       }
193     }
194   )
195 }