templates/website/page/indexes/support.html.twig line 1
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Vrshikyans — Support</title><meta name="description"content="Support for Vrshikyans TOEFL, SAT, IELTS, ACT. Tutors, tests, subscriptions. Ask and track your requests." /><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800;900&display=swap" rel="stylesheet"><link rel="icon" href="{{ asset('students/Vrshikyan_logo.ico') }}" /><meta name="color-scheme" content="dark light"><style>:root {--bg: #0e1220;--bg-2: #0c152b;--surface: rgba(255, 255, 255, .07);--surface-strong: rgba(12, 18, 40, .72);--card: rgba(20, 26, 52, .85);--border: rgba(140, 170, 255, .18);--text: #f5f8ff;--muted: #c7d1f2;--accent: #78a6ff;--accent-2: #66e6d2;--green: #35d49f;--violet: #a06bff;--shadow-1: 0 10px 24px rgba(0, 0, 0, .28);--shadow-2: 0 22px 60px rgba(0, 0, 0, .40);--radius: 18px;--blur: 14px;--speed: .25s;--fast: .15s;--g1: #1c2550;--g2: #142762;--nav-h: 64px;}html[data-theme="light"] {--bg: #f7f8fd;--bg-2: #eef2ff;--surface: rgba(255, 255, 255, .65);--surface-strong: rgba(255, 255, 255, .92);--card: rgba(255, 255, 255, .95);--border: rgba(23, 32, 58, .12);--text: #0f1428;--muted: #3e4a74;--shadow-1: 0 8px 20px rgba(23, 32, 58, .10);--shadow-2: 0 24px 60px rgba(23, 32, 58, .16);--g1: #dfe7ff;--g2: #cfe0ff;}* {box-sizing: border-box}html,body {height: 100%;margin: 0}body {font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans";color: var(--text);line-height: 1.65;overflow-x: hidden;background:radial-gradient(160vw 120vh at -20vw -20vh, var(--g1) 0%, rgba(0, 0, 0, 0) 60%),radial-gradient(160vw 120vh at 120vw -10vh, var(--g2) 0%, rgba(0, 0, 0, 0) 55%),linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);background-attachment: fixed, fixed, fixed;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;}body::before {content: "";position: fixed;inset: 0;z-index: 0;pointer-events: none;opacity: .05;background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0nNjQnIGhlaWdodD0nNjQnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zyc+PGZpbHRlciBpZD0nbi1uJz48ZmVUdXJidWxlbmNlIHR5cGU9J2ZyYWN0YWxOb2lzZScgYmFzZUZyZXF1ZW5jeT0nMC44JyBudW1PY3RhdmVzPScyJy8+PC9maWx0ZXI+PHJlY3Qgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScgZmlsbD0nd2hpdGUnIGZpbHRlcj0ndXJsKCMnKyc+PC9yZWN0Pjwvc3ZnPg==");background-size: 240px 240px;z-index: 0;}/* Nav */.nav {position: sticky;top: 0;z-index: 10;height: var(--nav-h);background: var(--surface-strong);border-bottom: 1px solid var(--border);backdrop-filter: blur(var(--blur)) saturate(140%);}.nav-inner {width: min(1120px, 92%);margin: 0 auto;height: 100%;display: flex;align-items: center;gap: 14px;}.brand {display: flex;gap: 12px;align-items: center;text-decoration: none;color: var(--text);font-weight: 900;letter-spacing: .2px;}.logo {width: 38px;height: 38px;border-radius: 12px;background: linear-gradient(180deg, #6ea3ff, #4b82ff);box-shadow: 0 10px 22px rgba(76, 130, 255, .22);overflow: hidden;}.logo img {width: 100%;height: 100%;object-fit: cover;display: block}.spacer {flex: 1}.theme-btn,.cta {display: inline-flex;align-items: center;justify-content: center;height: 40px;border-radius: 12px;}.theme-btn {width: 40px;border: 1px solid var(--border);background: rgba(255, 255, 255, .08);color: var(--text);cursor: pointer;}.cta {padding: 0 22px;background: linear-gradient(180deg, #35d49f, #18b98a);color: #061a11;font-weight: 900;text-decoration: none;border: 0;box-shadow: 0 10px 24px rgba(24, 185, 138, .22);}.inner {width: min(1120px, 92%);margin: 28px auto;position: relative;z-index: 1;}.h1 {margin: 10px 0 4px;font-size: clamp(34px, 4.8vw, 58px);font-weight: 900;text-shadow: 0 2px 16px rgba(0, 0, 0, .28);}.lead {margin: 0;color: var(--muted);}/* layout */.support-band {margin-top: 18px;border: 1px solid var(--border);border-radius: var(--radius);background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, .04));padding: 16px;display: flex;align-items: center;justify-content: space-between;gap: 14px;flex-wrap: wrap;}.support-layout {margin-top: 18px;display: grid;grid-template-columns: minmax(0, 320px) minmax(0, 1fr);gap: 16px;}@media (max-width:900px) {.support-layout {grid-template-columns: 1fr;}}.card {padding: 16px;border-radius: var(--radius);border: 1px solid var(--border);background: var(--card);box-shadow: var(--shadow-1);width: 100%;}.card h3 {margin: 0 0 6px;}.btn {height: 40px;padding: 0 16px;border-radius: 12px;border: 0;font-weight: 900;cursor: pointer;display: inline-flex;align-items: center;justify-content: center;gap: 6px;}.btn.primary {background: linear-gradient(180deg, #78a6ff, #4b82ff);color: #08152c;box-shadow: 0 10px 26px rgba(120, 166, 255, .26);}.btn.ghost {background: rgba(255, 255, 255, .06);border: 1px solid var(--border);color: var(--text);}.btn.subtle {background: transparent;border: 0;color: var(--muted);font-size: 13px;padding: 0 6px;height: auto;}label {font-weight: 800;display: block;margin: 10px 0 4px;font-size: 14px;}input[type="text"],select,textarea {width: 100%;border: 1px solid var(--border);background: rgba(255, 255, 255, .06);padding: 9px 11px;color: var(--text);border-radius: 12px;outline: none;font: inherit;}textarea {resize: vertical;min-height: 130px;}/* bigger */option {color: navy;}.row {display: grid;grid-template-columns: 1fr 1fr;gap: 10px;}@media (max-width:640px) {.row {grid-template-columns: 1fr;}}/* History panel */.history-header {display: flex;align-items: center;justify-content: space-between;gap: 8px;margin-bottom: 8px;}.history-list {display: flex;flex-direction: column;gap: 8px;max-height: 420px;overflow: auto;padding-right: 4px;}.ticket-row {border-radius: 14px;border: 1px solid var(--border);background: rgba(255, 255, 255, .04);padding: 10px 10px;text-align: left;width: 100%;cursor: pointer;display: flex;flex-direction: column;gap: 4px;position: relative;}.ticket-row:hover {background: rgba(255, 255, 255, .07);}.ticket-row.active {border-color: var(--accent);box-shadow: 0 0 0 1px rgba(120, 166, 255, .35);}.ticket-title {font-weight: 800;font-size: 14px;}.ticket-meta {font-size: 13px;color: var(--muted);}.ticket-badges {display: flex;flex-wrap: wrap;gap: 6px;margin-top: 2px;font-size: 12px;}.ticket-badge {padding: 3px 8px;border-radius: 999px;border: 1px solid var(--border);background: rgba(255, 255, 255, .06);color: var(--muted);font-weight: 700;}.ticket-status {position: absolute;right: 10px;top: 10px;padding: 3px 8px;border-radius: 999px;font-size: 11px;font-weight: 800;letter-spacing: .03em;text-transform: uppercase;border: 1px solid rgba(210, 255, 230, .28);color: #0f2016;background: rgba(53, 212, 159, .86);}.ticket-status.closed {background: rgba(160, 107, 255, .82);border-color: rgba(230, 210, 255, .4);color: #100621;}/* Chat card */.chat-card {display: flex;flex-direction: column;gap: 10px;min-height: 360px;}.chat-header {display: flex;align-items: center;justify-content: space-between;gap: 8px;flex-wrap: wrap;}.chat-header-main {display: flex;flex-direction: column;gap: 2px;}.chat-title {font-weight: 900;font-size: 18px;}.chat-sub {font-size: 13px;color: var(--muted);}.chat-chips {display: flex;flex-wrap: wrap;gap: 6px;font-size: 12px;}.chip {padding: 4px 9px;border-radius: 999px;border: 1px solid var(--border);background: rgba(255, 255, 255, .08);font-weight: 800;color: var(--muted);}.back-btn {display: none;}body.creating .back-btn {display: inline-flex;}.chat-body {flex: 1;min-height: 260px;border-radius: 16px;border: 1px solid var(--border);background: linear-gradient(160deg, rgba(255, 255, 255, .06), rgba(15, 19, 32, .6));padding: 12px;overflow: auto;max-height: 420px;width: 100%;}.chat-empty {height: 100%;display: flex;align-items: center;justify-content: center;text-align: center;color: var(--muted);font-size: 14px;padding: 12px;}/* Messages */.msg {max-width: min(80%, 480px);display: flex;flex-direction: column;gap: 3px;margin-bottom: 10px;}.msg-user {margin-left: auto;align-items: flex-end;}.msg-admin {margin-right: auto;align-items: flex-start;}.msg-meta {font-size: 11px;color: var(--muted);opacity: .9;}.msg-bubble {padding: 9px 11px;border-radius: 16px;background: rgba(255, 255, 255, .10);border: 1px solid rgba(255, 255, 255, .18);font-size: 14px;position: relative;}.msg-user .msg-bubble {background: linear-gradient(180deg, #78a6ff, #4b82ff);color: #050c1a;border-color: rgba(24, 185, 138, .0);}.msg-admin .msg-bubble {background: rgba(8, 14, 36, .9);border-color: rgba(140, 170, 255, .35);}.msg-photos {display: flex;flex-wrap: wrap;gap: 6px;margin-top: 6px;}.msg-photos img {width: 90px;height: 90px;border-radius: 10px;object-fit: cover;border: 1px solid rgba(255, 255, 255, .25);}/* Category step */.category-step {border-radius: 16px;border: 1px dashed var(--border);padding: 10px 10px 4px 10px;background: rgba(255, 255, 255, .03);font-size: 14px;width: 100%;}.category-grid {display: grid;grid-template-columns: 1.1fr 1fr;gap: 10px;}@media (max-width:640px) {.category-grid {grid-template-columns: 1fr;}}.subscription-extra {margin-top: 6px;display: none;}.topic-row {margin-top: 2px;}/* Uploader for composer */.composer {margin-top: 8px;border-radius: 16px;border: 1px solid var(--border);background: rgba(0, 0, 0, .18);padding: 10px;display: flex;flex-direction: column;gap: 8px;width: 100%;}.composer-top {display: flex;gap: 10px;align-items: flex-start;flex-wrap: wrap;}.composer-top textarea {flex: 1;}.composer-actions {display: flex;align-items: center;justify-content: space-between;gap: 10px;flex-wrap: wrap;}.uploader {border: 1px dashed var(--border);border-radius: 12px;padding: 8px;text-align: center;background: rgba(255, 255, 255, .04);font-size: 13px;flex: 1;}.uploader input {display: none;}.uploader .hint {color: var(--muted);font-size: 12px;margin-top: 2px;}.thumbs {display: flex;flex-wrap: wrap;gap: 6px;margin-top: 6px;}.thumb {position: relative;width: 80px;height: 80px;border-radius: 10px;overflow: hidden;border: 1px solid var(--border);background: rgba(255, 255, 255, .08);display: grid;place-items: center;}.thumb img {width: 100%;height: 100%;object-fit: cover;}.thumb button {position: absolute;top: 4px;right: 4px;border-radius: 999px;border: 1px solid var(--border);background: rgba(0, 0, 0, .5);color: #fff;font-size: 11px;padding: 1px 6px;cursor: pointer;}.category-step,.composer {display: none;}body.can-write .category-step,body.can-write .composer {display: block;}/* Mobile safety */img,video {max-width: 100%;height: auto;}.chat-body,.card,.support-layout {max-width: 100%;overflow-x: hidden;}/* Footer */footer {margin: 34px 0 18px;position: relative;z-index: 1;}.foot {width: min(1120px, 92%);margin: 0 auto;border: 1px solid var(--border);border-radius: var(--radius);background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, .04));padding: 16px;display: grid;grid-template-columns: 1fr 1fr;gap: 14px;}@media (max-width:640px) {.foot {grid-template-columns: 1fr;}}body.creating .history-panel {display: none;}body.creating .support-layout {grid-template-columns: 1fr;}</style><link rel="stylesheet" href="{{ asset('css/navbar.css') }}" /><script>(() => {const saved = localStorage.getItem('theme');if (saved) {document.documentElement.setAttribute('data-theme', saved);} else {document.documentElement.setAttribute('data-theme',matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');}})();</script></head><body><nav class="nav" role="navigation" aria-label="Primary"><div class="nav-inner"><a class="brand" href="/" aria-label="Exam-hub"><span class="logo" aria-hidden="true" style="overflow: hidden;"><img src="../students/Vrshikyan_logo.ico" width="39px" alt="Vrshikyans logo"></span><span>Vrshikyans</span> </a><div class="nav-links"><a class="nav-link" data-section="toefl" href="./test-selection?type=toefl" id="toeflNav">TOEFL</a><a class="nav-link" data-section="sat" href="./test-sat-selection#sat" >SAT</a><a class="nav-link" data-section="act" href="./test-sat-selection#act">ACT</a><a class="nav-link" data-section="reading" href="./test-selection?type=readingPractice" id="readingPrNav">Reading Practice</a><a class="nav-link active" data-section="support" href="./support">Support</a><a class="nav-link" data-section="reviews" href="./reviews">Reviews</a></div><button class="mobile-menu-btn" id="mobileMenuBtn">☰</button><div class="spacer"></div><button id="themeToggle" class="theme-btn" aria-label="Toggle theme">🌑</button><a class="cta" id="startTop" href="../indexes/account" aria-label="Account"style="width: 40px; height: 40px; background: whitesmoke;">👤</a></div></nav><div class="mobile-menu" id="mobileMenu"><div class="mobile-nav-links"><a class="mobile-nav-link" href="./test-selection?type=toefl">TOEFL</a><a class="mobile-nav-link" href="./test-sat-selection#sat">SAT</a><a class="mobile-nav-link" href="./test-sat-selection#act">ACT</a><a class="mobile-nav-link" href="./test-selection?type=readingPractice">Reading Practice</a><a class="mobile-nav-link" href="./support">Support</a><a class="mobile-nav-link" href="./reviews">Reviews</a></div></div><header class="inner"><h1 class="h1">Support</h1><p class="lead">Tutors, tests, subscriptions — ask anything and keep all your requests in one place.</p><div class="support-band"><div><strong>Need help fast?</strong><p class="lead" style="margin:.2rem 0 0 0; font-size:14px;">Open a new request and we’ll reply in the same chat, just like a messenger.</p></div><button class="btn primary" id="newRequestBandBtn">✨ New request</button></div><div class="support-layout" id="supportMain"><aside class="card history-panel" aria-label="Support history"><div class="history-header"><div><h3>Your requests</h3><p class="lead" style="margin:.1rem 0 0 0; font-size:13px;">Tap any request to reopen the chat.</p></div><button class="btn ghost" id="newRequestBtn">+ New</button></div><div class="history-list" id="historyList"></div></aside><section class="card chat-card" aria-label="Support conversation"><div class="chat-header"><div class="chat-header-main"><div class="chat-title" id="chatTitle">Support inbox</div><div class="chat-sub" id="chatSubtitle">Choose a request on the left or start a new one.</div></div><div style="display:flex; gap:6px; align-items:center; flex-wrap:wrap;"><div class="chat-chips" id="chatChips"></div><button class="btn ghost back-btn" id="backToList">← Back to requests</button></div></div><div class="category-step" id="categoryStep"><div style="display:flex; justify-content:space-between; align-items:center; gap:8px;"><spanstyle="font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:var(--muted); font-weight:800;">Request details</span><span id="categoryHint" style="font-size:12px; color:var(--muted);">Pick a category to unlock the message box.</span></div><div class="category-grid" style="margin-top:4px;"><div><label for="categorySelect">I need help with</label><select id="categorySelect"><option value="">Choose a category</option><option value="Tutors">Tutors</option><option value="Info">Information about tests</option><option value="Subscriptions">Subscriptions</option></select></div><div id="categorySecondaryWrapper" style="display:none;"><label id="secondaryLabel" for="secondarySelect">Exam</label><select id="secondarySelect"></select></div></div><div class="subscription-extra" id="subscriptionExtra"><p class="lead" style="font-size:13px; margin:.4rem 0 0 0;">Billing questions, upgrades, cancellations — you can also check your plan here:</p><a href="/#pricing" id="subscriptionLink" class="btn primary"style="margin-top:6px; font-size:13px;">↗ Open subscription page</a></div><div class="row topic-row"><div><label for="topicInput">Topic (optional)</label><input id="topicInput" type="text"placeholder="e.g., SAT tutor, TOEFL test date, Subscription plan"><div class="lead" style="font-size:12px; margin:.2rem 0 0 0;">This short title will appear in your history.</div></div></div></div><div class="chat-body" id="chatBody"><div class="chat-empty" id="chatEmpty"><div><p style="margin:0 0 4px 0;"><strong>No request selected</strong></p><p style="margin:0; font-size:13px;">Start a new request or choose one from the left.</p></div></div></div><form class="composer" id="composerForm" autocomplete="off"><div class="composer-top"><textarea id="messageInput"placeholder="Type your message… (at least a few characters)"></textarea><div class="uploader" id="uploader"><p style="margin:0 0 2px 0;"><strong>Attach images</strong> or<label style="text-decoration:underline; cursor:pointer;"><input type="file" id="photosInput" accept="image/*" multiple>browse</label></p><div class="hint">Screenshots of tasks, scores, billing pages, etc. (~1MB each is ideal).</div><div class="thumbs" id="thumbs"></div></div></div><div class="composer-actions"><div style="display:flex; flex-direction:column; gap:2px;"><span style="font-size:11px; color:var(--muted);" id="composerStatus">Choose a category above to send your first message.</span></div><button type="submit" class="btn primary" id="sendBtn">Send</button></div></form></section></div></header><footer><div class="foot"><div><b>Contact</b><p class="lead" style="margin:.4rem 0 0 0">examHubYerevan@gmail.com</p><p class="lead" style="margin:.2rem 0 0 0">+374 96 361 236</p></div><div><b>Vrshikyans</b><p class="lead" style="margin:.4rem 0 0 0">Yerevan • Since 2025</p><small>© <span id="year"></span> Vrshikyans — All rights reserved.</small></div></div></footer><script src="{{ asset('js/navbar.js') }}"></script><script>document.getElementById('year').textContent = new Date().getFullYear();const supportApi = {KEY: 'vrshikyans_support_v1',async _request(url, method = 'GET', params = {}) {const reqParams = {method: method,}if (Object.keys(params).length) {reqParams.body = JSON.stringify(params)}if (params instanceof FormData) {reqParams.body = params}const response = await fetch(url, reqParams);return await response.json();},async _loadAll() {return await this._request("/support/list");},async _saveAll(list) {localStorage.setItem(this.KEY, JSON.stringify(list));},async list() {const all = await this._loadAll();all.sort((a, b) => (b.lastUpdated || b.createdAt) - (a.lastUpdated || a.createdAt));return all;},async get(id) {return await this._request(`/support/list/${id}`);},async create(ticket) {return await this._request(`/support/create`, 'POST', ticket);},async createMsg(msg) {const fileInput = document.querySelector('#photosInput')const files = fileInput.files; // get selected filesconst formData = new FormData();for (const key in msg) {const value = msg[key];formData.append(key, value);}// Append all filesfor (let i = 0; i < files.length; i++) {formData.append('photos[]', files[i]);}return await this._request(`/support/${uiState.activeTicketId}/create-msg`, 'POST', formData);},async update(ticket) {const all = await this._loadAll();const idx = all.findIndex(t => t.id === ticket.id);if (idx !== -1) {all[idx] = ticket;await this._saveAll(all);return { ok: true };}return { ok: false };}};const uiState = {creating: false,activeTicketId: null,files: []};const historyList = document.getElementById('historyList');const newRequestBtn = document.getElementById('newRequestBtn');const newRequestBandBtn = document.getElementById('newRequestBandBtn');const backToList = document.getElementById('backToList');const chatTitle = document.getElementById('chatTitle');const chatSubtitle = document.getElementById('chatSubtitle');const chatChips = document.getElementById('chatChips');const chatBody = document.getElementById('chatBody');const chatEmpty = document.getElementById('chatEmpty');const categorySelect = document.getElementById('categorySelect');const categorySecondaryWrapper = document.getElementById('categorySecondaryWrapper');const secondarySelect = document.getElementById('secondarySelect');const secondaryLabel = document.getElementById('secondaryLabel');const subscriptionExtra = document.getElementById('subscriptionExtra');const topicInput = document.getElementById('topicInput');const composerStatus = document.getElementById('composerStatus');const composerForm = document.getElementById('composerForm');const messageInput = document.getElementById('messageInput');const sendBtn = document.getElementById('sendBtn');const uploader = document.getElementById('uploader');const photosInput = document.getElementById('photosInput');const thumbs = document.getElementById('thumbs');function escapeHtml(s) {return String(s).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", "'");}function formatDate(ts) {const d = new Date(ts);return d.toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'});}function formatTime(ts) {const d = new Date(ts);return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });}function shortCategory(main, sub) {if (!main && !sub) return '';if (main === 'Tutors') return 'Tutors' + (sub ? ' • ' + sub : '');if (main === 'Info') return 'Information • ' + (sub || 'Tests');if (main === 'Subscriptions') return 'Subscriptions';return [main, sub].filter(Boolean).join(' • ');}function isCategoryValidForNew() {const main = categorySelect.value;if (!main) return false;if (main === 'Tutors' || main === 'Info') {return !!secondarySelect.value;}return true;}function updateComposerStatus() {const hasTicket = !!uiState.activeTicketId;const main = categorySelect.value;const sec = secondarySelect.value;if (hasTicket) {composerStatus.textContent = 'You can continue writing in this chat.';messageInput.disabled = false;sendBtn.disabled = false;messageInput.placeholder = 'Type your message…';return;}if (!main) {composerStatus.textContent = 'Choose a category above to send your first message.';messageInput.disabled = true;sendBtn.disabled = true;messageInput.placeholder = 'Select a category to start typing…';messageInput.style.border = "1px solid red"} else if ((main === 'Tutors' || main === 'Info') && !sec) {composerStatus.textContent = 'Pick the exam to unlock the message box.';messageInput.disabled = true;sendBtn.disabled = true;messageInput.style.border = "1px solid red"messageInput.placeholder = 'Choose the exam first…';} else {composerStatus.textContent = 'Ready. Your first message will create a new support request.';messageInput.disabled = false;sendBtn.disabled = false;messageInput.style.border = ''messageInput.placeholder = 'Type your message… (at least a few characters)';}}function populateSecondary(main) {secondarySelect.innerHTML = '';const optEmpty = document.createElement('option');optEmpty.value = '';optEmpty.textContent = 'Choose an exam';secondarySelect.appendChild(optEmpty);const examsTutors = ['SAT', 'TOEFL', 'ACT', 'IELTS'];const examsInfo = ['SAT', 'TOEFL', 'ACT', 'IELTS', 'Overall information about all tests'];let list = [];if (main === 'Tutors') list = examsTutors;if (main === 'Info') list = examsInfo;list.forEach((name, idx) => {const o = document.createElement('option');o.value = (idx + 1);o.textContent = name;secondarySelect.appendChild(o);});}categorySelect.addEventListener('change', () => {const main = categorySelect.value;secondarySelect.value = '';subscriptionExtra.style.display = 'none';categorySecondaryWrapper.style.display = 'none';if (main === 'Tutors') {secondaryLabel.textContent = 'Which exam?';populateSecondary(main);categorySecondaryWrapper.style.display = '';} else if (main === 'Info') {secondaryLabel.textContent = 'About which test?';populateSecondary(main);categorySecondaryWrapper.style.display = '';} else if (main === 'Subscriptions') {subscriptionExtra.style.display = "block";}updateComposerStatus();});secondarySelect.addEventListener('change', updateComposerStatus);function addFiles(list) {const arr = [...list];arr.forEach(file => {if (!file.type.startsWith('image/')) return;const reader = new FileReader();reader.onload = () => {uiState.files.push({ file, dataUrl: reader.result });renderThumbs();};reader.readAsDataURL(file);});}photosInput.addEventListener('change', e => addFiles(e.target.files));uploader.addEventListener('dragover', e => {e.preventDefault();uploader.style.borderColor = 'var(--accent)';});uploader.addEventListener('dragleave', () => {uploader.style.borderColor = 'var(--border)';});uploader.addEventListener('drop', e => {e.preventDefault();uploader.style.borderColor = 'var(--border)';addFiles(e.dataTransfer.files);});function renderThumbs() {thumbs.innerHTML = '';uiState.files.forEach((f, idx) => {const el = document.createElement('div');el.className = 'thumb';el.innerHTML = `<img alt="preview ${idx + 1}"><button type="button">✕</button>`;el.querySelector('img').src = f.dataUrl;el.querySelector('button').addEventListener('click', () => {uiState.files.splice(idx, 1);renderThumbs();});thumbs.appendChild(el);});}function clearComposer() {messageInput.value = '';uiState.files = [];renderThumbs();}let cachedTickets = [];async function loadHistory() {cachedTickets = await supportApi.list();renderHistory();}function renderHistory() {historyList.innerHTML = '';if (!cachedTickets.length) {const p = document.createElement('p');p.className = 'lead';p.style.fontSize = '13px';p.style.margin = '0';p.textContent = 'No requests yet. Start with “New”.';historyList.appendChild(p);return;}cachedTickets.forEach(t => {const btn = document.createElement('button');btn.className = 'ticket-row' + (t.id === uiState.activeTicketId ? ' active' : '');btn.dataset.id = t.id;const subject = t.subject || shortCategory(t.categoryMain, t.categorySub) || 'Support request';const created = formatDate(t.createdAt);const statusClass = t.status === 'closed' ? 'ticket-status closed' : 'ticket-status';btn.innerHTML = `<div class="ticket-title">${escapeHtml(subject)}</div><div class="ticket-meta">${escapeHtml(created)}</div><div class="ticket-badges">${t.categoryMain ? `<span class="ticket-badge">${escapeHtml(t.categoryMain === 'Info' ? 'Information about tests' : t.categoryMain)}</span>` : ''}${t.categorySub ? `<span class="ticket-badge">${escapeHtml(t.categorySub)}</span>` : ''}</div><span class="${statusClass}">${t.status === 'closed' ? 'Closed' : 'Open'}</span>`;btn.addEventListener('click', () => openExistingTicket(t.id));historyList.appendChild(btn);});}function renderChat(ticket) {chatBody.innerHTML = '';chatEmpty.style.display = 'none';if (!ticket || !ticket.messages || !ticket.messages.length) {const empty = document.createElement('div');empty.className = 'chat-empty';empty.innerHTML = `<div><p style="margin:0 0 4px 0;"><strong>No messages yet</strong></p><p style="margin:0; font-size:13px;">Write your first message below to start the conversation.</p></div>`;chatBody.appendChild(empty);return;}ticket.messages.forEach(m => {const el = document.createElement('div');const isUser = m.from === 'user';el.className = 'msg ' + (isUser ? 'msg-user' : 'msg-admin');const fromLabel = isUser ? 'You' : 'Vrshikyans support';el.innerHTML = `<div class="msg-meta">${escapeHtml(fromLabel)} · ${escapeHtml(formatTime(m.createdAt))}</div><div class="msg-bubble">${m.text ? `<div>${escapeHtml(m.text)}</div>` : ''}${m.photos && m.photos.length ? `<div class="msg-photos">${m.photos.map((p, idx) => `<img src="${p.url}" alt="attachment ${idx + 1}">`).join('')}</div>`: ''}</div>`;chatBody.appendChild(el);});chatBody.scrollTop = chatBody.scrollHeight;}function updateChatHeader(ticket) {chatChips.innerHTML = '';if (!ticket) {chatTitle.textContent = 'New support request';chatSubtitle.textContent = 'Pick a category and send your first message.';return;}const subject = ticket.subject || shortCategory(ticket.categoryMain, ticket.categorySub) || 'Support request';chatTitle.textContent = subject;const created = formatDate(ticket.createdAt);chatSubtitle.textContent = `Created ${created} • ${ticket.status === 'closed' ? 'Closed' : 'Open'}`;if (ticket.categoryMain) {const chipMain = document.createElement('span');chipMain.className = 'chip';chipMain.textContent = ticket.categoryMain === 'Info' ? 'Information about tests' : ticket.categoryMain;chatChips.appendChild(chipMain);}if (ticket.categorySub) {const chipSub = document.createElement('span');chipSub.className = 'chip';chipSub.textContent = ticket.categorySub;chatChips.appendChild(chipSub);}}function syncCategoryUI(ticket) {if (!ticket) {categorySelect.disabled = false;secondarySelect.disabled = false;topicInput.disabled = false;categorySelect.value = '';secondarySelect.innerHTML = '';categorySecondaryWrapper.style.display = 'none';subscriptionExtra.style.display = 'none';topicInput.value = '';} else {categorySelect.disabled = true;secondarySelect.disabled = true;topicInput.disabled = true;categorySelect.value = ticket.categoryMain || '';if (ticket.categoryMain === 'Tutors') {populateSecondary('Tutors');categorySecondaryWrapper.style.display = '';} else if (ticket.categoryMain === 'Info') {populateSecondary('Info');categorySecondaryWrapper.style.display = '';} else {categorySecondaryWrapper.style.display = 'none';}if (ticket.categoryMain === 'Subscriptions') {subscriptionExtra.style.display = '';} else {subscriptionExtra.style.display = 'none';}if (ticket.categorySub) {secondarySelect.value = ticket.categorySub;}topicInput.value = ticket.subject || '';}updateComposerStatus();}function startNewRequest() {uiState.creating = true;uiState.activeTicketId = null;document.body.classList.add('creating', 'can-write');chatTitle.textContent = 'New support request';chatSubtitle.textContent = 'Pick a category and send your first message.';chatChips.innerHTML = '';chatBody.innerHTML = '';chatEmpty.style.display = 'block';chatEmpty.innerHTML = `<div><p style="margin:0 0 4px 0;"><strong>Describe your issue</strong></p><p style="margin:0; font-size:13px;">Once you send the first message, this will turn into a chat thread.</p></div>`;syncCategoryUI(null);clearComposer();renderHistory();}async function openExistingTicket(id) {uiState.creating = false;uiState.activeTicketId = id;document.body.classList.remove('creating');document.body.classList.add('can-write');const ticket = await supportApi.get(id);if (!ticket) return;updateChatHeader(ticket);syncCategoryUI(ticket);renderChat(ticket);renderHistory();}composerForm.addEventListener('submit', async (e) => {e.preventDefault();const text = messageInput.value.trim();const hasText = text.length >= 3;const hasPhotos = uiState.files.length > 0;if (!uiState.activeTicketId) {if (!isCategoryValidForNew()) {updateComposerStatus();messageInput.focus();return;}if (!hasText && !hasPhotos) {messageInput.focus();return;}} else {if (!hasText && !hasPhotos) return;}const photos = uiState.files.map(f => ({ url: f.dataUrl }));clearComposer();let ticket;if (!uiState.activeTicketId) {const id = 't_' + Math.random().toString(36).slice(2);const now = Date.now();const main = categorySelect.value || '';const sub = (main === 'Tutors' || main === 'Info') ? (secondarySelect.value || '') : '';const subject = topicInput.value.trim() || shortCategory(main, sub) || 'Support request';ticket = {subject,categoryMain: main,categorySub: sub,status: 'open',createdAt: now,lastUpdated: now,messages: []};const res = await supportApi.create(ticket);uiState.activeTicketId = res.id;uiState.creating = false;document.body.classList.remove('creating');document.body.classList.add('can-write');}ticket = await supportApi.get(uiState.activeTicketId);if (!ticket) return;const msg = {id: 'm_' + Math.random().toString(36).slice(2),from: 'user',text: text,photos: photos,createdAt: Date.now()};ticket.messages.push(msg);ticket.lastUpdated = msg.createdAt;await supportApi.createMsg(msg);updateChatHeader(ticket);syncCategoryUI(ticket);renderChat(ticket);await loadHistory();});newRequestBtn.addEventListener('click', startNewRequest);newRequestBandBtn.addEventListener('click', startNewRequest);backToList.addEventListener('click', () => {uiState.creating = false;document.body.classList.remove('creating', 'can-write');uiState.activeTicketId = null;chatTitle.textContent = 'Support inbox';chatSubtitle.textContent = 'Choose a request on the left or start a new one.';chatChips.innerHTML = '';chatBody.innerHTML = '';chatEmpty.style.display = 'block';chatEmpty.innerHTML = `<div><p style="margin:0 0 4px 0;"><strong>No request selected</strong></p><p style="margin:0; font-size:13px;">Pick a request from your history or create a new one.</p></div>`;syncCategoryUI(null);clearComposer();renderHistory();});(async () => {const existing = await supportApi.list();if (!existing.length) {const seed = [{id: 't_seed1',subject: 'SAT tutor',categoryMain: 'Tutors',categorySub: 'SAT',status: 'closed',createdAt: new Date('2024-12-22T10:00:00').getTime(),lastUpdated: new Date('2024-12-22T11:05:00').getTime(),messages: [{id: 'm1',from: 'user',text: 'Hi! I need a SAT tutor for March 2025. Can you recommend someone from Vrshikyans?',photos: [],createdAt: new Date('2024-12-22T10:00:00').getTime()},{id: 'm2',from: 'admin',text: 'Of course! We can connect you with a tutor who focuses on the math section and one for Reading/English. We’ll email you the options today.',photos: [],createdAt: new Date('2024-12-22T10:20:00').getTime()},{id: 'm3',from: 'user',text: 'Perfect, thank you so much!',photos: [],createdAt: new Date('2024-12-22T11:05:00').getTime()}]},{id: 't_seed2',subject: 'TOEFL practice tests',categoryMain: 'Info',categorySub: 'TOEFL',status: 'open',createdAt: new Date('2023-11-14T15:00:00').getTime(),lastUpdated: new Date('2023-11-14T15:35:00').getTime(),messages: [{id: 'm1',from: 'user',text: 'Hi, are your TOEFL tests updated to the new format?',photos: [],createdAt: new Date('2023-11-14T15:00:00').getTime()},{id: 'm2',from: 'admin',text: 'Yes! Our TOEFL Practice 2026 set follows the short reading + new speaking timing. Let us know which sections you care about most.',photos: [],createdAt: new Date('2023-11-14T15:20:00').getTime()},{id: 'm3',from: 'user',text: 'I need more listening practice sets. How many do you have?',photos: [],createdAt: new Date('2023-11-14T15:35:00').getTime()}]}];localStorage.setItem(supportApi.KEY, JSON.stringify(seed));}await loadHistory();updateComposerStatus();})();</script></body></html>