fix dupe fuction in ui.js
This commit is contained in:
parent
cab217cf24
commit
2072aa30ef
@ -1,7 +1,6 @@
|
|||||||
// js/ui.js
|
// js/ui.js
|
||||||
|
|
||||||
// --- IMPORTS ---
|
// --- IMPORTS ---
|
||||||
// Imports functions for server calls, utility formatting, and attaching event listeners.
|
|
||||||
import { apiCall } from './api.js';
|
import { apiCall } from './api.js';
|
||||||
import * as utils from './utils.js';
|
import * as utils from './utils.js';
|
||||||
import {
|
import {
|
||||||
@ -23,14 +22,11 @@ const welcomeMessage = document.getElementById('welcome-message');
|
|||||||
const modalContainer = document.getElementById('modal-container');
|
const modalContainer = document.getElementById('modal-container');
|
||||||
|
|
||||||
// --- MODULE-LEVEL STATE ---
|
// --- MODULE-LEVEL STATE ---
|
||||||
// These are specific to the UI and manage running timers.
|
|
||||||
let employeeTimerInterval = null;
|
let employeeTimerInterval = null;
|
||||||
let adminTimerIntervals = [];
|
let adminTimerIntervals = [];
|
||||||
// This state is populated by renderAdminDashboard and used by its helper functions like renderEditModal
|
|
||||||
let allTimeEntries = [];
|
let allTimeEntries = [];
|
||||||
let allUsers = [];
|
let allUsers = [];
|
||||||
|
|
||||||
|
|
||||||
// --- VIEW MANAGEMENT ---
|
// --- VIEW MANAGEMENT ---
|
||||||
export function showView(viewName) {
|
export function showView(viewName) {
|
||||||
clearInterval(employeeTimerInterval);
|
clearInterval(employeeTimerInterval);
|
||||||
@ -40,29 +36,33 @@ export function showView(viewName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- MASTER UI UPDATE FUNCTION ---
|
// --- MASTER UI UPDATE FUNCTION ---
|
||||||
|
|
||||||
export function updateUI() {
|
export function updateUI() {
|
||||||
|
// This function was empty, it has been corrected.
|
||||||
try {
|
try {
|
||||||
const storedUser = localStorage.getItem('user');
|
const storedUser = localStorage.getItem('user');
|
||||||
const authToken = localStorage.getItem('authToken');
|
const authToken = localStorage.getItem('authToken');
|
||||||
const user = storedUser ? JSON.parse(storedUser) : null;
|
const user = storedUser ? JSON.parse(storedUser) : null;
|
||||||
|
|
||||||
if (authToken && user) {
|
if (authToken && user) {
|
||||||
// ... (rest of the if block is fine)
|
navUserControls.classList.remove('hidden');
|
||||||
|
welcomeMessage.textContent = `Welcome, ${user.username}`;
|
||||||
|
if (user.role === 'admin') {
|
||||||
|
renderAdminDashboard();
|
||||||
|
} else {
|
||||||
|
renderEmployeeDashboard();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// ... (rest of the else block is fine)
|
navUserControls.classList.add('hidden');
|
||||||
|
renderAuthView();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// This is the corrected catch block
|
|
||||||
console.error("Corrupted session data. Clearing and reloading.", error);
|
console.error("Corrupted session data. Clearing and reloading.", error);
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
window.location.reload(); // Reload the page to a clean state
|
window.location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- RENDER FUNCTIONS ---
|
// --- RENDER FUNCTIONS ---
|
||||||
|
|
||||||
export function renderAuthView() {
|
export function renderAuthView() {
|
||||||
showView('auth');
|
showView('auth');
|
||||||
mainViews.auth.innerHTML = `
|
mainViews.auth.innerHTML = `
|
||||||
@ -133,7 +133,7 @@ export async function renderEmployeeDashboard() {
|
|||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
attachEmployeeDashboardListeners(); // Attach all listeners for this view
|
attachEmployeeDashboardListeners();
|
||||||
|
|
||||||
if (punchedIn) {
|
if (punchedIn) {
|
||||||
const durationCell = document.getElementById(`duration-${last.id}`);
|
const durationCell = document.getElementById(`duration-${last.id}`);
|
||||||
@ -147,14 +147,11 @@ export async function renderEmployeeDashboard() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In js/ui.js
|
|
||||||
|
|
||||||
export async function renderAdminDashboard() {
|
export async function renderAdminDashboard() {
|
||||||
showView('admin');
|
showView('admin');
|
||||||
const [logsRes, usersRes, requestsRes] = await Promise.all([apiCall('/admin/logs'), apiCall('/admin/users'), apiCall('/admin/time-off-requests/pending')]);
|
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;
|
if (!logsRes.success || !usersRes.success || !requestsRes.success) return;
|
||||||
|
|
||||||
// --- Existing data processing logic (no changes here) ---
|
|
||||||
allTimeEntries = logsRes.data;
|
allTimeEntries = logsRes.data;
|
||||||
allUsers = usersRes.data;
|
allUsers = usersRes.data;
|
||||||
const pendingRequests = requestsRes.data;
|
const pendingRequests = requestsRes.data;
|
||||||
@ -163,21 +160,17 @@ export async function renderAdminDashboard() {
|
|||||||
const punchedInEntries = allTimeEntries.filter(e => e.status === 'in');
|
const punchedInEntries = allTimeEntries.filter(e => e.status === 'in');
|
||||||
const employeesOnly = allUsers.filter(u => u.role === 'employee');
|
const employeesOnly = allUsers.filter(u => u.role === 'employee');
|
||||||
|
|
||||||
// --- New Tabbed HTML Structure ---
|
|
||||||
mainViews.admin.innerHTML = `
|
mainViews.admin.innerHTML = `
|
||||||
<div class="max-w-6xl mx-auto space-y-4">
|
<div class="max-w-6xl mx-auto space-y-4">
|
||||||
<div class="bg-white rounded-xl shadow-md p-4">
|
<div class="bg-white rounded-xl shadow-md p-4">
|
||||||
<h2 class="text-2xl font-bold">Admin Dashboard</h2>
|
<h2 class="text-2xl font-bold">Admin Dashboard</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="admin-tabs-nav" class="flex border-b border-gray-200 bg-white rounded-t-lg px-4">
|
<div id="admin-tabs-nav" class="flex border-b border-gray-200 bg-white rounded-t-lg px-4">
|
||||||
<button data-tab="overview" class="tab-btn active-tab py-3 px-4">Overview</button>
|
<button data-tab="overview" class="tab-btn active-tab py-3 px-4">Overview</button>
|
||||||
<button data-tab="logs" class="tab-btn py-3 px-4">Time Logs</button>
|
<button data-tab="logs" class="tab-btn py-3 px-4">Time Logs</button>
|
||||||
<button data-tab="users" class="tab-btn py-3 px-4">User Management</button>
|
<button data-tab="users" class="tab-btn py-3 px-4">User Management</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="admin-tabs-content" class="bg-white rounded-b-lg shadow-md p-6">
|
<div id="admin-tabs-content" class="bg-white rounded-b-lg shadow-md p-6">
|
||||||
|
|
||||||
<div id="tab-content-overview" class="space-y-8">
|
<div id="tab-content-overview" class="space-y-8">
|
||||||
<div><h3 class="text-xl font-bold text-gray-700 mb-2">Currently Punched In</h3><ul class="border rounded-lg divide-y">${punchedInEntries.map(e => `<li class="flex flex-col items-start space-y-2 p-3 sm:flex-row sm:items-center sm:justify-between sm:space-y-0"><span class="font-medium text-gray-800">${e.username}</span><div class="flex items-center space-x-4"><span class="text-sm text-gray-500">Since: ${utils.formatDateTime(e.punch_in_time)}</span><button class="force-clock-out-btn px-3 py-1 text-xs bg-red-500 text-white rounded whitespace-nowrap" data-userid="${e.user_id}" data-username="${e.username}">Force Clock Out</button></div></li>`).join('') || '<li class="p-4 text-center text-gray-500">None</li>'}</ul></div>
|
<div><h3 class="text-xl font-bold text-gray-700 mb-2">Currently Punched In</h3><ul class="border rounded-lg divide-y">${punchedInEntries.map(e => `<li class="flex flex-col items-start space-y-2 p-3 sm:flex-row sm:items-center sm:justify-between sm:space-y-0"><span class="font-medium text-gray-800">${e.username}</span><div class="flex items-center space-x-4"><span class="text-sm text-gray-500">Since: ${utils.formatDateTime(e.punch_in_time)}</span><button class="force-clock-out-btn px-3 py-1 text-xs bg-red-500 text-white rounded whitespace-nowrap" data-userid="${e.user_id}" data-username="${e.username}">Force Clock Out</button></div></li>`).join('') || '<li class="p-4 text-center text-gray-500">None</li>'}</ul></div>
|
||||||
<div><div class="flex justify-between items-center mb-4"><h3 class="text-xl font-bold text-gray-700">Pending Time Off Requests</h3><button id="view-time-off-history-btn" class="px-4 py-2 text-sm bg-gray-200 rounded-lg hover:bg-gray-300">View History</button></div><div class="overflow-x-auto border rounded-lg"><table class="min-w-full text-sm text-left"><thead class="bg-gray-50"><tr><th class="p-2">Employee</th><th class="p-2">Dates</th><th class="p-2">Reason</th><th class="p-2">Actions</th></tr></thead><tbody>${pendingRequests.map(r => `<tr class="border-t"><td class="p-2">${r.username}</td><td class="p-2 whitespace-nowrap">${utils.formatDate(r.start_date)} - ${utils.formatDate(r.end_date)}</td><td class="p-2">${r.reason||''}</td><td class="p-2"><div class="flex flex-col sm:flex-row gap-2"><button class="approve-request-btn font-medium text-green-600 hover:underline" data-id="${r.id}">Approve</button><button class="deny-request-btn font-medium text-red-600 hover:underline" data-id="${r.id}">Deny</button></div></td></tr>`).join('') || '<tr><td colspan="4" class="text-center p-4">No pending requests.</td></tr>'}</tbody></table></div></div>
|
<div><div class="flex justify-between items-center mb-4"><h3 class="text-xl font-bold text-gray-700">Pending Time Off Requests</h3><button id="view-time-off-history-btn" class="px-4 py-2 text-sm bg-gray-200 rounded-lg hover:bg-gray-300">View History</button></div><div class="overflow-x-auto border rounded-lg"><table class="min-w-full text-sm text-left"><thead class="bg-gray-50"><tr><th class="p-2">Employee</th><th class="p-2">Dates</th><th class="p-2">Reason</th><th class="p-2">Actions</th></tr></thead><tbody>${pendingRequests.map(r => `<tr class="border-t"><td class="p-2">${r.username}</td><td class="p-2 whitespace-nowrap">${utils.formatDate(r.start_date)} - ${utils.formatDate(r.end_date)}</td><td class="p-2">${r.reason||''}</td><td class="p-2"><div class="flex flex-col sm:flex-row gap-2"><button class="approve-request-btn font-medium text-green-600 hover:underline" data-id="${r.id}">Approve</button><button class="deny-request-btn font-medium text-red-600 hover:underline" data-id="${r.id}">Deny</button></div></td></tr>`).join('') || '<tr><td colspan="4" class="text-center p-4">No pending requests.</td></tr>'}</tbody></table></div></div>
|
||||||
@ -191,13 +184,11 @@ export async function renderAdminDashboard() {
|
|||||||
<div id="employee-notes-container" class="mt-4"></div>
|
<div id="employee-notes-container" class="mt-4"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="tab-content-logs" class="space-y-8 hidden">
|
<div id="tab-content-logs" class="space-y-8 hidden">
|
||||||
<div class="flex-shrink-0 space-x-2"><button id="view-archives-btn" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600">View Archives</button><button id="archive-btn" class="px-4 py-2 bg-amber-500 text-white rounded-lg hover:bg-amber-600">Archive All Completed Records</button></div>
|
<div class="flex-shrink-0 space-x-2"><button id="view-archives-btn" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600">View Archives</button><button id="archive-btn" class="px-4 py-2 bg-amber-500 text-white rounded-lg hover:bg-amber-600">Archive All Completed Records</button></div>
|
||||||
<div><h3 class="text-xl font-bold text-gray-700 mb-2">Hours by Employee</h3><div class="overflow-x-auto border rounded-lg"><table class="min-w-full text-sm text-left"><thead class="bg-gray-50"><tr><th class="p-2">Employee</th><th class="p-2">Total Hours</th></tr></thead><tbody>${Object.entries(employeeTotals).map(([username, totalMs]) => `<tr class="border-t"><td class="p-2 font-medium">${username}</td><td class="p-2">${utils.formatDecimal(totalMs)}</td></tr>`).join('') || '<tr><td colspan="2" class="text-center p-4">No data.</td></tr>'}</tbody></table></div></div>
|
<div><h3 class="text-xl font-bold text-gray-700 mb-2">Hours by Employee</h3><div class="overflow-x-auto border rounded-lg"><table class="min-w-full text-sm text-left"><thead class="bg-gray-50"><tr><th class="p-2">Employee</th><th class="p-2">Total Hours</th></tr></thead><tbody>${Object.entries(employeeTotals).map(([username, totalMs]) => `<tr class="border-t"><td class="p-2 font-medium">${username}</td><td class="p-2">${utils.formatDecimal(totalMs)}</td></tr>`).join('') || '<tr><td colspan="2" class="text-center p-4">No data.</td></tr>'}</tbody></table></div></div>
|
||||||
<div><h3 class="text-xl font-bold text-gray-700 mb-4">Detailed Logs</h3><div class="overflow-x-auto border rounded-lg"><table class="min-w-full text-sm text-left"><thead class="bg-gray-50"><tr><th class="p-2">Employee</th><th class="p-2">In</th><th class="p-2">Out</th><th class="p-2">Duration</th><th class="p-2">Actions</th></tr></thead><tbody>${allTimeEntries.map(e => `<tr class="border-t"><td class="p-2">${e.username||'N/A'}</td><td class="p-2">${utils.formatDateTime(e.punch_in_time)}</td><td class="p-2">${utils.formatDateTime(e.punch_out_time)}</td><td class="p-2" id="admin-duration-${e.id}">${e.punch_out_time ? utils.formatDecimal(new Date(e.punch_out_time) - new Date(e.punch_in_time)) + ' hrs' : '...'}</td><td class="p-2"><div class="flex flex-col sm:flex-row items-start sm:items-center gap-2"><button class="edit-btn font-medium text-blue-600 hover:underline" data-id="${e.id}">Edit</button><button class="delete-btn font-medium text-red-600 hover:underline" data-id="${e.id}">Delete</button></div></td></tr>`).join('')}</tbody></table></div></div>
|
<div><h3 class="text-xl font-bold text-gray-700 mb-4">Detailed Logs</h3><div class="overflow-x-auto border rounded-lg"><table class="min-w-full text-sm text-left"><thead class="bg-gray-50"><tr><th class="p-2">Employee</th><th class="p-2">In</th><th class="p-2">Out</th><th class="p-2">Duration</th><th class="p-2">Actions</th></tr></thead><tbody>${allTimeEntries.map(e => `<tr class="border-t"><td class="p-2">${e.username||'N/A'}</td><td class="p-2">${utils.formatDateTime(e.punch_in_time)}</td><td class="p-2">${utils.formatDateTime(e.punch_out_time)}</td><td class="p-2" id="admin-duration-${e.id}">${e.punch_out_time ? utils.formatDecimal(new Date(e.punch_out_time) - new Date(e.punch_in_time)) + ' hrs' : '...'}</td><td class="p-2"><div class="flex flex-col sm:flex-row items-start sm:items-center gap-2"><button class="edit-btn font-medium text-blue-600 hover:underline" data-id="${e.id}">Edit</button><button class="delete-btn font-medium text-red-600 hover:underline" data-id="${e.id}">Delete</button></div></td></tr>`).join('')}</tbody></table></div></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="tab-content-users" class="space-y-8 hidden">
|
<div id="tab-content-users" class="space-y-8 hidden">
|
||||||
<div class="grid md:grid-cols-2 gap-6">
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
<form id="create-user-form" class="space-y-3 bg-gray-50 p-4 rounded-lg"><h4 class="font-semibold">Create User</h4><input type="text" id="new-username" placeholder="Username" class="w-full p-2 border rounded" required><input type="password" id="new-password" placeholder="Password" class="w-full p-2 border rounded" required><select id="new-user-role" class="w-full p-2 border rounded"><option value="employee">Employee</option><option value="admin">Admin</option></select><button type="submit" class="w-full bg-green-600 text-white p-2 rounded hover:bg-green-700">Create User</button></form>
|
<form id="create-user-form" class="space-y-3 bg-gray-50 p-4 rounded-lg"><h4 class="font-semibold">Create User</h4><input type="text" id="new-username" placeholder="Username" class="w-full p-2 border rounded" required><input type="password" id="new-password" placeholder="Password" class="w-full p-2 border rounded" required><select id="new-user-role" class="w-full p-2 border rounded"><option value="employee">Employee</option><option value="admin">Admin</option></select><button type="submit" class="w-full bg-green-600 text-white p-2 rounded hover:bg-green-700">Create User</button></form>
|
||||||
@ -209,7 +200,6 @@ export async function renderAdminDashboard() {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// The rest of the function remains the same
|
|
||||||
attachAdminDashboardListeners();
|
attachAdminDashboardListeners();
|
||||||
punchedInEntries.forEach(entry => {
|
punchedInEntries.forEach(entry => {
|
||||||
const durationCell = document.getElementById(`admin-duration-${entry.id}`);
|
const durationCell = document.getElementById(`admin-duration-${entry.id}`);
|
||||||
@ -269,8 +259,8 @@ export function renderResetPasswordModal(username, submitHandler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function renderRequestHistoryModal(requests) {
|
export function renderRequestHistoryModal(requests) {
|
||||||
const modalBody = `...`; // Same as your original function
|
const modalBody = `<div class="max-h-[70vh] overflow-y-auto"><table class="min-w-full text-sm text-left"><thead class="bg-gray-50 sticky top-0"><tr><th class="p-2">Dates</th><th class="p-2">Reason</th><th class="p-2">Status</th></tr></thead><tbody>${requests.map(r => `<tr class="border-t"><td class="p-2 whitespace-nowrap">${utils.formatDate(r.start_date)} - ${utils.formatDate(r.end_date)}</td><td class="p-2">${r.reason || ''}</td><td class="p-2 font-medium capitalize text-${r.status === 'approved' ? 'green' : 'red'}-600">${r.status}</td></tr>`).join('') || '<tr><td colspan="3" class="text-center p-4">No history found.</td></tr>'}</tbody></table></div>`;
|
||||||
modalContainer.innerHTML = `...`; // Same as your original function
|
modalContainer.innerHTML = `<div class="modal-overlay"><div class="modal-content"><div class="flex justify-between items-center mb-4"><h3 class="text-xl font-bold">Full Time Off History</h3><button class="cancel-modal-btn font-bold text-2xl">×</button></div>${modalBody}</div></div>`;
|
||||||
document.querySelector('.cancel-modal-btn').addEventListener('click', () => modalContainer.innerHTML = '');
|
document.querySelector('.cancel-modal-btn').addEventListener('click', () => modalContainer.innerHTML = '');
|
||||||
document.querySelector('.modal-overlay').addEventListener('click', (e) => { if (e.target === e.currentTarget) modalContainer.innerHTML = ''; });
|
document.querySelector('.modal-overlay').addEventListener('click', (e) => { if (e.target === e.currentTarget) modalContainer.innerHTML = ''; });
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user