From 68b0f9c557589ac878a0ae00f9573787bd09f309 Mon Sep 17 00:00:00 2001 From: Alvin <524715@vistacollege.nl> Date: Wed, 22 Oct 2025 14:34:43 +0200 Subject: [PATCH] Add return pending status and related functionality for reservations --- models/Reservation.js | 2 +- public/admin-reservations.html | 1 + public/css/style.css | 6 ++++++ public/js/admin-reservations.js | 11 ++++++++--- public/js/student-reservations.js | 22 ++++++++++++---------- public/student-reservations.html | 1 + routes/reservations.js | 9 +++++---- 7 files changed, 34 insertions(+), 18 deletions(-) diff --git a/models/Reservation.js b/models/Reservation.js index 90fbce0..b93d56f 100644 --- a/models/Reservation.js +++ b/models/Reservation.js @@ -19,7 +19,7 @@ const reservationSchema = new mongoose.Schema({ }, status: { type: String, - enum: ['PENDING', 'APPROVED', 'REJECTED', 'RETURNED', 'ARCHIVED'], + enum: ['PENDING', 'APPROVED', 'REJECTED', 'RETURN_PENDING', 'RETURNED', 'ARCHIVED'], default: 'PENDING' }, reservedDate: { diff --git a/public/admin-reservations.html b/public/admin-reservations.html index 80187e3..b58274f 100644 --- a/public/admin-reservations.html +++ b/public/admin-reservations.html @@ -61,6 +61,7 @@ + diff --git a/public/css/style.css b/public/css/style.css index d1d4e0c..0ab4b84 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -299,6 +299,12 @@ body { border: 1px solid var(--vista-grey); } +.reservation-return_pending { + background-color: #ffc107 !important; + color: var(--vista-blue) !important; + border: 1px solid var(--vista-peach); +} + .reservation-returned { background-color: var(--vista-peach) !important; color: var(--vista-white) !important; diff --git a/public/js/admin-reservations.js b/public/js/admin-reservations.js index 7cde90f..16c79f6 100644 --- a/public/js/admin-reservations.js +++ b/public/js/admin-reservations.js @@ -75,10 +75,15 @@ function filterAndDisplayReservations() { - ` : reservation.status === 'APPROVED' ? ` - + + ` : reservation.status === 'APPROVED' ? ` + Item Loaned ` : reservation.status === 'RETURNED' ? ` ` : reservation.status === 'APPROVED' ? ` - ` : reservation.status === 'REJECTED' ? ` Rejected + ` : reservation.status === 'RETURN_PENDING' ? ` + Return Pending Approval ` : reservation.status === 'RETURNED' ? ` Returned ` : ''} @@ -126,7 +128,7 @@ async function deleteReservation(reservationId) { // Return reservation (mark as returned) async function returnReservation(reservationId) { - if (!confirm('Are you sure you want to return this item?')) return; + if (!confirm('Are you sure you want to request return for this item? An admin will need to approve the return.')) return; try { const response = await fetch(`/api/reservations/${reservationId}`, { @@ -135,29 +137,29 @@ async function returnReservation(reservationId) { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, - body: JSON.stringify({ status: 'RETURNED' }) + body: JSON.stringify({ status: 'RETURN_PENDING' }) }); if (response.ok) { - // Successfully returned, reload reservations + // Successfully requested return, reload reservations await loadReservations(); // Show success message const alert = document.createElement('div'); alert.className = 'alert alert-success alert-dismissible fade show'; alert.innerHTML = ` - Item returned successfully! + Return requested successfully! An admin will review your request. `; const container = document.querySelector('.container'); container.prepend(alert); - setTimeout(() => alert.remove(), 3000); + setTimeout(() => alert.remove(), 5000); } else { const error = await response.json(); - throw new Error(error.message || 'Failed to return item'); + throw new Error(error.message || 'Failed to request return'); } } catch (error) { - console.error('Error returning item:', error); - alert(`Failed to return item: ${error.message}`); + console.error('Error requesting return:', error); + alert(`Failed to request return: ${error.message}`); } } diff --git a/public/student-reservations.html b/public/student-reservations.html index d3ccd9a..a8ac5f4 100644 --- a/public/student-reservations.html +++ b/public/student-reservations.html @@ -58,6 +58,7 @@ + diff --git a/routes/reservations.js b/routes/reservations.js index 6a3aef7..7452220 100644 --- a/routes/reservations.js +++ b/routes/reservations.js @@ -108,18 +108,18 @@ router.patch('/:id', auth, async (req, res) => { // Check authorization const isAdmin = req.user.role === 'admin'; const isOwner = reservation.userId._id.toString() === req.user._id.toString(); - const isReturning = req.body.status === 'RETURNED'; + const isReturning = req.body.status === 'RETURN_PENDING'; if (!isAdmin && (!isOwner || !isReturning)) { return res.status(403).json({ - message: 'Not authorized. Students can only return their own items.' + message: 'Not authorized. Students can only request return of their own items.' }); } // Additional validation for students if (!isAdmin && isReturning && reservation.status !== 'APPROVED') { return res.status(400).json({ - message: 'Can only return approved items' + message: 'Can only request return for approved items' }); } @@ -143,7 +143,8 @@ router.patch('/:id', auth, async (req, res) => { if (oldStatus === 'PENDING' && newStatus === 'REJECTED') { item.reserved = Math.max(0, item.reserved - (reservation.quantity || 1)); await item.save(); - } else if (oldStatus === 'APPROVED' && newStatus === 'RETURNED') { + } else if (oldStatus === 'RETURN_PENDING' && newStatus === 'RETURNED') { + // Admin approved the return item.reserved = Math.max(0, item.reserved - (reservation.quantity || 1)); await item.save(); }