From eca6f4ece8bb57212a9d52bd2a95011ca8300311 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 20 Nov 2025 12:50:25 -0500 Subject: [PATCH] feat: Allow individual log archiving Adds the ability for admins to archive individual time log entries. - Adds an 'Archive' button to the detailed logs table in the admin UI. - Adds a new API endpoint to handle the archiving of a single log entry. - Updates the frontend to call the new endpoint when the 'Archive' button is clicked. --- public/js/main.js | 1 + public/js/ui.js | 3 ++- server.js | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/public/js/main.js b/public/js/main.js index 683cc48..36d41d2 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -301,6 +301,7 @@ function handleAdminDashboardClick(e) { if (target.classList.contains('edit-btn')) renderEditModal(id, handleEditSubmit); if (target.classList.contains('delete-btn') && confirm('Delete this time entry?')) apiCall(`/admin/logs/${id}`, 'DELETE').then(res => res.success && renderAdminDashboard()); + if (target.classList.contains('archive-log-btn') && confirm('Archive this time entry?')) apiCall(`/admin/logs/archive/${id}`, 'POST').then(res => res.success && renderAdminDashboard()); if (target.classList.contains('force-clock-out-btn') && confirm(`Force clock out ${username}?`)) apiCall('/admin/force-clock-out', 'POST', { userId: userid }).then(res => res.success && renderAdminDashboard()); if (target.classList.contains('reset-pw-btn')) renderResetPasswordModal(username, handleResetPassword); if (target.classList.contains('change-role-btn')) { const newRole = role === 'admin' ? 'employee' : 'admin'; if (confirm(`Change ${username} to ${newRole}?`)) apiCall('/admin/update-role', 'POST', { username, newRole }).then(res => res.success && renderAdminDashboard()); } diff --git a/public/js/ui.js b/public/js/ui.js index 55a97ad..963a599 100644 --- a/public/js/ui.js +++ b/public/js/ui.js @@ -242,7 +242,8 @@ export async function renderAdminDashboard() {

Hours by Employee

${Object.entries(employeeTotals).map(([username, totalMs]) => ``).join('') || ''}
EmployeeTotal Hours
${username}${utils.formatDecimal(totalMs)}
No data.
-

Detailed Logs

${allTimeEntries.map(e => ``).join('')}
EmployeeInOutDurationActions
${e.username||'N/A'}${utils.formatDateTime(e.punch_in_time)}${utils.formatDateTime(e.punch_out_time)}${e.punch_out_time ? utils.formatDecimal(new Date(e.punch_out_time) - new Date(e.punch_in_time)) + ' hrs' : '...'}
+

Detailed Logs

${allTimeEntries.map(e => ``).join('')}
EmployeeInOutDurationActions
${e.username||'N/A'}${utils.formatDateTime(e.punch_in_time)}${utils.formatDateTime(e.punch_out_time)}${e.punch_out_time ? utils.formatDecimal(new Date(e.punch_out_time) - new Date(e.punch_in_time)) + ' hrs' : '...'}
+${e.status === 'out' ? `` : ''}