(function () { const API = 'https://epictravelexpeditions.com/api'; const style = document.createElement('style'); style.textContent = ` #et-admin-section { padding: 32px 0; } #et-admin-section h3 { font-size: 1.4rem; font-weight: 700; color: #111827; margin-bottom: 16px; } .et-admin-card { background: #fff; border: 1px solid #e5e7eb; border-radius: 10px; padding: 20px; margin-bottom: 16px; display: flex; gap: 16px; align-items: flex-start; } .et-admin-avatar { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; flex-shrink: 0; background: #e5e7eb; } .et-admin-avatar-ph { width: 48px; height: 48px; border-radius: 50%; background: #2563eb; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 18px; flex-shrink: 0; } .et-admin-body { flex: 1; min-width: 0; } .et-admin-name { font-weight: 700; font-size: 14px; } .et-admin-loc { font-size: 12px; color: #6b7280; margin-bottom: 6px; } .et-admin-msg { font-size: 13px; color: #374151; margin-bottom: 10px; } .et-admin-status { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 11px; font-weight: 600; text-transform: uppercase; margin-bottom: 10px; } .et-status-pending { background: #fef3c7; color: #92400e; } .et-status-approved { background: #d1fae5; color: #065f46; } .et-status-denied { background: #fee2e2; color: #991b1b; } .et-admin-actions { display: flex; gap: 8px; flex-wrap: wrap; } .et-btn { padding: 6px 14px; border-radius: 6px; font-size: 12px; font-weight: 600; border: none; cursor: pointer; transition: opacity .15s; } .et-btn:hover { opacity: .8; } .et-btn-approve { background: #16a34a; color: #fff; } .et-btn-deny { background: #dc2626; color: #fff; } .et-btn-delete { background: #6b7280; color: #fff; } .et-btn-save { background: #2563eb; color: #fff; } .et-edit-area { width: 100%; box-sizing: border-box; border: 1px solid #d1d5db; border-radius: 6px; padding: 8px 10px; font-size: 13px; resize: vertical; min-height: 60px; margin-bottom: 6px; } .et-tabs { display: flex; gap: 4px; margin-bottom: 20px; } .et-tab { padding: 6px 16px; border-radius: 6px; font-size: 13px; font-weight: 600; cursor: pointer; border: 1px solid #d1d5db; background: #fff; color: #374151; } .et-tab.active { background: #2563eb; color: #fff; border-color: #2563eb; } .et-empty { color: #9ca3af; font-size: 14px; text-align: center; padding: 32px 0; } `; document.head.appendChild(style); function statusBadge(s) { return `${s}`; } function avatarHtml(t) { if (t.image_path) return ``; return `
${t.full_name.charAt(0).toUpperCase()}
`; } async function applyAction(id, payload) { const token = localStorage.getItem('auth_token'); const res = await fetch(`${API}/testimonials/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, body: JSON.stringify(payload) }); return res.json(); } async function deleteTestimonial(id) { const token = localStorage.getItem('auth_token'); await fetch(`${API}/testimonials/${id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${token}` } }); } function renderCards(list, container, reload) { container.innerHTML = ''; if (!list.length) { container.innerHTML = '

No testimonials in this category.

'; return; } list.forEach(t => { const card = document.createElement('div'); card.className = 'et-admin-card'; card.dataset.id = t.id; card.innerHTML = ` ${avatarHtml(t)}
${t.full_name}
${t.location}
${statusBadge(t.status)}
${t.message}
${t.status !== 'approved' ? '' : ''} ${t.status !== 'denied' ? '' : ''}
`; card.querySelectorAll('[data-action]').forEach(btn => { btn.addEventListener('click', async () => { const action = btn.dataset.action; const textarea = card.querySelector('.et-edit-area'); try { if (action === 'approve') await applyAction(t.id, { status: 'approved' }); else if (action === 'deny') await applyAction(t.id, { status: 'denied' }); else if (action === 'save') await applyAction(t.id, { message: textarea.value }); else if (action === 'delete') { if (!confirm('Delete this testimonial?')) return; await deleteTestimonial(t.id); } reload(); } catch (e) { alert('Error: ' + e.message); } }); }); container.appendChild(card); }); } async function buildAdminPanel(mountEl) { const token = localStorage.getItem('auth_token'); const res = await fetch(`${API}/testimonials/all`, { headers: { Authorization: `Bearer ${token}` } }); const all = await res.json(); const section = document.createElement('div'); section.id = 'et-admin-section'; section.innerHTML = `

Testimonials

`; let currentFilter = 'pending'; const cardsEl = section.querySelector('#et-admin-cards'); async function reload() { const res = await fetch(`${API}/testimonials/all`, { headers: { Authorization: `Bearer ${token}` } }); const fresh = await res.json(); const filtered = currentFilter === 'all' ? fresh : fresh.filter(t => t.status === currentFilter); renderCards(filtered, cardsEl, reload); // Update counts section.querySelectorAll('.et-tab').forEach(tab => { const f = tab.dataset.filter; const count = f === 'all' ? fresh.length : fresh.filter(t => t.status === f).length; tab.textContent = `${f.charAt(0).toUpperCase()+f.slice(1)} (${count})`; if (f === currentFilter) tab.classList.add('active'); else tab.classList.remove('active'); }); } section.querySelectorAll('.et-tab').forEach(tab => { tab.addEventListener('click', () => { currentFilter = tab.dataset.filter; reload(); }); }); const initialFiltered = all.filter(t => t.status === 'pending'); renderCards(initialFiltered, cardsEl, reload); mountEl.appendChild(section); } // Watch for admin dashboard let adminDone = false; const observer = new MutationObserver(() => { if (adminDone) return; if (!window.location.pathname.startsWith('/admin/dashboard')) return; if (!localStorage.getItem('isAdminAuthenticated')) return; // Find the main content area of the admin panel const main = document.querySelector('[class*="max-w-7xl"]'); if (!main) return; if (document.getElementById('et-admin-section')) return; adminDone = true; observer.disconnect(); buildAdminPanel(main); }); observer.observe(document.body, { childList: true, subtree: true }); })();