hotelkeeper-pro / room.html
creatomator's picture
Create a responsive internal web app for hotel housekeeping operations, optimized for tablet and mobile use during room rounds. The homepage should display a visual, clickable grid of all 124 rooms, each linking to a dedicated page showing cleaning status, maintenance needs, and occupancy. Use a dark, low-light-friendly interface inspired by Trello, with muted backgrounds, bright highlight colors, and legible typography for night use. Include a search bar and status filter, plus β€œ+” and β€œβ€“β€ buttons under each category to add or remove shared notes visible to all employees. Add a management dashboard summarizing room statuses, maintenance alerts, and pending cleanings. Implement user roles with two views: Housekeeping Staff(view and update individual room info) and Managers (access full dashboard and editing privileges across all rooms). Enable notification alerts when room statuses change, when maintenance is requested, or when new notes are added, ensuring timely updates for all users.
9529790 verified
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Room Details | HotelKeeper Pro</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen">
<custom-navbar></custom-navbar>
<main class="container mx-auto px-4 py-6">
<div class="flex flex-col md:flex-row gap-6">
<div class="md:w-1/3">
<div class="bg-gray-800 rounded-lg p-4">
<div class="flex justify-between items-center mb-4">
<h1 class="text-2xl font-bold" id="room-number">Room 101</h1>
<span class="status-badge px-3 py-1 rounded-full text-sm font-medium" id="room-status">Clean</span>
</div>
<div class="space-y-4">
<div>
<h3 class="text-gray-400 text-sm mb-1">Current Status</h3>
<div class="flex gap-2 flex-wrap">
<button class="status-btn bg-green-900/50 hover:bg-green-800 px-3 py-1 rounded-full" data-status="clean">Clean</button>
<button class="status-btn bg-red-900/50 hover:bg-red-800 px-3 py-1 rounded-full" data-status="dirty">Dirty</button>
<button class="status-btn bg-yellow-900/50 hover:bg-yellow-800 px-3 py-1 rounded-full" data-status="in-progress">In Progress</button>
<button class="status-btn bg-purple-900/50 hover:bg-purple-800 px-3 py-1 rounded-full" data-status="maintenance">Maintenance</button>
</div>
</div>
<div>
<h3 class="text-gray-400 text-sm mb-1">Occupancy</h3>
<div class="flex gap-2">
<button class="occupancy-btn bg-blue-900/50 hover:bg-blue-800 px-3 py-1 rounded-full" data-occupancy="occupied">Occupied</button>
<button class="occupancy-btn bg-gray-700 hover:bg-gray-600 px-3 py-1 rounded-full" data-occupancy="vacant">Vacant</button>
</div>
</div>
</div>
</div>
<div class="bg-gray-800 rounded-lg p-4 mt-4">
<div class="flex justify-between items-center mb-3">
<h3 class="font-medium">Maintenance Issues</h3>
<button class="add-issue-btn bg-primary-500 hover:bg-primary-600 px-2 py-1 rounded text-sm flex items-center">
<i data-feather="plus" class="w-4 h-4 mr-1"></i> Add
</button>
</div>
<ul class="space-y-2" id="issues-list">
<li class="flex items-center justify-between bg-gray-700/50 px-3 py-2 rounded">
<span>Broken shower head</span>
<button class="text-red-400 hover:text-red-300">
<i data-feather="trash-2" class="w-4 h-4"></i>
</button>
</li>
</ul>
</div>
</div>
<div class="md:w-2/3">
<div class="bg-gray-800 rounded-lg p-4">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold">Room Notes</h2>
<div class="flex gap-2">
<button class="add-note-btn bg-primary-500 hover:bg-primary-600 px-3 py-1 rounded-lg flex items-center">
<i data-feather="plus" class="mr-1"></i> Add Note
</button>
</div>
</div>
<div class="space-y-3" id="notes-container">
<div class="note-card bg-gray-700/50 p-3 rounded-lg">
<div class="flex justify-between items-start mb-2">
<span class="text-sm text-gray-400">Housekeeping - Today</span>
<button class="text-gray-400 hover:text-gray-200">
<i data-feather="x" class="w-4 h-4"></i>
</button>
</div>
<p>Extra towels requested by guest</p>
</div>
</div>
</div>
<div class="bg-gray-800 rounded-lg p-4 mt-4">
<h2 class="text-xl font-bold mb-4">Cleaning Checklist</h2>
<div class="space-y-2">
<label class="flex items-center space-x-3">
<input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
<span>Dust all surfaces</span>
</label>
<label class="flex items-center space-x-3">
<input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
<span>Vacuum carpets</span>
</label>
<label class="flex items-center space-x-3">
<input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
<span>Clean bathroom</span>
</label>
<label class="flex items-center space-x-3">
<input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
<span>Change linens</span>
</label>
<label class="flex items-center space-x-3">
<input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
<span>Restock amenities</span>
</label>
</div>
<button class="mt-4 w-full bg-primary-500 hover:bg-primary-600 px-4 py-2 rounded-lg">
Mark as Complete
</button>
</div>
</div>
</div>
</main>
<custom-footer></custom-footer>
<script src="components/navbar.js"></script>
<script src="components/footer.js"></script>
<script src="script.js"></script>
<script>
feather.replace();
// Get room number from URL
const urlParams = new URLSearchParams(window.location.search);
const roomNumber = urlParams.get('number');
document.getElementById('room-number').textContent = `Room ${roomNumber}`;
// Status buttons functionality
document.querySelectorAll('.status-btn').forEach(btn => {
btn.addEventListener('click', function() {
const status = this.dataset.status;
const statusBadge = document.getElementById('room-status');
// Update badge
statusBadge.textContent = status.charAt(0).toUpperCase() + status.slice(1).replace('-', ' ');
statusBadge.className = 'status-badge px-3 py-1 rounded-full text-sm font-medium';
if (status === 'clean') statusBadge.classList.add('bg-green-900/50', 'text-green-300');
else if (status === 'dirty') statusBadge.classList.add('bg-red-900/50', 'text-red-300');
else if (status === 'in-progress') statusBadge.classList.add('bg-yellow-900/50', 'text-yellow-300');
else if (status === 'maintenance') statusBadge.classList.add('bg-purple-900/50', 'text-purple-300');
// Show notification
showNotification(`Room status updated to ${status}`, 'success');
});
});
// Occupancy buttons
document.querySelectorAll('.occupancy-btn').forEach(btn => {
btn.addEventListener('click', function() {
const occupancy = this.dataset.occupancy;
// Toggle active state
document.querySelectorAll('.occupancy-btn').forEach(b => {
b.classList.remove('bg-blue-900/50', 'bg-gray-700');
b.classList.add('bg-gray-700');
});
if (occupancy === 'occupied') {
this.classList.remove('bg-gray-700');
this.classList.add('bg-blue-900/50');
}
showNotification(`Occupancy set to ${occupancy}`, 'info');
});
});
// Add note functionality
document.querySelector('.add-note-btn')?.addEventListener('click', function() {
const noteText = prompt('Enter your note:');
if (noteText) {
const notesContainer = document.getElementById('notes-container');
const now = new Date().toLocaleString();
notesContainer.insertAdjacentHTML('afterbegin', `
<div class="note-card bg-gray-700/50 p-3 rounded-lg">
<div class="flex justify-between items-start mb-2">
<span class="text-sm text-gray-400">${currentUser.name} - ${now}</span>
<button class="text-gray-400 hover:text-gray-200 delete-note-btn">
<i data-feather="x" class="w-4 h-4"></i>
</button>
</div>
<p>${noteText}</p>
</div>
`);
feather.replace();
showNotification('Note added successfully', 'success');
// Add delete handler to new note
document.querySelector('.delete-note-btn')?.addEventListener('click', function() {
this.closest('.note-card').remove();
showNotification('Note deleted', 'error');
});
}
});
</script>
</body>
</html>