|
|
<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/user-head :: head}"> <title>Victoria Public Hall – Entry Pass</title></head>
<style> body { background: linear-gradient(135deg, #f3efe7, #e6e0d6); min-height: 100vh; }
/* Remove pcoded paddings ONLY for this page */ .pcoded-content, .pcoded-wrapper, .page-wrapper, .main-body { padding-left: 0 !important; padding-right: 0 !important; background: transparent !important; }
/* ================== CENTER WRAPPER ================== */ .entry-wrapper { width: 100%; display: flex; justify-content: center; padding: 30px 12px; }
/* ================== ENTRY CARD ================== */ .entry-card { max-width: 500px; min-height: 400px; width: 100%; background: #fffdf8; border-radius: 18px; padding: 24px 20px 28px; box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15); position: relative; margin: 0 auto; }
/* ================== HEADER ================== */ .vph-logo { text-align: center; margin-bottom: 6px; }
.vph-logo img { width: 60px; }
.entry-title { text-align: center; font-weight: 700; font-size: 16px; letter-spacing: 0.5px; color: #7a4a12; margin-bottom: 22px; }
/* ---------- FIXED INFO GRID ---------- */ .info-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px 12px; margin-bottom: 40px; }
.info-cell { text-align: left; }
.info-cell.center { text-align: center; }
.info-cell.right { text-align: right; }
.info-label { font-size: 11px; text-transform: uppercase; color: #777; margin-bottom: 4px; }
.info-value {
font-size: 15px; font-weight: 700; color: #222;
}
/* ================== ACTION BUTTONS ================== */ .action-row { display: flex; gap: 12px; }
.btn-reject { flex: 1; background: #d90429; color: #fff; border-radius: 10px; font-weight: 600; }
.btn-accept { flex: 1; background: #0a8754; color: #fff; border-radius: 10px; font-weight: 600; }
.btn-reject:hover { background: #b80322; }
.btn-accept:hover { background: #086f46; }
/* ================== MOBILE ================== */ @media (max-width: 480px) { .entry-card { padding: 18px 16px 22px; } }
/* ================= PEOPLE DETAILS ================= */
.people-label { font-size: 11px; text-transform: uppercase; color: #777; margin-bottom: 4px; }
.people-value { font-size: 15px; font-weight: 700; color: #222; }
/* Mobile */ @media (max-width: 480px) { .people-grid { grid-template-columns: repeat(2, 1fr); } }
/* Disable state */ button:disabled { opacity: 0.6; cursor: not-allowed; }
input:disabled { background: #f1f1f1; cursor: not-allowed; }
.ticket-closed { display: flex; align-items: center; justify-content: center;
margin-top: 20px; padding: 14px;
font-size: 16px; font-weight: 700; color: #0b6b44;
background: #e6fbf1; border: 1px solid #9be3c2; border-radius: 10px; }</style>
<body>
<div th:replace="~{fragments/preloader :: div}"></div>
<div id="pcoded" class="pcoded"> <div class="pcoded-container">
<!-- NAV --> <nav th:replace="~{fragments/user-nav :: nav}"></nav>
<div class="pcoded-main-container"> <div class="pcoded-wrapper"> <div class="pcoded-content"> <div class="pcoded-inner-content"> <div class="main-body"> <div class="page-wrapper">
<!-- CENTERED ENTRY CARD --> <div class="entry-wrapper"> <div class="entry-card">
<!-- LOGO --> <div class="vph-logo"> <img src="/victoriapublichall/images/VPH-logo_main-EN%201.png" alt="Victoria Public Hall"> </div>
<div class="entry-title"> VICTORIA PUBLIC HALL – ENTRY PASS </div>
<div class="divider"></div>
<!-- DETAILS --> <div class="info-grid">
<div class="info-cell"> <div class="info-label">Reference ID</div> <div class="info-value" th:text="${booking.ref_id}"></div> </div>
<div class="info-cell center"> <div class="info-label">Visit Date</div> <div class="info-value" th:text="${booking.visit_date}"></div> </div>
<div class="info-cell right"> <div class="info-label">ID Proof</div> <div class="info-value" th:text="${booking.id_name}"></div> </div>
</div>
<div class="info-grid">
<div class="info-cell"> <div class="info-label">Visit Time</div> <div class="info-value" th:text="${booking.timing}"></div> </div>
<div class="info-cell center"> <div class="info-label">Total Visitors</div> <div class="info-value" th:text="${booking.no_of_people}"></div> </div>
<div class="info-cell right"> <div class="info-label">AV Slot</div> <div class="info-value" th:text="${booking.avslottime}"></div> </div>
</div>
<div class="info-grid">
<div class="info-cell"> <div class="people-label">Adults</div> <div class="people-value" th:text="${booking.adult_count}"></div> </div>
<div class="info-cell center"> <div class="people-label">Children</div> <div class="people-value" th:text="${booking.child_count}"></div> </div>
<div class="info-cell right"> <div class="people-label">Senior Citizen</div> <div class="people-value" th:text="${booking.sc_count}"></div> </div> </div>
<div class="info-grid"> <div class="info-cell"> <div class="people-label">Students</div> <div class="people-value" th:text="${booking.students_count}"></div> </div>
<div class="info-cell center"> <div class="people-label">Physically Challenged</div> <div class="people-value" th:text="${booking.pc_count}"></div> </div>
<div class="info-cell right"> <div class="people-label">Foreigners</div> <div class="people-value" th:text="${booking.foreigner_count}"> </div> </div>
</div>
<div class="info-grid" style="border-top: 1px dashed #ddd; padding-top: 15px;"> <div class="info-cell"> <div class="info-label" style="color:#0a8754;font-weight:700;"> Accepted</div> <div class="info-value" th:text="${booking.accepted_people != null ? booking.accepted_people : 0}"> </div> </div> <div class="info-cell center"> <div class="info-label" style="color:#d90429;font-weight:700;"> Rejected</div> <div class="info-value" th:text="${booking.rejected_people != null ? booking.rejected_people : 0}"> </div> </div> <div class="info-cell right"> <div class="info-label" style="color:#333;font-weight:700;"> Remaining</div> <div class="info-value" th:text="${booking.remaining_count}"></div> </div> </div>
<!-- ACTION SECTION (ONLY WHEN OPEN) --> <div th:if="${gateViewMode == 'PENDING'}">
<div class="row mt-3"> <div class="col-6"> <div class="form-group mb-2"> <label class="text-success fw-bold">Accepted Count</label> <input type="number" id="acceptedCount" class="form-control" placeholder="0" min="0"> </div> </div> <div class="col-6"> <div class="form-group mb-2"> <label class="text-danger fw-bold">Rejected Count</label> <input type="number" id="rejectedCount" class="form-control" placeholder="0" min="0"> </div> </div> </div>
<div class="d-flex mt-4 action-row justify-content-center"> <button id="submitBtn" class="btn btn-primary w-100" onclick="submitEntry()"> Submit Entry </button> </div>
</div>
<!-- FINAL STATUS (AFTER ACTION / REFRESH) --> <div th:if="${gateViewMode == 'CLOSED'}" class="text-center mt-4">
<div style="font-size:18px;font-weight:700;color:#0a8754;"> Ticket Closed </div>
<p class="mt-2 text-muted"> Entry already processed at the gate </p>
</div>
<div th:if="${gateViewMode == 'CANCELLED'}" class="text-center mt-4">
<div style="font-size:18px;font-weight:700;color:#d90429;"> Booking Cancelled </div>
<p class="mt-2 text-muted"> This booking was cancelled by the visitor </p>
</div>
<div th:if="${gateViewMode == 'INVALID'}" class="text-center mt-4">
<div style="font-size:18px;font-weight:700;color:#ff9800;"> Invalid QR Code </div>
</div>
</div> </div>
</div> </div> </div> </div> </div>
<!-- FOOTER --> <footer th:replace="~{fragments/footer :: footer}"></footer> </div> </div></div>
<script th:replace="~{fragments/user-script :: script}"></script>
<script> // Date Validation on Load document.addEventListener("DOMContentLoaded", function () { const visitDateStr = '[[${booking.visit_date}]]'; // Expected format dd-MM-yyyy
// Parse visitDate (dd-MM-yyyy) const parts = visitDateStr.split('-'); // new Date(year, monthIndex, day) const visitDate = new Date(parts[2], parts[1] - 1, parts[0]); visitDate.setHours(0, 0, 0, 0);
const currentSystemDateStr = '[[${currentDate}]]'; // yyyy-MM-dd const curParts = currentSystemDateStr.split('-'); const currentDate = new Date(curParts[0], curParts[1] - 1, curParts[2]); currentDate.setHours(0, 0, 0, 0);
const submitBtn = document.getElementById("submitBtn"); const acceptedInput = document.getElementById("acceptedCount"); const rejectedInput = document.getElementById("rejectedCount");
if (visitDate < currentDate) { Swal.fire({ icon: "error", title: "Ticket Expired", text: "This ticket is for a past date (" + visitDateStr + ")", allowOutsideClick: false }); disableInputs(); } else if (visitDate > currentDate) { Swal.fire({ icon: "warning", title: "Not Allowed", text: "Your booking date is " + visitDateStr + ". Entry not allowed today.", allowOutsideClick: false }); disableInputs(); }
function disableInputs() { if (submitBtn) submitBtn.disabled = true; if (acceptedInput) acceptedInput.disabled = true; if (rejectedInput) rejectedInput.disabled = true; } });
function submitEntry() {
const acceptedEl = document.getElementById("acceptedCount"); const rejectedEl = document.getElementById("rejectedCount");
if (!acceptedEl || !rejectedEl) { Swal.fire("Error", "Page not loaded correctly", "error"); return; }
let accepted = parseInt(acceptedEl.value) || 0; let rejected = parseInt(rejectedEl.value) || 0;
const remaining = parseInt('[[${booking.remaining_count}]]'); const refId = '[[${booking.ref_id}]]';
if (accepted < 0 || rejected < 0) { Swal.fire("Error", "Counts cannot be negative", "error"); return; }
if (accepted === 0 && rejected === 0) { Swal.fire("Error", "Please enter at least one accepted or rejected visitor", "warning"); return; }
if ((accepted + rejected) > remaining) { Swal.fire( "Error", "Total count (" + (accepted + rejected) + ") exceeds remaining visitors (" + remaining + ")", "error" ); return; }
Swal.fire({ title: "Confirm Entry?", html: `Accept: <b>${accepted}</b> <br> Reject: <b>${rejected}</b>`, icon: "question", showCancelButton: true, confirmButtonText: "Submit", confirmButtonColor: "#3085d6", cancelButtonColor: "#d33" }).then(result => {
if (!result.isConfirmed) return;
$.ajax({ url: "/victoriapublichall/bookingapi/entry-action", type: "POST", contentType: "application/json", data: JSON.stringify({ refId: refId, accepted: accepted, rejected: rejected }), success: function (res) { Swal.fire({ icon: "success", title: "Success", text: res.message, confirmButtonText: "OK" }).then(() => { location.reload(); }); }, error: function (err) { Swal.fire( "Error", err.responseText || "Action failed", "error" ); } }); }); }
</script>
</body>
</html>
|