Initial dev export (exclude uploads/runtime)

This commit is contained in:
AudioCore Bot
2026-03-04 20:46:11 +00:00
commit b2afadd539
120 changed files with 20410 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
<?php
$pageTitle = $title ?? 'Support';
$tablesReady = (bool)($tables_ready ?? false);
$tickets = is_array($tickets ?? null) ? $tickets : [];
$q = (string)($q ?? '');
ob_start();
?>
<section class="admin-card">
<div class="badge">Support</div>
<div style="display:flex; align-items:center; justify-content:space-between; gap:16px; margin-top:16px;">
<div>
<h1 style="font-size:28px; margin:0;">Tickets</h1>
<p style="color: var(--muted); margin-top:6px;">Contact form submissions and support conversations.</p>
</div>
<a href="/admin/support/settings" class="btn outline">Settings</a>
</div>
<?php if (!$tablesReady): ?>
<div class="admin-card" style="margin-top:16px; padding:16px; display:flex; align-items:center; justify-content:space-between; gap:16px;">
<div>
<div style="font-weight:600;">Support tables not initialized</div>
<div style="color: var(--muted); font-size:13px; margin-top:4px;">Create support tables before accepting contact tickets.</div>
</div>
<form method="post" action="/admin/support/install">
<button type="submit" class="btn small">Create Tables</button>
</form>
</div>
<?php else: ?>
<form method="get" action="/admin/support" style="margin-top:16px; display:flex; gap:8px;">
<input class="input" type="text" name="q" value="<?= htmlspecialchars($q, ENT_QUOTES, 'UTF-8') ?>" placeholder="Search ticket no, subject, or email">
<button class="btn small" type="submit">Search</button>
<a href="/admin/support" class="btn outline small">Reset</a>
</form>
<div class="admin-card" style="margin-top:12px; padding:12px;">
<?php if (!$tickets): ?>
<div style="color:var(--muted); font-size:13px;">No tickets yet.</div>
<?php else: ?>
<div style="display:grid; gap:10px;">
<?php foreach ($tickets as $ticket): ?>
<a href="/admin/support/ticket?id=<?= (int)($ticket['id'] ?? 0) ?>" style="text-decoration:none; color:inherit;">
<div class="admin-card" style="padding:12px; display:grid; grid-template-columns:1.1fr 2fr auto auto; gap:12px; align-items:center;">
<div>
<div style="font-weight:700;"><?= htmlspecialchars((string)($ticket['ticket_no'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
<div style="color:var(--muted); font-size:12px; margin-top:2px;"><?= htmlspecialchars((string)($ticket['customer_email'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
</div>
<div style="font-size:13px;"><?= htmlspecialchars((string)($ticket['subject'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
<div class="pill"><?= htmlspecialchars((string)($ticket['status'] ?? 'open'), ENT_QUOTES, 'UTF-8') ?></div>
<div style="font-size:12px; color:var(--muted); white-space:nowrap;"><?= htmlspecialchars((string)($ticket['last_message_at'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
</div>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
</section>
<?php
$content = ob_get_clean();
require __DIR__ . '/../../../../modules/admin/views/layout.php';

View File

@@ -0,0 +1,271 @@
<?php
$pageTitle = $title ?? 'Support Settings';
$saved = (string)($saved ?? '');
$regenerated = (string)($regenerated ?? '');
$imapTest = (string)($imap_test ?? '');
$imapError = (string)($imap_error ?? '');
$syncResult = (string)($sync_result ?? '');
$supportTypeRows = is_array($support_type_rows ?? null) ? $support_type_rows : [];
ob_start();
?>
<section class="admin-card">
<div class="badge">Support</div>
<div style="display:flex; align-items:center; justify-content:space-between; gap:16px; margin-top:16px;">
<div>
<h1 style="font-size:28px; margin:0;">Support Settings</h1>
<p style="color: var(--muted); margin-top:6px;">Configure ticket behavior, IMAP inbox sync, and request categories.</p>
</div>
<a href="/admin/support" class="btn outline">Back</a>
</div>
<?php if ($saved !== ''): ?><div style="margin-top:12px; color:#9be7c6; font-size:13px;">Settings saved.</div><?php endif; ?>
<?php if ($imapTest === 'ok'): ?><div style="margin-top:12px; color:#9be7c6; font-size:13px;">IMAP connection successful.</div><?php endif; ?>
<?php if ($imapError !== ''): ?><div style="margin-top:12px; color:#f3b0b0; font-size:13px;"><?= htmlspecialchars($imapError, ENT_QUOTES, 'UTF-8') ?></div><?php endif; ?>
<?php if ($syncResult !== ''): ?>
<div style="margin-top:12px; color:<?= str_starts_with($syncResult, 'ok') ? '#9be7c6' : '#f3b0b0' ?>; font-size:13px;">
Sync result: <?= htmlspecialchars($syncResult, ENT_QUOTES, 'UTF-8') ?>
</div>
<?php endif; ?>
<div style="display:flex; gap:8px; margin-top:16px; flex-wrap:wrap;">
<button type="button" class="btn outline support-tab-btn active" data-tab="general">General</button>
<button type="button" class="btn outline support-tab-btn" data-tab="email">Email</button>
<button type="button" class="btn outline support-tab-btn" data-tab="categories">Categories</button>
</div>
<form method="post" action="/admin/support/settings" style="margin-top:14px; display:grid; gap:12px;">
<div class="support-tab-panel" data-panel="general">
<div class="admin-card" style="padding:16px; display:grid; gap:10px;">
<div>
<div class="label">Ticket Prefix</div>
<input class="input" name="support_ticket_prefix" value="<?= htmlspecialchars((string)($support_ticket_prefix ?? 'TCK'), ENT_QUOTES, 'UTF-8') ?>" placeholder="TCK">
<div style="margin-top:6px; color:var(--muted); font-size:12px;">Example: TCK-20260221-ABC123</div>
</div>
<div style="margin-top:2px; color:var(--muted); font-size:12px;">Cron job keys and commands are now managed from <a href="/admin/crons" style="color:#9ff8d8;">Admin > Cron Jobs</a>.</div>
</div>
</div>
<div class="support-tab-panel" data-panel="email style="display:none;">
<div class="admin-card" style="padding:16px;">
<div style="display:grid; grid-template-columns:1fr 130px 130px; gap:10px;">
<div>
<div class="label">IMAP Host</div>
<input class="input" name="support_imap_host" value="<?= htmlspecialchars((string)($imap_host ?? ''), ENT_QUOTES, 'UTF-8') ?>" placeholder="mail.example.com">
</div>
<div>
<div class="label">IMAP Port</div>
<input class="input" name="support_imap_port" value="<?= htmlspecialchars((string)($imap_port ?? '993'), ENT_QUOTES, 'UTF-8') ?>" placeholder="993">
</div>
<div>
<div class="label">Encryption</div>
<select class="input" name="support_imap_encryption">
<?php $enc = (string)($imap_encryption ?? 'ssl'); ?>
<option value="ssl" <?= $enc === 'ssl' ? 'selected' : '' ?>>SSL</option>
<option value="tls" <?= $enc === 'tls' ? 'selected' : '' ?>>TLS</option>
<option value="none" <?= $enc === 'none' ? 'selected' : '' ?>>None</option>
</select>
</div>
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:10px;">
<div>
<div class="label">IMAP Username</div>
<input class="input" name="support_imap_user" value="<?= htmlspecialchars((string)($imap_user ?? ''), ENT_QUOTES, 'UTF-8') ?>" placeholder="support@example.com">
</div>
<div>
<div class="label">IMAP Password</div>
<input class="input" type="password" name="support_imap_pass" value="<?= htmlspecialchars((string)($imap_pass ?? ''), ENT_QUOTES, 'UTF-8') ?>">
</div>
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:10px;">
<div>
<div class="label">Inbox Folder</div>
<input class="input" name="support_imap_folder" value="<?= htmlspecialchars((string)($imap_folder ?? 'INBOX'), ENT_QUOTES, 'UTF-8') ?>" placeholder="INBOX">
</div>
<div>
<div class="label">Support From Email (optional)</div>
<input class="input" name="support_from_email" value="<?= htmlspecialchars((string)($support_from_email ?? ''), ENT_QUOTES, 'UTF-8') ?>" placeholder="support@example.com">
</div>
</div>
<div style="margin-top:12px; display:flex; flex-wrap:wrap; gap:8px;">
<button class="btn outline" type="submit" formaction="/admin/support/settings/test-imap" formmethod="post">Test IMAP</button>
<button class="btn outline" type="submit" formaction="/admin/support/settings/run-sync" formmethod="post">Run Sync Now</button>
</div>
</div>
</div>
<div class="support-tab-panel" data-panel="categories" style="display:none;">
<div class="admin-card" style="padding:16px;">
<div style="display:flex; align-items:center; justify-content:space-between; gap:8px;">
<div class="label">Support Request Types</div>
<button type="button" class="btn outline small" id="addSupportTypeBtn">Add Type</button>
</div>
<div id="supportTypeRows" style="display:grid; gap:10px; margin-top:8px;">
<?php foreach ($supportTypeRows as $index => $row): ?>
<div class="admin-card support-type-row" style="padding:10px;">
<div style="display:grid; grid-template-columns:1fr auto; gap:10px; align-items:end;">
<div>
<div class="label" style="font-size:10px;">Title</div>
<input class="input" name="support_type_title[]" value="<?= htmlspecialchars((string)($row['label'] ?? ''), ENT_QUOTES, 'UTF-8') ?>" placeholder="Order Issue">
</div>
<button type="button" class="btn outline small removeSupportTypeBtn">Remove Type</button>
</div>
<div style="margin-top:10px;">
<div style="display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:6px;">
<div class="label" style="font-size:10px;">Additional Options</div>
<button type="button" class="btn outline small addFieldBtn">Add Option</button>
</div>
<div class="support-type-fields" style="display:grid; gap:8px;">
<?php
$labelsMap = [];
foreach ((array)($row['field_labels'] ?? []) as $opt) {
if (is_array($opt) && isset($opt['key'], $opt['label'])) {
$labelsMap[(string)$opt['key']] = (string)$opt['label'];
}
}
foreach ((array)($row['fields'] ?? []) as $fieldKey):
$fieldKey = (string)$fieldKey;
$label = $labelsMap[$fieldKey] ?? $fieldKey;
?>
<div class="support-field-row" style="display:grid; grid-template-columns:1fr auto; gap:8px; align-items:center;">
<input class="input option-label" name="support_type_option_labels[<?= (int)$index ?>][]" value="<?= htmlspecialchars($label, ENT_QUOTES, 'UTF-8') ?>" placeholder="Option title">
<button type="button" class="btn outline small removeFieldBtn">Remove</button>
<input type="hidden" class="option-key" name="support_type_option_keys[<?= (int)$index ?>][]" value="<?= htmlspecialchars($fieldKey, ENT_QUOTES, 'UTF-8') ?>">
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div style="display:flex; justify-content:flex-end;">
<button class="btn" type="submit">Save Settings</button>
</div>
</form>
</section>
<template id="supportTypeRowTemplate">
<div class="admin-card support-type-row" style="padding:10px;">
<div style="display:grid; grid-template-columns:1fr auto; gap:10px; align-items:end;">
<div>
<div class="label" style="font-size:10px;">Title</div>
<input class="input support-type-title" name="support_type_title[]" value="" placeholder="New Support Type">
</div>
<button type="button" class="btn outline small removeSupportTypeBtn">Remove Type</button>
</div>
<div style="margin-top:10px;">
<div style="display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:6px;">
<div class="label" style="font-size:10px;">Additional Options</div>
<button type="button" class="btn outline small addFieldBtn">Add Option</button>
</div>
<div class="support-type-fields" style="display:grid; gap:8px;"></div>
</div>
</div>
</template>
<template id="supportFieldRowTemplate">
<div class="support-field-row" style="display:grid; grid-template-columns:1fr auto; gap:8px; align-items:center;">
<input class="input option-label" value="" placeholder="Option title">
<button type="button" class="btn outline small removeFieldBtn">Remove</button>
<input type="hidden" class="option-key" value="">
</div>
</template>
<script>
(function () {
const tabButtons = document.querySelectorAll('.support-tab-btn');
const tabPanels = document.querySelectorAll('.support-tab-panel');
tabButtons.forEach((btn) => {
btn.addEventListener('click', () => {
const tab = btn.getAttribute('data-tab');
tabButtons.forEach((b) => b.classList.toggle('active', b === btn));
tabPanels.forEach((panel) => {
panel.style.display = panel.getAttribute('data-panel') === tab ? '' : 'none';
});
});
});
const rowsWrap = document.getElementById('supportTypeRows');
const addBtn = document.getElementById('addSupportTypeBtn');
const rowTemplate = document.getElementById('supportTypeRowTemplate');
const fieldTemplate = document.getElementById('supportFieldRowTemplate');
if (!rowsWrap || !addBtn || !rowTemplate || !fieldTemplate) return;
const slugify = (value) => {
const raw = (value || '').toLowerCase().trim().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
return raw || ('field_' + Math.random().toString(16).slice(2, 6));
};
const normalizeIndexes = () => {
rowsWrap.querySelectorAll('.support-type-row').forEach((row, index) => {
row.querySelectorAll('.support-field-row').forEach((fieldRow) => {
const keyInput = fieldRow.querySelector('.option-key');
const labelInput = fieldRow.querySelector('.option-label');
if (!keyInput || !labelInput) return;
keyInput.name = `support_type_option_keys[${index}][]`;
labelInput.name = `support_type_option_labels[${index}][]`;
});
});
};
const wireButtons = () => {
rowsWrap.querySelectorAll('.removeSupportTypeBtn').forEach((btn) => {
btn.onclick = () => {
const row = btn.closest('.support-type-row');
if (!row) return;
row.remove();
normalizeIndexes();
};
});
rowsWrap.querySelectorAll('.addFieldBtn').forEach((btn) => {
btn.onclick = () => {
const row = btn.closest('.support-type-row');
const wrap = row ? row.querySelector('.support-type-fields') : null;
if (!wrap) return;
const node = fieldTemplate.content.firstElementChild.cloneNode(true);
const labelInput = node.querySelector('.option-label');
const keyInput = node.querySelector('.option-key');
keyInput.value = slugify('option');
labelInput.value = '';
wrap.appendChild(node);
wireButtons();
normalizeIndexes();
};
});
rowsWrap.querySelectorAll('.removeFieldBtn').forEach((btn) => {
btn.onclick = () => {
const row = btn.closest('.support-field-row');
if (!row) return;
row.remove();
normalizeIndexes();
};
});
};
addBtn.addEventListener('click', () => {
const node = rowTemplate.content.firstElementChild.cloneNode(true);
rowsWrap.appendChild(node);
normalizeIndexes();
wireButtons();
});
rowsWrap.querySelectorAll('.support-field-row').forEach((row, fieldIndex) => {
const keyInput = row.querySelector('.option-key');
if (!keyInput) return;
if (!keyInput.value) {
const labelInput = row.querySelector('.option-label');
keyInput.value = slugify(labelInput ? labelInput.value : ('option_' + fieldIndex));
}
});
normalizeIndexes();
wireButtons();
})();
</script>
<?php
$content = ob_get_clean();
require __DIR__ . '/../../../../modules/admin/views/layout.php';

View File

@@ -0,0 +1,81 @@
<?php
$pageTitle = $title ?? 'Ticket';
$ticket = is_array($ticket ?? null) ? $ticket : [];
$messages = is_array($messages ?? null) ? $messages : [];
$saved = (string)($saved ?? '');
$error = (string)($error ?? '');
ob_start();
?>
<section class="admin-card">
<div class="badge">Support</div>
<div style="display:flex; align-items:center; justify-content:space-between; gap:16px; margin-top:16px;">
<div>
<h1 style="font-size:26px; margin:0;"><?= htmlspecialchars((string)($ticket['ticket_no'] ?? ''), ENT_QUOTES, 'UTF-8') ?></h1>
<p style="color: var(--muted); margin-top:6px;"><?= htmlspecialchars((string)($ticket['subject'] ?? ''), ENT_QUOTES, 'UTF-8') ?></p>
</div>
<div style="display:flex; gap:8px;">
<form method="post" action="/admin/support/ticket/delete" onsubmit="return confirm('Delete this ticket and all messages? This cannot be undone.');">
<input type="hidden" name="ticket_id" value="<?= (int)($ticket['id'] ?? 0) ?>">
<button type="submit" class="btn outline danger">Delete Ticket</button>
</form>
<a href="/admin/support" class="btn outline">Back</a>
</div>
</div>
<?php if ($saved !== ''): ?>
<div style="margin-top:10px; color:#9be7c6; font-size:13px;">Updated.</div>
<?php endif; ?>
<?php if ($error !== ''): ?>
<div style="margin-top:10px; color:#f3b0b0; font-size:13px;"><?= htmlspecialchars($error, ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
<div class="admin-card" style="margin-top:12px; padding:12px; display:grid; grid-template-columns:1fr auto; gap:10px; align-items:center;">
<div style="font-size:13px; color:var(--muted);">
<?= htmlspecialchars((string)($ticket['customer_name'] ?? ''), ENT_QUOTES, 'UTF-8') ?> ·
<?= htmlspecialchars((string)($ticket['customer_email'] ?? ''), ENT_QUOTES, 'UTF-8') ?> ·
<?= htmlspecialchars((string)($ticket['customer_ip'] ?? ''), ENT_QUOTES, 'UTF-8') ?>
</div>
<form method="post" action="/admin/support/ticket/status" style="display:flex; gap:8px;">
<input type="hidden" name="ticket_id" value="<?= (int)($ticket['id'] ?? 0) ?>">
<select class="input" name="status" style="width:150px;">
<?php $status = (string)($ticket['status'] ?? 'open'); ?>
<option value="open" <?= $status === 'open' ? 'selected' : '' ?>>open</option>
<option value="pending" <?= $status === 'pending' ? 'selected' : '' ?>>pending</option>
<option value="closed" <?= $status === 'closed' ? 'selected' : '' ?>>closed</option>
</select>
<button class="btn small" type="submit">Set</button>
</form>
</div>
<div class="admin-card" style="margin-top:12px; padding:12px;">
<div class="label" style="margin-bottom:8px;">Thread</div>
<?php if (!$messages): ?>
<div style="color:var(--muted); font-size:13px;">No messages yet.</div>
<?php else: ?>
<div style="display:grid; gap:8px;">
<?php foreach ($messages as $msg): ?>
<?php $isAdmin = (string)($msg['sender_type'] ?? '') === 'admin'; ?>
<div class="admin-card" style="padding:10px; border-color:<?= $isAdmin ? 'rgba(34,242,165,.35)' : 'rgba(255,255,255,.1)' ?>;">
<div style="display:flex; justify-content:space-between; gap:12px; font-size:12px; color:var(--muted);">
<span><?= $isAdmin ? 'Admin' : 'Customer' ?> · <?= htmlspecialchars((string)($msg['sender_email'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
<span><?= htmlspecialchars((string)($msg['created_at'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
</div>
<div style="margin-top:8px; white-space:pre-wrap; line-height:1.6;"><?= htmlspecialchars((string)($msg['body_text'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<form method="post" action="/admin/support/ticket/reply" style="margin-top:12px; display:grid; gap:10px;">
<input type="hidden" name="ticket_id" value="<?= (int)($ticket['id'] ?? 0) ?>">
<div class="label">Reply</div>
<textarea class="input" name="body" rows="6" style="resize:vertical;" placeholder="Type reply..."></textarea>
<div style="display:flex; justify-content:flex-end;">
<button class="btn" type="submit">Send Reply</button>
</div>
</form>
</section>
<?php
$content = ob_get_clean();
require __DIR__ . '/../../../../modules/admin/views/layout.php';

View File

@@ -0,0 +1,197 @@
<?php
$pageTitle = $title ?? 'Contact';
$error = (string)($error ?? '');
$ok = (string)($ok ?? '');
$supportTypes = is_array($support_types ?? null) ? $support_types : [];
$supportTypes = $supportTypes ?: [['key' => 'general', 'label' => 'General', 'fields' => []]];
$supportTypesJson = json_encode($supportTypes, JSON_UNESCAPED_SLASHES) ?: '[]';
ob_start();
?>
<section class="card" style="display:grid; gap:14px;">
<div class="badge">Support</div>
<h1 style="margin:0; font-size:34px;">Contact</h1>
<p style="margin:0; color:var(--muted);">Send us a message and we will open a support ticket.</p>
<?php if ($error !== ''): ?>
<div class="support-alert support-alert-error"><?= htmlspecialchars($error, ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
<?php if ($ok !== ''): ?>
<div class="support-alert support-alert-ok"><?= htmlspecialchars($ok, ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
<form method="post" action="/contact" class="support-form">
<div class="support-grid-2">
<div class="support-field">
<label class="label support-label">Name</label>
<input class="support-input" name="name" required>
</div>
<div class="support-field">
<label class="label support-label">Email</label>
<input class="support-input" type="email" name="email" required>
</div>
</div>
<div class="support-field">
<label class="label support-label">Support Type</label>
<select class="support-input" id="supportType" name="support_type">
<?php foreach ($supportTypes as $i => $type): ?>
<option value="<?= htmlspecialchars((string)$type['key'], ENT_QUOTES, 'UTF-8') ?>" <?= $i === 0 ? 'selected' : '' ?>>
<?= htmlspecialchars((string)$type['label'], ENT_QUOTES, 'UTF-8') ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div id="supportExtraFields" class="support-extra-fields"></div>
<div class="support-field">
<label class="label support-label">Subject</label>
<input class="support-input" name="subject" required>
</div>
<div class="support-field">
<label class="label support-label">Message</label>
<textarea class="support-input support-textarea" name="message" rows="7" required></textarea>
</div>
<div class="support-actions">
<button class="support-btn" type="submit">Create Ticket</button>
</div>
</form>
</section>
<style>
.support-form {
display: grid;
gap: 18px;
margin-top: 10px;
padding: 18px;
border-radius: 16px;
border: 1px solid rgba(255,255,255,0.08);
background: rgba(8,10,16,0.38);
}
.support-field {
display: grid;
gap: 8px;
}
.support-label {
display: inline-block;
margin: 0;
font-size: 11px;
letter-spacing: .18em;
text-transform: uppercase;
color: rgba(236, 242, 255, 0.78);
}
.support-grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.support-input {
width: 100%;
height: 42px;
border-radius: 11px;
border: 1px solid rgba(255,255,255,0.14);
background: rgba(7,10,16,0.72);
color: #ecf1ff;
padding: 0 12px;
font-size: 14px;
outline: none;
transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
}
.support-input:focus {
border-color: rgba(34,242,165,.55);
box-shadow: 0 0 0 2px rgba(34,242,165,.14);
background: rgba(9,13,20,0.9);
}
.support-textarea {
min-height: 180px;
height: auto;
resize: vertical;
padding: 11px 12px;
line-height: 1.6;
}
.support-actions {
display: flex;
justify-content: flex-end;
}
.support-extra-fields {
display: grid;
gap: 14px;
}
.support-btn {
height: 42px;
border-radius: 999px;
border: 1px solid rgba(34,242,165,.85);
background: linear-gradient(180deg, #2df5ae, #1ddf98);
color: #08150f;
padding: 0 20px;
font-size: 12px;
text-transform: uppercase;
letter-spacing: .18em;
font-weight: 700;
cursor: pointer;
}
.support-btn:hover { filter: brightness(1.04); }
.support-alert {
padding: 12px 14px;
border-radius: 12px;
font-size: 13px;
}
.support-alert-error {
border: 1px solid rgba(255,120,120,.4);
color: #f3b0b0;
background: rgba(80,20,20,.2);
}
.support-alert-ok {
border: 1px solid rgba(34,242,165,.4);
color: #9be7c6;
background: rgba(16,64,52,.3);
}
@media (max-width: 760px) {
.support-grid-2 {
grid-template-columns: 1fr;
}
}
</style>
<script>
(function () {
const supportTypes = <?= $supportTypesJson ?>;
const typeSelect = document.getElementById('supportType');
const extraWrap = document.getElementById('supportExtraFields');
if (!typeSelect || !extraWrap) return;
const map = {};
supportTypes.forEach((type) => {
map[type.key] = type;
});
const esc = (v) => String(v || '').replace(/[&<>"']/g, (m) => ({
'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
}[m]));
const sync = () => {
const selectedType = map[typeSelect.value] || { fields: [], field_labels: [] };
const labels = {};
(selectedType.field_labels || []).forEach((row) => {
if (!row || !row.key) return;
labels[row.key] = row.label || row.key;
});
const html = (selectedType.fields || []).map((fieldKey) => {
const label = labels[fieldKey] || fieldKey;
return `
<div class="support-field">
<label class="label support-label">${esc(label)}</label>
<input class="support-input" name="support_extra[${esc(fieldKey)}]" placeholder="${esc(label)}" required>
</div>
`;
}).join('');
extraWrap.innerHTML = html;
};
typeSelect.addEventListener('change', sync);
sync();
})();
</script>
<?php
$content = ob_get_clean();
require __DIR__ . '/../../../../views/site/layout.php';