![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/private_html/ |
<?php
session_start();
require_once 'config/database.php';
require_once 'includes/translations.php';
require_once 'includes/event_permissions.php';
if (!isset($_SESSION['user_id'])) {
header('Location: /auth/login.php');
exit;
}
$event_id = isset($_GET['event_id']) ? (int)$_GET['event_id'] : 0;
$focus_ticket = isset($_GET['ticket']) ? trim($_GET['ticket']) : '';
if ($event_id <= 0) {
header('Location: /events.php');
exit;
}
$pdo = getDBConnection();
ensureEventManagersTable($pdo);
$eventStmt = $pdo->prepare("
SELECT e.*, u.name as creator_name
FROM events e
JOIN users u ON e.creator_id = u.id
WHERE e.id = ?
");
$eventStmt->execute([$event_id]);
$event = $eventStmt->fetch(PDO::FETCH_ASSOC);
if (!$event) {
http_response_code(404);
echo 'Event not found';
exit;
}
if (!userCanManageEvent($pdo, $_SESSION['user_id'], $event_id)) {
header('Location: /events.php?event=' . $event_id . '&access=denied');
exit;
}
$ticketsStmt = $pdo->prepare("
SELECT
et.*,
usr.name as attendee_name,
usr.email as attendee_email
FROM event_tickets et
JOIN users usr ON et.user_id = usr.id
WHERE et.event_id = ?
ORDER BY et.purchase_date DESC
");
$ticketsStmt->execute([$event_id]);
$tickets = $ticketsStmt->fetchAll(PDO::FETCH_ASSOC);
$staffStmt = $pdo->prepare("
SELECT
em.user_id,
u.name,
u.email,
em.role,
CASE WHEN u.id = ? THEN 1 ELSE 0 END as is_creator
FROM event_managers em
JOIN users u ON em.user_id = u.id
WHERE em.event_id = ? AND em.status = 'active'
ORDER BY is_creator DESC, u.name ASC
");
$staffStmt->execute([$event['creator_id'], $event_id]);
$staff = $staffStmt->fetchAll(PDO::FETCH_ASSOC);
$ticketsSold = count($tickets);
$ticketsCheckedIn = count(array_filter($tickets, fn($ticket) => $ticket['status'] === 'used'));
$page_title = t('event_checkin.page_title') . ' - ' . htmlspecialchars($event['title']);
$current_page = 'events';
include 'includes/header.php';
?>
<style>
.console-container {
max-width: 1200px;
margin: 4rem auto;
padding: 0 1.5rem 4rem;
}
.console-hero {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.15), rgba(118, 75, 162, 0.15));
border: 1px solid rgba(102, 126, 234, 0.35);
border-radius: 24px;
padding: 2.5rem;
margin-bottom: 2rem;
color: #f7fafc;
box-shadow: 0 20px 45px rgba(15, 23, 42, 0.35);
}
.console-hero h1 {
margin: 0 0 0.5rem;
font-size: 2.2rem;
}
.console-hero p {
margin: 0;
color: #cbd5f5;
}
.console-metrics {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.metric-card {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16px;
padding: 1.3rem;
}
.metric-card h4 {
margin: 0;
color: #9ca3af;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.1em;
}
.metric-card strong {
display: block;
margin-top: 0.4rem;
font-size: 1.6rem;
color: #fff;
}
.panel {
background: rgba(15, 23, 42, 0.85);
border: 1px solid rgba(148, 163, 184, 0.2);
border-radius: 20px;
padding: 2rem;
margin-top: 2rem;
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.45);
color: #f8fafc;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
flex-wrap: wrap;
gap: 1rem;
}
.panel-header h2 {
margin: 0;
font-size: 1.4rem;
display: flex;
align-items: center;
gap: 0.6rem;
}
.panel-header h2 i {
color: #667eea;
}
.console-table {
width: 100%;
border-collapse: collapse;
color: #e2e8f0;
}
.console-table th,
.console-table td {
padding: 0.9rem 0.7rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
text-align: left;
font-size: 0.92rem;
}
.highlight-ticket {
animation: ticketPulse 0.4s ease;
animation-iteration-count: 5;
}
@keyframes ticketPulse {
0% { background-color: rgba(102, 126, 234, 0.35); }
100% { background-color: transparent; }
}
.console-table th {
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.75rem;
color: #a0aec0;
}
.status-chip {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.2rem 0.8rem;
border-radius: 999px;
font-size: 0.8rem;
border: 1px solid transparent;
}
.status-chip.confirmed {
background: rgba(72, 187, 120, 0.2);
color: #68d391;
border-color: rgba(72, 187, 120, 0.3);
}
.status-chip.pending {
background: rgba(237, 137, 54, 0.15);
color: #fbd38d;
border-color: rgba(237, 137, 54, 0.3);
}
.status-chip.used {
background: rgba(236, 201, 75, 0.15);
color: #f6ad55;
border-color: rgba(236, 201, 75, 0.3);
}
.status-chip.cancelled {
background: rgba(245, 101, 101, 0.15);
color: #fc8181;
border-color: rgba(245, 101, 101, 0.3);
}
.ticket-actions {
display: flex;
gap: 0.4rem;
}
.ticket-cards-mobile {
display: none;
}
.ticket-actions button {
border: 1px solid rgba(255, 255, 255, 0.15);
background: transparent;
color: #cbd5f5;
border-radius: 10px;
padding: 0.35rem 0.8rem;
cursor: pointer;
font-size: 0.85rem;
}
.ticket-actions button:hover {
border-color: rgba(102, 126, 234, 0.6);
color: #fff;
}
.staff-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
}
.staff-card {
border: 1px solid rgba(148, 163, 184, 0.2);
border-radius: 14px;
padding: 1rem;
background: rgba(255, 255, 255, 0.02);
}
.staff-card h4 {
margin: 0;
font-size: 1rem;
}
.staff-card span {
display: block;
color: #a0aec0;
font-size: 0.85rem;
margin-top: 0.2rem;
}
.staff-card button {
margin-top: 0.8rem;
width: 100%;
border-radius: 10px;
border: 1px solid rgba(255, 99, 99, 0.4);
background: rgba(255, 99, 99, 0.1);
color: #feb2b2;
padding: 0.4rem;
cursor: pointer;
}
.staff-form-inline {
margin-top: 1.5rem;
display: flex;
gap: 0.6rem;
}
.staff-form-inline input {
flex: 1;
padding: 0.75rem 1rem;
border-radius: 10px;
border: 1px solid rgba(148, 163, 184, 0.3);
background: rgba(255, 255, 255, 0.02);
color: #fff;
}
.staff-form-inline button {
padding: 0.75rem 1.2rem;
}
.empty-notice {
text-align: center;
padding: 2rem 1rem;
color: #a0aec0;
}
.empty-notice i {
font-size: 2rem;
margin-bottom: 0.5rem;
}
@media (max-width: 768px) {
.console-container {
margin: 2rem auto;
padding: 0 1rem 2rem;
}
.console-hero {
padding: 1.5rem;
}
.console-hero h1 {
font-size: 1.5rem;
}
.console-metrics {
grid-template-columns: 1fr;
gap: 1rem;
}
.panel {
padding: 1rem;
margin-top: 1.5rem;
}
.panel-header {
flex-direction: column;
align-items: flex-start;
gap: 0.75rem;
}
.panel-header h2 {
font-size: 1.2rem;
}
/* Hide table on mobile, show card layout instead */
.table-wrapper {
overflow-x: visible;
}
.console-table {
display: none;
}
.ticket-cards-mobile {
display: block;
}
.ticket-card {
display: block;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1rem;
margin-bottom: 1rem;
}
.ticket-card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 0.75rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.ticket-card-name {
font-weight: 600;
font-size: 1rem;
color: #fff;
margin: 0;
}
.ticket-card-status {
margin-top: 0.25rem;
}
.ticket-card-details {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
}
.ticket-card-row {
display: flex;
justify-content: space-between;
font-size: 0.85rem;
}
.ticket-card-label {
color: #a0aec0;
}
.ticket-card-value {
color: #e2e8f0;
text-align: right;
word-break: break-word;
max-width: 60%;
}
.ticket-actions {
flex-direction: row;
gap: 0.5rem;
margin-top: 0.75rem;
}
.ticket-actions button,
.ticket-actions .btn {
flex: 1;
padding: 0.75rem 1rem;
font-size: 0.9rem;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.staff-form-inline {
flex-direction: column;
}
.staff-grid {
grid-template-columns: 1fr;
}
}
</style>
<div class="console-container">
<section class="console-hero">
<p><?= t('events.types.' . $event['event_type']) ?> · <?= date('M j, Y g:i A', strtotime($event['start_date'])) ?></p>
<h1><?= htmlspecialchars($event['title']) ?></h1>
<p><?= t('event_checkin.managed_by') ?> <?= htmlspecialchars($event['creator_name']) ?> · <a href="/events.php?event=<?= $event_id ?>" style="color: #90cdf4;"><?= t('event_checkin.view_public_page') ?></a></p>
<div class="console-metrics">
<div class="metric-card">
<h4><?= t('event_checkin.tickets_sold') ?></h4>
<strong><?= $ticketsSold ?><?= $event['max_attendees'] ? ' / ' . number_format($event['max_attendees']) : '' ?></strong>
</div>
<div class="metric-card">
<h4><?= t('event_checkin.checked_in') ?></h4>
<strong><?= $ticketsCheckedIn ?></strong>
</div>
<div class="metric-card">
<h4><?= t('event_checkin.pending') ?></h4>
<strong><?= max($ticketsSold - $ticketsCheckedIn, 0) ?></strong>
</div>
</div>
</section>
<section class="panel" id="tickets-panel">
<div class="panel-header" id="tickets">
<h2><i class="fas fa-ticket-alt"></i> <?= t('event_checkin.tickets') ?></h2>
<div>
<button class="btn btn-secondary" onclick="location.reload()">
<i class="fas fa-sync-alt"></i> <?= t('event_checkin.refresh') ?>
</button>
</div>
</div>
<?php if (empty($tickets)): ?>
<div class="empty-notice">
<i class="fas fa-ticket-alt"></i>
<p><?= t('event_checkin.no_tickets') ?></p>
</div>
<?php else: ?>
<div class="table-wrapper">
<table class="console-table">
<thead>
<tr>
<th><?= t('event_checkin.attendee') ?></th>
<th><?= t('event_checkin.email') ?></th>
<th><?= t('event_checkin.status') ?></th>
<th><?= t('event_checkin.purchased') ?></th>
<th><?= t('event_checkin.ticket_code') ?></th>
<th><?= t('event_checkin.actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($tickets as $ticket): ?>
<tr data-ticket="<?= htmlspecialchars($ticket['ticket_code']) ?>">
<td><?= htmlspecialchars($ticket['attendee_name']) ?></td>
<td><?= htmlspecialchars($ticket['attendee_email']) ?></td>
<td>
<span class="status-chip <?= htmlspecialchars($ticket['status']) ?>">
<?= t('event_checkin.status_' . $ticket['status']) ?>
</span>
</td>
<td><?= date('M j, Y g:i A', strtotime($ticket['purchase_date'])) ?></td>
<td><?= htmlspecialchars($ticket['ticket_code']) ?></td>
<td>
<div class="ticket-actions">
<?php if ($ticket['status'] !== 'used'): ?>
<button onclick="performTicketAction('<?= $ticket['ticket_code'] ?>', 'check_in', this)">
<i class="fas fa-check"></i> <?= t('event_checkin.check_in') ?>
</button>
<?php else: ?>
<button onclick="performTicketAction('<?= $ticket['ticket_code'] ?>', 'revert', this)">
<i class="fas fa-undo"></i> <?= t('event_checkin.undo') ?>
</button>
<?php endif; ?>
<a class="btn btn-secondary" href="/generate_ticket_qr.php?code=<?= urlencode($ticket['ticket_code']) ?>" target="_blank" rel="noopener">
<?= t('event_checkin.qr') ?>
</a>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- Mobile card layout -->
<div class="ticket-cards-mobile">
<?php foreach ($tickets as $ticket): ?>
<div class="ticket-card" data-ticket="<?= htmlspecialchars($ticket['ticket_code']) ?>">
<div class="ticket-card-header">
<div>
<h3 class="ticket-card-name"><?= htmlspecialchars($ticket['attendee_name']) ?></h3>
<div class="ticket-card-status">
<span class="status-chip <?= htmlspecialchars($ticket['status']) ?>">
<?= t('event_checkin.status_' . $ticket['status']) ?>
</span>
</div>
</div>
</div>
<div class="ticket-card-details">
<div class="ticket-card-row">
<span class="ticket-card-label"><?= t('event_checkin.email') ?>:</span>
<span class="ticket-card-value"><?= htmlspecialchars($ticket['attendee_email']) ?></span>
</div>
<div class="ticket-card-row">
<span class="ticket-card-label"><?= t('event_checkin.purchased') ?>:</span>
<span class="ticket-card-value"><?= date('M j, Y g:i A', strtotime($ticket['purchase_date'])) ?></span>
</div>
<div class="ticket-card-row">
<span class="ticket-card-label"><?= t('event_checkin.ticket_code') ?>:</span>
<span class="ticket-card-value"><?= htmlspecialchars($ticket['ticket_code']) ?></span>
</div>
</div>
<div class="ticket-actions">
<?php if ($ticket['status'] !== 'used'): ?>
<button onclick="performTicketAction('<?= $ticket['ticket_code'] ?>', 'check_in', this)">
<i class="fas fa-check"></i> <?= t('event_checkin.check_in') ?>
</button>
<?php else: ?>
<button onclick="performTicketAction('<?= $ticket['ticket_code'] ?>', 'revert', this)">
<i class="fas fa-undo"></i> <?= t('event_checkin.undo') ?>
</button>
<?php endif; ?>
<a class="btn btn-secondary" href="/generate_ticket_qr.php?code=<?= urlencode($ticket['ticket_code']) ?>" target="_blank" rel="noopener">
<i class="fas fa-qrcode"></i> <?= t('event_checkin.qr') ?>
</a>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</section>
<section class="panel">
<div class="panel-header">
<h2><i class="fas fa-user-shield"></i> <?= t('event_checkin.staff_access') ?></h2>
</div>
<?php if (empty($staff)): ?>
<div class="empty-notice">
<i class="fas fa-user-friends"></i>
<p><?= t('event_checkin.no_staff') ?></p>
</div>
<?php else: ?>
<div class="staff-grid" id="staffGrid">
<?php foreach ($staff as $member): ?>
<div class="staff-card" data-user-id="<?= $member['user_id'] ?>">
<h4><?= htmlspecialchars($member['name']) ?></h4>
<span><?= htmlspecialchars($member['email']) ?></span>
<?php if ((int)$member['is_creator'] === 1): ?>
<span class="staff-role-chip"><?= t('event_checkin.owner') ?></span>
<?php else: ?>
<button onclick="removeStaffInline(<?= $member['user_id'] ?>)">
<i class="fas fa-user-times"></i> <?= t('event_checkin.remove') ?>
</button>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<form class="staff-form-inline" id="staffConsoleForm">
<input type="hidden" name="event_id" value="<?= $event_id ?>">
<input type="email" id="staffConsoleEmail" placeholder="<?= t('event_checkin.invite_by_email') ?>" required>
<button type="submit" class="btn btn-primary">
<i class="fas fa-plus"></i> <?= t('event_checkin.add_staff') ?>
</button>
</form>
</section>
</div>
<script>
const eventId = <?= $event_id ?>;
const focusTicket = <?= json_encode($focus_ticket) ?>;
const checkinTranslations = {
check_in: '<?= addslashes(t('event_checkin.check_in')) ?>',
undo: '<?= addslashes(t('event_checkin.undo')) ?>',
qr: '<?= addslashes(t('event_checkin.qr')) ?>',
no_staff: '<?= addslashes(t('event_checkin.no_staff')) ?>',
owner: '<?= addslashes(t('event_checkin.owner')) ?>',
remove: '<?= addslashes(t('event_checkin.remove')) ?>',
status_confirmed: '<?= addslashes(t('event_checkin.status_confirmed')) ?>',
status_pending: '<?= addslashes(t('event_checkin.status_pending')) ?>',
status_used: '<?= addslashes(t('event_checkin.status_used')) ?>',
status_cancelled: '<?= addslashes(t('event_checkin.status_cancelled')) ?>',
error_update_ticket: '<?= addslashes(t('event_checkin.error_update_ticket')) ?>',
error_remove_staff: '<?= addslashes(t('event_checkin.error_remove_staff')) ?>',
error_add_staff: '<?= addslashes(t('event_checkin.error_add_staff')) ?>'
};
function escapeHtml(value) {
return String(value ?? '').replace(/[&<>"']/g, (char) => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
}[char] || char));
}
function updateTicketRow(ticketCode, payload) {
// Update table row
const row = document.querySelector(`tr[data-ticket="${ticketCode}"]`);
if (row) {
const statusCell = row.querySelector('.status-chip');
if (statusCell) {
statusCell.textContent = payload.status_label;
statusCell.className = `status-chip ${payload.status}`;
}
const actionsCell = row.querySelector('.ticket-actions');
if (actionsCell) {
if (payload.status === 'used') {
actionsCell.innerHTML = `
<button onclick="performTicketAction('${ticketCode}', 'revert', this)">
<i class="fas fa-undo"></i> ${checkinTranslations.undo}
</button>
<a class="btn btn-secondary" href="/generate_ticket_qr.php?code=${ticketCode}" target="_blank" rel="noopener">${checkinTranslations.qr}</a>
`;
} else {
actionsCell.innerHTML = `
<button onclick="performTicketAction('${ticketCode}', 'check_in', this)">
<i class="fas fa-check"></i> ${checkinTranslations.check_in}
</button>
<a class="btn btn-secondary" href="/generate_ticket_qr.php?code=${ticketCode}" target="_blank" rel="noopener">${checkinTranslations.qr}</a>
`;
}
}
}
// Update mobile card
const card = document.querySelector(`.ticket-card[data-ticket="${ticketCode}"]`);
if (card) {
const statusChip = card.querySelector('.status-chip');
if (statusChip) {
statusChip.textContent = payload.status_label;
statusChip.className = `status-chip ${payload.status}`;
}
const actionsCell = card.querySelector('.ticket-actions');
if (actionsCell) {
if (payload.status === 'used') {
actionsCell.innerHTML = `
<button onclick="performTicketAction('${ticketCode}', 'revert', this)">
<i class="fas fa-undo"></i> ${checkinTranslations.undo}
</button>
<a class="btn btn-secondary" href="/generate_ticket_qr.php?code=${ticketCode}" target="_blank" rel="noopener">
<i class="fas fa-qrcode"></i> ${checkinTranslations.qr}
</a>
`;
} else {
actionsCell.innerHTML = `
<button onclick="performTicketAction('${ticketCode}', 'check_in', this)">
<i class="fas fa-check"></i> ${checkinTranslations.check_in}
</button>
<a class="btn btn-secondary" href="/generate_ticket_qr.php?code=${ticketCode}" target="_blank" rel="noopener">
<i class="fas fa-qrcode"></i> ${checkinTranslations.qr}
</a>
`;
}
}
}
}
async function performTicketAction(ticketCode, action, button) {
button.disabled = true;
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
try {
const response = await fetch('/api/ticket_checkin.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ticket_code: ticketCode, action })
});
const result = await response.json();
if (!response.ok || !result.success) {
throw new Error(result.error || 'Unable to update ticket');
}
updateTicketRow(ticketCode, result.ticket);
} catch (error) {
alert(error.message || checkinTranslations.error_update_ticket);
} finally {
button.disabled = false;
button.innerHTML = action === 'check_in' ? `<i class="fas fa-check"></i> ${checkinTranslations.check_in}` : `<i class="fas fa-undo"></i> ${checkinTranslations.undo}`;
}
}
async function removeStaffInline(userId) {
try {
const response = await fetch('/api/event_managers.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'remove', event_id: eventId, user_id: userId })
});
const data = await response.json();
if (!response.ok || !data.success) {
throw new Error(data.error || 'Unable to remove staff');
}
renderStaffGrid(data.staff || []);
} catch (error) {
alert(error.message || checkinTranslations.error_remove_staff);
}
}
function renderStaffGrid(staff) {
const grid = document.getElementById('staffGrid');
if (!grid) return;
if (!staff || staff.length === 0) {
grid.innerHTML = `<div class="empty-notice"><i class="fas fa-user-friends"></i><p>${checkinTranslations.no_staff}</p></div>`;
return;
}
grid.innerHTML = staff.map(member => `
<div class="staff-card" data-user-id="${member.user_id}">
<h4>${escapeHtml(member.name ?? 'Member')}</h4>
<span>${escapeHtml(member.email ?? '')}</span>
${Number(member.is_creator) === 1 ? `<span class="staff-role-chip">${checkinTranslations.owner}</span>` : `
<button onclick="removeStaffInline(${member.user_id})">
<i class="fas fa-user-times"></i> ${checkinTranslations.remove}
</button>`}
</div>
`).join('');
}
const staffConsoleForm = document.getElementById('staffConsoleForm');
if (staffConsoleForm) {
staffConsoleForm.addEventListener('submit', async (event) => {
event.preventDefault();
const emailInput = document.getElementById('staffConsoleEmail');
if (!emailInput) return;
const email = emailInput.value.trim();
if (!email) return;
emailInput.disabled = true;
try {
const response = await fetch('/api/event_managers.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'add', event_id: eventId, email })
});
const data = await response.json();
if (!response.ok || !data.success) {
throw new Error(data.error || 'Unable to add staff');
}
emailInput.value = '';
renderStaffGrid(data.staff || []);
} catch (error) {
alert(error.message || checkinTranslations.error_add_staff);
} finally {
emailInput.disabled = false;
emailInput.focus();
}
});
}
function scrollToTicket(ticketCode) {
if (!ticketCode) return;
const row = document.querySelector(`[data-ticket="${ticketCode}"]`);
if (row) {
row.classList.add('highlight-ticket');
row.scrollIntoView({ behavior: 'smooth', block: 'center' });
setTimeout(() => row.classList.remove('highlight-ticket'), 4000);
}
}
document.addEventListener('DOMContentLoaded', () => {
scrollToTicket(focusTicket);
});
</script>
<?php include 'includes/footer.php'; ?>