From bdc5356f28ab63822ebb1f1931e3437d38cabfe1 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 2 Aug 2025 09:03:36 -0400 Subject: [PATCH] add time elapsed instead of running --- public/index.html | 163 ++++++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 72 deletions(-) diff --git a/public/index.html b/public/index.html index d90874f..b9d00a1 100644 --- a/public/index.html +++ b/public/index.html @@ -53,7 +53,8 @@ const navUserControls = document.getElementById('nav-user-controls'), welcomeMessage = document.getElementById('welcome-message'), signOutBtn = document.getElementById('sign-out-btn'); const messageBox = document.getElementById('message-box'), loadingSpinner = document.getElementById('loading-spinner'), modalContainer = document.getElementById('modal-container'); let authToken, user, allTimeEntries = [], allUsers = [], employeeTimerInterval = null; - + let adminTimerIntervals = []; + // --- Helper Functions --- const showLoading = (show) => { loadingSpinner.innerHTML = show ? `
` : ''; }; const showMessage = (message, type = 'success') => { messageBox.innerHTML = ``; messageBox.classList.remove('hidden'); }; @@ -104,10 +105,15 @@ } // --- View Management --- - const showView = (viewName) => { - clearInterval(employeeTimerInterval); - Object.keys(mainViews).forEach(v => mainViews[v].classList.toggle('hidden', v !== viewName)); - } +// --- View Management --- +const showView = (viewName) => { + // Clear all timers when the view changes + clearInterval(employeeTimerInterval); + adminTimerIntervals.forEach(clearInterval); + adminTimerIntervals = []; + + Object.keys(mainViews).forEach(v => mainViews[v].classList.toggle('hidden', v !== viewName)); +} // --- UI Rendering --- function updateUI() { @@ -219,75 +225,88 @@ } async function renderAdminDashboard() { - const [logsRes, usersRes, requestsRes] = await Promise.all([apiCall('/admin/logs'), apiCall('/admin/users'), apiCall('/admin/time-off-requests/pending')]); - if (!logsRes.success || !usersRes.success || !requestsRes.success) return; - - allTimeEntries = logsRes.data; - allUsers = usersRes.data; - const pendingRequests = requestsRes.data; - - const employeeTotals = allTimeEntries.reduce((acc, entry) => { - const dur = entry.punch_out_time ? (new Date(entry.punch_out_time) - new Date(entry.punch_in_time)) : (Date.now() - new Date(entry.punch_in_time)); - acc[entry.username] = (acc[entry.username] || 0) + dur; - return acc; - }, {}); - - const punchedInEntries = allTimeEntries.filter(e => e.status === 'in'); - - mainViews.admin.innerHTML = ` -
-
-
-

Admin Dashboard

-
- - -
+ const [logsRes, usersRes, requestsRes] = await Promise.all([apiCall('/admin/logs'), apiCall('/admin/users'), apiCall('/admin/time-off-requests/pending')]); + if (!logsRes.success || !usersRes.success || !requestsRes.success) return; + + allTimeEntries = logsRes.data; + allUsers = usersRes.data; + const pendingRequests = requestsRes.data; + + const employeeTotals = allTimeEntries.reduce((acc, entry) => { + const dur = entry.punch_out_time ? (new Date(entry.punch_out_time) - new Date(entry.punch_in_time)) : (Date.now() - new Date(entry.punch_in_time)); + acc[entry.username] = (acc[entry.username] || 0) + dur; + return acc; + }, {}); + + const punchedInEntries = allTimeEntries.filter(e => e.status === 'in'); + + mainViews.admin.innerHTML = ` +
+
+
+

Admin Dashboard

+
+ + +
+
+
+
+

Currently Punched In

+
    ${punchedInEntries.map(e => ` +
  • + ${e.username} +
    + Since: ${formatDateTime(e.punch_in_time)} +
    -
-
-

Currently Punched In

-
    ${punchedInEntries.map(e => ` -
  • - ${e.username} -
    - Since: ${formatDateTime(e.punch_in_time)} - -
    -
  • `).join('') || '
  • None
  • '} -
-
-
-
-

Pending Time Off Requests

- -
-
${pendingRequests.map(r => ``).join('') || ''}
EmployeeDatesReasonActions
${r.username}${formatDate(r.start_date)} - ${formatDate(r.end_date)}${r.reason||''}
No pending requests.
-
-
-

Hours by Employee

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

Detailed Logs

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

User & Payroll Management

-
-

Create User

-

Add Manual Punch

-
-

Manage Users

${allUsers.map(u => ``).join('')}
UsernameRoleActions
${u.username}${u.role}${u.isPrimary ? `Primary Admin` : `${u.username !== user.username ? `` : ''}`}
-
-
`; - document.getElementById('archive-btn').addEventListener('click', handleArchive); - document.getElementById('view-archives-btn').addEventListener('click', renderArchiveView); - document.getElementById('view-time-off-history-btn').addEventListener('click', renderTimeOffHistoryView); - document.getElementById('create-user-form').addEventListener('submit', handleCreateUser); - document.getElementById('add-punch-form').addEventListener('submit', handleAddPunch); - document.getElementById('admin-dashboard').addEventListener('click', handleAdminDashboardClick); + `).join('') || '
  • None
  • '} + +
    +
    +
    +

    Pending Time Off Requests

    + +
    +
    ${pendingRequests.map(r => ``).join('') || ''}
    EmployeeDatesReasonActions
    ${r.username}${formatDate(r.start_date)} - ${formatDate(r.end_date)}${r.reason||''}
    No pending requests.
    +
    +
    +

    Hours by Employee

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

    Detailed Logs

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

    User & Payroll Management

    +
    +

    Create User

    +

    Add Manual Punch

    +
    +

    Manage Users

    ${allUsers.map(u => ``).join('')}
    UsernameRoleActions
    ${u.username}${u.role}${u.isPrimary ? `Primary Admin` : `${u.username !== user.username ? `` : ''}`}
    +
    +
    `; + + // ** NEW: Start timers for all currently punched-in users ** + punchedInEntries.forEach(entry => { + const durationCell = document.getElementById(`admin-duration-${entry.id}`); + if (durationCell) { + const punchInTime = new Date(entry.punch_in_time); + const intervalId = setInterval(() => { + durationCell.textContent = formatDuration(Date.now() - punchInTime.getTime()); + }, 1000); + adminTimerIntervals.push(intervalId); // Store the timer to clear it later } + }); + + document.getElementById('archive-btn').addEventListener('click', handleArchive); + document.getElementById('view-archives-btn').addEventListener('click', renderArchiveView); + document.getElementById('view-time-off-history-btn').addEventListener('click', renderTimeOffHistoryView); + document.getElementById('create-user-form').addEventListener('submit', handleCreateUser); + document.getElementById('add-punch-form').addEventListener('submit', handleAddPunch); + document.getElementById('admin-dashboard').addEventListener('click', handleAdminDashboardClick); +} function renderArchiveView() { apiCall('/admin/archives').then(res => {