0% found this document useful (0 votes)
36 views36 pages

Doctype HTML

Uploaded by

Bagas Rahmadani
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views36 pages

Doctype HTML

Uploaded by

Bagas Rahmadani
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

<!

DOCTYPE html>

<html lang="id">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Sistem Absensi Guru - SMK Teknologi</title>

<script src="[Link]

<script src="[Link]

<style>

*{

margin: 0;

padding: 0;

box-sizing: border-box;

body {

font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

min-height: 100vh;

.container {

max-width: 1400px;

margin: 0 auto;

padding: 20px;

.header {

background: white;

padding: 20px 30px;

border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);

margin-bottom: 30px;

display: flex;

justify-content: space-between;

align-items: center;

flex-wrap: wrap;

.header h1 {

color: #2d3748;

font-size: 28px;

margin-bottom: 5px;

.header .subtitle {

color: #718096;

font-size: 14px;

.user-info {

display: flex;

align-items: center;

gap: 15px;

flex-wrap: wrap;

.role-badge {

padding: 8px 16px;

border-radius: 25px;

font-size: 12px;

font-weight: 600;
text-transform: uppercase;

.role-kepala { background: #ffd700; color: #8b6914; }

.role-guru { background: #e3f2fd; color: #1976d2; }

.role-operator { background: #e8f5e8; color: #2e7d32; }

.logout-btn {

background: #ef4444;

color: white;

border: none;

padding: 10px 20px;

border-radius: 8px;

cursor: pointer;

transition: all 0.3s;

.logout-btn:hover {

background: #dc2626;

transform: translateY(-1px);

.dashboard-grid {

display: grid;

grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));

gap: 20px;

margin-bottom: 30px;

.card {

background: white;
border-radius: 15px;

padding: 25px;

box-shadow: 0 10px 30px rgba(0,0,0,0.1);

transition: transform 0.3s ease;

.card:hover {

transform: translateY(-5px);

.stat-card {

text-align: center;

background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

color: white;

.stat-number {

font-size: 48px;

font-weight: bold;

margin-bottom: 10px;

text-shadow: 0 2px 4px rgba(0,0,0,0.3);

.stat-label {

font-size: 16px;

opacity: 0.9;

.section-title {

color: #2d3748;

font-size: 20px;
margin-bottom: 20px;

display: flex;

align-items: center;

gap: 10px;

.tabs {

display: flex;

background: #f7fafc;

border-radius: 10px;

padding: 5px;

margin-bottom: 20px;

flex-wrap: wrap;

.tab {

flex: 1;

padding: 12px 20px;

border: none;

background: none;

border-radius: 8px;

cursor: pointer;

transition: all 0.3s;

font-weight: 500;

min-width: 120px;

.[Link] {

background: white;

color: #667eea;

box-shadow: 0 2px 10px rgba(0,0,0,0.1);


}

.tab-content {

display: none;

.[Link] {

display: block;

.attendance-list {

max-height: 400px;

overflow-y: auto;

.attendance-item {

display: flex;

justify-content: space-between;

align-items: center;

padding: 15px;

border-bottom: 1px solid #e2e8f0;

transition: background 0.3s;

.attendance-item:hover {

background: #f7fafc;

.attendance-item:last-child {

border-bottom: none;

}
.teacher-info {

display: flex;

align-items: center;

gap: 15px;

.teacher-avatar {

width: 45px;

height: 45px;

border-radius: 50%;

background: linear-gradient(135deg, #667eea, #764ba2);

display: flex;

align-items: center;

justify-content: center;

color: white;

font-weight: bold;

font-size: 18px;

.teacher-details h4 {

color: #2d3748;

margin-bottom: 2px;

.teacher-details p {

color: #718096;

font-size: 14px;

.status-badge {
padding: 6px 12px;

border-radius: 20px;

font-size: 12px;

font-weight: 600;

.status-hadir { background: #dcfce7; color: #166534; }

.status-terlambat { background: #fef3c7; color: #92400e; }

.status-tidak-hadir { background: #fee2e2; color: #991b1b; }

.controls {

display: flex;

justify-content: between;

align-items: center;

gap: 15px;

margin-bottom: 20px;

flex-wrap: wrap;

.search-box, .date-filter, .export-btn {

padding: 10px 15px;

border: 2px solid #e2e8f0;

border-radius: 8px;

font-size: 14px;

transition: all 0.3s;

.search-box:focus, .date-filter:focus {

outline: none;

border-color: #667eea;

box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);


}

.export-btn {

background: #10b981;

color: white;

border: none;

cursor: pointer;

display: flex;

align-items: center;

gap: 8px;

.export-btn:hover {

background: #059669;

transform: translateY(-1px);

.data-table {

width: 100%;

border-collapse: collapse;

margin-top: 20px;

.data-table th, .data-table td {

padding: 12px 15px;

text-align: left;

border-bottom: 1px solid #e2e8f0;

.data-table th {

background: #f7fafc;
color: #2d3748;

font-weight: 600;

.data-table tr:hover {

background: #f7fafc;

.chart-container {

position: relative;

height: 300px;

margin-top: 20px;

.rfid-status {

display: flex;

align-items: center;

gap: 10px;

padding: 15px;

border-radius: 10px;

margin-bottom: 20px;

.rfid-connected {

background: #dcfce7;

color: #166534;

.rfid-disconnected {

background: #fee2e2;

color: #991b1b;
}

.status-dot {

width: 12px;

height: 12px;

border-radius: 50%;

.dot-green { background: #22c55e; }

.dot-red { background: #ef4444; }

@media (max-width: 768px) {

.header {

flex-direction: column;

text-align: center;

gap: 15px;

.dashboard-grid {

grid-template-columns: 1fr;

.controls {

flex-direction: column;

align-items: stretch;

.tabs {

flex-direction: column;

}
.tab {

min-width: auto;

.loading {

display: inline-block;

width: 20px;

height: 20px;

border: 3px solid #f3f3f3;

border-top: 3px solid #667eea;

border-radius: 50%;

animation: spin 1s linear infinite;

@keyframes spin {

0% { transform: rotate(0deg); }

100% { transform: rotate(360deg); }

</style>

</head>

<body>

<div class="container">

<!-- Header -->

<div class="header">

<div>

<h1>Sistem Absensi Guru</h1>

<p class="subtitle">SMK Teknologi Pekanbaru</p>

</div>

<div class="user-info">

<span class="role-badge role-kepala" id="userRole">Kepala Sekolah</span>


<span id="userName">Budi Santoso, [Link]</span>

<button class="logout-btn" onclick="logout()">Keluar</button>

</div>

</div>

<!-- RFID Status -->

<div class="rfid-status rfid-connected" id="rfidStatus">

<div class="status-dot dot-green"></div>

<span>ESP8266 & MFRC522 Connected</span>

<span style="margin-left: auto; font-size: 12px;">Last sync: <span id="lastSync">2 detik


lalu</span></span>

</div>

<!-- Dashboard Stats -->

<div class="dashboard-grid">

<div class="card stat-card">

<div class="stat-number" id="todayPresent">24</div>

<div class="stat-label">Hadir Hari Ini</div>

</div>

<div class="card stat-card">

<div class="stat-number" id="todayLate">3</div>

<div class="stat-label">Terlambat</div>

</div>

<div class="card stat-card">

<div class="stat-number" id="todayAbsent">1</div>

<div class="stat-label">Tidak Hadir</div>

</div>

<div class="card stat-card">

<div class="stat-number" id="totalTeachers">28</div>

<div class="stat-label">Total Guru</div>

</div>
</div>

<!-- Main Content -->

<div class="card">

<div class="tabs">

<button class="tab active" onclick="switchTab('dashboard')">Dashboard</button>

<button class="tab" onclick="switchTab('attendance')">Kehadiran Hari Ini</button>

<button class="tab" onclick="switchTab('reports')">Laporan & Rekap</button>

<button class="tab" onclick="switchTab('teachers')">Data Guru</button>

</div>

<!-- Dashboard Tab -->

<div id="dashboard" class="tab-content active">

<h3 class="section-title">📊 Dashboard Kehadiran</h3>

<div class="chart-container">

<canvas id="attendanceChart"></canvas>

</div>

</div>

<!-- Attendance Tab -->

<div id="attendance" class="tab-content">

<h3 class="section-title">📅 Kehadiran Hari Ini - <span id="currentDate"></span></h3>

<div class="controls">

<input type="text" class="search-box" placeholder="Cari nama guru..."


id="searchTeacher">

<button class="export-btn" onclick="exportTodayAttendance()">

📊 Export Excel Hari Ini

</button>

</div>

<div class="attendance-list" id="attendanceList">

<!-- Attendance items will be populated by JavaScript -->


</div>

</div>

<!-- Reports Tab -->

<div id="reports" class="tab-content">

<h3 class="section-title">📈 Laporan & Rekap Absensi</h3>

<div class="controls">

<input type="date" class="date-filter" id="startDate">

<input type="date" class="date-filter" id="endDate">

<button class="export-btn" onclick="exportPeriodReport()">

📋 Export Periode

</button>

<button class="export-btn" onclick="exportMonthlyReport()" style="background:


#3b82f6;">

📅 Rekap Bulanan

</button>

</div>

<table class="data-table">

<thead>

<tr>

<th>Nama Guru</th>

<th>NIP</th>

<th>Total Hadir</th>

<th>Total Terlambat</th>

<th>Total Tidak Hadir</th>

<th>Persentase Kehadiran</th>

</tr>

</thead>

<tbody id="reportsTable">

<!-- Data will be populated by JavaScript -->

</tbody>
</table>

</div>

<!-- Teachers Tab -->

<div id="teachers" class="tab-content">

<h3 class="section-title">👥 Data Guru</h3>

<div class="controls">

<input type="text" class="search-box" placeholder="Cari guru..." id="searchAllTeachers">

<button class="export-btn" onclick="exportTeachersData()" style="background:


#8b5cf6;">

👥 Export Data Guru

</button>

</div>

<table class="data-table">

<thead>

<tr>

<th>Nama</th>

<th>NIP</th>

<th>Mata Pelajaran</th>

<th>RFID Card ID</th>

<th>Status</th>

<th>Aksi</th>

</tr>

</thead>

<tbody id="teachersTable">

<!-- Data will be populated by JavaScript -->

</tbody>

</table>

</div>

</div>

</div>
<script>

// Sample data - replace with real API calls

const currentUser = {

name: "Budi Santoso, [Link]",

role: "kepala", // kepala, guru, operator

id: "001"

};

const teachers = [

{ id: "001", name: "Budi Santoso, [Link]", nip: "196801012000031001", subject: "Matematika",
rfidId: "A1B2C3D4", status: "aktif" },

{ id: "002", name: "Sari Dewi, [Link]", nip: "198503152010122002", subject: "Pemrograman",
rfidId: "E5F6G7H8", status: "aktif" },

{ id: "003", name: "Ahmad Rahman, S.T", nip: "197912052005021003", subject: "Jaringan",
rfidId: "I9J0K1L2", status: "aktif" },

{ id: "004", name: "Maya Sari, [Link]", nip: "198207102008012004", subject: "Bahasa
Indonesia", rfidId: "M3N4O5P6", status: "aktif" },

{ id: "005", name: "Dedi Kurniawan, [Link]", nip: "199001152012011005", subject:


"Database", rfidId: "Q7R8S9T0", status: "aktif" }

];

const todayAttendance = [

{ teacherId: "001", name: "Budi Santoso, [Link]", checkIn: "07:15", status: "hadir", subject:
"Matematika" },

{ teacherId: "002", name: "Sari Dewi, [Link]", checkIn: "07:45", status: "terlambat", subject:
"Pemrograman" },

{ teacherId: "003", name: "Ahmad Rahman, S.T", checkIn: "07:10", status: "hadir", subject:
"Jaringan" },

{ teacherId: "004", name: "Maya Sari, [Link]", checkIn: "-", status: "tidak-hadir", subject:
"Bahasa Indonesia" },

{ teacherId: "005", name: "Dedi Kurniawan, [Link]", checkIn: "07:20", status: "hadir", subject:
"Database" }

];
// Initialize page

[Link]('DOMContentLoaded', function() {

setupUserRole();

setCurrentDate();

populateAttendanceList();

populateReportsTable();

populateTeachersTable();

createAttendanceChart();

simulateRealTime();

setDefaultDates();

});

function setupUserRole() {

const roleElement = [Link]('userRole');

const roleClasses = {

'kepala': 'role-kepala',

'guru': 'role-guru',

'operator': 'role-operator'

};

const roleTexts = {

'kepala': 'Kepala Sekolah',

'guru': 'Guru',

'operator': 'Operator'

};

[Link] = `role-badge ${roleClasses[[Link]]}`;

[Link] = roleTexts[[Link]];

[Link]('userName').textContent = [Link];

}
function setCurrentDate() {

const today = new Date();

const options = {

weekday: 'long',

year: 'numeric',

month: 'long',

day: 'numeric'

};

[Link]('currentDate').textContent = [Link]('id-ID',
options);

function setDefaultDates() {

const today = new Date();

const firstDay = new Date([Link](), [Link](), 1);

[Link]('startDate').valueAsDate = firstDay;

[Link]('endDate').valueAsDate = today;

function switchTab(tabName) {

// Remove active class from all tabs and content

[Link]('.tab').forEach(tab => [Link]('active'));

[Link]('.tab-content').forEach(content =>
[Link]('active'));

// Add active class to clicked tab and corresponding content

[Link]('active');

[Link](tabName).[Link]('active');

}
function populateAttendanceList() {

const listContainer = [Link]('attendanceList');

[Link] = '';

[Link](attendance => {

const item = [Link]('div');

[Link] = 'attendance-item';

const statusClass = {

'hadir': 'status-hadir',

'terlambat': 'status-terlambat',

'tidak-hadir': 'status-tidak-hadir'

};

const statusText = {

'hadir': 'Hadir',

'terlambat': 'Terlambat',

'tidak-hadir': 'Tidak Hadir'

};

[Link] = `

<div class="teacher-info">

<div class="teacher-avatar">${[Link](0)}</div>

<div class="teacher-details">

<h4>${[Link]}</h4>

<p>${[Link]} • ${[Link] !== '-' ? 'Masuk: ' +


[Link] : 'Belum absen'}</p>

</div>

</div>

<div class="status-badge ${statusClass[[Link]]}">

${statusText[[Link]]}
</div>

`;

[Link](item);

});

function populateReportsTable() {

const tbody = [Link]('reportsTable');

[Link] = '';

[Link](teacher => {

const row = [Link]('tr');

const hadir = [Link]([Link]() * 20) + 15;

const terlambat = [Link]([Link]() * 3);

const tidakHadir = [Link]([Link]() * 2);

const total = hadir + terlambat + tidakHadir;

const persentase = ((hadir / total) * 100).toFixed(1);

[Link] = `

<td>${[Link]}</td>

<td>${[Link]}</td>

<td>${hadir}</td>

<td>${terlambat}</td>

<td>${tidakHadir}</td>

<td><strong>${persentase}%</strong></td>

`;

[Link](row);

});

}
function populateTeachersTable() {

const tbody = [Link]('teachersTable');

[Link] = '';

[Link](teacher => {

const row = [Link]('tr');

[Link] = `

<td>${[Link]}</td>

<td>${[Link]}</td>

<td>${[Link]}</td>

<td><code>${[Link]}</code></td>

<td><span class="status-badge status-hadir">Aktif</span></td>

<td>

<button onclick="editTeacher('${[Link]}')" style="background: #3b82f6; color:


white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; margin-right:
5px;">Edit</button>

<button onclick="deleteTeacher('${[Link]}')" style="background: #ef4444; color:


white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer;">Hapus</button>

</td>

`;

[Link](row);

});

function createAttendanceChart() {

const ctx = [Link]('attendanceChart').getContext('2d');

// Sample data for the last 7 days

const labels = [];

const hadirData = [];

const terlambatData = [];

const tidakHadirData = [];


for (let i = 6; i >= 0; i--) {

const date = new Date();

[Link]([Link]() - i);

[Link]([Link]('id-ID', { weekday: 'short', day: 'numeric' }));

[Link]([Link]([Link]() * 5) + 20);

[Link]([Link]([Link]() * 3) + 1);

[Link]([Link]([Link]() * 2));

new Chart(ctx, {

type: 'line',

data: {

labels: labels,

datasets: [

label: 'Hadir',

data: hadirData,

borderColor: '#10b981',

backgroundColor: 'rgba(16, 185, 129, 0.1)',

tension: 0.4

},

label: 'Terlambat',

data: terlambatData,

borderColor: '#f59e0b',

backgroundColor: 'rgba(245, 158, 11, 0.1)',

tension: 0.4

},

{
label: 'Tidak Hadir',

data: tidakHadirData,

borderColor: '#ef4444',

backgroundColor: 'rgba(239, 68, 68, 0.1)',

tension: 0.4

},

options: {

responsive: true,

maintainAspectRatio: false,

plugins: {

legend: {

position: 'top',

},

title: {

display: true,

text: 'Tren Kehadiran 7 Hari Terakhir'

},

scales: {

y: {

beginAtZero: true

});

function simulateRealTime() {

setInterval(() => {
const lastSyncEl = [Link]('lastSync');

const randomSeconds = [Link]([Link]() * 30) + 1;

[Link] = `${randomSeconds} detik lalu`;

}, 5000);

// Export functions

function exportTodayAttendance() {

const data = [Link](att => ({

'Nama Guru': [Link],

'Mata Pelajaran': [Link],

'Waktu Masuk': [Link],

'Status': [Link] === 'hadir' ? 'Hadir' : [Link] === 'terlambat' ? 'Terlambat' : 'Tidak
Hadir'

}));

exportToExcel(data, 'Absensi_Hari_Ini');

function exportPeriodReport() {

const startDate = [Link]('startDate').value;

const endDate = [Link]('endDate').value;

if (!startDate || !endDate) {

alert('Mohon pilih tanggal mulai dan akhir');

return;

// Simulate period report data

const data = [Link](teacher => {

const hadir = [Link]([Link]() * 20) + 15;


const terlambat = [Link]([Link]() * 3);

const tidakHadir = [Link]([Link]() * 2);

const total = hadir + terlambat + tidakHadir;

return {

'Nama Guru': [Link],

'NIP': [Link],

'Mata Pelajaran': [Link],

'Total Hadir': hadir,

'Total Terlambat': terlambat,

'Total Tidak Hadir': tidakHadir,

'Persentase Kehadiran': `${((hadir / total) * 100).toFixed(1)}%`

};

});

exportToExcel(data, `Laporan_Periode_${startDate}_${endDate}`);

function exportMonthlyReport() {

const currentMonth = new Date().toLocaleDateString('id-ID', { year: 'numeric', month:


'long' });

// Simulate monthly data with daily breakdown

const data = [];

[Link](teacher => {

for (let day = 1; day <= 30; day++) {

const status = [Link]() > 0.1 ? ([Link]() > 0.15 ? 'Hadir' : 'Terlambat') :
'Tidak Hadir';

const waktu = status === 'Tidak Hadir' ? '-' : `07:${String([Link]([Link]() *


45)).padStart(2, '0')}`;

[Link]({
'Tanggal': `${day}/${new Date().getMonth() + 1}/${new Date().getFullYear()}`,

'Nama Guru': [Link],

'NIP': [Link],

'Waktu Masuk': waktu,

'Status': status

});

});

exportToExcel(data, `Rekap_Bulanan_${[Link](' ', '_')}`);

function exportTeachersData() {

const data = [Link](teacher => ({

'Nama': [Link],

'NIP': [Link],

'Mata Pelajaran': [Link],

'RFID Card ID': [Link],

'Status': [Link]

}));

exportToExcel(data, 'Data_Guru_Lengkap');

function exportToExcel(data, filename) {

const wb = [Link].book_new();

const ws = [Link].json_to_sheet(data);

// Auto-width columns

const colWidths = [];

const headers = [Link](data[0] || {});


[Link](header => {

const maxWidth = [Link](

[Link],

...[Link](row => String(row[header] || '').length)

);

[Link]({ width: [Link](maxWidth + 2, 50) });

});

ws['!cols'] = colWidths;

[Link].book_append_sheet(wb, ws, 'Data');

const today = new Date().toISOString().split('T')[0];

[Link](wb, `${filename}_${today}.xlsx`);

showNotification('File Excel berhasil didownload!', 'success');

// Search functions

[Link]('searchTeacher')?.addEventListener('input', function(e) {

const searchTerm = [Link]();

const items = [Link]('.attendance-item');

[Link](item => {

const teacherName = [Link]('.teacher-details h4').[Link]();

[Link] = [Link](searchTerm) ? 'flex' : 'none';

});

});

[Link]('searchAllTeachers')?.addEventListener('input', function(e) {

const searchTerm = [Link]();

const rows = [Link]('#teachersTable tr');


[Link](row => {

const teacherName = [Link][0]?.[Link]() || '';

const nip = [Link][1]?.[Link]() || '';

const subject = [Link][2]?.[Link]() || '';

const matches = [Link](searchTerm) ||

[Link](searchTerm) ||

[Link](searchTerm);

[Link] = matches ? 'table-row' : 'none';

});

});

// Teacher management functions

function editTeacher(teacherId) {

const teacher = [Link](t => [Link] === teacherId);

if (!teacher) return;

// Simple prompt-based editing (in real app, use modal)

const newName = prompt('Nama Guru:', [Link]);

const newSubject = prompt('Mata Pelajaran:', [Link]);

const newRfidId = prompt('RFID Card ID:', [Link]);

if (newName && newSubject && newRfidId) {

[Link] = newName;

[Link] = newSubject;

[Link] = newRfidId;

populateTeachersTable();

showNotification('Data guru berhasil diupdate!', 'success');


}

function deleteTeacher(teacherId) {

if (confirm('Apakah Anda yakin ingin menghapus data guru ini?')) {

const index = [Link](t => [Link] === teacherId);

if (index > -1) {

[Link](index, 1);

populateTeachersTable();

showNotification('Data guru berhasil dihapus!', 'success');

function logout() {

if (confirm('Apakah Anda yakin ingin keluar?')) {

showNotification('Logout berhasil!', 'info');

// In real app, redirect to login page

setTimeout(() => {

[Link]();

}, 1000);

// Notification system

function showNotification(message, type = 'info') {

const notification = [Link]('div');

[Link] = `

position: fixed;

top: 20px;

right: 20px;
padding: 15px 20px;

border-radius: 8px;

color: white;

font-weight: 500;

z-index: 1000;

animation: slideIn 0.3s ease;

max-width: 300px;

box-shadow: 0 4px 12px rgba(0,0,0,0.2);

`;

const colors = {

success: '#10b981',

error: '#ef4444',

info: '#3b82f6',

warning: '#f59e0b'

};

[Link] = colors[type] || [Link];

[Link] = message;

[Link](notification);

setTimeout(() => {

[Link] = 'slideOut 0.3s ease';

setTimeout(() => {

[Link](notification);

}, 300);

}, 3000);

// Add CSS animations


const style = [Link]('style');

[Link] = `

@keyframes slideIn {

from { transform: translateX(100%); opacity: 0; }

to { transform: translateX(0); opacity: 1; }

@keyframes slideOut {

from { transform: translateX(0); opacity: 1; }

to { transform: translateX(100%); opacity: 0; }

`;

[Link](style);

// Simulate real-time RFID scanning

function simulateRFIDScan() {

const rfidStatus = [Link]('rfidStatus');

const randomDelay = [Link]() * 10000 + 5000; // 5-15 seconds

setTimeout(() => {

// Simulate random teacher scanning card

const randomTeacher = teachers[[Link]([Link]() * [Link])];

const currentTime = new Date().toLocaleTimeString('id-ID', {

hour: '2-digit',

minute: '2-digit'

});

// Update attendance list if teacher not already checked in

const existingAttendance = [Link](att => [Link] ===


[Link]);

if (!existingAttendance) {

const status = [Link]() > 0.8 ? 'terlambat' : 'hadir';


[Link]({

teacherId: [Link],

name: [Link],

checkIn: currentTime,

status: status,

subject: [Link]

});

populateAttendanceList();

updateStats();

showNotification(`${[Link]} baru saja absen masuk (${currentTime})`,


'success');

simulateRFIDScan(); // Continue simulation

}, randomDelay);

function updateStats() {

const present = [Link](att => [Link] === 'hadir').length;

const late = [Link](att => [Link] === 'terlambat').length;

const absent = [Link] - [Link];

[Link]('todayPresent').textContent = present;

[Link]('todayLate').textContent = late;

[Link]('todayAbsent').textContent = absent;

// Start RFID simulation when page loads

[Link]('DOMContentLoaded', function() {

setTimeout(() => {
simulateRFIDScan();

}, 3000);

});

// Simulate ESP8266 connection status

function simulateConnectionStatus() {

const rfidStatus = [Link]('rfidStatus');

const isConnected = [Link]() > 0.05; // 95% uptime

if (isConnected) {

[Link] = 'rfid-status rfid-connected';

[Link] = `

<div class="status-dot dot-green"></div>

<span>ESP8266 & MFRC522 Connected</span>

<span style="margin-left: auto; font-size: 12px;">Last sync: <span id="lastSync">2 detik


lalu</span></span>

`;

} else {

[Link] = 'rfid-status rfid-disconnected';

[Link] = `

<div class="status-dot dot-red"></div>

<span>ESP8266 Connection Lost</span>

<span style="margin-left: auto; font-size: 12px;">Reconnecting...</span>

`;

setTimeout(simulateConnectionStatus, [Link]() * 30000 + 30000); // Check every 30-


60 seconds

// Start connection monitoring

[Link]('DOMContentLoaded', function() {
setTimeout(simulateConnectionStatus, 10000);

});

// Add keyboard shortcuts

[Link]('keydown', function(e) {

if ([Link] || [Link]) {

switch([Link]) {

case '1':

[Link]();

switchTab('dashboard');

[Link]('[onclick="switchTab(\'dashboard\')"]').[Link]('active');

break;

case '2':

[Link]();

switchTab('attendance');

[Link]('[onclick="switchTab(\'attendance\')"]').[Link]('active');

break;

case '3':

[Link]();

switchTab('reports');

[Link]('[onclick="switchTab(\'reports\')"]').[Link]('active');

break;

case '4':

[Link]();

switchTab('teachers');

[Link]('[onclick="switchTab(\'teachers\')"]').[Link]('active');

break;

});
// Add help tooltip

const helpText = [Link]('div');

[Link] = '💡 Tips: Gunakan Ctrl+1,2,3,4 untuk navigasi cepat antar tab';

[Link] = `

position: fixed;

bottom: 20px;

left: 20px;

background: rgba(0,0,0,0.8);

color: white;

padding: 8px 12px;

border-radius: 6px;

font-size: 12px;

opacity: 0.7;

z-index: 1000;

`;

[Link](helpText);

// Auto-refresh data every 30 seconds

setInterval(() => {

if ([Link] === 'visible') {

// In real app, fetch fresh data from API

updateStats();

showNotification('Data diperbarui', 'info');

}, 30000);

</script>

</body>

</html>

You might also like