Admin Dashboard (complete): - Created /admin/login.html with JWT authentication - Created /admin/dashboard.html with full management UI - Moderation queue with approve/reject workflows - User management interface - Document management interface - Real-time statistics dashboard - Activity feed monitoring - All CSP-compliant (external JS files) API Reference Documentation (complete): - Created /api-reference.html with complete API docs - Authentication endpoints (login, verify) - Document endpoints (list, get, search) - Governance status endpoint - Admin endpoints (stats, moderation, users) - Error codes reference table - Request/response examples for all endpoints - Query parameters documentation Files Created (5): - public/admin/login.html (auth interface) - public/admin/dashboard.html (admin UI) - public/js/admin/login.js (auth logic) - public/js/admin/dashboard.js (dashboard logic) - public/api-reference.html (complete API docs) All pages tested and accessible (200 OK) Zero CSP violations - all resources from same origin 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
59 lines
1.7 KiB
JavaScript
59 lines
1.7 KiB
JavaScript
const loginForm = document.getElementById('login-form');
|
|
const errorMessage = document.getElementById('error-message');
|
|
const errorText = document.getElementById('error-text');
|
|
const loginBtn = document.getElementById('login-btn');
|
|
|
|
loginForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const email = document.getElementById('email').value;
|
|
const password = document.getElementById('password').value;
|
|
|
|
// Hide previous errors
|
|
errorMessage.classList.add('hidden');
|
|
|
|
// Disable button
|
|
loginBtn.disabled = true;
|
|
loginBtn.innerHTML = '<span>Signing in...</span>';
|
|
|
|
try {
|
|
const response = await fetch('/api/auth/login', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ email, password }),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok && data.success) {
|
|
// Store token
|
|
localStorage.setItem('admin_token', data.token);
|
|
localStorage.setItem('admin_user', JSON.stringify(data.user));
|
|
|
|
// Redirect to dashboard
|
|
window.location.href = '/admin/dashboard.html';
|
|
} else {
|
|
// Show error
|
|
showError(data.message || 'Invalid credentials');
|
|
loginBtn.disabled = false;
|
|
loginBtn.innerHTML = 'Sign in';
|
|
}
|
|
} catch (error) {
|
|
console.error('Login error:', error);
|
|
showError('Network error. Please try again.');
|
|
loginBtn.disabled = false;
|
|
loginBtn.innerHTML = 'Sign in';
|
|
}
|
|
});
|
|
|
|
function showError(message) {
|
|
errorText.textContent = message;
|
|
errorMessage.classList.remove('hidden');
|
|
}
|
|
|
|
// Auto-fill for development (optional)
|
|
if (window.location.hostname === 'localhost') {
|
|
document.getElementById('email').value = 'admin@tractatus.local';
|
|
}
|