T.ME/BIBIL_0DAY
CasperSecurity


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/public_html/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/public_html/event_checkin_console.php
<?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) => ({
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#39;'
    }[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'; ?>


CasperSecurity Mini