updated reports
This commit is contained in:
@@ -32,14 +32,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
updateThemeToggleButtonText(); // Update the button text after toggling
|
||||
});
|
||||
|
||||
// Helper function to format dates
|
||||
function formatDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
if (!isNaN(date)) {
|
||||
return date.toISOString().split('T')[0]; // Format as yyyy-mm-dd
|
||||
}
|
||||
return dateString; // Fallback if not a valid date
|
||||
}
|
||||
// Date formatting is now handled consistently on the backend
|
||||
|
||||
// Function to populate the table with data
|
||||
function populateTable(data) {
|
||||
@@ -50,7 +43,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
tableHead.innerHTML = '';
|
||||
tableBody.innerHTML = '';
|
||||
|
||||
if (data.headers && data.rows) {
|
||||
if (data.headers && data.rows && data.rows.length > 0) {
|
||||
// Populate table headers
|
||||
data.headers.forEach((header) => {
|
||||
const th = document.createElement('th');
|
||||
@@ -64,23 +57,32 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
row.forEach((cell, index) => {
|
||||
const td = document.createElement('td');
|
||||
|
||||
// Format the "Date" column
|
||||
if (data.headers[index].toLowerCase() === 'date' && cell) {
|
||||
td.textContent = formatDate(cell);
|
||||
} else {
|
||||
td.textContent = cell;
|
||||
}
|
||||
// Use the cell data as-is since backend now handles formatting
|
||||
td.textContent = cell;
|
||||
|
||||
tr.appendChild(td);
|
||||
});
|
||||
tableBody.appendChild(tr);
|
||||
});
|
||||
} else {
|
||||
// No data available
|
||||
// Handle no data scenarios
|
||||
const tr = document.createElement('tr');
|
||||
const td = document.createElement('td');
|
||||
td.textContent = 'No data available.';
|
||||
td.colSpan = data.headers ? data.headers.length : 1;
|
||||
|
||||
// Use custom message if provided, otherwise use default
|
||||
if (data.message) {
|
||||
td.textContent = data.message;
|
||||
} else if (data.error) {
|
||||
td.textContent = `Error: ${data.error}`;
|
||||
} else {
|
||||
td.textContent = 'No data available.';
|
||||
}
|
||||
|
||||
td.colSpan = data.headers ? data.headers.length || 1 : 1;
|
||||
td.style.textAlign = 'center';
|
||||
td.style.padding = '20px';
|
||||
td.style.fontStyle = 'italic';
|
||||
td.style.color = '#666';
|
||||
tr.appendChild(td);
|
||||
tableBody.appendChild(tr);
|
||||
}
|
||||
@@ -115,9 +117,20 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
// Handle report button clicks
|
||||
reportButtons.forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
// Skip buttons that have their own handlers
|
||||
if (button.id === 'select-day-report' || button.id === 'date-range-report' || button.id === 'select-day-defects-report') {
|
||||
return;
|
||||
}
|
||||
|
||||
const reportNumber = button.dataset.report;
|
||||
const reportLabel = button.textContent.trim();
|
||||
|
||||
// Check if reportNumber exists
|
||||
if (!reportNumber) {
|
||||
console.warn('Report button clicked but no data-report attribute found:', button);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the title dynamically
|
||||
reportTitle.textContent = `Data for "${reportLabel}"`;
|
||||
|
||||
@@ -131,6 +144,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
})
|
||||
.then((data) => {
|
||||
console.log("Fetched data:", data); // Debugging
|
||||
|
||||
// Update title with additional info
|
||||
if (data.message) {
|
||||
reportTitle.textContent = data.message;
|
||||
} else if (data.rows && data.rows.length > 0) {
|
||||
reportTitle.textContent = `${reportLabel} (${data.rows.length} records)`;
|
||||
} else {
|
||||
reportTitle.textContent = `${reportLabel} - No data found`;
|
||||
}
|
||||
|
||||
populateTable(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -153,6 +176,79 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
exportTableToCSV(filename);
|
||||
});
|
||||
|
||||
// Test Database Button
|
||||
const testDatabaseBtn = document.getElementById('test-database');
|
||||
if (testDatabaseBtn) {
|
||||
testDatabaseBtn.addEventListener('click', () => {
|
||||
console.log('Testing database connection...');
|
||||
reportTitle.textContent = 'Testing Database Connection...';
|
||||
|
||||
fetch('/test_database')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('Database test results:', data);
|
||||
|
||||
if (data.success) {
|
||||
reportTitle.textContent = `Database Test Results - ${data.total_records} records found`;
|
||||
|
||||
// Create a detailed results table
|
||||
const thead = reportTable.querySelector('thead tr');
|
||||
const tbody = reportTable.querySelector('tbody');
|
||||
|
||||
// Clear existing content
|
||||
thead.innerHTML = '';
|
||||
tbody.innerHTML = '';
|
||||
|
||||
// Add headers
|
||||
const headers = ['Test Item', 'Result', 'Details'];
|
||||
headers.forEach(header => {
|
||||
const th = document.createElement('th');
|
||||
th.textContent = header;
|
||||
thead.appendChild(th);
|
||||
});
|
||||
|
||||
// Add test results
|
||||
const results = [
|
||||
['Database Connection', data.database_connection, 'Connection successful'],
|
||||
['Table Exists', data.table_exists ? 'YES' : 'NO', 'scan1_orders table check'],
|
||||
['Total Records', data.total_records, 'Number of rows in table'],
|
||||
['Table Structure', `${data.table_structure.length} columns`, data.table_structure.map(col => `${col.field} (${col.type})`).join(', ')],
|
||||
['Available Dates', data.available_dates.length, data.available_dates.join(', ') || 'No dates found'],
|
||||
['Sample Data', data.sample_data.length > 0 ? 'Available' : 'Empty', `${data.sample_data.length} sample rows`]
|
||||
];
|
||||
|
||||
results.forEach(result => {
|
||||
const row = document.createElement('tr');
|
||||
result.forEach(cell => {
|
||||
const td = document.createElement('td');
|
||||
td.textContent = cell;
|
||||
row.appendChild(td);
|
||||
});
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
|
||||
// Show alert with summary
|
||||
alert(`Database Test Complete!\n\nConnection: ${data.database_connection}\nTable exists: ${data.table_exists}\nTotal records: ${data.total_records}\nMessage: ${data.message}`);
|
||||
|
||||
} else {
|
||||
reportTitle.textContent = 'Database Test Failed';
|
||||
alert(`Database test failed: ${data.message}`);
|
||||
|
||||
// Show error in table
|
||||
const thead = reportTable.querySelector('thead tr');
|
||||
const tbody = reportTable.querySelector('tbody');
|
||||
thead.innerHTML = '<th>Error</th>';
|
||||
tbody.innerHTML = `<tr><td>${data.message}</td></tr>`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Database test error:', error);
|
||||
reportTitle.textContent = 'Database Test Error';
|
||||
alert(`Error testing database: ${error.message}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Placeholder for PDF export functionality
|
||||
exportPdfButton.addEventListener('click', () => {
|
||||
alert('Exporting current report as PDF...');
|
||||
@@ -307,6 +403,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
// Show calendar modal for quality defects report
|
||||
const selectDayDefectsReportBtn = document.getElementById('select-day-defects-report');
|
||||
if (selectDayDefectsReportBtn) {
|
||||
selectDayDefectsReportBtn.addEventListener('click', () => {
|
||||
console.log('DEBUG: Select Day Quality Defects Report button clicked!');
|
||||
calendarModal.style.display = 'block';
|
||||
generateCalendar(currentDate);
|
||||
|
||||
// Mark this as a defects report by setting a flag
|
||||
calendarModal.setAttribute('data-report-type', 'defects');
|
||||
});
|
||||
}
|
||||
|
||||
// Close modal events
|
||||
if (closeModal) {
|
||||
closeModal.addEventListener('click', closeCalendarModal);
|
||||
@@ -340,13 +449,32 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
// Confirm date selection
|
||||
if (confirmDate) {
|
||||
confirmDate.addEventListener('click', () => {
|
||||
console.log('DEBUG: Calendar Generate Report button clicked!');
|
||||
if (selectedDate) {
|
||||
// Format date as YYYY-MM-DD
|
||||
const formattedDate = selectedDate.toISOString().split('T')[0];
|
||||
// Format date as YYYY-MM-DD (timezone-safe)
|
||||
const year = selectedDate.getFullYear();
|
||||
const month = String(selectedDate.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(selectedDate.getDate()).padStart(2, '0');
|
||||
const formattedDate = `${year}-${month}-${day}`;
|
||||
console.log(`DEBUG: Selected date object:`, selectedDate);
|
||||
console.log(`DEBUG: Selected date formatted as: ${formattedDate}`);
|
||||
|
||||
// Check if this is a defects report or regular report
|
||||
const reportType = calendarModal.getAttribute('data-report-type');
|
||||
console.log(`DEBUG: Report type: ${reportType}`);
|
||||
|
||||
closeCalendarModal();
|
||||
|
||||
// Fetch report data for the selected date
|
||||
fetchCustomDateReport(formattedDate);
|
||||
// Fetch appropriate report data for the selected date
|
||||
if (reportType === 'defects') {
|
||||
console.log('DEBUG: About to call fetchCustomDefectsReport');
|
||||
fetchCustomDefectsReport(formattedDate);
|
||||
} else {
|
||||
console.log('DEBUG: About to call fetchCustomDateReport');
|
||||
fetchCustomDateReport(formattedDate);
|
||||
}
|
||||
} else {
|
||||
console.log('DEBUG: No date selected when Generate Report clicked');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -356,6 +484,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
selectedDate = null;
|
||||
confirmDate.disabled = true;
|
||||
|
||||
// Clear report type
|
||||
calendarModal.removeAttribute('data-report-type');
|
||||
|
||||
// Remove selected class from all days
|
||||
const selectedDays = document.querySelectorAll('.calendar-day.selected');
|
||||
selectedDays.forEach(day => day.classList.remove('selected'));
|
||||
@@ -417,23 +548,387 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
function fetchCustomDateReport(dateString) {
|
||||
reportTitle.textContent = `Loading report for ${dateString}...`;
|
||||
console.log(`DEBUG: fetchCustomDateReport called with date: ${dateString}`);
|
||||
|
||||
fetch(`/generate_report?report=6&date=${dateString}`)
|
||||
.then(response => response.json())
|
||||
// Get elements directly to avoid scope issues
|
||||
const reportTitleElement = document.getElementById('report-title');
|
||||
const reportTableElement = document.getElementById('report-table');
|
||||
|
||||
console.log(`DEBUG: reportTitle element:`, reportTitleElement);
|
||||
console.log(`DEBUG: reportTable element:`, reportTableElement);
|
||||
|
||||
if (!reportTitleElement) {
|
||||
console.error('ERROR: report-title element not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
reportTitleElement.textContent = `Loading report for ${dateString}...`;
|
||||
|
||||
// Local function to populate table to avoid scope issues
|
||||
function localPopulateTable(data) {
|
||||
const tableHead = reportTableElement.querySelector('thead tr');
|
||||
const tableBody = reportTableElement.querySelector('tbody');
|
||||
|
||||
// Clear existing table content
|
||||
tableHead.innerHTML = '';
|
||||
tableBody.innerHTML = '';
|
||||
|
||||
if (data.headers && data.rows && data.rows.length > 0) {
|
||||
// Populate table headers
|
||||
data.headers.forEach((header) => {
|
||||
const th = document.createElement('th');
|
||||
th.textContent = header;
|
||||
tableHead.appendChild(th);
|
||||
});
|
||||
|
||||
// Populate table rows
|
||||
data.rows.forEach((row) => {
|
||||
const tr = document.createElement('tr');
|
||||
row.forEach((cell, index) => {
|
||||
const td = document.createElement('td');
|
||||
// Format dates properly
|
||||
if (data.headers[index].toLowerCase() === 'date' && cell) {
|
||||
td.textContent = cell; // Use as-is since backend already formats it
|
||||
} else {
|
||||
td.textContent = cell;
|
||||
}
|
||||
tr.appendChild(td);
|
||||
});
|
||||
tableBody.appendChild(tr);
|
||||
});
|
||||
} else {
|
||||
// Handle no data scenarios
|
||||
const tr = document.createElement('tr');
|
||||
const td = document.createElement('td');
|
||||
td.colSpan = 10; // Span all columns
|
||||
td.textContent = 'No data available.';
|
||||
td.style.textAlign = 'center';
|
||||
tr.appendChild(td);
|
||||
tableBody.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
const url = `/generate_report?report=6&date=${dateString}`;
|
||||
console.log(`DEBUG: Making request to URL: ${url}`);
|
||||
|
||||
fetch(url)
|
||||
.then(response => {
|
||||
console.log(`DEBUG: Response status: ${response.status}`);
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('DEBUG: Response data:', data);
|
||||
if (data.error) {
|
||||
reportTitle.textContent = `Error: ${data.error}`;
|
||||
populateTable({ headers: [], rows: [] });
|
||||
reportTitleElement.textContent = `Error: ${data.error}`;
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
} else if (data.message) {
|
||||
reportTitleElement.textContent = data.message;
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
} else if (data.rows && data.rows.length === 0) {
|
||||
reportTitleElement.textContent = `No data found for ${dateString}`;
|
||||
localPopulateTable(data);
|
||||
} else {
|
||||
reportTitle.textContent = `Daily Report for ${dateString}`;
|
||||
populateTable(data);
|
||||
reportTitleElement.textContent = `Daily Report for ${dateString} (${data.rows ? data.rows.length : 0} records)`;
|
||||
localPopulateTable(data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching custom date report:', error);
|
||||
reportTitle.textContent = 'Error loading report';
|
||||
populateTable({ headers: [], rows: [] });
|
||||
reportTitleElement.textContent = 'Error loading report';
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
});
|
||||
}
|
||||
|
||||
// Function to fetch quality defects report for specific date
|
||||
function fetchCustomDefectsReport(dateString) {
|
||||
console.log(`DEBUG: fetchCustomDefectsReport called with date: ${dateString}`);
|
||||
|
||||
// Get elements directly to avoid scope issues
|
||||
const reportTitleElement = document.getElementById('report-title');
|
||||
const reportTableElement = document.getElementById('report-table');
|
||||
|
||||
console.log(`DEBUG: reportTitle element:`, reportTitleElement);
|
||||
console.log(`DEBUG: reportTable element:`, reportTableElement);
|
||||
|
||||
if (!reportTitleElement) {
|
||||
console.error('ERROR: report-title element not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
reportTitleElement.textContent = `Loading quality defects report for ${dateString}...`;
|
||||
|
||||
// Local function to populate table to avoid scope issues
|
||||
function localPopulateTable(data) {
|
||||
const tableHead = reportTableElement.querySelector('thead tr');
|
||||
const tableBody = reportTableElement.querySelector('tbody');
|
||||
|
||||
// Clear existing table content
|
||||
tableHead.innerHTML = '';
|
||||
tableBody.innerHTML = '';
|
||||
|
||||
if (data.headers && data.rows && data.rows.length > 0) {
|
||||
// Populate table headers
|
||||
data.headers.forEach((header) => {
|
||||
const th = document.createElement('th');
|
||||
th.textContent = header;
|
||||
tableHead.appendChild(th);
|
||||
});
|
||||
|
||||
// Populate table rows
|
||||
data.rows.forEach((row) => {
|
||||
const tr = document.createElement('tr');
|
||||
row.forEach((cell, index) => {
|
||||
const td = document.createElement('td');
|
||||
// Highlight quality code column for defects
|
||||
if (data.headers[index] === 'Quality Code' && cell != '0') {
|
||||
td.style.backgroundColor = '#ffebee'; // Light red background
|
||||
td.style.fontWeight = 'bold';
|
||||
}
|
||||
td.textContent = cell;
|
||||
tr.appendChild(td);
|
||||
});
|
||||
tableBody.appendChild(tr);
|
||||
});
|
||||
} else {
|
||||
// Handle no data scenarios
|
||||
const tr = document.createElement('tr');
|
||||
const td = document.createElement('td');
|
||||
td.colSpan = 10; // Span all columns
|
||||
td.textContent = 'No quality defects found for this date.';
|
||||
td.style.textAlign = 'center';
|
||||
tr.appendChild(td);
|
||||
tableBody.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
const url = `/generate_report?report=8&date=${dateString}`;
|
||||
console.log(`DEBUG: Making request to URL: ${url}`);
|
||||
|
||||
fetch(url)
|
||||
.then(response => {
|
||||
console.log(`DEBUG: Response status: ${response.status}`);
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('DEBUG: Quality defects response data:', data);
|
||||
|
||||
if (data.error) {
|
||||
reportTitleElement.textContent = `Error: ${data.error}`;
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
} else if (data.message) {
|
||||
reportTitleElement.textContent = data.message;
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
} else if (data.rows && data.rows.length === 0) {
|
||||
reportTitleElement.textContent = `No quality defects found for ${dateString}`;
|
||||
localPopulateTable(data);
|
||||
} else {
|
||||
let titleText = `Quality Defects Report for ${dateString} (${data.rows ? data.rows.length : 0} defective items)`;
|
||||
|
||||
// Add defects summary info if available
|
||||
if (data.defects_summary) {
|
||||
const summary = data.defects_summary;
|
||||
titleText += ` | ${summary.unique_defect_types} defect types, ${summary.total_rejected_quantity} rejected items`;
|
||||
}
|
||||
|
||||
reportTitleElement.textContent = titleText;
|
||||
localPopulateTable(data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching quality defects report:', error);
|
||||
reportTitleElement.textContent = 'Error loading quality defects report';
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
});
|
||||
}
|
||||
|
||||
// ===== DATE RANGE MODAL FUNCTIONALITY =====
|
||||
|
||||
const dateRangeReportBtn = document.getElementById('date-range-report');
|
||||
const dateRangeModal = document.getElementById('date-range-modal');
|
||||
const closeDateRange = document.getElementById('close-date-range');
|
||||
const cancelDateRange = document.getElementById('cancel-date-range');
|
||||
const confirmDateRange = document.getElementById('confirm-date-range');
|
||||
const startDateInput = document.getElementById('start-date');
|
||||
const endDateInput = document.getElementById('end-date');
|
||||
|
||||
if (dateRangeReportBtn && dateRangeModal) {
|
||||
// Open date range modal
|
||||
dateRangeReportBtn.addEventListener('click', () => {
|
||||
console.log('DEBUG: Date Range Report button clicked!');
|
||||
|
||||
// Set default dates (last 7 days to today)
|
||||
const today = new Date();
|
||||
const weekAgo = new Date();
|
||||
weekAgo.setDate(today.getDate() - 6); // Last 7 days including today
|
||||
|
||||
const todayStr = formatDateForInput(today);
|
||||
const weekAgoStr = formatDateForInput(weekAgo);
|
||||
|
||||
startDateInput.value = weekAgoStr;
|
||||
endDateInput.value = todayStr;
|
||||
|
||||
console.log(`DEBUG: Default date range set to ${weekAgoStr} - ${todayStr}`);
|
||||
|
||||
dateRangeModal.style.display = 'block';
|
||||
validateDateRange(); // Enable/disable confirm button based on inputs
|
||||
});
|
||||
|
||||
// Close modal functions
|
||||
function closeDateRangeModal() {
|
||||
dateRangeModal.style.display = 'none';
|
||||
startDateInput.value = '';
|
||||
endDateInput.value = '';
|
||||
confirmDateRange.disabled = true;
|
||||
}
|
||||
|
||||
closeDateRange.addEventListener('click', closeDateRangeModal);
|
||||
cancelDateRange.addEventListener('click', closeDateRangeModal);
|
||||
|
||||
// Close modal when clicking outside
|
||||
window.addEventListener('click', (e) => {
|
||||
if (e.target === dateRangeModal) {
|
||||
closeDateRangeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate date range and enable/disable confirm button
|
||||
function validateDateRange() {
|
||||
const startDate = startDateInput.value;
|
||||
const endDate = endDateInput.value;
|
||||
|
||||
if (startDate && endDate) {
|
||||
const start = new Date(startDate);
|
||||
const end = new Date(endDate);
|
||||
|
||||
if (start <= end) {
|
||||
confirmDateRange.disabled = false;
|
||||
console.log(`DEBUG: Valid date range: ${startDate} to ${endDate}`);
|
||||
} else {
|
||||
confirmDateRange.disabled = true;
|
||||
console.log('DEBUG: Invalid date range: start date is after end date');
|
||||
}
|
||||
} else {
|
||||
confirmDateRange.disabled = true;
|
||||
console.log('DEBUG: Missing start or end date');
|
||||
}
|
||||
}
|
||||
|
||||
// Validate when dates change
|
||||
startDateInput.addEventListener('change', validateDateRange);
|
||||
endDateInput.addEventListener('change', validateDateRange);
|
||||
|
||||
// Confirm date range selection
|
||||
confirmDateRange.addEventListener('click', () => {
|
||||
const startDate = startDateInput.value;
|
||||
const endDate = endDateInput.value;
|
||||
|
||||
console.log(`DEBUG: Generating date range report from ${startDate} to ${endDate}`);
|
||||
closeDateRangeModal();
|
||||
|
||||
// Fetch report data for the selected date range
|
||||
fetchDateRangeReport(startDate, endDate);
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to format date for input field
|
||||
function formatDateForInput(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
// Function to fetch date range report
|
||||
function fetchDateRangeReport(startDate, endDate) {
|
||||
console.log(`DEBUG: Fetching date range report from ${startDate} to ${endDate}`);
|
||||
|
||||
// Get elements directly to avoid scope issues
|
||||
const reportTitleElement = document.getElementById('report-title');
|
||||
const reportTableElement = document.getElementById('report-table');
|
||||
|
||||
if (!reportTitleElement) {
|
||||
console.error('ERROR: report-title element not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
reportTitleElement.textContent = `Loading report for ${startDate} to ${endDate}...`;
|
||||
|
||||
// Local function to populate table to avoid scope issues
|
||||
function localPopulateTable(data) {
|
||||
const tableHead = reportTableElement.querySelector('thead tr');
|
||||
const tableBody = reportTableElement.querySelector('tbody');
|
||||
|
||||
// Clear existing table content
|
||||
tableHead.innerHTML = '';
|
||||
tableBody.innerHTML = '';
|
||||
|
||||
if (data.headers && data.rows && data.rows.length > 0) {
|
||||
// Populate table headers
|
||||
data.headers.forEach((header) => {
|
||||
const th = document.createElement('th');
|
||||
th.textContent = header;
|
||||
tableHead.appendChild(th);
|
||||
});
|
||||
|
||||
// Populate table rows
|
||||
data.rows.forEach((row) => {
|
||||
const tr = document.createElement('tr');
|
||||
row.forEach((cell, index) => {
|
||||
const td = document.createElement('td');
|
||||
td.textContent = cell;
|
||||
tr.appendChild(td);
|
||||
});
|
||||
tableBody.appendChild(tr);
|
||||
});
|
||||
} else {
|
||||
// Handle no data scenarios
|
||||
const tr = document.createElement('tr');
|
||||
const td = document.createElement('td');
|
||||
td.colSpan = 10; // Span all columns
|
||||
td.textContent = 'No data available for the selected date range.';
|
||||
td.style.textAlign = 'center';
|
||||
tr.appendChild(td);
|
||||
tableBody.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
const url = `/generate_report?report=7&start_date=${startDate}&end_date=${endDate}`;
|
||||
console.log(`DEBUG: Making date range request to URL: ${url}`);
|
||||
|
||||
fetch(url)
|
||||
.then(response => {
|
||||
console.log(`DEBUG: Response status: ${response.status}`);
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('DEBUG: Date range response data:', data);
|
||||
|
||||
if (data.error) {
|
||||
reportTitleElement.textContent = `Error: ${data.error}`;
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
} else if (data.message) {
|
||||
reportTitleElement.textContent = data.message;
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
} else if (data.rows && data.rows.length === 0) {
|
||||
reportTitleElement.textContent = `No data found for ${startDate} to ${endDate}`;
|
||||
localPopulateTable(data);
|
||||
} else {
|
||||
const recordCount = data.rows ? data.rows.length : 0;
|
||||
let titleText = `Date Range Report: ${startDate} to ${endDate} (${recordCount} records)`;
|
||||
|
||||
// Add summary info if available
|
||||
if (data.summary) {
|
||||
titleText += ` | Approved: ${data.summary.total_approved}, Rejected: ${data.summary.total_rejected}`;
|
||||
}
|
||||
|
||||
reportTitleElement.textContent = titleText;
|
||||
localPopulateTable(data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching date range report:', error);
|
||||
reportTitleElement.textContent = 'Error loading date range report';
|
||||
localPopulateTable({ headers: [], rows: [] });
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -748,6 +748,16 @@ body.dark-mode .export-description {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.test-db-btn {
|
||||
background-color: #6c757d !important; /* Gray color for test button */
|
||||
border-color: #6c757d !important;
|
||||
}
|
||||
|
||||
.test-db-btn:hover {
|
||||
background-color: #5a6268 !important;
|
||||
border-color: #545b62 !important;
|
||||
}
|
||||
|
||||
.report-form-card .export-section .form-centered.last-buttons {
|
||||
padding: 5px 0; /* Reduced padding for export section */
|
||||
}
|
||||
@@ -829,13 +839,14 @@ body.dark-mode .export-description {
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
background-color: #ffffff;
|
||||
margin: 5% auto;
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
width: 400px;
|
||||
max-width: 90%;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
@@ -843,7 +854,7 @@ body.dark-mode .export-description {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
background-color: #f8f9fa;
|
||||
background-color: #f4f4f9;
|
||||
border-radius: 8px 8px 0 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
@@ -851,6 +862,7 @@ body.dark-mode .export-description {
|
||||
.modal-header h4 {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.close-modal {
|
||||
@@ -859,6 +871,7 @@ body.dark-mode .export-description {
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
line-height: 1;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.close-modal:hover {
|
||||
@@ -867,6 +880,7 @@ body.dark-mode .export-description {
|
||||
|
||||
.modal-body {
|
||||
padding: 20px;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
@@ -876,7 +890,152 @@ body.dark-mode .export-description {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ddd;
|
||||
border-radius: 0 0 8px 8px;
|
||||
background-color: #f8f9fa;
|
||||
background-color: #f4f4f9;
|
||||
}
|
||||
|
||||
/* Dark Mode Support for Calendar Modal */
|
||||
body.dark-mode .modal-content {
|
||||
background-color: #2c2c2c;
|
||||
border: 1px solid #555;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-header {
|
||||
background-color: #1e1e1e;
|
||||
border-bottom: 1px solid #555;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-header h4 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .close-modal {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
body.dark-mode .close-modal:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-body {
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-footer {
|
||||
background-color: #1e1e1e;
|
||||
border-top: 1px solid #555;
|
||||
}
|
||||
|
||||
/* Modal Button Styling */
|
||||
.modal-footer .btn {
|
||||
padding: 8px 16px;
|
||||
font-size: 0.9em;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.modal-footer .btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.modal-footer .btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.modal-footer .btn-primary:disabled {
|
||||
background-color: #6c757d;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.modal-footer .btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.modal-footer .btn-secondary:hover {
|
||||
background-color: #545b62;
|
||||
}
|
||||
|
||||
/* Dark Mode Modal Buttons */
|
||||
body.dark-mode .modal-footer .btn-primary {
|
||||
background-color: #007bff;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-footer .btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-footer .btn-secondary {
|
||||
background-color: #6c757d;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-footer .btn-secondary:hover {
|
||||
background-color: #545b62;
|
||||
}
|
||||
|
||||
/* Date Range Modal Styles */
|
||||
.date-range-container {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.date-input-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.date-input-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.date-input {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 8px;
|
||||
font-size: 1em;
|
||||
background-color: #fff;
|
||||
transition: border-color 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.date-input:focus {
|
||||
outline: none;
|
||||
border-color: #007bff;
|
||||
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
|
||||
}
|
||||
|
||||
.date-help {
|
||||
display: block;
|
||||
font-size: 0.8em;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Dark mode styles for date range modal */
|
||||
body.dark-mode .date-input-group label {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode .date-input {
|
||||
background-color: #2d3748;
|
||||
border-color: #4a5568;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode .date-input:focus {
|
||||
border-color: #63b3ed;
|
||||
box-shadow: 0 0 0 3px rgba(99, 179, 237, 0.1);
|
||||
}
|
||||
|
||||
body.dark-mode .date-help {
|
||||
color: #a0aec0;
|
||||
}
|
||||
|
||||
/* Calendar Styles */
|
||||
@@ -898,18 +1057,20 @@ body.dark-mode .export-description {
|
||||
}
|
||||
|
||||
.calendar-nav {
|
||||
background: none;
|
||||
background-color: #f4f4f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
color: #333;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.calendar-nav:hover {
|
||||
background-color: #f0f0f0;
|
||||
color: #333;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
.calendar-grid {
|
||||
@@ -929,7 +1090,8 @@ body.dark-mode .export-description {
|
||||
font-weight: bold;
|
||||
font-size: 0.85em;
|
||||
color: #666;
|
||||
background-color: #f8f9fa;
|
||||
background-color: #f4f4f9;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.calendar-days {
|
||||
@@ -948,30 +1110,83 @@ body.dark-mode .export-description {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.calendar-day:hover {
|
||||
background-color: #e9ecef;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
.calendar-day.other-month {
|
||||
color: #ccc;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.calendar-day.today {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.calendar-day.selected {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.calendar-day.selected:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
/* Dark Mode Calendar Styles */
|
||||
body.dark-mode .calendar-header h3 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .calendar-nav {
|
||||
background-color: #3c3c3c;
|
||||
border-color: #555;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .calendar-nav:hover {
|
||||
background-color: #007bff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
body.dark-mode .calendar-weekdays div {
|
||||
background-color: #3c3c3c;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
body.dark-mode .calendar-day {
|
||||
background-color: #2c2c2c;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .calendar-day:hover {
|
||||
background-color: #444;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
body.dark-mode .calendar-day.other-month {
|
||||
color: #666;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
body.dark-mode .calendar-day.today {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
body.dark-mode .calendar-day.selected {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Responsive Calendar */
|
||||
@media (max-width: 480px) {
|
||||
.modal-content {
|
||||
|
||||
Reference in New Issue
Block a user