File size: 5,136 Bytes
df53738
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
131
132
133
134
135
136
const video = document.getElementById('videoFeed');
const empIdInput = document.getElementById('empId');
const empNameInput = document.getElementById('empName');
const btnRegister = document.getElementById('btnRegister');
const statusText = document.getElementById('statusText');
const progressCircle = document.getElementById('progressCircle');
const spoofToast = document.getElementById('spoofToast');
const spoofToastMessage = document.getElementById('spoofToastMessage');

let capturedFrames = [];
let isCapturing = false;
const REQUIRED_FRAMES = 5;
let toastDismissTimer = null;

// Start Camera
navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user', width: 640, height: 480 } })
    .then(stream => { video.srcObject = stream; })
    .catch(err => console.error(err));

// Monitor inputs to enable capture
[empIdInput, empNameInput].forEach(input => {
    input.addEventListener('input', checkInputs);
});

function checkInputs() {
    const valid = empIdInput.value.trim().length > 0 && empNameInput.value.trim().length > 0;
    if (valid && !isCapturing && capturedFrames.length === 0) {
        btnRegister.disabled = false;
        btnRegister.textContent = "START CAPTURE";
        btnRegister.onclick = startCaptureProcess;
    } else if (capturedFrames.length === REQUIRED_FRAMES) {
        btnRegister.disabled = false;
        btnRegister.textContent = "Register";
        btnRegister.onclick = submitRegistration;
    } else {
        btnRegister.disabled = true;
    }
}

function startCaptureProcess() {
    isCapturing = true;
    btnRegister.disabled = true;
    capturedFrames = [];
    statusText.textContent = "Keep face steady...";
    
    let count = 0;
    const interval = setInterval(() => {
        if (count >= REQUIRED_FRAMES) {
            clearInterval(interval);
            finishCapture();
            return;
        }
        
        const canvas = document.createElement('canvas');
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        canvas.getContext('2d').drawImage(video, 0, 0);
        capturedFrames.push(canvas.toDataURL('image/jpeg', 0.8));
        
        count++;
        updateProgress(count / REQUIRED_FRAMES);
        statusText.textContent = `Scanning... ${Math.round((count/REQUIRED_FRAMES)*100)}%`;
        
    }, 600);
}

function updateProgress(percent) {
    const offset = 113 - (113 * percent);
    progressCircle.style.strokeDashoffset = offset;
}

function finishCapture() {
    isCapturing = false;
    statusText.textContent = "Face captured ✓";
    statusText.style.color = "var(--color-primary)";
    checkInputs(); // Re-enable button for submit
}

async function submitRegistration() {
    btnRegister.disabled = true;
    btnRegister.textContent = "REGISTERING...";
    
    const payload = {
        employee_id: empIdInput.value.trim(),
        name: empNameInput.value.trim(),
        frames: capturedFrames
    };
    
    try {
        const res = await fetch('/api/register', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload)
        });
        
        const data = await res.json();

        if (data.status === 'registered') {
            document.getElementById('registerForm').style.display = 'none';
            document.getElementById('successState').style.display = 'block';
            document.getElementById('successChip').textContent = `${payload.name}${payload.employee_id}`;
        } else if (data.status === 'spoof') {
            showSpoofToast(data);
            btnRegister.disabled = false;
            btnRegister.textContent = "Register";
        } else {
            // Duplicate user or other error → snackbar
            var msg = data.message || "Unknown error";
            if (msg.indexOf("already registered") !== -1 || msg.indexOf("already registered to") !== -1) {
                if (typeof showSnackbar === 'function') showSnackbar("Duplicate registration — this face is already registered.", 'error');
            } else if (msg.indexOf("No face detected") !== -1 || msg.indexOf("no face") !== -1) {
                if (typeof showSnackbar === 'function') showSnackbar("Clear photo — ensure your face is visible and well lit.", 'info');
            } else {
                if (typeof showSnackbar === 'function') showSnackbar(msg, 'error');
            }
            btnRegister.disabled = false;
            btnRegister.textContent = "Register";
        }
    } catch (e) {
        if (typeof showSnackbar === 'function') showSnackbar("Network error. Please try again.", 'error');
        btnRegister.disabled = false;
        btnRegister.textContent = "Register";
    }
}

function showSpoofToast(data) {
    const msg = data.reason || data.message || "Use a live face, not a photo or screen.";
    spoofToastMessage.textContent = msg;
    spoofToast.classList.add('show');
    if (toastDismissTimer) clearTimeout(toastDismissTimer);
    toastDismissTimer = setTimeout(() => {
        spoofToast.classList.remove('show');
        toastDismissTimer = null;
    }, 4500);
}