598 lines
21 KiB
JavaScript
598 lines
21 KiB
JavaScript
// Tambah Pengunjung JavaScript
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const form = document.getElementById('addVisitorForm');
|
|
const namaAnakInput = document.getElementById('namaAnak');
|
|
const scanStatusDiv = document.getElementById('scanStatus');
|
|
const kodeGelangInput = document.getElementById('kodeGelang');
|
|
const noHpOrtuInput = document.getElementById('noHpOrtu');
|
|
const durationSelect = document.getElementById('durasi');
|
|
const priceDisplay = document.getElementById('priceDisplay');
|
|
const errorMessage = document.getElementById('errorMessage');
|
|
const successMessage = document.getElementById('successMessage');
|
|
const submitBtn = document.getElementById('submitBtn');
|
|
const loadingSpinner = document.getElementById('loadingSpinner');
|
|
const btnText = document.getElementById('btnText');
|
|
const endSessionModal = document.getElementById('endSessionModal');
|
|
const endSessionBtn = document.getElementById('endSessionBtn');
|
|
const cancelEndBtn = document.getElementById('cancelEndBtn');
|
|
const currentUserInfo = document.getElementById('currentUserInfo');
|
|
const unknownRfidModal = document.getElementById('unknownRfidModal'); // Get the new modal from HTML
|
|
const displayUnknownRfidCode = document.getElementById('displayUnknownRfidCode');
|
|
const closeUnknownRfidModalBtn = document.getElementById('closeUnknownRfidModalBtn');
|
|
|
|
// Price configuration
|
|
const prices = {
|
|
30: 15000, // 30 menit
|
|
60: 25000, // 1 jam
|
|
90: 35000, // 1.5 jam
|
|
120: 45000, // 2 jam
|
|
180: 60000, // 3 jam
|
|
240: 75000 // 4 jam
|
|
};
|
|
|
|
let currentKodeGelang = null;
|
|
let isFormEnabled = false;
|
|
let scanInterval = null;
|
|
|
|
// Start scanning process
|
|
function startScanning() {
|
|
if (scanInterval) {
|
|
clearInterval(scanInterval);
|
|
}
|
|
|
|
scanInterval = setInterval(async () => {
|
|
try {
|
|
const response = await fetch('../api/tambah_pengunjung.php?action=get_scanned_rfid');
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'success' && result.data.scanned && result.data.kode_gelang) {
|
|
// Stop scanning while processing
|
|
clearInterval(scanInterval);
|
|
scanInterval = null;
|
|
|
|
// Check RFID status
|
|
await handleRfidScan(result.data.kode_gelang);
|
|
}
|
|
} catch (error) {
|
|
console.log('Background scan check failed:', error);
|
|
}
|
|
}, 2000);
|
|
}
|
|
|
|
// Handle RFID scan result
|
|
async function handleRfidScan(kodeGelang) {
|
|
try {
|
|
const response = await fetch('../api/tambah_pengunjung.php?action=check_rfid');
|
|
const result = await response.json();
|
|
|
|
// Sembunyikan pesan sukses/error yang mungkin ada sebelumnya
|
|
successMessage.style.display = 'none';
|
|
errorMessage.style.display = 'none';
|
|
|
|
if (result.status === 'available') {
|
|
// Gelang tersedia - bisa digunakan
|
|
kodeGelangInput.value = result.data.kode_gelang;
|
|
kodeGelangInput.classList.add('success');
|
|
kodeGelangInput.classList.remove('error');
|
|
currentKodeGelang = result.data.kode_gelang;
|
|
|
|
// Hide scan info
|
|
const scanInfo = document.querySelector('.scan-info');
|
|
if (scanInfo) scanInfo.style.display = 'none';
|
|
|
|
// Enable form
|
|
setFormEnabled(true);
|
|
showSuccess('Gelang berhasil di-scan, silakan isi data pengunjung.'); // Tambahkan pesan sukses
|
|
|
|
} else if (result.status === 'in_use') {
|
|
// Gelang sedang digunakan - tampilkan modal
|
|
setFormEnabled(false); // Nonaktifkan form utama
|
|
kodeGelangInput.classList.remove('success');
|
|
kodeGelangInput.classList.add('error');
|
|
showEndSessionModal(result.data); // Ini akan mengatur currentKodeGelang
|
|
|
|
} else if (result.status === 'error') {
|
|
// Gelang tidak dikenali (termasuk "Belum ada gelang yang di-scan" jika rfid_temp kosong)
|
|
setFormEnabled(false); // Nonaktifkan form utama
|
|
kodeGelangInput.classList.remove('success');
|
|
kodeGelangInput.classList.add('error');
|
|
|
|
// Tentukan pesan dan modal yang tampil
|
|
if (result.message === 'Gelang tidak dikenali') {
|
|
showUnknownRfidModal(kodeGelang); // Tampilkan modal gelang tidak dikenali
|
|
} else {
|
|
// Ini akan menangani 'Belum ada gelang yang di-scan' atau error lain dari check_rfid
|
|
showError(result.message || 'Terjadi kesalahan saat memeriksa gelang.');
|
|
}
|
|
|
|
// Penting: Clear temp dan restart scanning setelah menampilkan modal error/unknown
|
|
await clearRfidTemp();
|
|
setTimeout(() => {
|
|
startScanning();
|
|
}, 1000); // Tunggu sebentar sebelum restart
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Error checking RFID:', error);
|
|
showError('Error memeriksa status gelang: ' + error.message); // Tampilkan detail error
|
|
|
|
// Clear temp dan restart scanning jika ada error koneksi
|
|
await clearRfidTemp();
|
|
setTimeout(() => {
|
|
startScanning();
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
// Format currency
|
|
function formatCurrency(amount) {
|
|
return new Intl.NumberFormat('id-ID', {
|
|
style: 'currency',
|
|
currency: 'IDR',
|
|
minimumFractionDigits: 0
|
|
}).format(amount);
|
|
}
|
|
|
|
// Format duration
|
|
function formatDuration(minutes) {
|
|
if (minutes < 60) {
|
|
return `${minutes} menit`;
|
|
} else {
|
|
const hours = minutes / 60;
|
|
return hours % 1 === 0 ? `${hours} jam` : `${hours} jam`;
|
|
}
|
|
}
|
|
|
|
// Update price display
|
|
function updatePriceDisplay() {
|
|
const selectedDuration = durationSelect.value;
|
|
if (selectedDuration) {
|
|
const duration = parseInt(selectedDuration);
|
|
const price = prices[duration];
|
|
const durationText = formatDuration(duration);
|
|
const priceText = formatCurrency(price);
|
|
|
|
priceDisplay.innerHTML = `
|
|
<strong>${durationText}</strong><br>
|
|
<span style="color: #6B46C1; font-size: 1.1em;">${priceText}</span>
|
|
`;
|
|
} else {
|
|
priceDisplay.textContent = 'Pilih durasi untuk melihat harga';
|
|
}
|
|
}
|
|
|
|
// Enable/disable form
|
|
function setFormEnabled(enabled) {
|
|
isFormEnabled = enabled;
|
|
submitBtn.disabled = !enabled || !currentKodeGelang;
|
|
|
|
if (enabled) {
|
|
namaAnakInput.focus();
|
|
}
|
|
}
|
|
|
|
// Show end session modal
|
|
function showEndSessionModal(userData) {
|
|
const nama = userData.nama;
|
|
const kodeGelang = userData.kode_gelang;
|
|
const sisaWaktu = userData.sisa_waktu;
|
|
const statusWaktu = userData.status_waktu;
|
|
const colorClass = userData.color_class;
|
|
|
|
currentUserInfo.innerHTML = `
|
|
<p><strong>Nama:</strong> ${nama}</p>
|
|
<p><strong>Kode Gelang:</strong> ${kodeGelang}</p>
|
|
<p><strong>Sisa Waktu:</strong> <span class="${colorClass}">${sisaWaktu}</span></p>
|
|
<p class="status-info ${statusWaktu === 'tersisa' ? 'text-green-600' : 'text-red-600'}">
|
|
${statusWaktu === 'tersisa' ? 'Waktu masih tersisa' : 'Waktu sudah habis'}
|
|
</p>
|
|
`;
|
|
|
|
endSessionModal.style.display = 'flex';
|
|
currentKodeGelang = kodeGelang;
|
|
}
|
|
|
|
// Hide end session modal
|
|
function hideEndSessionModal() {
|
|
endSessionModal.style.display = 'none';
|
|
currentKodeGelang = null;
|
|
}
|
|
|
|
// Show unknown RFID modal
|
|
function showUnknownRfidModal(kodeGelang) {
|
|
displayUnknownRfidCode.textContent = kodeGelang;
|
|
unknownRfidModal.style.display = 'flex';
|
|
// currentKodeGelang = kodeGelang; // Bisa disimpan atau tidak, tergantung kebutuhan lebih lanjut
|
|
}
|
|
|
|
// Hide unknown RFID modal
|
|
function hideUnknownRfidModal() {
|
|
unknownRfidModal.style.display = 'none';
|
|
}
|
|
|
|
// Clear RFID temp
|
|
async function clearRfidTemp() {
|
|
try {
|
|
await fetch('../api/tambah_pengunjung.php?action=clear_temp', {
|
|
method: 'POST'
|
|
});
|
|
} catch (error) {
|
|
console.error('Error clearing temp:', error);
|
|
}
|
|
}
|
|
|
|
// End play session
|
|
async function endPlaySession() {
|
|
if (!currentKodeGelang) return;
|
|
|
|
try {
|
|
setLoading(true);
|
|
|
|
const formData = new FormData();
|
|
formData.append('action', 'end_session');
|
|
formData.append('kode_gelang', currentKodeGelang);
|
|
|
|
const response = await fetch('../api/tambah_pengunjung.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'success') {
|
|
showSuccess(result.message);
|
|
hideEndSessionModal();
|
|
|
|
// Clear form and restart scanning
|
|
resetForm();
|
|
setTimeout(() => {
|
|
startScanning();
|
|
}, 2000);
|
|
} else {
|
|
showError(result.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error ending session:', error);
|
|
showError('Error mengakhiri sesi permainan');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
// Reset form to initial state
|
|
function resetForm() {
|
|
form.reset();
|
|
|
|
// Reset all visual states
|
|
document.querySelectorAll('.form-input, .form-select').forEach(field => {
|
|
field.classList.remove('error', 'success');
|
|
});
|
|
|
|
// Reset kodeGelang input
|
|
kodeGelangInput.value = '';
|
|
kodeGelangInput.classList.remove('error', 'success');
|
|
|
|
// Reset price display
|
|
priceDisplay.textContent = 'Pilih durasi untuk melihat harga';
|
|
|
|
// Show scan info again
|
|
const scanInfo = document.querySelector('.scan-info');
|
|
if (scanInfo) scanInfo.style.display = 'block';
|
|
|
|
// Reset form state
|
|
setFormEnabled(false);
|
|
currentKodeGelang = null; // Penting: Reset currentKodeGelang
|
|
|
|
// NEW: Hide all modals and messages
|
|
hideEndSessionModal();
|
|
hideUnknownRfidModal(); // Sembunyikan modal baru
|
|
errorMessage.style.display = 'none';
|
|
successMessage.style.display = 'none';
|
|
}
|
|
|
|
// Setup event listeners
|
|
durationSelect.addEventListener('change', updatePriceDisplay);
|
|
|
|
// Nama anak validation
|
|
namaAnakInput.addEventListener('input', function() {
|
|
const nama = this.value.trim();
|
|
|
|
if (nama.length >= 2) {
|
|
this.classList.remove('error');
|
|
this.classList.add('success');
|
|
} else if (nama.length > 0) {
|
|
this.classList.add('error');
|
|
this.classList.remove('success');
|
|
} else {
|
|
this.classList.remove('error', 'success');
|
|
}
|
|
});
|
|
|
|
// Phone number validation
|
|
noHpOrtuInput.addEventListener('input', function() {
|
|
let value = this.value.replace(/\D/g, ''); // Remove non-digits
|
|
|
|
// Format phone number as user types
|
|
if (value.startsWith('0')) {
|
|
// Indonesian format starting with 0
|
|
if (value.length > 4) {
|
|
value = value.substring(0, 4) + '-' + value.substring(4);
|
|
}
|
|
if (value.length > 9) {
|
|
value = value.substring(0, 9) + '-' + value.substring(9);
|
|
}
|
|
} else if (value.startsWith('62')) {
|
|
// Indonesian format starting with 62
|
|
if (value.length > 3) {
|
|
value = value.substring(0, 3) + '-' + value.substring(3);
|
|
}
|
|
if (value.length > 8) {
|
|
value = value.substring(0, 8) + '-' + value.substring(8);
|
|
}
|
|
}
|
|
|
|
this.value = value;
|
|
|
|
// Validation
|
|
const cleanNumber = value.replace(/\D/g, '');
|
|
if (cleanNumber.length >= 10 && cleanNumber.length <= 15) {
|
|
this.classList.remove('error');
|
|
this.classList.add('success');
|
|
} else if (cleanNumber.length > 0) {
|
|
this.classList.add('error');
|
|
this.classList.remove('success');
|
|
} else {
|
|
this.classList.remove('error', 'success');
|
|
}
|
|
});
|
|
|
|
// Form validation
|
|
function validateForm() {
|
|
const namaAnak = namaAnakInput.value.trim();
|
|
const noHpOrtu = noHpOrtuInput.value.replace(/\D/g, '');
|
|
const selectedDuration = durationSelect.value;
|
|
const kodeGelang = kodeGelangInput.value.trim();
|
|
|
|
let isValid = true;
|
|
let errorMsg = '';
|
|
|
|
// Reset all field states
|
|
document.querySelectorAll('.form-input, .form-select').forEach(field => {
|
|
field.classList.remove('error');
|
|
});
|
|
|
|
// RFID validation first
|
|
if (!kodeGelang) {
|
|
isValid = false;
|
|
errorMsg = 'Silakan scan gelang terlebih dahulu';
|
|
kodeGelangInput.classList.add('error');
|
|
return { isValid, errorMsg };
|
|
}
|
|
|
|
// Nama anak validation
|
|
if (namaAnak.length < 2) {
|
|
isValid = false;
|
|
errorMsg = 'Nama anak harus minimal 2 karakter';
|
|
namaAnakInput.classList.add('error');
|
|
}
|
|
|
|
// Phone number validation
|
|
if (noHpOrtu.length < 10 || noHpOrtu.length > 15) {
|
|
isValid = false;
|
|
errorMsg = 'Nomor HP harus 10-15 digit';
|
|
noHpOrtuInput.classList.add('error');
|
|
}
|
|
|
|
// Duration validation
|
|
if (!selectedDuration) {
|
|
isValid = false;
|
|
errorMsg = 'Silakan pilih durasi bermain';
|
|
durationSelect.classList.add('error');
|
|
}
|
|
|
|
return { isValid, errorMsg };
|
|
}
|
|
|
|
// Show error message
|
|
function showError(message) {
|
|
errorMessage.textContent = message;
|
|
errorMessage.style.display = 'block';
|
|
successMessage.style.display = 'none';
|
|
|
|
// Scroll to top to show error
|
|
document.querySelector('.login-right').scrollTop = 0;
|
|
|
|
setTimeout(() => {
|
|
errorMessage.style.display = 'none';
|
|
}, 5000);
|
|
}
|
|
|
|
// Show success message
|
|
function showSuccess(message) {
|
|
successMessage.textContent = message;
|
|
successMessage.style.display = 'block';
|
|
errorMessage.style.display = 'none';
|
|
|
|
// Scroll to top to show success
|
|
document.querySelector('.login-right').scrollTop = 0;
|
|
|
|
setTimeout(() => {
|
|
successMessage.style.display = 'none';
|
|
}, 3000);
|
|
}
|
|
|
|
// Set loading state
|
|
function setLoading(loading) {
|
|
if (loading) {
|
|
submitBtn.disabled = true;
|
|
loadingSpinner.style.display = 'inline-block';
|
|
btnText.textContent = 'Mendaftarkan...';
|
|
} else {
|
|
// Tombol daftar harus tetap disabled jika form tidak enabled atau kode gelang belum valid
|
|
submitBtn.disabled = !isFormEnabled || !currentKodeGelang;
|
|
loadingSpinner.style.display = 'none';
|
|
btnText.textContent = 'Daftarkan Pengunjung';
|
|
}
|
|
}
|
|
|
|
// Form submission
|
|
form.addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const validation = validateForm();
|
|
if (!validation.isValid) {
|
|
showError(validation.errorMsg);
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
|
|
// Prepare form data
|
|
const formData = new FormData();
|
|
formData.append('action', 'add_visitor');
|
|
formData.append('kodeGelang', currentKodeGelang);
|
|
formData.append('namaAnak', namaAnakInput.value.trim());
|
|
formData.append('noHpOrtu', noHpOrtuInput.value.replace(/\D/g, ''));
|
|
formData.append('durasi', parseInt(durationSelect.value));
|
|
|
|
try {
|
|
const response = await fetch('../api/tambah_pengunjung.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
// Check if response is ok
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const contentType = response.headers.get('content-type');
|
|
if (!contentType || !contentType.includes('application/json')) {
|
|
const text = await response.text();
|
|
console.error('Non-JSON response:', text);
|
|
throw new Error('Server returned non-JSON response');
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'success') {
|
|
showSuccess(result.message);
|
|
|
|
// Stop scanning
|
|
if (scanInterval) {
|
|
clearInterval(scanInterval);
|
|
scanInterval = null;
|
|
}
|
|
|
|
// Redirect after 2 seconds
|
|
setTimeout(() => {
|
|
window.location.href = 'dashboard.html';
|
|
}, 2000);
|
|
|
|
} else {
|
|
showError(result.message || 'Terjadi kesalahan saat mendaftarkan pengunjung');
|
|
|
|
// Handle specific field errors
|
|
if (result.field === 'namaAnak') {
|
|
namaAnakInput.classList.add('error');
|
|
namaAnakInput.focus();
|
|
} else if (result.field === 'noHpOrtu') {
|
|
noHpOrtuInput.classList.add('error');
|
|
noHpOrtuInput.focus();
|
|
} else if (result.field === 'durasi') {
|
|
durationSelect.classList.add('error');
|
|
durationSelect.focus();
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
showError('Terjadi kesalahan koneksi. Silakan coba lagi.');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
});
|
|
|
|
// End session modal handlers
|
|
endSessionBtn.addEventListener('click', endPlaySession);
|
|
|
|
cancelEndBtn.addEventListener('click', function() {
|
|
hideEndSessionModal();
|
|
// Clear temp and start new scanning
|
|
clearRfidTemp().then(() => {
|
|
setTimeout(() => {
|
|
startScanning();
|
|
}, 500);
|
|
});
|
|
});
|
|
|
|
// Close modal when clicking outside
|
|
endSessionModal.addEventListener('click', function(e) {
|
|
if (e.target === endSessionModal) {
|
|
hideEndSessionModal();
|
|
// Clear temp and start new scanning
|
|
clearRfidTemp().then(() => {
|
|
setTimeout(() => {
|
|
startScanning();
|
|
}, 500);
|
|
});
|
|
}
|
|
});
|
|
|
|
// Close unknown RFID modal handlers
|
|
closeUnknownRfidModalBtn.addEventListener('click', function() {
|
|
hideUnknownRfidModal();
|
|
// Clear temp dan restart scanning setelah modal ditutup
|
|
clearRfidTemp().then(() => {
|
|
setTimeout(() => {
|
|
startScanning();
|
|
}, 500);
|
|
});
|
|
});
|
|
|
|
// Close unknown RFID modal when clicking outside
|
|
unknownRfidModal.addEventListener('click', function(e) {
|
|
if (e.target === unknownRfidModal) {
|
|
hideUnknownRfidModal();
|
|
// Clear temp dan restart scanning setelah modal ditutup
|
|
clearRfidTemp().then(() => {
|
|
setTimeout(() => {
|
|
startScanning();
|
|
}, 500);
|
|
});
|
|
}
|
|
});
|
|
|
|
// Clear temp when page is about to unload
|
|
window.addEventListener('beforeunload', function() {
|
|
if (scanInterval) {
|
|
clearInterval(scanInterval);
|
|
}
|
|
// Clear temp data
|
|
navigator.sendBeacon('../api/tambah_pengunjung.php?action=clear_temp');
|
|
});
|
|
|
|
// Clear temp when page loses focus
|
|
window.addEventListener('blur', function() {
|
|
clearRfidTemp();
|
|
});
|
|
|
|
// Check authentication status
|
|
async function checkAuth() {
|
|
try {
|
|
const response = await fetch('../api/dashboard.php');
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'error' && result.redirect) {
|
|
window.location.href = result.redirect;
|
|
}
|
|
} catch (error) {
|
|
console.error('Auth check failed:', error);
|
|
}
|
|
}
|
|
|
|
// Initialize page
|
|
checkAuth();
|
|
resetForm(); // Panggil resetForm untuk mengatur UI ke keadaan awal
|
|
startScanning(); // Kemudian baru mulai scanning
|
|
updatePriceDisplay(); // Pastikan harga tampil jika ada default selected
|
|
}); |