all working

This commit is contained in:
HotSwapp
2025-08-10 21:34:11 -05:00
parent 14ee479edc
commit 1512b2d12a
22 changed files with 1453 additions and 489 deletions

View File

@@ -435,25 +435,51 @@
<script>
// Document Management JavaScript
document.addEventListener('DOMContentLoaded', function() {
// Initialize page
loadTemplates();
loadQdros();
loadCategories();
// Check authentication first
const token = localStorage.getItem('auth_token');
if (!token) {
window.location.href = '/login';
return;
}
// Set up keyboard shortcuts
setupKeyboardShortcuts();
// Set up event handlers
setupEventHandlers();
// Auto-refresh every 30 seconds
setInterval(function() {
if (document.querySelector('#templates-tab').classList.contains('active')) {
loadTemplates();
} else if (document.querySelector('#qdros-tab').classList.contains('active')) {
loadQdros();
// Wait for API helpers to be ready, then initialize
function initializeDocuments() {
if (typeof apiGet === 'function') {
// Ensure API headers are set up with token
if (window.apiHeaders && token) {
window.apiHeaders['Authorization'] = `Bearer ${token}`;
}
// Initialize the first tab as active
document.getElementById('templates-tab').click();
// Load initial data
loadCategories();
// Set up keyboard shortcuts
setupKeyboardShortcuts();
// Set up event handlers
setupEventHandlers();
// Auto-refresh every 30 seconds
setInterval(function() {
const templatesTab = document.querySelector('#templates-tab');
const qdrosTab = document.querySelector('#qdros-tab');
if (templatesTab.classList.contains('text-blue-500')) {
loadTemplates();
} else if (qdrosTab.classList.contains('text-blue-500')) {
loadQdros();
}
}, 30000);
} else {
// API helpers not ready yet, try again in 100ms
setTimeout(initializeDocuments, 100);
}
}, 30000);
}
initializeDocuments();
});
function setupKeyboardShortcuts() {
@@ -568,8 +594,18 @@ function setupEventHandlers() {
document.getElementById('refreshQdrosBtn').addEventListener('click', loadQdros);
}
// Helper function for authenticated API calls
function getAuthHeaders() {
const token = localStorage.getItem('auth_token');
return {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
}
async function loadTemplates() {
try {
console.log('🔍 DEBUG: loadTemplates() called');
const search = document.getElementById('templateSearch').value;
const category = document.getElementById('categoryFilter').value;
@@ -577,14 +613,34 @@ async function loadTemplates() {
if (search) url += `search=${encodeURIComponent(search)}&`;
if (category) url += `category=${encodeURIComponent(category)}&`;
const response = await fetch(url);
if (!response.ok) throw new Error('Failed to load templates');
// Ensure we have auth token for this API call
const token = localStorage.getItem('auth_token');
console.log('🔍 DEBUG: Token exists:', !!token, 'Length:', token?.length);
if (!token) {
console.log('🔍 DEBUG: No token found, redirecting to login');
window.location.href = '/login';
return;
}
console.log('🔍 DEBUG: Making API call to:', url);
const response = await fetch(url, {
headers: getAuthHeaders()
});
console.log('🔍 DEBUG: Response status:', response.status);
if (!response.ok) {
const errorData = await response.json().catch(() => ({ detail: 'Unknown error' }));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
const templates = await response.json();
console.log('🔍 DEBUG: Templates loaded:', templates.length, 'items');
displayTemplates(templates);
} catch (error) {
console.error('Error loading templates:', error);
showAlert('Error loading templates: ' + error.message, 'danger');
console.error('🔍 DEBUG: Error in loadTemplates:', error);
try { logClientError({ message: 'Error loading templates', action: 'loadTemplates', error }); } catch (_) {}
showAlert('Error loading templates: ' + (error && error.message ? error.message : 'Unknown error'), 'danger');
}
}
@@ -634,14 +690,27 @@ async function loadQdros() {
if (search) url += `search=${encodeURIComponent(search)}&`;
if (status) url += `status_filter=${encodeURIComponent(status)}&`;
const response = await fetch(url);
if (!response.ok) throw new Error('Failed to load QDROs');
const token = localStorage.getItem('auth_token');
if (!token) {
window.location.href = '/login';
return;
}
const response = await fetch(url, {
headers: getAuthHeaders()
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ detail: 'Unknown error' }));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
const qdros = await response.json();
displayQdros(qdros);
} catch (error) {
console.error('Error loading QDROs:', error);
showAlert('Error loading QDROs: ' + error.message, 'danger');
try { logClientError({ message: 'Error loading QDROs', action: 'loadQdros', error }); } catch (_) {}
showAlert('Error loading QDROs: ' + (error && error.message ? error.message : 'Unknown error'), 'danger');
}
}
@@ -693,10 +762,23 @@ function getStatusBadgeClass(status) {
async function loadCategories() {
try {
const response = await fetch('/api/documents/categories/');
if (!response.ok) throw new Error('Failed to load categories');
const token = localStorage.getItem('auth_token');
if (!token) {
window.location.href = '/login';
return;
}
const response = await fetch('/api/documents/categories/', {
headers: getAuthHeaders()
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ detail: 'Unknown error' }));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
const categories = await response.json();
const select = document.getElementById('categoryFilter');
const templateSelect = document.getElementById('templateCategory');
@@ -711,6 +793,7 @@ async function loadCategories() {
});
} catch (error) {
console.error('Error loading categories:', error);
try { logClientError({ message: 'Error loading categories', action: 'loadCategories', error }); } catch (_) {}
}
}
@@ -736,7 +819,9 @@ function openTemplateModal(templateId = null) {
async function loadTemplateForEditing(templateId) {
try {
const response = await fetch(`/api/documents/templates/${templateId}`);
const response = await fetch(`/api/documents/templates/${templateId}`, {
headers: getAuthHeaders()
});
if (!response.ok) throw new Error('Failed to load template');
const template = await response.json();
@@ -750,7 +835,8 @@ async function loadTemplateForEditing(templateId) {
updateVariableCount();
} catch (error) {
console.error('Error loading template:', error);
showAlert('Error loading template: ' + error.message, 'danger');
try { logClientError({ message: 'Error loading template for edit', action: 'loadTemplateForEditing', error, extra: { templateId } }); } catch (_) {}
showAlert('Error loading template: ' + (error && error.message ? error.message : 'Unknown error'), 'danger');
}
}
@@ -788,7 +874,8 @@ async function saveTemplate() {
loadTemplates();
} catch (error) {
console.error('Error saving template:', error);
showAlert('Error saving template: ' + error.message, 'danger');
try { logClientError({ message: 'Error saving template', action: 'saveTemplate', error }); } catch (_) {}
showAlert('Error saving template: ' + (error && error.message ? error.message : 'Unknown error'), 'danger');
}
}
@@ -814,7 +901,9 @@ function extractVariables(content) {
async function loadDocumentStats() {
try {
const response = await fetch('/api/documents/stats/summary');
const response = await fetch('/api/documents/stats/summary', {
headers: getAuthHeaders()
});
if (!response.ok) throw new Error('Failed to load statistics');
const stats = await response.json();
@@ -855,7 +944,8 @@ async function loadDocumentStats() {
openModal('statsModal');
} catch (error) {
console.error('Error loading statistics:', error);
showAlert('Error loading statistics: ' + error.message, 'danger');
try { logClientError({ message: 'Error loading statistics', action: 'loadDocumentStats', error }); } catch (_) {}
showAlert('Error loading statistics: ' + (error && error.message ? error.message : 'Unknown error'), 'danger');
}
}
@@ -882,6 +972,27 @@ function showAlert(message, type = 'info') {
}
}
// Lightweight client error logger specific to Documents page
async function logClientError({ message, action = null, error = null, extra = null }) {
try {
const payload = {
message: String(message || (error && error.message) || 'Unknown error'),
action,
stack: error && error.stack ? String(error.stack) : null,
url: window.location.href,
user_agent: navigator.userAgent,
extra
};
await fetch('/api/documents/client-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
} catch (_) {
// swallow
}
}
// Placeholder functions for additional features
async function editTemplate(templateId) {
openTemplateModal(templateId);
@@ -900,7 +1011,8 @@ async function deleteTemplate(templateId) {
if (confirm('Are you sure you want to delete this template?')) {
try {
const response = await fetch(`/api/documents/templates/${templateId}`, {
method: 'DELETE'
method: 'DELETE',
headers: getAuthHeaders()
});
if (!response.ok) throw new Error('Failed to delete template');
@@ -909,7 +1021,8 @@ async function deleteTemplate(templateId) {
loadTemplates();
} catch (error) {
console.error('Error deleting template:', error);
showAlert('Error deleting template: ' + error.message, 'danger');
try { logClientError({ message: 'Error deleting template', action: 'deleteTemplate', error, extra: { templateId } }); } catch (_) {}
showAlert('Error deleting template: ' + (error && error.message ? error.message : 'Unknown error'), 'danger');
}
}
}
@@ -921,7 +1034,9 @@ function openGenerateModal() {
async function loadTemplatesForGeneration() {
try {
const response = await fetch('/api/documents/templates/');
const response = await fetch('/api/documents/templates/', {
headers: getAuthHeaders()
});
if (!response.ok) throw new Error('Failed to load templates');
const templates = await response.json();
@@ -936,18 +1051,22 @@ async function loadTemplatesForGeneration() {
});
} catch (error) {
console.error('Error loading templates:', error);
try { logClientError({ message: 'Error loading templates for generation', action: 'loadTemplatesForGeneration', error }); } catch (_) {}
}
}
async function loadTemplatePreview(templateId) {
try {
const response = await fetch(`/api/documents/templates/${templateId}`);
const response = await fetch(`/api/documents/templates/${templateId}`, {
headers: getAuthHeaders()
});
if (!response.ok) throw new Error('Failed to load template');
const template = await response.json();
document.getElementById('templatePreview').value = template.content;
} catch (error) {
console.error('Error loading template preview:', error);
try { logClientError({ message: 'Error loading template preview', action: 'loadTemplatePreview', error, extra: { templateId } }); } catch (_) {}
}
}
@@ -983,9 +1102,7 @@ async function generateDocument() {
const response = await fetch(`/api/documents/generate/${templateId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
headers: getAuthHeaders(),
body: JSON.stringify(requestData)
});
@@ -1005,7 +1122,8 @@ async function generateDocument() {
}
} catch (error) {
console.error('Error generating document:', error);
showAlert('Error generating document: ' + error.message, 'danger');
try { logClientError({ message: 'Error generating document', action: 'generateDocument', error, extra: { templateId: (document.getElementById('generateTemplate')?.value || null) } }); } catch (_) {}
showAlert('Error generating document: ' + (error && error.message ? error.message : 'Unknown error'), 'danger');
}
}
@@ -1062,5 +1180,36 @@ async function deleteQdro(qdroId) {
showAlert('QDRO delete functionality will be implemented', 'info');
}
}
// Tab navigation functionality
function openTab(evt, tabName) {
// Declare all variables
var i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].classList.add('hidden');
}
// Get all elements with class="tablinks" and remove the "active" class
tablinks = document.querySelectorAll('nav button');
for (i = 0; i < tablinks.length; i++) {
tablinks[i].classList.remove('border-blue-500', 'text-blue-500', 'dark:text-blue-400');
tablinks[i].classList.add('border-transparent');
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(tabName).classList.remove('hidden');
evt.currentTarget.classList.add('border-blue-500', 'text-blue-500', 'dark:text-blue-400');
evt.currentTarget.classList.remove('border-transparent');
// Load data for the active tab
if (tabName === 'templates') {
loadTemplates();
} else if (tabName === 'qdros') {
loadQdros();
}
}
</script>
{% endblock %}