TKK_E32230908/resources/views/transaksi/konfirmasi-kembali.blade.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>