379 lines
12 KiB
PHP
379 lines
12 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Konfirmasi Pengembalian | Pustaka Nawasena</title>
|
|
<link rel="icon" href="{{ asset('images/kartu.png') }}" type="image/png">
|
|
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--lib-navy: #0f172a;
|
|
--lib-gold: #b45309;
|
|
--lib-orange: #f97316;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Plus Jakarta Sans', sans-serif;
|
|
background-color: #0f172a;
|
|
background-image: linear-gradient(rgba(15, 23, 42, 0.94), rgba(15, 23, 42, 0.94)), url("{{ asset('images/utama.jpg') }}");
|
|
background-size: cover;
|
|
background-position: center;
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.top-bar {
|
|
background: rgba(255, 255, 255, 0.98);
|
|
backdrop-filter: blur(15px);
|
|
border-bottom: 4px solid var(--lib-gold);
|
|
padding: 0.5rem 3rem;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
height: 90px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.logo-frame {
|
|
background: white;
|
|
border: 2px solid #e2e8f0;
|
|
padding: 6px 12px;
|
|
border-radius: 16px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.main-content {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 2rem;
|
|
}
|
|
|
|
.kiosk-card {
|
|
background: white;
|
|
width: 100%;
|
|
max-width: 950px;
|
|
border-radius: 2rem;
|
|
display: flex;
|
|
overflow: hidden;
|
|
box-shadow: 0 50px 100px -20px rgba(0, 0, 0, 0.6);
|
|
animation: slideIn 0.4s cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
@keyframes slideIn {
|
|
from { transform: translateY(30px); opacity: 0; }
|
|
to { transform: translateY(0); opacity: 1; }
|
|
}
|
|
|
|
.info-side { flex: 1.2; padding: 3.5rem; }
|
|
.action-side {
|
|
flex: 0.8;
|
|
background: #f8fafc;
|
|
padding: 3.5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
text-align: center;
|
|
border-left: 1px solid #e2e8f0;
|
|
}
|
|
|
|
.data-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
|
|
.data-row { border-left: 4px solid var(--lib-orange); padding-left: 1.5rem; }
|
|
.data-row.full { grid-column: span 2; }
|
|
|
|
.label { font-size: 10px; font-weight: 800; text-transform: uppercase; color: #94a3b8; letter-spacing: 0.1em; margin-bottom: 0.25rem; }
|
|
.value { font-size: 1.1rem; font-weight: 800; color: var(--lib-navy); line-height: 1.2; }
|
|
.value.large { font-size: 1.6rem; color: var(--lib-gold); }
|
|
|
|
.btn-primary {
|
|
width: 100%; background: var(--lib-navy); color: white; padding: 1.2rem;
|
|
border-radius: 0.8rem; font-weight: 800; font-size: 0.9rem;
|
|
text-transform: uppercase; letter-spacing: 0.15em; transition: all 0.3s ease;
|
|
}
|
|
.btn-primary:hover:not(:disabled) { background: var(--lib-orange); transform: translateY(-3px); }
|
|
.btn-primary:disabled { opacity: 0.7; cursor: not-allowed; }
|
|
|
|
.footer-terminal {
|
|
background: rgba(15, 23, 42, 0.8);
|
|
padding: 1.25rem 4rem;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.status-dot { width: 8px; height: 8px; background: #22c55e; border-radius: 50%; display: inline-block; margin-right: 8px; }
|
|
.footer-text { color: rgba(255, 255, 255, 0.4); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<nav class="top-bar">
|
|
<div class="logo-frame">
|
|
<img src="{{ asset('images/kartu.png') }}" class="h-10">
|
|
<div class="w-[2px] h-8 bg-slate-200 mx-1"></div>
|
|
<img src="{{ asset('images/bakorwil.png') }}" class="h-10">
|
|
<div class="ml-2">
|
|
<h1 class="text-slate-800 font-black text-xl leading-none">NAWASENA</h1>
|
|
<p class="text-orange-700 text-[10px] font-bold uppercase tracking-[0.2em] mt-1">Smart Library System</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-right">
|
|
<div id="clock" class="text-3xl font-black text-slate-800 leading-none">00:00:00</div>
|
|
<div id="date" class="text-[10px] font-bold text-slate-400 uppercase tracking-widest mt-2">MEMUAT...</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="main-content">
|
|
<div class="kiosk-card">
|
|
<div class="info-side">
|
|
<p class="text-orange-600 font-black text-[10px] tracking-[0.3em] uppercase mb-2">Verifikasi Transaksi</p>
|
|
<h2 class="text-4xl font-black text-slate-900 mb-10 tracking-tight">Konfirmasi Kembali</h2>
|
|
|
|
<div id="data-display" class="data-grid">
|
|
<div class="data-row full">
|
|
<p class="label">Judul Koleksi</p>
|
|
<p id="val-judul" class="value large">Memuat...</p>
|
|
</div>
|
|
<div class="data-row">
|
|
<p class="label">Tanggal Pinjam</p>
|
|
<p id="val-tgl" class="value">-- / -- / ----</p>
|
|
</div>
|
|
<div class="data-row">
|
|
<p class="label">Peminjam</p>
|
|
<p id="val-nama" class="value">---</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="action-side">
|
|
<div class="mb-8 bg-white w-20 h-20 rounded-3xl flex items-center justify-center shadow-sm border border-slate-100">
|
|
<span class="text-4xl">🔄</span>
|
|
</div>
|
|
<h3 class="text-xl font-bold text-slate-800 mb-3">Selesaikan?</h3>
|
|
<p class="text-slate-400 text-sm mb-10 px-6">
|
|
Sistem akan mencatat pengembalian secara otomatis ke dalam database.
|
|
</p>
|
|
|
|
<div class="w-full max-w-[260px]">
|
|
<button id="btn-ok" onclick="kembalikan()" class="btn-primary">
|
|
Proses Selesai ➔
|
|
</button>
|
|
<button onclick="batal()" class="w-full mt-5 text-slate-400 text-[10px] font-bold uppercase hover:text-red-500 transition-all">
|
|
✕ Batalkan
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="footer-terminal">
|
|
<div class="status-dot" id="mqtt-status"></div>
|
|
<span class="footer-text">© 2026 Pustaka Nawasena Bakorwil III Malang</span>
|
|
</footer>
|
|
<script>
|
|
// ===============================
|
|
// 1. CLOCK
|
|
// ===============================
|
|
function updateDateTime() {
|
|
const now = new Date();
|
|
|
|
document.getElementById('clock').textContent =
|
|
now.toLocaleTimeString('id-ID', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
hour12: false
|
|
});
|
|
|
|
document.getElementById('date').textContent =
|
|
now.toLocaleDateString('id-ID', {
|
|
weekday: 'long',
|
|
day: 'numeric',
|
|
month: 'long',
|
|
year: 'numeric'
|
|
}).toUpperCase();
|
|
}
|
|
|
|
setInterval(updateDateTime, 1000);
|
|
updateDateTime();
|
|
|
|
// ===============================
|
|
// 2. MQTT INIT
|
|
// ===============================
|
|
const mqttClient = mqtt.connect(
|
|
'ws://' + window.location.hostname + ':9001'
|
|
);
|
|
|
|
mqttClient.on('connect', () => {
|
|
console.log('MQTT Connected');
|
|
|
|
const indicator = document.getElementById('mqtt-status');
|
|
if (indicator) {
|
|
indicator.style.backgroundColor = '#22c55e';
|
|
}
|
|
});
|
|
|
|
mqttClient.on('error', (err) => {
|
|
console.error('MQTT Error:', err);
|
|
|
|
const indicator = document.getElementById('mqtt-status');
|
|
if (indicator) {
|
|
indicator.style.backgroundColor = '#ef4444';
|
|
}
|
|
});
|
|
|
|
// ===============================
|
|
// 3. LOAD DATA
|
|
// ===============================
|
|
function loadTransactionData() {
|
|
|
|
const storageData = localStorage.getItem('trx_buku');
|
|
|
|
if (!storageData) {
|
|
console.warn("trx_buku tidak ditemukan");
|
|
|
|
window.location.href = '/transaksi/scan-barcode';
|
|
return;
|
|
}
|
|
|
|
try {
|
|
|
|
const data = JSON.parse(storageData);
|
|
|
|
document.getElementById('val-judul').innerText =
|
|
data.judul || 'Judul Tidak Tersedia';
|
|
|
|
document.getElementById('val-nama').innerText =
|
|
data.peminjam_saat_ini || 'Anggota';
|
|
|
|
if (data.tanggal_pinjam) {
|
|
|
|
const tgl = new Date(data.tanggal_pinjam);
|
|
|
|
document.getElementById('val-tgl').innerText =
|
|
tgl.toLocaleDateString('id-ID', {
|
|
day: '2-digit',
|
|
month: 'long',
|
|
year: 'numeric'
|
|
});
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.error("JSON Error:", e);
|
|
|
|
window.location.href = '/transaksi/scan-barcode';
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
setTimeout(loadTransactionData, 100);
|
|
});
|
|
|
|
// ===============================
|
|
// 4. PROSES KEMBALI (QUEUE VERSION)
|
|
// ===============================
|
|
async function kembalikan() {
|
|
|
|
const btn = document.getElementById('btn-ok');
|
|
|
|
btn.disabled = true;
|
|
btn.innerHTML = `
|
|
<span class="animate-pulse">
|
|
⏳ MEMPROSES...
|
|
</span>
|
|
`;
|
|
|
|
try {
|
|
|
|
const res = await fetch('/api/esp/proses-kembali');
|
|
|
|
const result = await res.json();
|
|
|
|
console.log(result);
|
|
|
|
// ===============================
|
|
// HANDLE QUEUE RESPONSE
|
|
// ===============================
|
|
|
|
if (
|
|
result.status === 'queued' ||
|
|
result.status === 'diproses' ||
|
|
result.status === 'berhasil'
|
|
) {
|
|
|
|
// tandai async process
|
|
localStorage.setItem(
|
|
'nawasena_return_status',
|
|
'processing'
|
|
);
|
|
|
|
// redirect langsung
|
|
window.location.href =
|
|
'/transaksi/pengembalian-berhasil';
|
|
|
|
} else {
|
|
|
|
throw new Error(
|
|
result.message ||
|
|
'Pengembalian gagal'
|
|
);
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error);
|
|
|
|
alert(
|
|
'Terjadi Kesalahan: ' + error.message
|
|
);
|
|
|
|
btn.disabled = false;
|
|
|
|
btn.innerHTML = `
|
|
Proses Selesai ➔
|
|
`;
|
|
}
|
|
}
|
|
|
|
// ===============================
|
|
// 5. BATALKAN
|
|
// ===============================
|
|
async function batal() {
|
|
|
|
if (!confirm('Batalkan pengembalian buku ini?')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
|
|
await fetch('/api/esp/batalkan-transaksi');
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e);
|
|
|
|
} finally {
|
|
|
|
localStorage.removeItem('trx_buku');
|
|
|
|
window.location.href =
|
|
'/transaksi/scan-barcode';
|
|
}
|
|
}
|
|
</script>
|
|
</html>
|
|
|