import { apiGet, apiPost, apiPut, apiDelete } from '../api.js';
import { canEdit, showToast, getRole } from '../app.js';
import { navigate } from '../router.js';
export async function dashboardPage() {
const app = document.getElementById('app');
app.innerHTML = `
`;
if (canEdit()) {
document.getElementById('headerActions').innerHTML = `
+ New Questionnaire
`;
bindImportBundle();
}
try {
const data = await apiGet('questionnaires.php');
renderGrid(data.questionnaires || []);
} catch (e) {
showToast(e.message, 'error');
document.getElementById('qGrid').innerHTML = `${e.message}
`;
}
}
function renderGrid(questionnaires) {
const grid = document.getElementById('qGrid');
if (!questionnaires.length) {
grid.innerHTML = `
No questionnaires yet
Create your first questionnaire to get started.
`;
return;
}
grid.innerHTML = questionnaires.map(q => {
const stateClass = `badge-${(q.state || 'draft').toLowerCase().replace(/\s+/g, '_')}`;
const showPts = parseInt(q.showPoints || 0, 10);
return `
v${esc(q.version || '—')}
${q.questionCount || 0} question${q.questionCount == 1 ? '' : 's'}
#${q.orderIndex ?? '—'}
${showPts ? 'pts' : ''}
`;
}).join('');
grid.querySelectorAll('.q-card').forEach(card => {
card.addEventListener('click', (e) => {
if (e.target.closest('.q-card-actions') || e.target.closest('.drag-handle')) return;
navigate(`#/questionnaire/${card.dataset.id}`);
});
});
grid.querySelectorAll('.delete-q-btn').forEach(btn => {
btn.addEventListener('click', async (e) => {
e.stopPropagation();
if (!confirm('Delete this questionnaire and all its data?')) return;
try {
await apiDelete('questionnaires.php', { questionnaireID: btn.dataset.id });
showToast('Questionnaire deleted', 'success');
btn.closest('.q-card').remove();
} catch (err) {
showToast(err.message, 'error');
}
});
});
if (canEdit()) initGridDrag(questionnaires);
}
function initGridDrag(questionnaires) {
const grid = document.getElementById('qGrid');
if (!grid) return;
let dragItem = null;
grid.addEventListener('dragstart', (e) => {
const card = e.target.closest('.q-card');
if (!card || !e.target.closest('.drag-handle')) { e.preventDefault(); return; }
dragItem = card;
card.style.opacity = '0.5';
e.dataTransfer.effectAllowed = 'move';
});
grid.addEventListener('dragover', (e) => {
e.preventDefault();
if (!dragItem) return;
const cards = [...grid.querySelectorAll('.q-card:not([style*="opacity"])')];
const afterCard = cards.reduce((closest, child) => {
const box = child.getBoundingClientRect();
const offset = e.clientY - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) return { offset, element: child };
return closest;
}, { offset: Number.NEGATIVE_INFINITY }).element;
if (afterCard) grid.insertBefore(dragItem, afterCard);
else grid.appendChild(dragItem);
});
grid.addEventListener('dragend', async () => {
if (!dragItem) return;
dragItem.style.opacity = '';
const newOrder = [...grid.querySelectorAll('.q-card')].map(el => el.dataset.id);
dragItem = null;
for (let i = 0; i < newOrder.length; i++) {
const id = newOrder[i];
const q = questionnaires.find(q => q.questionnaireID === id);
if (q && parseInt(q.orderIndex, 10) !== i) {
try {
await apiPut('questionnaires.php', { questionnaireID: id, orderIndex: i });
q.orderIndex = i;
} catch (e) {
showToast(e.message, 'error');
return;
}
}
}
showToast('Order saved', 'success');
});
}
function bindImportBundle() {
const fileInput = document.getElementById('importBundleFile');
const btn = document.getElementById('importBundleBtn');
if (!fileInput || !btn) return;
btn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', async () => {
const file = fileInput.files?.[0];
fileInput.value = '';
if (!file) return;
let bundle;
try {
const text = await file.text();
bundle = JSON.parse(text);
} catch {
showToast('Invalid JSON file', 'error');
return;
}
if (!bundle?.questionnaires || !Array.isArray(bundle.questionnaires)) {
showToast('Not a questionnaire bundle (missing questionnaires array)', 'error');
return;
}
const count = bundle.questionnaires.length;
if (!confirm(`Import ${count} questionnaire(s) from this file?`)) return;
const replace = confirm(
'If a questionnaire ID from the file already exists:\n\n' +
'OK — replace that questionnaire\n' +
'Cancel — import as a new copy (new ID)'
);
btn.disabled = true;
const prev = btn.textContent;
btn.textContent = 'Importing…';
try {
const result = await apiPost('questionnaires.php', {
action: 'importBundle',
bundle,
replaceIfExists: replace,
});
const n = result.imported ?? count;
showToast(`Imported ${n} questionnaire(s)`, 'success');
await dashboardPage();
} catch (e) {
showToast(e.message, 'error');
} finally {
btn.disabled = false;
btn.textContent = prev;
}
});
}
function esc(s) {
const d = document.createElement('div');
d.textContent = s ?? '';
return d.innerHTML;
}