| <!DOCTYPE html>
|
| <html lang="en">
|
|
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>Student Portal - Attendr</title>
|
| <link rel="stylesheet" href="style.css">
|
| <link
|
| href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@700;800&display=swap"
|
| rel="stylesheet">
|
| </head>
|
|
|
| <body>
|
|
|
|
|
| {% include '_navbar.html' %}
|
|
|
|
|
| <section class="section">
|
| <div class="container" style="max-width: 800px;">
|
| <h1 class="text-center mb-3">Student Attendance Portal</h1>
|
|
|
|
|
| <div id="step1" class="glass-card mb-2">
|
| <h2>Step 1: Enter Student ID</h2>
|
| <div class="form-group">
|
| <label class="form-label">Student ID</label>
|
| <input type="text" id="studentId" class="form-input" placeholder="e.g., A20EC0001">
|
| </div>
|
| <div class="form-group">
|
| <label class="form-label">Select Session</label>
|
| <select id="sessionSelect" class="form-select">
|
| <option value="">Loading sessions...</option>
|
| </select>
|
| </div>
|
| <button id="startBtn" class="btn btn-primary" disabled>Start Verification</button>
|
| </div>
|
|
|
|
|
| <div id="step2" class="glass-card mb-2 hidden">
|
| <h2>Step 2: Enable Permissions</h2>
|
| <p class="text-muted">We need access to your camera and location to verify your attendance.</p>
|
|
|
| <div class="grid grid-2 gap-2 mt-2">
|
| <div class="status-badge status-info" id="cameraStatus">
|
| <span>๐ท</span>
|
| <span>Camera: Waiting...</span>
|
| </div>
|
| <div class="status-badge status-info" id="gpsStatus">
|
| <span>๐</span>
|
| <span>GPS: Waiting...</span>
|
| </div>
|
| </div>
|
|
|
| <button id="enablePermissionsBtn" class="btn btn-primary mt-2">Enable Camera & GPS</button>
|
| </div>
|
|
|
|
|
| <div id="step3" class="glass-card mb-2 hidden">
|
| <h2>Step 3: Face Verification</h2>
|
| <p class="text-muted">Position your face in the frame for verification.</p>
|
|
|
| <div class="video-container mt-2">
|
| <video id="videoPreview" class="video-preview" autoplay playsinline></video>
|
| <canvas id="canvas" style="display: none;"></canvas>
|
| </div>
|
|
|
| <div id="faceStatus" class="mt-2"></div>
|
|
|
| <button id="verifyFaceBtn" class="btn btn-primary mt-2">Verify My Face</button>
|
| </div>
|
|
|
|
|
| <div id="step4" class="glass-card mb-2 hidden">
|
| <h2>Step 4: Location Verification</h2>
|
| <p class="text-muted">Verifying you are in the classroom...</p>
|
|
|
| <div id="locationStatus" class="mt-2"></div>
|
|
|
| <button id="verifyLocationBtn" class="btn btn-primary mt-2">Verify Location</button>
|
| </div>
|
|
|
|
|
| <div id="step5" class="glass-card mb-2 hidden">
|
| <h2>Step 5: Enter Attendance Code</h2>
|
| <p class="text-muted">Enter the code displayed by your lecturer.</p>
|
|
|
| <div class="form-group mt-2">
|
| <label class="form-label">Attendance Code</label>
|
| <input type="text" id="attendanceCode" class="form-input" placeholder="Enter 6-digit code"
|
| maxlength="6"
|
| style="text-transform: uppercase; font-size: 1.5rem; text-align: center; letter-spacing: 0.5rem;">
|
| </div>
|
|
|
| <button id="submitAttendanceBtn" class="btn btn-success mt-2">Mark Attendance</button>
|
| </div>
|
|
|
|
|
| <div id="successMessage" class="glass-card hidden"
|
| style="background: rgba(34, 197, 94, 0.1); border: 2px solid var(--color-success);">
|
| <div class="text-center">
|
| <div style="font-size: 4rem; margin-bottom: 1rem;">โ
</div>
|
| <h2 style="color: var(--color-success);">Attendance Marked Successfully!</h2>
|
| <p id="successDetails" class="text-muted mt-2"></p>
|
| <button onclick="location.reload()" class="btn btn-primary mt-2">Mark Another Attendance</button>
|
| </div>
|
| </div>
|
|
|
|
|
| <div id="errorDisplay" class="hidden"></div>
|
| </div>
|
| </section>
|
|
|
|
|
| <div id="loadingOverlay" class="loading-overlay hidden">
|
| <div class="text-center">
|
| <div class="spinner"></div>
|
| <p class="mt-2" id="loadingText">Processing...</p>
|
| </div>
|
| </div>
|
|
|
| <script src="{{ url_for('static', filename='js/student.js') }}"></script>
|
| <script>
|
| async function logout() {
|
| if (!confirm('Are you sure you want to logout?')) return;
|
|
|
| try {
|
| const response = await fetch('/api/auth/logout', {
|
| method: 'POST',
|
| headers: { 'Content-Type': 'application/json' }
|
| });
|
|
|
| const data = await response.json();
|
|
|
| if (data.success) {
|
| alert(data.message);
|
| window.location.href = '/';
|
| } else {
|
| alert('Logout failed');
|
| }
|
| } catch (error) {
|
| alert('Logout failed');
|
| }
|
| }
|
| </script>
|
| </body>
|
|
|
| </html> |