add admin time off edit fuctionaliy
This commit is contained in:
parent
2a7f0b5762
commit
772f034914
@ -206,6 +206,40 @@ function handleAdminDashboardClick(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.classList.contains('set-pending-btn')) {
|
||||
if (confirm('Are you sure you want to move this request back to pending?')) {
|
||||
apiCall('/admin/update-time-off-status', 'POST', { requestId: id, status: 'pending' })
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
showMessage('Request status set to pending.', 'success');
|
||||
renderTimeOffHistoryView();
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.classList.contains('admin-delete-request-btn')) {
|
||||
if (confirm('Are you sure you want to permanently delete this request? This cannot be undone.')) {
|
||||
apiCall(`/admin/time-off-requests/${id}`, 'DELETE')
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
showMessage('Request deleted.', 'success');
|
||||
if (document.getElementById('tab-content-overview')) {
|
||||
apiCall('/admin/time-off-requests/pending').then(requestsRes => {
|
||||
if (requestsRes.success) {
|
||||
updatePendingRequestsList(requestsRes.data);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
renderTimeOffHistoryView();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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('force-clock-out-btn') && confirm(`Force clock out ${username}?`)) apiCall('/admin/force-clock-out', 'POST', { userId: userid }).then(res => res.success && renderAdminDashboard());
|
||||
@ -215,7 +249,6 @@ function handleAdminDashboardClick(e) {
|
||||
if (target.classList.contains('delete-note-btn')) { if (confirm('Delete this note?')) { apiCall(`/admin/notes/${noteId}`, 'DELETE').then(res => { if (res.success) { showMessage('Note deleted.', 'success'); handleViewNotesClick(); }});}}
|
||||
}
|
||||
|
||||
// --- NEW: Handler for editing a time-off request ---
|
||||
async function handleEditTimeOffSubmit(e) {
|
||||
e.preventDefault();
|
||||
const id = e.target.elements['edit-request-id'].value;
|
||||
@ -231,7 +264,7 @@ async function handleEditTimeOffSubmit(e) {
|
||||
if (res.success) {
|
||||
showMessage(res.data.message, 'success');
|
||||
document.getElementById('modal-container').innerHTML = '';
|
||||
renderEmployeeDashboard(); // Refresh the dashboard to show changes
|
||||
renderEmployeeDashboard();
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,12 +274,10 @@ export function attachAuthFormListener() {
|
||||
if (form) form.addEventListener('submit', handleAuthSubmit);
|
||||
}
|
||||
|
||||
// --- UPDATED: Employee dashboard listeners now use event delegation ---
|
||||
export function attachEmployeeDashboardListeners() {
|
||||
const dashboard = document.getElementById('employee-dashboard');
|
||||
if (!dashboard) return;
|
||||
|
||||
// Use one listener for the entire dashboard
|
||||
dashboard.addEventListener('click', async (e) => {
|
||||
const target = e.target;
|
||||
|
||||
@ -271,7 +302,6 @@ export function attachEmployeeDashboardListeners() {
|
||||
}
|
||||
if (target.classList.contains('edit-request-btn')) {
|
||||
const id = target.dataset.id;
|
||||
// We need to get the full request data to pre-fill the form
|
||||
const res = await apiCall('/user/time-off-requests/history');
|
||||
if (res.success) {
|
||||
const requestToEdit = res.data.find(r => r.id == id);
|
||||
@ -282,7 +312,6 @@ export function attachEmployeeDashboardListeners() {
|
||||
}
|
||||
});
|
||||
|
||||
// Handle form submissions separately
|
||||
const timeOffForm = document.getElementById('time-off-form');
|
||||
if (timeOffForm) {
|
||||
timeOffForm.addEventListener('submit', handleTimeOffRequest);
|
||||
|
||||
@ -201,7 +201,30 @@ export async function renderAdminDashboard() {
|
||||
<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><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>
|
||||
<button class="admin-delete-request-btn font-medium text-gray-500 hover:underline" data-id="${r.id}">Delete</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('') || '<tr><td colspan="4" class="text-center p-4">No pending requests.</td></tr>'}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-xl font-bold text-gray-700 mb-4">Employee Notes</h3>
|
||||
<form id="add-note-form" class="space-y-3 bg-gray-50 p-4 rounded-lg">
|
||||
@ -263,7 +286,38 @@ export function renderTimeOffHistoryView() {
|
||||
if (!res.success) return;
|
||||
showView('timeOffHistory');
|
||||
mainViews.timeOffHistory.innerHTML = `
|
||||
<div class="max-w-6xl mx-auto bg-white rounded-xl shadow-md p-6"><div class="flex justify-between items-center mb-4"><h2 class="text-2xl font-bold">Time Off History</h2><button id="back-to-dash-btn" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600">Back to Dashboard</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">Status</th></tr></thead><tbody>${res.data.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 font-medium capitalize text-${r.status === 'approved' ? 'green' : 'red'}-600">${r.status}</td></tr>`).join('') || '<tr><td colspan="4" class="text-center p-4">No history.</td></tr>'}</tbody></table></div></div>`;
|
||||
<div class="max-w-6xl mx-auto bg-white rounded-xl shadow-md p-6">
|
||||
<div class="flex justify-between items-center mb-4"><h2 class="text-2xl font-bold">Time Off History</h2><button id="back-to-dash-btn" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600">Back to Dashboard</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">Status</th>
|
||||
<th class="p-2">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${res.data.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 font-medium capitalize text-${r.status === 'approved' ? 'green' : 'red'}-600">${r.status}</td>
|
||||
<td class="p-2">
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<button class="set-pending-btn font-medium text-blue-600 hover:underline" data-id="${r.id}">Set to Pending</button>
|
||||
<button class="admin-delete-request-btn font-medium text-red-600 hover:underline" data-id="${r.id}">Delete</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('') || '<tr><td colspan="5" class="text-center p-4">No history.</td></tr>'}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>`;
|
||||
document.getElementById('back-to-dash-btn').addEventListener('click', renderAdminDashboard);
|
||||
});
|
||||
}
|
||||
@ -374,6 +428,7 @@ export function updatePendingRequestsList(requests) {
|
||||
<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>
|
||||
<button class="admin-delete-request-btn font-medium text-gray-500 hover:underline" data-id="${r.id}">Delete</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
13
server.js
13
server.js
@ -385,6 +385,19 @@ function setupRoutes() {
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/admin/time-off-requests/:id', authenticateToken, requireRole('admin'), async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const result = await db.run('DELETE FROM time_off_requests WHERE id = ?', [id]);
|
||||
if (result.changes === 0) {
|
||||
return res.status(404).json({ message: "Request not found." });
|
||||
}
|
||||
res.json({ message: 'Time off request permanently deleted.' });
|
||||
} catch (err) {
|
||||
res.status(500).json({ message: 'Error deleting time off request.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/admin/notes', authenticateToken, requireRole('admin'), async (req, res) => {
|
||||
try {
|
||||
const { userId, noteText } = req.body;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user