You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

199 lines
8.0 KiB

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>VPH Booking Summary</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600&display=swap" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.6.4.min.js"
integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8="
crossorigin="anonymous"></script>
<style>
:root { --ink:#1f2937; --muted:#6b7280; --bg1:#eff6ff; --bg2:#f0fdfa; --brand:#3b82f6; }
*{box-sizing:border-box}
body{
font-family:'Montserrat',system-ui,Arial;
background:linear-gradient(135deg,var(--bg1) 0%, var(--bg2) 100%);
min-height:100vh; margin:0; padding:2rem 1rem;
color:var(--ink);
}
.container{ max-width:64rem; margin:0 auto; }
.header{ text-align:center; margin-bottom:1.5rem; }
.header h1{ font-size:2rem; margin:.25rem 0; }
.confirmation-header{ text-align:center; margin:1.25rem 0 1rem; }
.success-icon{ font-size:3rem; margin-bottom:.75rem; }
.confirmation-header h2{ margin:.25rem 0 .25rem; }
.confirmation-header p{ color:var(--muted); margin:0; }
.card{
background:#fff; border-radius:12px; padding:1.25rem;
box-shadow:0 10px 15px -3px rgba(0,0,0,.1);
}
.booking-summary h3{ margin:0 0 .75rem; font-size:1.1rem;text-align:center; }
/* table layout (rock-solid for html2pdf) */
.summary-table{
width: 80%;
margin-left: 100px; border-collapse:collapse; background:#f9fafb; border-radius:8px; overflow:hidden;
}
.summary-table th, .summary-table td{ padding:12px 10px; border-bottom:1px solid #e5e7eb; text-align:left; vertical-align:top; }
.summary-table th{ width:450px; color:var(--muted); font-weight:600; }
.summary-table tr:last-child th, .summary-table tr:last-child td{ border-bottom:0; }
.important-note{ background:#eff6ff; padding:1rem; border-radius:8px; font-size:.95rem; color:#1e40af; margin-top:1rem; }
.actions{ display:flex; justify-content:center; gap:12px; margin-top:1.25rem; }
.btn{ border:0; border-radius:8px; padding:.75rem 1.25rem; font-weight:600; cursor:pointer; }
.btn-secondary{ background:#e5e7eb; color:#111827; }
.btn-secondary:hover{ background:#d1d5db; }
.btn[disabled]{ opacity:.6; cursor:not-allowed; }
.muted{ text-align:center; color:var(--muted); margin-top:.5rem; font-size:.9rem; }
body.pdf-export { padding: 0 !important; }
body.pdf-export .header { display: none !important; }
body.pdf-export #bookingSummary { margin: 0 !important; }
body.pdf-export .confirmation-header { margin: .5rem 0 !important; }
body.pdf-export .summary-table { width: 100% !important; margin-left: 0 !important; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Victoria Public Hall — Experiential Museum</h1>
</div>
<div id="bookingSummary" class="card">
<div class="confirmation-header">
<div class="success-icon">✅</div>
<h2>Booking Confirmed!</h2>
<p>Your VPH visit has been successfully booked</p>
</div>
<div class="booking-summary">
<h3>Booking Summary</h3>
<table class="summary-table">
<tr><th>Contact Person</th><td id="summaryName"></td></tr>
<tr><th>Phone</th><td id="summaryPhone"></td></tr>
<tr><th>Number of Persons</th><td id="summaryMembers"></td></tr>
<tr><th>Visit Date</th><td id="summaryDate"></td></tr>
<tr><th>Time Slot</th><td id="summaryTimeSlot"></td></tr>
<tr><th>Selected Slots</th><td id="summarySlots"></td></tr>
</table>
</div>
<div class="important-note">
<strong>Important:</strong> Please arrive 15 minutes before your scheduled time. Bring a valid ID proof for verification.
</div>
</div>
<div class="actions">
<button id="downloadBtn" class="btn btn-secondary" disabled>Preparing…</button>
<a href="/victoriapublichall" class="btn btn-secondary">Book Another Visit</a>
</div>
</div>
<script>
async function ensureHtml2pdf() {
if (window.html2pdf) return;
try {
await new Promise((resolve, reject) => {
const s = document.createElement('script');
s.src = 'https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js';
s.onload = resolve; s.onerror = reject; document.head.appendChild(s);
});
} catch (e) {
await new Promise((resolve, reject) => {
const s = document.createElement('script');
s.src = 'https://cdn.jsdelivr.net/npm/html2pdf.js@0.10.1/dist/html2pdf.bundle.min.js';
s.onload = resolve; s.onerror = reject; document.head.appendChild(s);
});
}
}
(function () {
const $btn = $('#downloadBtn');
let summaryLoaded = false;
const qs = new URLSearchParams(location.search);
const refId = qs.get('refId') || '';
if (!refId) { alert('Missing refId. Open this page as booking-summary.html?refId=YOUR_REF_ID'); return; }
// build API URL — default uses @GetMapping("/summary/{refId}")
const apiUrl = `/victoriapublichall/api/summary/${encodeURIComponent(refId)}`;
// if your controller uses @RequestParam instead, switch to:
// const apiUrl = `/victoriapublichall/api/summary?refId=${encodeURIComponent(refId)}`;
$.getJSON(apiUrl)
.done(function (data) {
$('#summaryName').text(data.name || '');
$('#summaryPhone').text(data.mobileno || '');
$('#summaryMembers').text(data.noofpersons ?? '');
if (data.booking_date) {
const d = new Date(data.booking_date);
const day = String(d.getDate()).padStart(2,'0');
const month = String(d.getMonth()+1).padStart(2,'0'); // months are 0-indexed
const year = d.getFullYear();
$('#summaryDate').text(`${day}-${month}-${year}`);
} else {
$('#summaryDate').text('-');
} $('#summaryTimeSlot').text(data.slot_timing || '');
// seats -> "G1: n, G2: n" (10 per group)
const seatsRaw = (data.seats || '').toString();
const numbers = seatsRaw.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n));
const groupCounts = {};
numbers.forEach(n => { const g = Math.ceil(n / 10); groupCounts[g] = (groupCounts[g] || 0) + 1; });
const lines = Object.keys(groupCounts).sort((a,b)=>a-b).map(g => `G${g}: ${groupCounts[g]}`).join(', ');
$('#summarySlots').text(lines || seatsRaw || '-');
summaryLoaded = true;
$btn.prop('disabled', false).text('Download PDF');
})
.fail(function (xhr) {
alert(xhr?.responseJSON?.message || 'No booking found for this refId.');
});
$btn.on('click', async function () {
if (!summaryLoaded) { alert('Please wait, loading details…'); return; }
await ensureHtml2pdf();
if (!window.html2pdf) { alert('PDF engine failed to load.'); return; }
// Enter "PDF export" layout to reduce spacing
document.body.classList.add('pdf-export');
// Make sure fonts/layout are ready before capture
if (document.fonts?.ready) { try { await document.fonts.ready; } catch {} }
await new Promise(r => requestAnimationFrame(r));
await new Promise(r => setTimeout(r, 30)); // tiny extra paint buffer
const element = document.getElementById('bookingSummary');
window.html2pdf().set({
margin: 10,
filename: 'VPH_booking_summary.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2, useCORS: true, backgroundColor: null, scrollY: 0 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
// let it paginate instead of clipping the bottom
pagebreak: { mode: ['css', 'legacy'] }
})
.from(element)
.save()
.then(() => {
// restore normal layout
document.body.classList.remove('pdf-export');
})
.catch(() => {
document.body.classList.remove('pdf-export');
});
});
})();
</script>
</body>
</html>