Spaces:
Runtime error
Runtime error
File size: 6,169 Bytes
701628b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | {% extends "base.html" %}
{% block content %}
<div class="top-bar">
<a href="/dashboard" style="color: var(--color-text); text-decoration: none;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M19 12H5M12 19l-7-7 7-7"/>
</svg>
</a>
<h2>Register</h2>
<a href="/dashboard" class="top-bar-logo-wrap">
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="One Step Greener" class="top-bar-logo top-bar-logo-sm" />
</a>
</div>
<!-- PIN gate: always shown first; hidden after correct PIN -->
<div id="pinGate" class="pin-gate">
<p class="pin-prompt">Enter PIN to access Register.</p>
<input type="password" id="pinInput" class="pin-input" placeholder="PIN" maxlength="8" inputmode="numeric" autocomplete="off" />
<button type="button" id="pinSubmit" class="btn-primary pin-submit">Continue</button>
<p id="pinError" class="pin-error" style="display: none;"></p>
</div>
<!-- Register form: hidden until PIN verified; switchable tab Employee | Manforce -->
<div id="registerForm" class="register-form-locked" style="display: none;">
<div class="register-tabs" role="tablist">
<button type="button" id="tabEmployee" class="register-tab active" role="tab" aria-selected="true" data-tab="employee">Employee</button>
<button type="button" id="tabManforce" class="register-tab" role="tab" aria-selected="false" data-tab="manforce">Manforce</button>
</div>
<div id="panelEmployee" class="register-panel active" role="tabpanel">
<input type="text" id="employeeCode" placeholder="Employee code">
<p class="status-text" id="statusTextEmployee">Align face within frame</p>
<button id="btnRegisterEmployee" class="btn-primary" disabled>Register</button>
</div>
<div id="panelManforce" class="register-panel" role="tabpanel" hidden>
<input type="text" id="manforceAadhaar" placeholder="Aadhaar number">
<input type="text" id="manforceName" placeholder="Full name">
<input type="text" id="manforceMobile" placeholder="Mobile number">
<p class="status-text" id="statusTextManforce">Align face within frame</p>
<button id="btnRegisterManforce" class="btn-primary" disabled>Register</button>
</div>
<div class="video-rect-container register-video-shared">
<video id="videoFeed" autoplay playsinline muted></video>
<div class="rect-overlay"></div>
<svg class="progress-ring" viewBox="0 0 40 40">
<circle cx="20" cy="20" r="18" stroke="#333" stroke-width="4" fill="none"/>
<circle id="progressCircle" cx="20" cy="20" r="18" stroke="var(--color-primary)" stroke-width="4" fill="none" stroke-dasharray="113" stroke-dashoffset="113" transform="rotate(-90 20 20)"/>
</svg>
</div>
<p class="status-text" id="statusText">Align face within frame</p>
<p class="status-hint register-capture-hint">Look at the camera and blink naturally during capture.</p>
</div>
<!-- Spoof toast (same as attendance) -->
<div id="spoofToast" class="toast toast-danger" role="alert" aria-live="polite">
<span class="toast-icon">⚠</span>
<div class="toast-body">
<strong class="toast-title">Spoofing detected</strong>
<p class="toast-message" id="spoofToastMessage">Use a live face, not a photo or screen.</p>
</div>
</div>
<div id="successState" class="success-state" style="display:none;">
<img src="{{ url_for('static', filename='images/face-id-success.png') }}" alt="Face registered" class="success-face-icon" />
<h2>Registered</h2>
<div class="chip" id="successChip"></div>
<button class="btn-outline" onclick="location.reload()">Register Another</button>
<br>
<a href="/dashboard" style="color: var(--color-text-muted); font-size: 13px; margin-top: 20px; display:inline-block;">Back to check in</a>
</div>
{% endblock %}
{% block scripts %}
<script>
(function() {
var pinGate = document.getElementById('pinGate');
var registerForm = document.getElementById('registerForm');
var pinInput = document.getElementById('pinInput');
var pinSubmit = document.getElementById('pinSubmit');
var pinError = document.getElementById('pinError');
if (pinGate && registerForm && pinInput && pinSubmit) {
function doVerify() {
var pin = (pinInput.value || '').trim();
pinError.style.display = 'none';
if (!pin) {
pinError.textContent = 'Enter PIN';
pinError.style.display = 'block';
return;
}
pinSubmit.disabled = true;
fetch('/api/verify-pin', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pin: pin })
})
.then(function(r) { return r.json(); })
.then(function(data) {
pinSubmit.disabled = false;
if (data.status === 'ok') {
pinGate.style.display = 'none';
registerForm.style.display = 'block';
if (window.loadRegisterScript) window.loadRegisterScript();
} else {
pinError.textContent = data.message || 'Incorrect PIN';
pinError.style.display = 'block';
}
})
.catch(function() {
pinSubmit.disabled = false;
pinError.textContent = 'Request failed';
pinError.style.display = 'block';
});
}
pinSubmit.addEventListener('click', doVerify);
pinInput.addEventListener('keydown', function(e) { if (e.key === 'Enter') doVerify(); });
window.loadRegisterScript = function() {
if (window.registerScriptLoaded) return;
window.registerScriptLoaded = true;
var s = document.createElement('script');
s.src = "{{ url_for('static', filename='js/register.js') }}";
document.body.appendChild(s);
};
}
})();
</script>
{% endblock %}
|