Time by Project/Task:
`;
Object.keys(projectTime).sort((a,b) => projectTime[b] - projectTime[a]).forEach(projName => {
summaryHTML += `- ${projName}: ${rtwlFormatDuration(projectTime[projName])}
`;
});
summaryHTML += `
`;
if(rtwlReportSummaryEl) rtwlReportSummaryEl.innerHTML = summaryHTML;
if(rtwlReportOutputAreaEl) rtwlReportOutputAreaEl.style.display = 'block';
if(rtwlDownloadPdfBtn) rtwlDownloadPdfBtn.style.display = entriesInPeriod.length > 0 ? 'block' : 'none';
}
function handlePdfDownload() { /* ... same as stlHandlePdfDownload, with rtwl prefix ... */
const periodText = rtwlReportPeriodDisplayEl.textContent;
const totalTimeText = rtwlReportSummaryEl.querySelector('p strong')?.parentElement.textContent || "Total Time Logged: N/A";
const projectSummaryData = [];
const projectLis = rtwlReportSummaryEl.querySelectorAll('ul li');
projectLis.forEach(li => projectSummaryData.push(li.textContent));
const detailTableRowsData = [];
const detailTableHtmlRows = rtwlReportDetailsTableBodyEl.querySelectorAll('tr');
detailTableHtmlRows.forEach(row => {
const cells = Array.from(row.cells).map(cell => cell.textContent);
detailTableRowsData.push(cells);
});
if(detailTableRowsData.length === 0 && totalTimeText.includes("N/A") && projectSummaryData.length === 0) {
alert("No data to export for the selected report period."); return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
doc.setFontSize(18);
doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--rtwl-primary-color').trim());
doc.text("Real-Time Work Log Report", 14, 22);
doc.setFontSize(12);
doc.setTextColor(100);
doc.text(`Period: ${periodText}`, 14, 30);
doc.text(totalTimeText, 14, 38);
let yPos = 46;
if (projectSummaryData.length > 0) {
doc.setFontSize(11);
doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--rtwl-text-color').trim());
doc.text("Summary by Project/Task:", 14, yPos);
yPos += 7;
doc.setFontSize(9);
projectSummaryData.forEach(item => {
if (yPos > 270) { doc.addPage(); yPos = 20; }
doc.text(`\u2022 ${item}`, 16, yPos);
yPos += 5;
});
yPos += 5;
}
if (detailTableRowsData.length > 0) {
if (yPos > 250) { doc.addPage(); yPos = 20; }
doc.setFontSize(11);
doc.setTextColor(getComputedStyle(document.documentElement).getPropertyValue('--rtwl-text-color').trim());
doc.text("Detailed Log:", 14, yPos);
yPos += 7;
doc.autoTable({
head: [['Date', 'Project', 'Task Description', 'Start', 'End', 'Duration', 'Notes']],
body: detailTableRowsData,
startY: yPos,
theme: 'striped',
headStyles: { fillColor: getComputedStyle(document.documentElement).getPropertyValue('--rtwl-primary-color').trim() },
styles: { fontSize: 8, cellPadding: 1.5, overflow: 'linebreak' },
columnStyles: {
1: { cellWidth: 30 },
2: { cellWidth: 50 },
6: { cellWidth: 'auto'}
}
});
}
doc.save(`TimeLogReport_${periodText.replace(/[^a-zA-Z0-9]/g, '_')}.pdf`);
}
window.rtwlCloseModal = (modalId) => { /* ... */
const modal = document.getElementById(modalId);
if(modal) modal.style.display = 'none';
// Reset timer-related modal fields if active timer was cleared during modal interaction.
if (!rtwlActiveTimer && modalId === 'rtwlTimeEntryModal' && rtwlTimeEntryModalTitleEl.textContent.includes("Confirm & Log Timed Entry")) {
if(rtwlTaskSelectTimerEl) rtwlTaskSelectTimerEl.value = "";
if(rtwlAdhocTaskNameTimerEl) rtwlAdhocTaskNameTimerEl.value = "";
if(rtwlAdhocTaskNameGroupEl) rtwlAdhocTaskNameGroupEl.style.display = "none";
}
}
// --- DOMContentLoaded ---
document.addEventListener('DOMContentLoaded', () => {
// Assign DOM elements
rtwlTaskSelectTimerEl = document.getElementById('rtwlTaskSelectTimer');
rtwlAdhocTaskNameGroupEl = document.getElementById('rtwlAdhocTaskNameGroup');
rtwlAdhocTaskNameTimerEl = document.getElementById('rtwlAdhocTaskNameTimer');
rtwlStartNewTimerButtonEl = document.getElementById('rtwlStartNewTimerButton');
rtwlActiveTimerAreaEl = document.getElementById('rtwlActiveTimerArea');
rtwlActiveTaskNameDisplayEl = document.getElementById('rtwlActiveTaskNameDisplay');
rtwlActiveTimerDisplayEl = document.getElementById('rtwlActiveTimerDisplay');
rtwlPauseResumeTimerButtonEl = document.getElementById('rtwlPauseResumeTimerButton');
rtwlStopTimerButtonEl = document.getElementById('rtwlStopTimerButton');
rtwlDiscardTimerButtonEl = document.getElementById('rtwlDiscardTimerButton');
rtwlCurrentDateDisplayEl = document.getElementById('rtwlCurrentDateDisplay');
rtwlLogViewDateEl = document.getElementById('rtwlLogViewDate');
rtwlDailyLogEntriesListEl = document.getElementById('rtwlDailyLogEntriesList');
rtwlQuickStartButtonsEl = document.getElementById('rtwlQuickStartButtons');
rtwlAddProjectForm = document.getElementById('rtwlAddProjectForm');
rtwlProjectNameInputEl = document.getElementById('rtwlProjectNameInput');
rtwlProjectColorInputEl = document.getElementById('rtwlProjectColorInput');
rtwlProjectsListEl = document.getElementById('rtwlProjectsList');
rtwlReportPeriodSelectEl = document.getElementById('rtwlReportPeriodSelect');
rtwlCustomDateRangePickerEl = document.getElementById('rtwlCustomDateRangePicker');
rtwlReportStartDateInputEl = document.getElementById('rtwlReportStartDate');
rtwlReportEndDateInputEl = document.getElementById('rtwlReportEndDate');
rtwlReportOutputAreaEl = document.getElementById('rtwlReportOutputArea');
rtwlReportPeriodDisplayEl = document.getElementById('rtwlReportPeriodDisplay');
rtwlReportSummaryEl = document.getElementById('rtwlReportSummary');
rtwlReportDetailsTableBodyEl = document.querySelector('#rtwlReportDetailsTable tbody'); // Corrected selector
rtwlTimeEntryModalEl = document.getElementById('rtwlTimeEntryModal');
rtwlTimeEntryModalTitleEl = document.getElementById('rtwlTimeEntryModalTitle');
rtwlTimeEntryForm = document.getElementById('rtwlTimeEntryForm');
rtwlEntryIdInput = document.getElementById('rtwlEntryId');
rtwlEntryTaskDescriptionInput = document.getElementById('rtwlEntryTaskDescription');
rtwlEntryProjectIdSelectEl = document.getElementById('rtwlEntryProjectId');
rtwlEntryStartDateInput = document.getElementById('rtwlEntryStartDate');
rtwlEntryStartTimeInput = document.getElementById('rtwlEntryStartTime');
rtwlEntryEndDateInput = document.getElementById('rtwlEntryEndDate');
rtwlEntryEndTimeInput = document.getElementById('rtwlEntryEndTime');
rtwlEntryDurationMinutesInput = document.getElementById('rtwlEntryDurationMinutes');
rtwlEntryNotesInput = document.getElementById('rtwlEntryNotes');
rtwlDownloadPdfBtn = document.getElementById('rtwlDownloadPdfButton');
// Check if all critical elements are found
const criticalElements = [rtwlTaskSelectTimerEl, rtwlAddProjectForm, rtwlTimeEntryForm, rtwlLogViewDateEl, rtwlReportPeriodSelectEl];
if (criticalElements.some(el => !el)) {
console.error("RealTimeWorkHourLoggingTool: Not all critical DOM elements were found. Tool may not function correctly.");
alert("Error initializing the Time Logger: Some UI elements are missing. Please ensure the HTML code is complete.");
return; // Stop further initialization if critical parts are missing
}
// Attach event listeners
if(rtwlAddProjectForm) rtwlAddProjectForm.addEventListener('submit', handleAddProjectFormSubmit);
if(rtwlTimeEntryForm) rtwlTimeEntryForm.addEventListener('submit', handleTimeEntryFormSubmit);
if(rtwlTaskSelectTimerEl) rtwlTaskSelectTimerEl.addEventListener('change', () => {
if(rtwlAdhocTaskNameGroupEl) rtwlAdhocTaskNameGroupEl.style.display = rtwlTaskSelectTimerEl.value === 'adhoc' ? 'block' : 'none';
});
if(rtwlStartNewTimerButtonEl) rtwlStartNewTimerButtonEl.addEventListener('click', rtwlStartNewTimer);
if(rtwlPauseResumeTimerButtonEl) rtwlPauseResumeTimerButtonEl.addEventListener('click', rtwlTogglePauseResumeTimer);
if(rtwlStopTimerButtonEl) rtwlStopTimerButtonEl.addEventListener('click', rtwlStopAndLogTimer);
if(rtwlDiscardTimerButtonEl) rtwlDiscardTimerButtonEl.addEventListener('click', rtwlDiscardActiveTimer);
if(rtwlLogViewDateEl) rtwlLogViewDateEl.addEventListener('change', rtwlRenderDailyLogEntries);
if(rtwlReportPeriodSelectEl) rtwlReportPeriodSelectEl.addEventListener('change', () => {
if(rtwlCustomDateRangePickerEl) rtwlCustomDateRangePickerEl.style.display = rtwlReportPeriodSelectEl.value === 'custom_range' ? 'grid' : 'none';
});
if(rtwlDownloadPdfBtn) rtwlDownloadPdfBtn.addEventListener('click', handlePdfDownload);
[rtwlEntryStartDateInput, rtwlEntryStartTimeInput, rtwlEntryEndDateInput, rtwlEntryEndTimeInput].forEach(el => {
if(el) el.addEventListener('change', rtwlCalculateDurationManual);
});
// Removed rtwlAdjustEndTimeManual listener from duration input as it's now read-only in modal
const today = new Date(2025, 4, 14); // May 14, 2025
if(rtwlLogViewDateEl) rtwlLogViewDateEl.value = rtwlFormatDateKey(today);
if(rtwlCurrentDateDisplayEl) rtwlCurrentDateDisplayEl.textContent = today.toLocaleDateString();
rtwlLoadData();
const firstTabButton = document.querySelector('#realTimeWorkHourLoggingTool .rtwl-tab-button');
if (firstTabButton) firstTabButton.click();
window.addEventListener('click', function(event) {
if (event.target.classList.contains('rtwl-modal')) {
rtwlCloseModal(event.target.id);
}
});
});