// js/ui.js // --- IMPORTS --- import { apiCall } from './api.js'; import * as utils from './utils.js'; import { attachAuthFormListener, attachAdminDashboardListeners, attachEmployeeDashboardListeners, attachTimeOffHistoryListeners, lastAdminTab } from './main.js'; // --- DOM ELEMENT SELECTORS --- const mainViews = { auth: document.getElementById('auth-view'), employee: document.getElementById('employee-dashboard'), admin: document.getElementById('admin-dashboard'), archive: document.getElementById('admin-archive-view'), timeOffHistory: document.getElementById('admin-time-off-history-view') }; const navUserControls = document.getElementById('nav-user-controls'); const welcomeMessage = document.getElementById('welcome-message'); const modalContainer = document.getElementById('modal-container'); // --- MODULE-LEVEL STATE --- let employeeTimerInterval = null; let adminTimerIntervals = []; let allTimeEntries = []; let allUsers = []; let allEmployeeEntries = []; // Convenience alias const esc = utils.escapeHtml; // --- VIEW MANAGEMENT --- export function showView(viewName) { clearInterval(employeeTimerInterval); adminTimerIntervals.forEach(clearInterval); adminTimerIntervals = []; Object.keys(mainViews).forEach(v => mainViews[v].classList.toggle('hidden', v !== viewName)); } // --- MASTER UI UPDATE FUNCTION --- export function updateUI() { try { const storedUser = localStorage.getItem('user'); const authToken = localStorage.getItem('authToken'); const user = storedUser ? JSON.parse(storedUser) : null; if (authToken && user) { navUserControls.classList.remove('hidden'); welcomeMessage.textContent = `Welcome, ${user.username}`; if (user.role === 'admin') { renderAdminDashboard(); } else { renderEmployeeDashboard(); } } else { navUserControls.classList.add('hidden'); renderAuthView(); } } catch (error) { console.error("Corrupted session data. Clearing and reloading.", error); localStorage.clear(); window.location.reload(); } } // --- RENDER FUNCTIONS --- export function renderAuthView() { showView('auth'); mainViews.auth.innerHTML = `
${punchedIn ? 'Punched In' : 'Punched Out'}
${punchedIn ? 'Since:' : 'Last Punch:'} ${utils.formatDateTime(punchedIn ? last.punch_in_time : last?.punch_out_time)}
"${esc(note.note_text)}"
- ${esc(note.admin_username)} on ${utils.formatDate(note.created_at)}
You have no new notes.
'}${utils.formatDecimal(totalMilliseconds)}
| Dates | Reason | Status | Actions |
|---|---|---|---|
| ${utils.formatDate(r.start_date)} - ${utils.formatDate(r.end_date)} | ${esc(r.reason)} | ${esc(r.status)} |
${r.status === 'pending' ? `
|
| No upcoming or pending requests. | |||
| In | Out | Duration (Hours) |
|---|---|---|
| ${utils.formatDateTime(e.punch_in_time)} | ${utils.formatDateTime(e.punch_out_time)} | ${e.status === 'in' ? 'Running...' : utils.formatDecimal(new Date(e.punch_out_time) - new Date(e.punch_in_time))} |
| No entries. | ||
| Employee | Dates | Reason | Actions |
|---|---|---|---|
| ${esc(r.username)} | ${utils.formatDate(r.start_date)} - ${utils.formatDate(r.end_date)} | ${esc(r.reason)} |
|
| No pending requests. | |||
Loading calendar...
'; const res = await apiCall('/admin/calendar-url'); if (res.success && res.data.url) { calendarContainer.innerHTML = ''; document.getElementById('admin-cal-frame').src = res.data.url; } else { calendarContainer.innerHTML = `Please configure the Nextcloud calendar embed URL in the Admin Settings tab.
| Employee | In | Out | Duration (Hrs) | Archived On |
|---|---|---|---|---|
| ${esc(e.username) || 'N/A'} | ${utils.formatDateTime(e.punch_in_time)} | ${utils.formatDateTime(e.punch_out_time)} | ${utils.formatDecimal(new Date(e.punch_out_time) - new Date(e.punch_in_time))} | ${utils.formatDateTime(e.archived_at)} |
| No archived entries found. | ||||
| Employee | Dates | Reason | Status | Actions |
|---|---|---|---|---|
| ${esc(r.username)} | ${utils.formatDate(r.start_date)} - ${utils.formatDate(r.end_date)} | ${esc(r.reason)} | ${esc(r.status)} |
|
| No history. | ||||
| Dates | Reason | Status |
|---|---|---|
| ${utils.formatDate(r.start_date)} - ${utils.formatDate(r.end_date)} | ${esc(r.reason)} | ${esc(r.status)} |
| No history found. | ||
"${esc(note.note_text)}"
- ${esc(note.admin_username)} on ${utils.formatDate(note.created_at)}
No notes found for this employee.
'; } } else { container.innerHTML = 'Could not load notes.
'; } } export function renderAdminLogsContent(startDate, endDate) { const container = document.getElementById('admin-logs-content'); if (!container) return; let filtered = allTimeEntries; if (startDate) { const start = new Date(startDate + 'T00:00:00'); filtered = filtered.filter(e => new Date(e.punch_in_time) >= start); } if (endDate) { const end = new Date(endDate + 'T23:59:59.999'); filtered = filtered.filter(e => new Date(e.punch_in_time) <= end); } const employeeTotals = filtered.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; }, {}); container.innerHTML = `| Employee | Total Hours |
|---|---|
| ${esc(username)} | ${utils.formatDecimal(totalMs)} |
| No data. | |
| Employee | In | Out | Duration | Actions |
|---|---|---|---|---|
| ${esc(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' ? `` : ''} |
| No entries in selected range. | ||||