179 lines
9.2 KiB
PHP
179 lines
9.2 KiB
PHP
<div class="space-y-6">
|
|
<div>
|
|
<h1 class="text-xl font-semibold">Pengaturan Presensi</h1>
|
|
<p class="text-gray-600 dark:text-gray-400 mt-1">Satu pengaturan terpusat: <strong>koordinat sekolah</strong> (untuk semua absen) dan <strong>jadwal jam masuk & jam pulang</strong>.</p>
|
|
</div>
|
|
|
|
<div id="presence-loading" class="rounded-2xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-12 text-center text-gray-500 dark:text-gray-400">
|
|
Memuat…
|
|
</div>
|
|
<div id="presence-error" class="hidden rounded-2xl border border-red-200 dark:border-red-800 bg-red-50 dark:bg-red-900/20 p-6 text-red-700 dark:text-red-300"></div>
|
|
<div id="presence-form-wrap" class="hidden space-y-6">
|
|
<!-- Zona sekolah -->
|
|
<div class="rounded-2xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow-sm p-6">
|
|
<h2 class="text-base font-semibold text-gray-900 dark:text-gray-100 mb-1">Koordinat Sekolah (Zona Presensi)</h2>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">Semua absen (mobile & device) hanya valid jika siswa berada di dalam radius ini.</p>
|
|
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
|
<div>
|
|
<label class="block mb-1 text-sm text-gray-600 dark:text-gray-300">Latitude</label>
|
|
<input type="number" step="0.00000001" id="zone-lat" class="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block mb-1 text-sm text-gray-600 dark:text-gray-300">Longitude</label>
|
|
<input type="number" step="0.00000001" id="zone-lng" class="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block mb-1 text-sm text-gray-600 dark:text-gray-300">Radius (meter)</label>
|
|
<input type="number" min="1" id="zone-radius" class="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Jam masuk & pulang -->
|
|
<div class="rounded-2xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow-sm p-6">
|
|
<h2 class="text-base font-semibold text-gray-900 dark:text-gray-100 mb-1">Jadwal Masuk & Pulang</h2>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">Window waktu untuk absen masuk dan absen pulang (format 24 jam).</p>
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<div>
|
|
<label class="block mb-1 text-sm text-gray-600 dark:text-gray-300">Jam masuk (mulai)</label>
|
|
<input type="time" id="time-masuk-start" class="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block mb-1 text-sm text-gray-600 dark:text-gray-300">Jam masuk (akhir)</label>
|
|
<input type="time" id="time-masuk-end" class="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block mb-1 text-sm text-gray-600 dark:text-gray-300">Jam pulang (mulai)</label>
|
|
<input type="time" id="time-pulang-start" class="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block mb-1 text-sm text-gray-600 dark:text-gray-300">Jam pulang (akhir)</label>
|
|
<input type="time" id="time-pulang-end" class="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex justify-end">
|
|
<button type="button" id="btn-save" class="inline-flex items-center justify-center px-5 py-2.5 rounded-lg bg-primary text-white text-sm font-medium hover:bg-primary-hover">
|
|
Simpan Pengaturan
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
var baseUrl = '<?= base_url() ?>'.replace(/\/$/, '');
|
|
var apiUrl = baseUrl + '/api/dashboard/presence-settings';
|
|
|
|
var loading = document.getElementById('presence-loading');
|
|
var errorEl = document.getElementById('presence-error');
|
|
var formWrap = document.getElementById('presence-form-wrap');
|
|
var zoneLat = document.getElementById('zone-lat');
|
|
var zoneLng = document.getElementById('zone-lng');
|
|
var zoneRadius = document.getElementById('zone-radius');
|
|
var timeMasukStart = document.getElementById('time-masuk-start');
|
|
var timeMasukEnd = document.getElementById('time-masuk-end');
|
|
var timePulangStart = document.getElementById('time-pulang-start');
|
|
var timePulangEnd = document.getElementById('time-pulang-end');
|
|
var btnSave = document.getElementById('btn-save');
|
|
|
|
function showError(msg) {
|
|
errorEl.textContent = msg || 'Terjadi kesalahan';
|
|
errorEl.classList.remove('hidden');
|
|
formWrap.classList.add('hidden');
|
|
}
|
|
|
|
function timeToHhMm(val) {
|
|
if (!val) return '';
|
|
if (val.length === 5 && val.indexOf(':') !== -1) return val;
|
|
var parts = (val + '').trim().split(/[:\s]/);
|
|
if (parts.length >= 2) return parts[0].padStart(2, '0') + ':' + parts[1].padStart(2, '0');
|
|
return val.substring(0, 5);
|
|
}
|
|
|
|
function hhMmToTimeInput(hhmmss) {
|
|
if (!hhmmss) return '';
|
|
var s = (hhmmss + '').trim();
|
|
if (s.length >= 5) return s.substring(0, 5);
|
|
return s;
|
|
}
|
|
|
|
function load() {
|
|
loading.classList.remove('hidden');
|
|
errorEl.classList.add('hidden');
|
|
formWrap.classList.add('hidden');
|
|
fetch(apiUrl, { method: 'GET', headers: { 'X-Requested-With': 'XMLHttpRequest' }, credentials: 'same-origin' })
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(res) {
|
|
loading.classList.add('hidden');
|
|
if (res && res.success && res.data) {
|
|
var zone = res.data.zone || {};
|
|
var times = res.data.times || {};
|
|
zoneLat.value = zone.latitude != null ? zone.latitude : '';
|
|
zoneLng.value = zone.longitude != null ? zone.longitude : '';
|
|
zoneRadius.value = zone.radius_meters != null ? zone.radius_meters : '150';
|
|
timeMasukStart.value = hhMmToTimeInput(times.time_masuk_start);
|
|
timeMasukEnd.value = hhMmToTimeInput(times.time_masuk_end);
|
|
timePulangStart.value = hhMmToTimeInput(times.time_pulang_start);
|
|
timePulangEnd.value = hhMmToTimeInput(times.time_pulang_end);
|
|
formWrap.classList.remove('hidden');
|
|
} else {
|
|
showError(res && res.message ? res.message : 'Gagal memuat pengaturan');
|
|
}
|
|
})
|
|
.catch(function() {
|
|
loading.classList.add('hidden');
|
|
showError('Gagal memuat pengaturan (jaringan).');
|
|
});
|
|
}
|
|
|
|
btnSave.addEventListener('click', function() {
|
|
var lat = parseFloat(zoneLat.value);
|
|
var lng = parseFloat(zoneLng.value);
|
|
var radius = parseInt(zoneRadius.value, 10);
|
|
if (isNaN(lat) || isNaN(lng) || isNaN(radius) || radius < 1) {
|
|
alert('Isi koordinat sekolah (Latitude, Longitude, Radius) dengan benar.');
|
|
return;
|
|
}
|
|
var payload = {
|
|
zone: {
|
|
latitude: lat,
|
|
longitude: lng,
|
|
radius_meters: radius,
|
|
zone_name: 'Zona Sekolah'
|
|
},
|
|
times: {
|
|
time_masuk_start: timeToHhMm(timeMasukStart.value) + ':00',
|
|
time_masuk_end: timeToHhMm(timeMasukEnd.value) + ':00',
|
|
time_pulang_start: timeToHhMm(timePulangStart.value) + ':00',
|
|
time_pulang_end: timeToHhMm(timePulangEnd.value) + ':00'
|
|
}
|
|
};
|
|
btnSave.disabled = true;
|
|
fetch(apiUrl, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
|
|
credentials: 'same-origin',
|
|
body: JSON.stringify(payload)
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(res) {
|
|
btnSave.disabled = false;
|
|
if (res && res.success) {
|
|
if (typeof showToast === 'function') showToast('Pengaturan presensi berhasil disimpan', 'success');
|
|
else alert('Pengaturan berhasil disimpan.');
|
|
} else {
|
|
alert(res && res.message ? res.message : 'Gagal menyimpan');
|
|
}
|
|
})
|
|
.catch(function() {
|
|
btnSave.disabled = false;
|
|
alert('Gagal menyimpan (jaringan).');
|
|
});
|
|
});
|
|
|
|
load();
|
|
})();
|
|
</script>
|