chualinwei3 commited on
Commit
3c1fdfa
·
verified ·
1 Parent(s): ecd52b4

Update register.html

Browse files
Files changed (1) hide show
  1. register.html +365 -365
register.html CHANGED
@@ -1,366 +1,366 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Register - Attendr</title>
8
- <link rel="stylesheet" href="style.css">
9
- <link
10
- href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@700;800&display=swap"
11
- rel="stylesheet">
12
- </head>
13
-
14
- <body>
15
- <!-- Navigation -->
16
- <!-- Navigation -->
17
- {% include '_navbar.html' %}
18
-
19
- <!-- Main Content -->
20
- <section class="section">
21
- <div class="container" style="max-width: 800px;">
22
- <h1 class="text-center mb-3">Register Account</h1>
23
- <p class="text-center text-muted mb-3">
24
- Create your student or lecturer account
25
- </p>
26
-
27
- <!-- Step 1: Account Details -->
28
- <div id="step1Card" class="glass-card">
29
- <h2 class="mb-2">Step 1: Account Information</h2>
30
-
31
- <div class="form-group">
32
- <label class="form-label">I am a...</label>
33
- <select id="roleSelect" class="form-select">
34
- <option value="">Select your role</option>
35
- <option value="student">Student</option>
36
- <option value="lecturer">Lecturer</option>
37
- </select>
38
- </div>
39
-
40
- <div class="form-group">
41
- <label class="form-label">Matric Number</label>
42
- <input type="text" id="matricNo" class="form-input" placeholder="e.g., A20EC0001 or L001"
43
- style="text-transform: uppercase;">
44
- <small class="text-muted" id="matricHelp" style="font-size: 0.875rem;">
45
- Select your role first
46
- </small>
47
- </div>
48
-
49
- <div class="form-group">
50
- <label class="form-label">Full Name</label>
51
- <input type="text" id="fullName" class="form-input" placeholder="Your full name">
52
- </div>
53
-
54
- <div class="form-group">
55
- <label class="form-label">Email (Optional)</label>
56
- <input type="email" id="email" class="form-input" placeholder="your.email@graduate.utm.my">
57
- </div>
58
-
59
- <div class="form-group">
60
- <label class="form-label">Password</label>
61
- <input type="password" id="password" class="form-input" placeholder="Create a strong password">
62
- </div>
63
-
64
- <div class="form-group">
65
- <label class="form-label">Confirm Password</label>
66
- <input type="password" id="confirmPassword" class="form-input" placeholder="Re-enter your password">
67
- </div>
68
-
69
- <div id="statusMessage" class="mt-2"></div>
70
-
71
- <button id="nextBtn" class="btn btn-primary mt-2" style="width: 100%;">
72
- Next: Face Registration →
73
- </button>
74
-
75
- <div class="text-center mt-2">
76
- <p class="text-muted">
77
- Already have an account? <a href="/login" style="color: var(--color-primary);">Login here</a>
78
- </p>
79
- </div>
80
- </div>
81
-
82
- <!-- Step 2: Face Registration (Students Only) -->
83
- <div id="step2Card" class="glass-card mt-2 hidden">
84
- <h2 class="mb-2">Step 2: Face Registration</h2>
85
- <p class="text-muted mb-2">Capture your face for biometric verification</p>
86
-
87
- <div class="text-center">
88
- <video id="video" width="400" height="300" autoplay
89
- style="border-radius: 12px; border: 2px solid var(--color-primary);"></video>
90
- <canvas id="canvas" width="400" height="300" style="display: none;"></canvas>
91
-
92
- <div id="preview" class="mt-2 hidden">
93
- <img id="capturedImage"
94
- style="max-width: 400px; border-radius: 12px; border: 2px solid var(--color-success);">
95
- </div>
96
- </div>
97
-
98
- <div id="faceStatusMessage" class="mt-2"></div>
99
-
100
- <div class="flex-center gap-2 mt-2">
101
- <button id="startCameraBtn" class="btn btn-secondary">
102
- 📷 Start Camera
103
- </button>
104
- <button id="captureBtn" class="btn btn-primary hidden">
105
- 📸 Capture Face
106
- </button>
107
- <button id="retakeBtn" class="btn btn-outline hidden">
108
- 🔄 Retake
109
- </button>
110
- <button id="registerBtn" class="btn btn-success hidden">
111
- ✅ Complete Registration
112
- </button>
113
- </div>
114
-
115
- <div class="text-center mt-2">
116
- <button id="backBtn" class="btn btn-outline">
117
- ← Back to Account Details
118
- </button>
119
- </div>
120
- </div>
121
-
122
- <!-- Success Message -->
123
- <div id="successCard" class="glass-card mt-2 hidden"
124
- style="background: rgba(34, 197, 94, 0.1); border: 2px solid var(--color-success);">
125
- <div class="text-center">
126
- <div style="font-size: 4rem; margin-bottom: 1rem;">✅</div>
127
- <h2 style="color: var(--color-success);">Registration Successful!</h2>
128
- <p class="text-muted mt-2" id="successMessage">Your account has been created successfully.</p>
129
- <div class="flex-center gap-2 mt-2">
130
- <a href="/login" class="btn btn-primary">Go to Login</a>
131
- </div>
132
- </div>
133
- </div>
134
- </div>
135
- </section>
136
-
137
- <!-- Loading Overlay -->
138
- <div id="loadingOverlay" class="loading-overlay hidden">
139
- <div class="text-center">
140
- <div class="spinner"></div>
141
- <p class="mt-2" id="loadingText">Processing...</p>
142
- </div>
143
- </div>
144
-
145
- <script>
146
- let videoStream = null;
147
- let capturedImageData = null;
148
- let userRole = null;
149
-
150
- // Update matric number help text based on role
151
- document.getElementById('roleSelect').addEventListener('change', (e) => {
152
- userRole = e.target.value;
153
- const helpText = document.getElementById('matricHelp');
154
-
155
- if (userRole === 'student') {
156
- helpText.textContent = 'Student matric number must start with A or B (e.g., A20EC0001)';
157
- helpText.style.color = 'var(--color-primary)';
158
- } else if (userRole === 'lecturer') {
159
- helpText.textContent = 'Lecturer matric number must start with L (e.g., L001)';
160
- helpText.style.color = 'var(--color-primary)';
161
- } else {
162
- helpText.textContent = 'Select your role first';
163
- helpText.style.color = 'var(--color-text-muted)';
164
- }
165
- });
166
-
167
- // Next button - validate and move to face registration
168
- document.getElementById('nextBtn').addEventListener('click', async () => {
169
- const role = document.getElementById('roleSelect').value;
170
- const matricNo = document.getElementById('matricNo').value.trim().toUpperCase();
171
- const fullName = document.getElementById('fullName').value.trim();
172
- const password = document.getElementById('password').value;
173
- const confirmPassword = document.getElementById('confirmPassword').value;
174
-
175
- // Validation
176
- if (!role) {
177
- showStatus('Please select your role', 'error');
178
- return;
179
- }
180
-
181
- if (!matricNo || !fullName || !password) {
182
- showStatus('Please fill in all required fields', 'error');
183
- return;
184
- }
185
-
186
- if (password !== confirmPassword) {
187
- showStatus('Passwords do not match', 'error');
188
- return;
189
- }
190
-
191
- if (password.length < 6) {
192
- showStatus('Password must be at least 6 characters long', 'error');
193
- return;
194
- }
195
-
196
- // If lecturer, register directly (no face needed)
197
- if (role === 'lecturer') {
198
- await registerUser(false);
199
- } else {
200
- // Student - go to face registration
201
- document.getElementById('step1Card').classList.add('hidden');
202
- document.getElementById('step2Card').classList.remove('hidden');
203
- }
204
- });
205
-
206
- // Back button
207
- document.getElementById('backBtn').addEventListener('click', () => {
208
- stopCamera();
209
- document.getElementById('step2Card').classList.add('hidden');
210
- document.getElementById('step1Card').classList.remove('hidden');
211
- });
212
-
213
- // Camera controls
214
- document.getElementById('startCameraBtn').addEventListener('click', startCamera);
215
- document.getElementById('captureBtn').addEventListener('click', captureFace);
216
- document.getElementById('retakeBtn').addEventListener('click', retake);
217
- document.getElementById('registerBtn').addEventListener('click', () => registerUser(true));
218
-
219
- async function startCamera() {
220
- try {
221
- videoStream = await navigator.mediaDevices.getUserMedia({ video: true });
222
- document.getElementById('video').srcObject = videoStream;
223
- document.getElementById('startCameraBtn').classList.add('hidden');
224
- document.getElementById('captureBtn').classList.remove('hidden');
225
- showFaceStatus('Camera ready! Position your face in the frame', 'success');
226
- } catch (error) {
227
- showFaceStatus('Camera access denied. Please allow camera access.', 'error');
228
- }
229
- }
230
-
231
- function stopCamera() {
232
- if (videoStream) {
233
- videoStream.getTracks().forEach(track => track.stop());
234
- videoStream = null;
235
- }
236
- }
237
-
238
- function captureFace() {
239
- const video = document.getElementById('video');
240
- const canvas = document.getElementById('canvas');
241
- const context = canvas.getContext('2d');
242
-
243
- context.drawImage(video, 0, 0, 400, 300);
244
- capturedImageData = canvas.toDataURL('image/jpeg');
245
-
246
- document.getElementById('capturedImage').src = capturedImageData;
247
- document.getElementById('preview').classList.remove('hidden');
248
- document.getElementById('video').style.display = 'none';
249
- document.getElementById('captureBtn').classList.add('hidden');
250
- document.getElementById('retakeBtn').classList.remove('hidden');
251
- document.getElementById('registerBtn').classList.remove('hidden');
252
-
253
- stopCamera();
254
- showFaceStatus('Face captured! Click "Complete Registration" to finish', 'success');
255
- }
256
-
257
- function retake() {
258
- document.getElementById('preview').classList.add('hidden');
259
- document.getElementById('video').style.display = 'block';
260
- document.getElementById('retakeBtn').classList.add('hidden');
261
- document.getElementById('registerBtn').classList.add('hidden');
262
- capturedImageData = null;
263
- startCamera();
264
- }
265
-
266
- async function registerUser(includeFace) {
267
- const role = document.getElementById('roleSelect').value;
268
- const matricNo = document.getElementById('matricNo').value.trim().toUpperCase();
269
- const fullName = document.getElementById('fullName').value.trim();
270
- const email = document.getElementById('email').value.trim();
271
- const password = document.getElementById('password').value;
272
-
273
- if (includeFace && !capturedImageData) {
274
- showFaceStatus('Please capture your face first', 'error');
275
- return;
276
- }
277
-
278
- showLoading('Creating your account...');
279
-
280
- try {
281
- // Step 1: Create user account
282
- const userResponse = await fetch('/api/auth/register', {
283
- method: 'POST',
284
- headers: { 'Content-Type': 'application/json' },
285
- body: JSON.stringify({
286
- role: role,
287
- matric_no: matricNo,
288
- name: fullName,
289
- email: email || null,
290
- password: password
291
- })
292
- });
293
-
294
- const userData = await userResponse.json();
295
-
296
- if (!userData.success) {
297
- hideLoading();
298
- showStatus(userData.error, 'error');
299
- return;
300
- }
301
-
302
- // Step 2: Register face if student
303
- if (includeFace) {
304
- const faceResponse = await fetch('/api/register_face', {
305
- method: 'POST',
306
- headers: { 'Content-Type': 'application/json' },
307
- body: JSON.stringify({
308
- student_id: matricNo,
309
- name: fullName,
310
- email: email || null,
311
- image: capturedImageData
312
- })
313
- });
314
-
315
- const faceData = await faceResponse.json();
316
- hideLoading();
317
-
318
- if (!faceData.success) {
319
- showFaceStatus(faceData.error, 'error');
320
- return;
321
- }
322
- }
323
-
324
- hideLoading();
325
-
326
- // Show success
327
- document.getElementById('step1Card').classList.add('hidden');
328
- document.getElementById('step2Card').classList.add('hidden');
329
- document.getElementById('successCard').classList.remove('hidden');
330
- document.getElementById('successMessage').textContent =
331
- `Your ${role} account has been created successfully${includeFace ? ' with face registration' : ''}. You can now login to access the system.`;
332
-
333
- } catch (error) {
334
- hideLoading();
335
- showStatus('Registration failed. Please try again.', 'error');
336
- }
337
- }
338
-
339
- function showLoading(text) {
340
- document.getElementById('loadingText').textContent = text;
341
- document.getElementById('loadingOverlay').classList.remove('hidden');
342
- }
343
-
344
- function hideLoading() {
345
- document.getElementById('loadingOverlay').classList.add('hidden');
346
- }
347
-
348
- function showStatus(message, type) {
349
- const statusDiv = document.getElementById('statusMessage');
350
- const alertClass = type === 'success' ? 'alert-success' : 'alert-error';
351
- statusDiv.innerHTML = `<div class="alert ${alertClass}">${message}</div>`;
352
-
353
- setTimeout(() => {
354
- statusDiv.innerHTML = '';
355
- }, 5000);
356
- }
357
-
358
- function showFaceStatus(message, type) {
359
- const statusDiv = document.getElementById('faceStatusMessage');
360
- const alertClass = type === 'success' ? 'alert-success' : 'alert-error';
361
- statusDiv.innerHTML = `<div class="alert ${alertClass}">${message}</div>`;
362
- }
363
- </script>
364
- </body>
365
-
366
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Register - Attendr</title>
8
+ <link rel="stylesheet" href="style.css">
9
+ <link
10
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@700;800&display=swap"
11
+ rel="stylesheet">
12
+ </head>
13
+
14
+ <body>
15
+ <!-- Navigation -->
16
+ <!-- Navigation -->
17
+ {% include '_navbar.html' %}
18
+
19
+ <!-- Main Content -->
20
+ <section class="section">
21
+ <div class="container" style="max-width: 800px;">
22
+ <h1 class="text-center mb-3">Register Account</h1>
23
+ <p class="text-center text-muted mb-3">
24
+ Create your student or lecturer account
25
+ </p>
26
+
27
+ <!-- Step 1: Account Details -->
28
+ <div id="step1Card" class="glass-card">
29
+ <h2 class="mb-2">Step 1: Account Information</h2>
30
+
31
+ <div class="form-group">
32
+ <label class="form-label">I am a...</label>
33
+ <select id="roleSelect" class="form-select">
34
+ <option value="">Select your role</option>
35
+ <option value="student">Student</option>
36
+ <option value="lecturer">Lecturer</option>
37
+ </select>
38
+ </div>
39
+
40
+ <div class="form-group">
41
+ <label class="form-label">Matric Number</label>
42
+ <input type="text" id="matricNo" class="form-input" placeholder="e.g., A20EC0001 or L001"
43
+ style="text-transform: uppercase;">
44
+ <small class="text-muted" id="matricHelp" style="font-size: 0.875rem;">
45
+ Select your role first
46
+ </small>
47
+ </div>
48
+
49
+ <div class="form-group">
50
+ <label class="form-label">Full Name</label>
51
+ <input type="text" id="fullName" class="form-input" placeholder="Your full name">
52
+ </div>
53
+
54
+ <div class="form-group">
55
+ <label class="form-label">Email (Optional)</label>
56
+ <input type="email" id="email" class="form-input" placeholder="your.email@graduate.utm.my">
57
+ </div>
58
+
59
+ <div class="form-group">
60
+ <label class="form-label">Password</label>
61
+ <input type="password" id="password" class="form-input" placeholder="Create a strong password">
62
+ </div>
63
+
64
+ <div class="form-group">
65
+ <label class="form-label">Confirm Password</label>
66
+ <input type="password" id="confirmPassword" class="form-input" placeholder="Re-enter your password">
67
+ </div>
68
+
69
+ <div id="statusMessage" class="mt-2"></div>
70
+
71
+ <button id="nextBtn" class="btn btn-primary mt-2" style="width: 100%;">
72
+ Next: Face Registration →
73
+ </button>
74
+
75
+ <div class="text-center mt-2">
76
+ <p class="text-muted">
77
+ Already have an account? <a href="/login" style="color: var(--color-primary);">Login here</a>
78
+ </p>
79
+ </div>
80
+ </div>
81
+
82
+ <!-- Step 2: Face Registration (Students Only) -->
83
+ <div id="step2Card" class="glass-card mt-2 hidden">
84
+ <h2 class="mb-2">Step 2: Face Registration</h2>
85
+ <p class="text-muted mb-2">Capture your face for biometric verification</p>
86
+
87
+ <div class="text-center">
88
+ <video id="video" width="400" height="300" autoplay
89
+ style="border-radius: 12px; border: 2px solid var(--color-primary);"></video>
90
+ <canvas id="canvas" width="400" height="300" style="display: none;"></canvas>
91
+
92
+ <div id="preview" class="mt-2 hidden">
93
+ <img id="capturedImage"
94
+ style="max-width: 400px; border-radius: 12px; border: 2px solid var(--color-success);">
95
+ </div>
96
+ </div>
97
+
98
+ <div id="faceStatusMessage" class="mt-2"></div>
99
+
100
+ <div class="flex-center gap-2 mt-2">
101
+ <button id="startCameraBtn" class="btn btn-secondary">
102
+ 📷 Start Camera
103
+ </button>
104
+ <button id="captureBtn" class="btn btn-primary hidden">
105
+ 📸 Capture Face
106
+ </button>
107
+ <button id="retakeBtn" class="btn btn-outline hidden">
108
+ 🔄 Retake
109
+ </button>
110
+ <button id="registerBtn" class="btn btn-success hidden">
111
+ ✅ Complete Registration
112
+ </button>
113
+ </div>
114
+
115
+ <div class="text-center mt-2">
116
+ <button id="backBtn" class="btn btn-outline">
117
+ ← Back to Account Details
118
+ </button>
119
+ </div>
120
+ </div>
121
+
122
+ <!-- Success Message -->
123
+ <div id="successCard" class="glass-card mt-2 hidden"
124
+ style="background: rgba(34, 197, 94, 0.1); border: 2px solid var(--color-success);">
125
+ <div class="text-center">
126
+ <div style="font-size: 4rem; margin-bottom: 1rem;">✅</div>
127
+ <h2 style="color: var(--color-success);">Registration Successful!</h2>
128
+ <p class="text-muted mt-2" id="successMessage">Your account has been created successfully.</p>
129
+ <div class="flex-center gap-2 mt-2">
130
+ <a href="/login" class="btn btn-primary">Go to Login</a>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </section>
136
+
137
+ <!-- Loading Overlay -->
138
+ <div id="loadingOverlay" class="loading-overlay hidden">
139
+ <div class="text-center">
140
+ <div class="spinner"></div>
141
+ <p class="mt-2" id="loadingText">Processing...</p>
142
+ </div>
143
+ </div>
144
+
145
+ <script>
146
+ let videoStream = null;
147
+ let capturedImageData = null;
148
+ let userRole = null;
149
+
150
+ // Update matric number help text based on role
151
+ document.getElementById('roleSelect').addEventListener('change', (e) => {
152
+ userRole = e.target.value;
153
+ const helpText = document.getElementById('matricHelp');
154
+
155
+ if (userRole === 'student') {
156
+ helpText.textContent = 'Student matric number must start with A or B (e.g., A20EC0001)';
157
+ helpText.style.color = 'var(--color-primary)';
158
+ } else if (userRole === 'lecturer') {
159
+ helpText.textContent = 'Lecturer matric number must start with L (e.g., L001)';
160
+ helpText.style.color = 'var(--color-primary)';
161
+ } else {
162
+ helpText.textContent = 'Select your role first';
163
+ helpText.style.color = 'var(--color-text-muted)';
164
+ }
165
+ });
166
+
167
+ // Next button - validate and move to face registration
168
+ document.getElementById('nextBtn').addEventListener('click', async () => {
169
+ const role = document.getElementById('roleSelect').value;
170
+ const matricNo = document.getElementById('matricNo').value.trim().toUpperCase();
171
+ const fullName = document.getElementById('fullName').value.trim();
172
+ const password = document.getElementById('password').value;
173
+ const confirmPassword = document.getElementById('confirmPassword').value;
174
+
175
+ // Validation
176
+ if (!role) {
177
+ showStatus('Please select your role', 'error');
178
+ return;
179
+ }
180
+
181
+ if (!matricNo || !fullName || !password) {
182
+ showStatus('Please fill in all required fields', 'error');
183
+ return;
184
+ }
185
+
186
+ if (password !== confirmPassword) {
187
+ showStatus('Passwords do not match', 'error');
188
+ return;
189
+ }
190
+
191
+ if (password.length < 6) {
192
+ showStatus('Password must be at least 6 characters long', 'error');
193
+ return;
194
+ }
195
+
196
+ // If lecturer, register directly (no face needed)
197
+ if (role === 'lecturer') {
198
+ await registerUser(false);
199
+ } else {
200
+ // Student - go to face registration
201
+ document.getElementById('step1Card').classList.add('hidden');
202
+ document.getElementById('step2Card').classList.remove('hidden');
203
+ }
204
+ });
205
+
206
+ // Back button
207
+ document.getElementById('backBtn').addEventListener('click', () => {
208
+ stopCamera();
209
+ document.getElementById('step2Card').classList.add('hidden');
210
+ document.getElementById('step1Card').classList.remove('hidden');
211
+ });
212
+
213
+ // Camera controls
214
+ document.getElementById('startCameraBtn').addEventListener('click', startCamera);
215
+ document.getElementById('captureBtn').addEventListener('click', captureFace);
216
+ document.getElementById('retakeBtn').addEventListener('click', retake);
217
+ document.getElementById('registerBtn').addEventListener('click', () => registerUser(true));
218
+
219
+ async function startCamera() {
220
+ try {
221
+ videoStream = await navigator.mediaDevices.getUserMedia({ video: true });
222
+ document.getElementById('video').srcObject = videoStream;
223
+ document.getElementById('startCameraBtn').classList.add('hidden');
224
+ document.getElementById('captureBtn').classList.remove('hidden');
225
+ showFaceStatus('Camera ready! Position your face in the frame', 'success');
226
+ } catch (error) {
227
+ showFaceStatus('Camera access denied. Please allow camera access.', 'error');
228
+ }
229
+ }
230
+
231
+ function stopCamera() {
232
+ if (videoStream) {
233
+ videoStream.getTracks().forEach(track => track.stop());
234
+ videoStream = null;
235
+ }
236
+ }
237
+
238
+ function captureFace() {
239
+ const video = document.getElementById('video');
240
+ const canvas = document.getElementById('canvas');
241
+ const context = canvas.getContext('2d');
242
+
243
+ context.drawImage(video, 0, 0, 400, 300);
244
+ capturedImageData = canvas.toDataURL('image/jpeg');
245
+
246
+ document.getElementById('capturedImage').src = capturedImageData;
247
+ document.getElementById('preview').classList.remove('hidden');
248
+ document.getElementById('video').style.display = 'none';
249
+ document.getElementById('captureBtn').classList.add('hidden');
250
+ document.getElementById('retakeBtn').classList.remove('hidden');
251
+ document.getElementById('registerBtn').classList.remove('hidden');
252
+
253
+ stopCamera();
254
+ showFaceStatus('Face captured! Click "Complete Registration" to finish', 'success');
255
+ }
256
+
257
+ function retake() {
258
+ document.getElementById('preview').classList.add('hidden');
259
+ document.getElementById('video').style.display = 'block';
260
+ document.getElementById('retakeBtn').classList.add('hidden');
261
+ document.getElementById('registerBtn').classList.add('hidden');
262
+ capturedImageData = null;
263
+ startCamera();
264
+ }
265
+
266
+ async function registerUser(includeFace) {
267
+ const role = document.getElementById('roleSelect').value;
268
+ const matricNo = document.getElementById('matricNo').value.trim().toUpperCase();
269
+ const fullName = document.getElementById('fullName').value.trim();
270
+ const email = document.getElementById('email').value.trim();
271
+ const password = document.getElementById('password').value;
272
+
273
+ if (includeFace && !capturedImageData) {
274
+ showFaceStatus('Please capture your face first', 'error');
275
+ return;
276
+ }
277
+
278
+ showLoading('Creating your account...');
279
+
280
+ try {
281
+ // Step 1: Create user account
282
+ const userResponse = await fetch('/api/auth/register', {
283
+ method: 'POST',
284
+ headers: { 'Content-Type': 'application/json' },
285
+ body: JSON.stringify({
286
+ role: role,
287
+ matric_no: matricNo,
288
+ name: fullName,
289
+ email: email || null,
290
+ password: password
291
+ })
292
+ });
293
+
294
+ const userData = await userResponse.json();
295
+
296
+ if (!userData.success) {
297
+ hideLoading();
298
+ showStatus(userData.error, 'error');
299
+ return;
300
+ }
301
+
302
+ // Step 2: Register face if student
303
+ if (includeFace) {
304
+ const faceResponse = await fetch('/api/register_face', {
305
+ method: 'POST',
306
+ headers: { 'Content-Type': 'application/json' },
307
+ body: JSON.stringify({
308
+ student_id: matricNo,
309
+ name: fullName,
310
+ email: email || null,
311
+ image: capturedImageData
312
+ })
313
+ });
314
+
315
+ const faceData = await faceResponse.json();
316
+ hideLoading();
317
+
318
+ if (!faceData.success) {
319
+ showFaceStatus(faceData.error, 'error');
320
+ return;
321
+ }
322
+ }
323
+
324
+ hideLoading();
325
+
326
+ // Show success
327
+ document.getElementById('step1Card').classList.add('hidden');
328
+ document.getElementById('step2Card').classList.add('hidden');
329
+ document.getElementById('successCard').classList.remove('hidden');
330
+ document.getElementById('successMessage').textContent =
331
+ `Your ${role} account has been created successfully. Your application is now pending approval by an Admin. You will be able to login once approved.`;
332
+
333
+ } catch (error) {
334
+ hideLoading();
335
+ showStatus('Registration failed. Please try again.', 'error');
336
+ }
337
+ }
338
+
339
+ function showLoading(text) {
340
+ document.getElementById('loadingText').textContent = text;
341
+ document.getElementById('loadingOverlay').classList.remove('hidden');
342
+ }
343
+
344
+ function hideLoading() {
345
+ document.getElementById('loadingOverlay').classList.add('hidden');
346
+ }
347
+
348
+ function showStatus(message, type) {
349
+ const statusDiv = document.getElementById('statusMessage');
350
+ const alertClass = type === 'success' ? 'alert-success' : 'alert-error';
351
+ statusDiv.innerHTML = `<div class="alert ${alertClass}">${message}</div>`;
352
+
353
+ setTimeout(() => {
354
+ statusDiv.innerHTML = '';
355
+ }, 5000);
356
+ }
357
+
358
+ function showFaceStatus(message, type) {
359
+ const statusDiv = document.getElementById('faceStatusMessage');
360
+ const alertClass = type === 'success' ? 'alert-success' : 'alert-error';
361
+ statusDiv.innerHTML = `<div class="alert ${alertClass}">${message}</div>`;
362
+ }
363
+ </script>
364
+ </body>
365
+
366
  </html>