TKK_E32230908/resources/views/transaksi/hasil-transaksi.blade.php

496 lines
15 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 Peminjaman | 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-success: #10b981;
}
* { box-sizing: border-box; user-select: none; }
body {
font-family: 'Plus Jakarta Sans', sans-serif;
background-image: linear-gradient(rgba(15, 23, 42, 0.85), rgba(15, 23, 42, 0.85)), url("{{ asset('images/utama.jpg') }}");
background-size: cover;
background-position: center;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
margin: 0;
}
.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;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
z-index: 100;
}
.logo-frame {
background: white;
border: 2px solid #e2e8f0;
padding: 6px 16px;
border-radius: 16px;
display: flex;
align-items: center;
gap: 12px;
position: relative;
}
.img-container { height: 45px; display: flex; align-items: center; }
.img-container img { height: 100%; width: auto; object-fit: contain; }
.main-content {
flex: 1; display: flex; align-items: center; justify-content: center; padding: 1rem 2rem;
}
.kiosk-card {
background: white;
width: 95%;
max-width: 1000px;
height: 65vh;
min-height: 500px;
border-radius: 2.5rem;
display: grid;
grid-template-columns: 0.8fr 1.2fr;
overflow: hidden;
box-shadow: 0 50px 100px -20px rgba(0, 0, 0, 0.6);
animation: cardPop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes cardPop {
from { opacity: 0; transform: scale(0.9) translateY(30px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
.visual-side {
background: var(--lib-navy);
padding: 3rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
text-align: center;
}
.success-blob {
width: 100px; height: 100px;
background: rgba(16, 185, 129, 0.2);
border: 2px solid var(--lib-success);
border-radius: 40% 60% 70% 30% / 40% 50% 60% 70%;
display: flex; align-items: center; justify-content: center;
margin-bottom: 2rem;
animation: blobby 10s infinite linear;
}
@keyframes blobby {
0% { border-radius: 40% 60% 70% 30% / 40% 50% 60% 70%; }
50% { border-radius: 60% 40% 30% 70% / 50% 60% 70% 40%; }
100% { border-radius: 40% 60% 70% 30% / 40% 50% 60% 70%; }
}
.data-side {
padding: 3rem 3.5rem;
display: flex; flex-direction: column; background: white;
}
.info-row {
margin-bottom: 1.25rem;
border-bottom: 1px solid #f1f5f9;
padding-bottom: 0.75rem;
}
.info-label {
font-size: 10px; font-weight: 800; text-transform: uppercase;
letter-spacing: 0.15em; color: var(--lib-gold); margin-bottom: 4px;
}
.info-value {
font-size: 1.25rem; font-weight: 700; color: var(--lib-navy); line-height: 1.2;
}
.note-box {
background: #fffbeb; border: 1px solid #fef3c7;
padding: 1rem; border-radius: 1rem;
display: flex; gap: 12px; margin-top: auto; margin-bottom: 1.5rem;
}
.btn-action {
height: 55px; border-radius: 1rem; font-weight: 800;
text-transform: uppercase; letter-spacing: 0.1em;
transition: all 0.3s ease; display: flex; align-items: center;
justify-content: center; cursor: pointer; width: 100%; font-size: 0.8rem;
}
.btn-confirm { background: var(--lib-success); color: white; border: none; }
.btn-confirm:hover { background: #059669; transform: translateY(-2px); }
.btn-cancel { background: #f8fafc; color: #64748b; border: 1px solid #e2e8f0; }
.btn-cancel:hover { background: #fee2e2; color: #ef4444; }
.btn-hint {
font-size: 8px; color: #94a3b8; margin-top: 6px;
text-align: center; text-transform: uppercase; letter-spacing: 0.05em;
}
.lib-footer {
background: rgba(0, 0, 0, 0.9); color: rgba(255,255,255,0.4);
padding: 1.5rem 0.8rem 2.5rem; text-align: center; font-size: 0.7rem;
letter-spacing: 2px;
}
</style>
</head>
<body>
<nav class="top-bar">
<div class="logo-frame">
<div class="img-container"><img src="{{ asset('images/kartu.png') }}" alt="Logo"></div>
<div class="w-[1px] h-8 bg-slate-200"></div>
<div class="img-container"><img src="{{ asset('images/bakorwil.png') }}" alt="Logo"></div>
<div class="ml-2 pr-2">
<h1 class="text-slate-800 font-extrabold text-xl leading-none tracking-tighter uppercase">NAWASENA</h1>
<p class="text-orange-700 text-[9px] font-bold uppercase tracking-[0.2em] mt-1">Smart Library System</p>
</div>
</div>
<div class="text-right">
<div id="clock" class="text-4xl font-black text-slate-800 tracking-tighter leading-none">00:00</div>
<div id="date" class="text-[9px] font-bold text-slate-400 uppercase tracking-widest mt-2">Memuat...</div>
</div>
</nav>
<main class="main-content">
<div class="kiosk-card">
<div class="visual-side">
<div class="success-blob">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7" />
</svg>
</div>
<h2 class="text-2xl font-black mb-2 uppercase tracking-tight">Finalisasi<br>Peminjaman</h2>
<div class="w-12 h-1 bg-emerald-500 rounded-full mb-6"></div>
<p class="text-[11px] text-slate-400 leading-relaxed px-8 italic">
"Identitas valid. Silakan konfirmasi data peminjaman di sebelah kanan."
</p>
</div>
<div class="data-side">
<div id="data-container" class="flex-1">
</div>
<div class="note-box">
<div class="text-lg">⚠️</div>
<div class="text-[10px] text-amber-700 leading-relaxed font-medium">
Wajib membawa <strong>Kartu Identitas</strong> saat pengambilan fisik dan pastikan buku dikembalikan tepat waktu.
</div>
</div>
<div class="flex gap-4">
<div class="flex-1">
<!-- Pastikan onclick memanggil batalkan() -->
<button id="btn-batal" onclick="batalkan()" class="btn-action btn-cancel cursor-pointer">
Batalkan
</button>
<p class="btn-hint">Hapus semua sesi</p>
</div>
<div class="flex-[1.5]">
<button id="btn-final" onclick="selesai()" class="btn-action btn-confirm">Selesaikan Transaksi </button>
<p class="btn-hint font-bold text-emerald-600">Simpan ke database</p>
</div>
</div>
</div>
</div>
</main>
<footer class="lib-footer">
BAKORWIL III MALANG &bull; SMART TERMINAL V4.2.0 &bull; 2026
</footer>
<script>
// ===============================
// 1. CLOCK
// ===============================
function updateDateTime() {
const now = new Date();
document.getElementById('clock').textContent =
now.toLocaleTimeString('id-ID', {
hour: '2-digit',
minute: '2-digit',
hour12: false
});
document.getElementById('date').textContent =
now.toLocaleDateString('id-ID', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
});
}
setInterval(updateDateTime, 1000);
// ===============================
// 2. RENDER DATA
// ===============================
function renderConfirmation() {
const userData =
JSON.parse(localStorage.getItem('last_borrower') || '{}');
const bookData =
JSON.parse(localStorage.getItem('trx_buku') || '{}');
const backupData =
JSON.parse(localStorage.getItem('trx') || '{}');
const namaPeminjam =
userData.nama ||
backupData.nama_peminjam ||
"Nama Tidak Terdeteksi";
const judulBuku =
bookData.judul ||
backupData.judul ||
"Judul Tidak Terdeteksi";
const barcodeBuku =
bookData.barcode ||
backupData.barcode ||
"-";
const container =
document.getElementById('data-container');
if (container) {
container.innerHTML = `
<div class="space-y-4">
<div class="info-row">
<div class="info-label">
Nama Peminjam
</div>
<div class="info-value text-emerald-600 font-bold">
${namaPeminjam}
</div>
</div>
<div class="info-row">
<div class="info-label">
Judul Koleksi
</div>
<div class="info-value font-medium">
${judulBuku}
</div>
</div>
<div class="info-row">
<div class="info-label">
ID Barcode
</div>
<div class="info-value text-slate-500">
${barcodeBuku}
</div>
</div>
</div>
`;
}
}
// ===============================
// 3. BATAL TRANSAKSI
// ===============================
async function batalkan() {
const btnBatal =
document.getElementById('btn-batal');
const btnFinal =
document.getElementById('btn-final');
if (!confirm(
"Apakah Anda yakin ingin membatalkan transaksi ini?"
)) return;
btnBatal.disabled = true;
btnFinal.disabled = true;
btnBatal.innerHTML =
"⏳ MEMBATALKAN...";
try {
await fetch('/api/esp/batalkan-transaksi');
localStorage.removeItem('last_borrower');
localStorage.removeItem('trx_buku');
localStorage.removeItem('trx');
window.location.href =
"/transaksi/scan-barcode";
} catch (err) {
console.error(err);
window.location.href =
"/transaksi/scan-barcode";
}
}
// ===============================
// 4. SIMPAN / PINJAM
// ===============================
async function selesai() {
const btn =
document.getElementById('btn-final');
const btnBatal =
document.getElementById('btn-batal');
btn.disabled = true;
if (btnBatal) {
btnBatal.disabled = true;
}
btn.innerHTML =
"⏳ MEMPROSES...";
try {
const response =
await fetch('/api/esp/konfirmasi-pinjam');
const result =
await response.json();
console.log(result);
/*
==========================================
QUEUE SUCCESS
==========================================
*/
if (
result.status === 'queued' ||
result.status === 'diproses' ||
result.status === 'berhasil_pinjam'
) {
const user =
JSON.parse(
localStorage.getItem('last_borrower') || '{}'
);
const book =
JSON.parse(
localStorage.getItem('trx_buku') || '{}'
);
const payloadStruk = {
nama:
user.nama || "Anggota",
judul:
book.judul || "Buku",
tanggal:
new Date().toLocaleDateString('id-ID')
};
localStorage.setItem(
'nawasena_hasil_akhir',
JSON.stringify(payloadStruk)
);
localStorage.setItem(
'nawasena_status',
'processing'
);
// redirect
window.location.href =
"/transaksi/peminjaman-berhasil";
return;
}
/*
==========================================
ERROR
==========================================
*/
alert(
"Gagal menyimpan: " +
(result.message || "Terjadi kesalahan")
);
btn.disabled = false;
if (btnBatal) {
btnBatal.disabled = false;
}
btn.innerHTML = "LANJUTKAN";
} catch (err) {
console.error(err);
alert(
"Terjadi masalah koneksi ke server."
);
btn.disabled = false;
if (btnBatal) {
btnBatal.disabled = false;
}
btn.innerHTML = "LANJUTKAN";
}
}
// ===============================
// INIT
// ===============================
window.onload = () => {
updateDateTime();
renderConfirmation();
};
</script>
</body>
</html>