ui improvments mobile

This commit is contained in:
chris 2025-07-31 11:38:37 -04:00
parent f48db59b8b
commit 6edb7f7a7d

View File

@ -21,16 +21,15 @@
<body class="bg-gray-100">
<div id="app" class="min-h-screen">
<!-- Header -->
<header class="bg-white shadow-md">
<nav class="container mx-auto px-6 py-3 flex justify-between items-center">
<div class="flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-blue-600"><path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"></path><path d="M12 6v6l4 2"></path></svg>
<h1 class="text-xl font-bold text-gray-800 ml-2">TimeTracker</h1>
</div>
<div id="nav-user-controls" class="hidden">
<span id="welcome-message" class="text-gray-600 mr-4 hidden md:block"></span>
<button id="sign-out-btn" class="bg-red-500 text-white py-2 px-4 rounded-lg hover:bg-red-600">Sign Out</button>
<div id="nav-user-controls" class="hidden flex items-center">
<span id="welcome-message" class="text-gray-600 mr-3 text-sm sm:text-base truncate"></span>
<button id="sign-out-btn" class="bg-red-500 text-white py-2 px-3 sm:px-4 rounded-lg hover:bg-red-600 text-sm whitespace-nowrap">Sign Out</button>
</div>
</nav>
</header>
@ -65,9 +64,8 @@
const formatDuration = (ms) => { if (!ms || ms < 0) return '00:00:00'; const s = Math.floor(ms / 1000); const h = Math.floor(s / 3600); const m = Math.floor((s % 3600) / 60); return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`; };
// --- API Calls ---
// MODIFIED: This now points to the full server address, including the port.
const API_BASE_URL = '/api';
async function apiCall(endpoint, method = 'GET', body = null) {
async function apiCall(endpoint, method = 'GET', body = null) {
const headers = { 'Content-Type': 'application/json' };
if (authToken) headers['Authorization'] = `Bearer ${authToken}`;
try {
@ -86,14 +84,23 @@
// --- UI Rendering ---
function updateUI() {
if (authToken && user) {
navUserControls.classList.remove('hidden');
welcomeMessage.textContent = `Welcome, ${user.username}`;
user.role === 'admin' ? (showView('admin'), renderAdminDashboard()) : (showView('employee'), renderEmployeeDashboard());
} else {
navUserControls.classList.add('hidden');
showView('auth');
renderAuthView();
try {
const storedUser = localStorage.getItem('user');
user = storedUser ? JSON.parse(storedUser) : null;
authToken = localStorage.getItem('authToken');
if (authToken && user) {
navUserControls.classList.remove('hidden');
welcomeMessage.textContent = `Welcome, ${user.username}`;
user.role === 'admin' ? (showView('admin'), renderAdminDashboard()) : (showView('employee'), renderEmployeeDashboard());
} else {
navUserControls.classList.add('hidden');
showView('auth');
renderAuthView();
}
} catch (error) {
console.error("Error in updateUI:", error);
handleSignOut("There was an error loading your session.");
}
}
@ -160,7 +167,20 @@
mainViews.admin.innerHTML = `
<div class="max-w-6xl mx-auto space-y-8">
<div class="bg-white rounded-xl shadow-md p-6"><div class="flex justify-between items-center mb-4"><h2 class="text-2xl font-bold">Admin Dashboard</h2><div class="space-x-2"><button id="view-archives-btn" class="px-4 py-2 bg-gray-500 text-white rounded-lg">View Archives</button><button id="archive-btn" class="px-4 py-2 bg-amber-500 text-white rounded-lg">Archive Records</button></div></div></div>
<div class="bg-white rounded-xl shadow-md p-6"><h3 class="text-xl font-bold text-gray-700 mb-2">Currently Punched In</h3><ul id="punched-in-list" class="border rounded-lg divide-y">${punchedInEntries.map(e => `<li class="flex justify-between items-center p-3"><span class="font-medium">${e.username}</span><div class="flex items-center space-x-4"><span class="text-sm text-gray-600">Since: ${formatDateTime(e.punch_in_time)}</span><button class="force-clock-out-btn px-2 py-1 text-xs bg-red-500 text-white rounded" data-userid="${e.user_id}">Clock Out</button></div></li>`).join('') || '<li class="p-4 text-center">None</li>'}</ul></div>
<div class="bg-white rounded-xl shadow-md p-6">
<h3 class="text-xl font-bold text-gray-700 mb-2">Currently Punched In</h3>
<ul id="punched-in-list" 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: ${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}">Clock Out</button>
</div>
</li>
`).join('') || '<li class="p-4 text-center">None</li>'}</ul>
</div>
<div class="bg-white rounded-xl shadow-md p-6"><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">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 id="time-off-requests-table">${pendingRequests.map(r => `<tr class="border-t"><td class="p-2">${r.username}</td><td class="p-2">${formatDate(r.start_date)} - ${formatDate(r.end_date)}</td><td class="p-2">${r.reason||''}</td><td class="p-2 space-x-1"><button class="approve-request-btn text-green-600" data-id="${r.id}">Approve</button><button class="deny-request-btn text-red-600" data-id="${r.id}">Deny</button></td></tr>`).join('') || '<tr><td colspan="4" class="text-center p-4">No pending requests.</td></tr>'}</tbody></table></div></div>
<div class="bg-white rounded-xl shadow-md p-6"><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.keys(employeeTotals).map(u => `<tr class="border-t"><td class="p-2 font-medium">${u}</td><td class="p-2">${formatDecimal(employeeTotals[u])}</td></tr>`).join('')}</tbody></table></div></div>
<div class="bg-white rounded-xl shadow-md p-6"><h3 class="text-xl font-bold text-gray-700 mb-4">Detailed Logs</h3><div class="overflow-x-auto"><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 id="admin-table">${allTimeEntries.map(e => `<tr class="border-t"><td class="p-2">${e.username||'N/A'}</td><td class="p-2">${formatDateTime(e.punch_in_time)}</td><td class="p-2">${formatDateTime(e.punch_out_time)}</td><td class="p-2">${formatDecimal(new Date(e.punch_out_time) - new Date(e.punch_in_time))}</td><td class="p-2 space-x-2"><button class="edit-btn text-blue-600" data-id="${e.id}">Edit</button><button class="delete-btn text-red-600" data-id="${e.id}">Delete</button></td></tr>`).join('')}</tbody></table></div></div>
@ -250,7 +270,7 @@
signOutBtn.addEventListener('click', () => handleSignOut());
updateUI();
console.log("Attempting to register service worker...");
// Add the registration code here, inside the same script
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
@ -264,6 +284,5 @@
}
</script>
</body>
</html>