creatomator commited on
Commit
9529790
·
verified ·
1 Parent(s): d463508

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.

Browse files
Files changed (7) hide show
  1. README.md +7 -4
  2. components/footer.js +62 -0
  3. components/navbar.js +106 -0
  4. index.html +138 -19
  5. room.html +203 -0
  6. script.js +130 -0
  7. style.css +81 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Hotelkeeper Pro
3
- emoji: 🏃
4
- colorFrom: purple
5
  colorTo: gray
 
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: HotelKeeper Pro 🏨
3
+ colorFrom: blue
 
4
  colorTo: gray
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/footer.js ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomFooter extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ width: 100%;
9
+ background-color: rgb(17, 24, 39);
10
+ color: rgba(255, 255, 255, 0.6);
11
+ padding: 1.5rem;
12
+ margin-top: 2rem;
13
+ }
14
+ .footer-content {
15
+ max-width: 1200px;
16
+ margin: 0 auto;
17
+ display: flex;
18
+ justify-content: space-between;
19
+ align-items: center;
20
+ flex-wrap: wrap;
21
+ }
22
+ .footer-links {
23
+ display: flex;
24
+ gap: 1.5rem;
25
+ }
26
+ .footer-link {
27
+ color: rgba(255, 255, 255, 0.6);
28
+ text-decoration: none;
29
+ transition: color 0.2s;
30
+ }
31
+ .footer-link:hover {
32
+ color: white;
33
+ }
34
+ .copyright {
35
+ font-size: 0.875rem;
36
+ }
37
+ @media (max-width: 768px) {
38
+ .footer-content {
39
+ flex-direction: column;
40
+ gap: 1rem;
41
+ text-align: center;
42
+ }
43
+ .footer-links {
44
+ order: -1;
45
+ }
46
+ }
47
+ </style>
48
+ <div class="footer-content">
49
+ <div class="copyright">
50
+ &copy; ${new Date().getFullYear()} RoomRanger. All rights reserved.
51
+ </div>
52
+ <div class="footer-links">
53
+ <a href="/privacy" class="footer-link">Privacy</a>
54
+ <a href="/terms" class="footer-link">Terms</a>
55
+ <a href="/contact" class="footer-link">Contact</a>
56
+ <a href="/help" class="footer-link">Help</a>
57
+ </div>
58
+ </div>
59
+ `;
60
+ }
61
+ }
62
+ customElements.define('custom-footer', CustomFooter);
components/navbar.js ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomNavbar extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ width: 100%;
9
+ background-color: rgb(17, 24, 39);
10
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
11
+ }
12
+ .navbar {
13
+ display: flex;
14
+ justify-content: space-between;
15
+ align-items: center;
16
+ padding: 1rem 1.5rem;
17
+ max-width: 100%;
18
+ }
19
+ .logo {
20
+ display: flex;
21
+ align-items: center;
22
+ font-weight: 700;
23
+ font-size: 1.25rem;
24
+ color: white;
25
+ }
26
+ .logo-icon {
27
+ margin-right: 0.75rem;
28
+ color: #3B82F6;
29
+ }
30
+ .nav-links {
31
+ display: flex;
32
+ gap: 1.5rem;
33
+ }
34
+ .nav-link {
35
+ color: rgba(255, 255, 255, 0.7);
36
+ text-decoration: none;
37
+ transition: color 0.2s;
38
+ display: flex;
39
+ align-items: center;
40
+ }
41
+ .nav-link:hover {
42
+ color: white;
43
+ }
44
+ .nav-icon {
45
+ margin-right: 0.5rem;
46
+ width: 1rem;
47
+ height: 1rem;
48
+ }
49
+ .user-menu {
50
+ display: flex;
51
+ align-items: center;
52
+ gap: 1rem;
53
+ }
54
+ .avatar {
55
+ width: 2.5rem;
56
+ height: 2.5rem;
57
+ border-radius: 9999px;
58
+ background-color: rgb(55, 65, 81);
59
+ display: flex;
60
+ align-items: center;
61
+ justify-content: center;
62
+ color: white;
63
+ font-weight: 600;
64
+ }
65
+ @media (max-width: 768px) {
66
+ .nav-links {
67
+ display: none;
68
+ }
69
+ .mobile-menu-button {
70
+ display: block;
71
+ }
72
+ }
73
+ </style>
74
+ <nav class="navbar">
75
+ <a href="/" class="logo">
76
+ <i data-feather="home" class="logo-icon"></i>
77
+ RoomRanger
78
+ </a>
79
+
80
+ <div class="nav-links">
81
+ <a href="/" class="nav-link">
82
+ <i data-feather="grid" class="nav-icon"></i>
83
+ Dashboard
84
+ </a>
85
+ <a href="/rooms.html" class="nav-link">
86
+ <i data-feather="list" class="nav-icon"></i>
87
+ All Rooms
88
+ </a>
89
+ <a href="/reports.html" class="nav-link">
90
+ <i data-feather="file-text" class="nav-icon"></i>
91
+ Reports
92
+ </a>
93
+ <a href="/settings.html" class="nav-link">
94
+ <i data-feather="settings" class="nav-icon"></i>
95
+ Settings
96
+ </a>
97
+ </div>
98
+
99
+ <div class="user-menu">
100
+ <div class="avatar">JD</div>
101
+ </div>
102
+ </nav>
103
+ `;
104
+ }
105
+ }
106
+ customElements.define('custom-navbar', CustomNavbar);
index.html CHANGED
@@ -1,19 +1,138 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>RoomRanger | Dashboard</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <script>
12
+ tailwind.config = {
13
+ darkMode: 'class',
14
+ theme: {
15
+ extend: {
16
+ colors: {
17
+ primary: {
18
+ 500: '#3B82F6',
19
+ 600: '#2563EB'
20
+ },
21
+ secondary: {
22
+ 500: '#10B981',
23
+ 600: '#059669'
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ </script>
30
+ </head>
31
+ <body class="bg-gray-900 text-gray-100 min-h-screen">
32
+ <custom-navbar></custom-navbar>
33
+ <main class="container mx-auto px-4 py-6">
34
+ <div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-6 gap-4">
35
+ <h1 class="text-2xl font-bold">Room Status Dashboard</h1>
36
+
37
+ <div class="flex flex-col sm:flex-row gap-2 w-full md:w-auto">
38
+ <div class="relative w-full">
39
+ <input type="text" placeholder="Search rooms..." class="bg-gray-800 border border-gray-700 rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-primary-500 w-full">
40
+ <i data-feather="search" class="absolute left-3 top-2.5 text-gray-400"></i>
41
+ </div>
42
+
43
+ <div class="flex gap-2">
44
+ <div class="relative">
45
+ <button class="filter-btn bg-primary-500 hover:bg-primary-600 px-4 py-2 rounded-lg flex items-center whitespace-nowrap">
46
+ <i data-feather="filter" class="mr-2"></i> Status Filter
47
+ </button>
48
+ <div class="filter-dropdown hidden absolute right-0 mt-2 bg-gray-800 border border-gray-700 rounded-lg shadow-lg z-10 w-48">
49
+ <ul class="py-1">
50
+ <li><a href="#" class="filter-option block px-4 py-2 hover:bg-gray-700" data-status="all">All Rooms</a></li>
51
+ <li><a href="#" class="filter-option block px-4 py-2 hover:bg-gray-700" data-status="clean">Clean</a></li>
52
+ <li><a href="#" class="filter-option block px-4 py-2 hover:bg-gray-700" data-status="dirty">Dirty</a></li>
53
+ <li><a href="#" class="filter-option block px-4 py-2 hover:bg-gray-700" data-status="in-progress">In Progress</a></li>
54
+ <li><a href="#" class="filter-option block px-4 py-2 hover:bg-gray-700" data-status="maintenance">Maintenance</a></li>
55
+ </ul>
56
+ </div>
57
+ </div>
58
+
59
+ <button id="manager-view-btn" class="hidden bg-purple-600 hover:bg-purple-700 px-4 py-2 rounded-lg flex items-center">
60
+ <i data-feather="bar-chart-2" class="mr-2"></i> Manager View
61
+ </button>
62
+ </div>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="hidden md:block mb-6 p-4 bg-gray-800 rounded-lg" id="stats-dashboard">
67
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
68
+ <div class="stat-card bg-green-900/50 border-l-4 border-green-500 p-3">
69
+ <h3 class="text-gray-400 text-sm">Clean Rooms</h3>
70
+ <p class="text-2xl font-bold" id="clean-count">0</p>
71
+ </div>
72
+ <div class="stat-card bg-red-900/50 border-l-4 border-red-500 p-3">
73
+ <h3 class="text-gray-400 text-sm">Dirty Rooms</h3>
74
+ <p class="text-2xl font-bold" id="dirty-count">0</p>
75
+ </div>
76
+ <div class="stat-card bg-yellow-900/50 border-l-4 border-yellow-500 p-3">
77
+ <h3 class="text-gray-400 text-sm">In Progress</h3>
78
+ <p class="text-2xl font-bold" id="progress-count">0</p>
79
+ </div>
80
+ <div class="stat-card bg-purple-900/50 border-l-4 border-purple-500 p-3">
81
+ <h3 class="text-gray-400 text-sm">Maintenance</h3>
82
+ <p class="text-2xl font-bold" id="maintenance-count">0</p>
83
+ </div>
84
+ </div>
85
+ </div>
86
+
87
+ <div class="grid grid-cols-1 xs:grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3">
88
+ <!-- Room cards will be dynamically generated here -->
89
+ </div>
90
+ </main>
91
+
92
+ <custom-footer></custom-footer>
93
+
94
+ <script src="components/navbar.js"></script>
95
+ <script src="components/footer.js"></script>
96
+ <script src="script.js"></script>
97
+ <script>
98
+ feather.replace();
99
+ // Generate room cards dynamically
100
+ document.addEventListener('DOMContentLoaded', function() {
101
+ const roomGrid = document.querySelector('.grid');
102
+ for (let i = 1; i <= 124; i++) {
103
+ const statuses = ['clean', 'dirty', 'in-progress', 'maintenance'];
104
+ const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
105
+
106
+ roomGrid.innerHTML += `
107
+ <a href="room.html?number=${i}" class="room-card bg-gray-800 rounded-lg p-3 border-l-4 ${randomStatus === 'clean' ? 'border-green-500' : randomStatus === 'dirty' ? 'border-red-500' : randomStatus === 'in-progress' ? 'border-yellow-500' : 'border-purple-500'} hover:bg-gray-700 transition-colors relative">
108
+ <div class="absolute top-2 right-2 flex gap-1">
109
+ <button class="note-btn bg-gray-700 hover:bg-gray-600 rounded-full w-6 h-6 flex items-center justify-center text-xs" data-room="${i}" data-action="add">
110
+ <i data-feather="plus" class="w-3 h-3"></i>
111
+ </button>
112
+ <button class="note-btn bg-gray-700 hover:bg-gray-600 rounded-full w-6 h-6 flex items-center justify-center text-xs" data-room="${i}" data-action="remove">
113
+ <i data-feather="minus" class="w-3 h-3"></i>
114
+ </button>
115
+ </div>
116
+ <div class="flex justify-between items-start">
117
+ <h3 class="font-bold text-lg">Room ${i}</h3>
118
+ <span class="text-xs px-2 py-1 rounded-full ${randomStatus === 'clean' ? 'bg-green-900 text-green-300' : randomStatus === 'dirty' ? 'bg-red-900 text-red-300' : randomStatus === 'in-progress' ? 'bg-yellow-900 text-yellow-300' : 'bg-purple-900 text-purple-300'}">${randomStatus.replace('-', ' ')}</span>
119
+ </div>
120
+ <div class="mt-2 text-sm text-gray-400">
121
+ <div class="flex items-center">
122
+ <i data-feather="${Math.random() > 0.5 ? 'user' : 'user-check'}" class="w-4 h-4 mr-2"></i>
123
+ ${Math.random() > 0.5 ? 'Occupied' : 'Vacant'}
124
+ </div>
125
+ <div class="flex items-center mt-1">
126
+ <i data-feather="alert-circle" class="w-4 h-4 mr-2"></i>
127
+ ${Math.random() > 0.7 ? 'Maintenance' : 'No issues'}
128
+ </div>
129
+ </div>
130
+ </a>
131
+ `;
132
+ }
133
+ feather.replace();
134
+ });
135
+ </script>
136
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
137
+ </body>
138
+ </html>
room.html ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Room Details | HotelKeeper Pro</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ </head>
11
+ <body class="bg-gray-900 text-gray-100 min-h-screen">
12
+ <custom-navbar></custom-navbar>
13
+
14
+ <main class="container mx-auto px-4 py-6">
15
+ <div class="flex flex-col md:flex-row gap-6">
16
+ <div class="md:w-1/3">
17
+ <div class="bg-gray-800 rounded-lg p-4">
18
+ <div class="flex justify-between items-center mb-4">
19
+ <h1 class="text-2xl font-bold" id="room-number">Room 101</h1>
20
+ <span class="status-badge px-3 py-1 rounded-full text-sm font-medium" id="room-status">Clean</span>
21
+ </div>
22
+
23
+ <div class="space-y-4">
24
+ <div>
25
+ <h3 class="text-gray-400 text-sm mb-1">Current Status</h3>
26
+ <div class="flex gap-2 flex-wrap">
27
+ <button class="status-btn bg-green-900/50 hover:bg-green-800 px-3 py-1 rounded-full" data-status="clean">Clean</button>
28
+ <button class="status-btn bg-red-900/50 hover:bg-red-800 px-3 py-1 rounded-full" data-status="dirty">Dirty</button>
29
+ <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>
30
+ <button class="status-btn bg-purple-900/50 hover:bg-purple-800 px-3 py-1 rounded-full" data-status="maintenance">Maintenance</button>
31
+ </div>
32
+ </div>
33
+
34
+ <div>
35
+ <h3 class="text-gray-400 text-sm mb-1">Occupancy</h3>
36
+ <div class="flex gap-2">
37
+ <button class="occupancy-btn bg-blue-900/50 hover:bg-blue-800 px-3 py-1 rounded-full" data-occupancy="occupied">Occupied</button>
38
+ <button class="occupancy-btn bg-gray-700 hover:bg-gray-600 px-3 py-1 rounded-full" data-occupancy="vacant">Vacant</button>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </div>
43
+
44
+ <div class="bg-gray-800 rounded-lg p-4 mt-4">
45
+ <div class="flex justify-between items-center mb-3">
46
+ <h3 class="font-medium">Maintenance Issues</h3>
47
+ <button class="add-issue-btn bg-primary-500 hover:bg-primary-600 px-2 py-1 rounded text-sm flex items-center">
48
+ <i data-feather="plus" class="w-4 h-4 mr-1"></i> Add
49
+ </button>
50
+ </div>
51
+ <ul class="space-y-2" id="issues-list">
52
+ <li class="flex items-center justify-between bg-gray-700/50 px-3 py-2 rounded">
53
+ <span>Broken shower head</span>
54
+ <button class="text-red-400 hover:text-red-300">
55
+ <i data-feather="trash-2" class="w-4 h-4"></i>
56
+ </button>
57
+ </li>
58
+ </ul>
59
+ </div>
60
+ </div>
61
+
62
+ <div class="md:w-2/3">
63
+ <div class="bg-gray-800 rounded-lg p-4">
64
+ <div class="flex justify-between items-center mb-4">
65
+ <h2 class="text-xl font-bold">Room Notes</h2>
66
+ <div class="flex gap-2">
67
+ <button class="add-note-btn bg-primary-500 hover:bg-primary-600 px-3 py-1 rounded-lg flex items-center">
68
+ <i data-feather="plus" class="mr-1"></i> Add Note
69
+ </button>
70
+ </div>
71
+ </div>
72
+
73
+ <div class="space-y-3" id="notes-container">
74
+ <div class="note-card bg-gray-700/50 p-3 rounded-lg">
75
+ <div class="flex justify-between items-start mb-2">
76
+ <span class="text-sm text-gray-400">Housekeeping - Today</span>
77
+ <button class="text-gray-400 hover:text-gray-200">
78
+ <i data-feather="x" class="w-4 h-4"></i>
79
+ </button>
80
+ </div>
81
+ <p>Extra towels requested by guest</p>
82
+ </div>
83
+ </div>
84
+ </div>
85
+
86
+ <div class="bg-gray-800 rounded-lg p-4 mt-4">
87
+ <h2 class="text-xl font-bold mb-4">Cleaning Checklist</h2>
88
+ <div class="space-y-2">
89
+ <label class="flex items-center space-x-3">
90
+ <input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
91
+ <span>Dust all surfaces</span>
92
+ </label>
93
+ <label class="flex items-center space-x-3">
94
+ <input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
95
+ <span>Vacuum carpets</span>
96
+ </label>
97
+ <label class="flex items-center space-x-3">
98
+ <input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
99
+ <span>Clean bathroom</span>
100
+ </label>
101
+ <label class="flex items-center space-x-3">
102
+ <input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
103
+ <span>Change linens</span>
104
+ </label>
105
+ <label class="flex items-center space-x-3">
106
+ <input type="checkbox" class="form-checkbox h-5 w-5 text-primary-500 rounded">
107
+ <span>Restock amenities</span>
108
+ </label>
109
+ </div>
110
+
111
+ <button class="mt-4 w-full bg-primary-500 hover:bg-primary-600 px-4 py-2 rounded-lg">
112
+ Mark as Complete
113
+ </button>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </main>
118
+
119
+ <custom-footer></custom-footer>
120
+
121
+ <script src="components/navbar.js"></script>
122
+ <script src="components/footer.js"></script>
123
+ <script src="script.js"></script>
124
+ <script>
125
+ feather.replace();
126
+
127
+ // Get room number from URL
128
+ const urlParams = new URLSearchParams(window.location.search);
129
+ const roomNumber = urlParams.get('number');
130
+ document.getElementById('room-number').textContent = `Room ${roomNumber}`;
131
+
132
+ // Status buttons functionality
133
+ document.querySelectorAll('.status-btn').forEach(btn => {
134
+ btn.addEventListener('click', function() {
135
+ const status = this.dataset.status;
136
+ const statusBadge = document.getElementById('room-status');
137
+
138
+ // Update badge
139
+ statusBadge.textContent = status.charAt(0).toUpperCase() + status.slice(1).replace('-', ' ');
140
+ statusBadge.className = 'status-badge px-3 py-1 rounded-full text-sm font-medium';
141
+
142
+ if (status === 'clean') statusBadge.classList.add('bg-green-900/50', 'text-green-300');
143
+ else if (status === 'dirty') statusBadge.classList.add('bg-red-900/50', 'text-red-300');
144
+ else if (status === 'in-progress') statusBadge.classList.add('bg-yellow-900/50', 'text-yellow-300');
145
+ else if (status === 'maintenance') statusBadge.classList.add('bg-purple-900/50', 'text-purple-300');
146
+
147
+ // Show notification
148
+ showNotification(`Room status updated to ${status}`, 'success');
149
+ });
150
+ });
151
+
152
+ // Occupancy buttons
153
+ document.querySelectorAll('.occupancy-btn').forEach(btn => {
154
+ btn.addEventListener('click', function() {
155
+ const occupancy = this.dataset.occupancy;
156
+
157
+ // Toggle active state
158
+ document.querySelectorAll('.occupancy-btn').forEach(b => {
159
+ b.classList.remove('bg-blue-900/50', 'bg-gray-700');
160
+ b.classList.add('bg-gray-700');
161
+ });
162
+
163
+ if (occupancy === 'occupied') {
164
+ this.classList.remove('bg-gray-700');
165
+ this.classList.add('bg-blue-900/50');
166
+ }
167
+
168
+ showNotification(`Occupancy set to ${occupancy}`, 'info');
169
+ });
170
+ });
171
+
172
+ // Add note functionality
173
+ document.querySelector('.add-note-btn')?.addEventListener('click', function() {
174
+ const noteText = prompt('Enter your note:');
175
+ if (noteText) {
176
+ const notesContainer = document.getElementById('notes-container');
177
+ const now = new Date().toLocaleString();
178
+
179
+ notesContainer.insertAdjacentHTML('afterbegin', `
180
+ <div class="note-card bg-gray-700/50 p-3 rounded-lg">
181
+ <div class="flex justify-between items-start mb-2">
182
+ <span class="text-sm text-gray-400">${currentUser.name} - ${now}</span>
183
+ <button class="text-gray-400 hover:text-gray-200 delete-note-btn">
184
+ <i data-feather="x" class="w-4 h-4"></i>
185
+ </button>
186
+ </div>
187
+ <p>${noteText}</p>
188
+ </div>
189
+ `);
190
+
191
+ feather.replace();
192
+ showNotification('Note added successfully', 'success');
193
+
194
+ // Add delete handler to new note
195
+ document.querySelector('.delete-note-btn')?.addEventListener('click', function() {
196
+ this.closest('.note-card').remove();
197
+ showNotification('Note deleted', 'error');
198
+ });
199
+ }
200
+ });
201
+ </script>
202
+ </body>
203
+ </html>
script.js ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ // User roles and authentication simulation
3
+ let currentUser = {
4
+ role: 'staff', // Default to staff view
5
+ name: 'Housekeeper'
6
+ };
7
+
8
+ // Check for manager view
9
+ function checkUserRole() {
10
+ const urlParams = new URLSearchParams(window.location.search);
11
+ if (urlParams.has('role') && urlParams.get('role') === 'manager') {
12
+ currentUser.role = 'manager';
13
+ document.getElementById('manager-view-btn').classList.remove('hidden');
14
+ document.getElementById('stats-dashboard').classList.remove('hidden');
15
+ }
16
+ }
17
+
18
+ // Room status counters
19
+ const statusCounts = {
20
+ clean: 0,
21
+ dirty: 0,
22
+ 'in-progress': 0,
23
+ maintenance: 0
24
+ };
25
+
26
+ // Shared functionality across pages
27
+ document.addEventListener('DOMContentLoaded', function() {
28
+ checkUserRole();
29
+
30
+ // Filter functionality
31
+ const filterBtn = document.querySelector('.filter-btn');
32
+ const filterDropdown = document.querySelector('.filter-dropdown');
33
+ const filterOptions = document.querySelectorAll('.filter-option');
34
+ const roomCards = document.querySelectorAll('.room-card');
35
+
36
+ filterBtn.addEventListener('click', () => {
37
+ filterDropdown.classList.toggle('hidden');
38
+ });
39
+
40
+ filterOptions.forEach(option => {
41
+ option.addEventListener('click', (e) => {
42
+ e.preventDefault();
43
+ const status = option.dataset.status;
44
+
45
+ roomCards.forEach(card => {
46
+ if (status === 'all') {
47
+ card.style.display = 'block';
48
+ } else {
49
+ card.style.display = card.classList.contains(`border-${status === 'clean' ? 'green' : status === 'dirty' ? 'red' : status === 'in-progress' ? 'yellow' : 'purple'}-500`) ? 'block' : 'none';
50
+ }
51
+ });
52
+
53
+ filterDropdown.classList.add('hidden');
54
+ });
55
+ });
56
+
57
+ // Count statuses
58
+ document.querySelectorAll('.room-card').forEach(card => {
59
+ if (card.classList.contains('border-green-500')) statusCounts.clean++;
60
+ else if (card.classList.contains('border-red-500')) statusCounts.dirty++;
61
+ else if (card.classList.contains('border-yellow-500')) statusCounts['in-progress']++;
62
+ else if (card.classList.contains('border-purple-500')) statusCounts.maintenance++;
63
+ });
64
+
65
+ // Update stats dashboard
66
+ document.getElementById('clean-count').textContent = statusCounts.clean;
67
+ document.getElementById('dirty-count').textContent = statusCounts.dirty;
68
+ document.getElementById('progress-count').textContent = statusCounts['in-progress'];
69
+ document.getElementById('maintenance-count').textContent = statusCounts.maintenance;
70
+
71
+ // Note buttons functionality
72
+ document.querySelectorAll('.note-btn').forEach(btn => {
73
+ btn.addEventListener('click', (e) => {
74
+ e.stopPropagation();
75
+ const roomNumber = btn.dataset.room;
76
+ const action = btn.dataset.action;
77
+
78
+ if (action === 'add') {
79
+ showNotification(`Note added to Room ${roomNumber}`, 'success');
80
+ } else {
81
+ showNotification(`Note removed from Room ${roomNumber}`, 'error');
82
+ }
83
+ });
84
+ });
85
+
86
+ // Manager view button
87
+ document.getElementById('manager-view-btn')?.addEventListener('click', () => {
88
+ window.location.href = window.location.pathname + '?role=manager';
89
+ });
90
+ // Initialize tooltips
91
+ const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
92
+ tooltipTriggerList.map(function (tooltipTriggerEl) {
93
+ return new bootstrap.Tooltip(tooltipTriggerEl);
94
+ });
95
+
96
+ // Handle status filter dropdown
97
+ const filterButton = document.querySelector('.filter-button');
98
+ if (filterButton) {
99
+ filterButton.addEventListener('click', function() {
100
+ document.querySelector('.filter-dropdown').classList.toggle('hidden');
101
+ });
102
+ }
103
+
104
+ // Close dropdown when clicking outside
105
+ document.addEventListener('click', function(event) {
106
+ if (!event.target.closest('.filter-button') && !event.target.closest('.filter-dropdown')) {
107
+ const dropdowns = document.querySelectorAll('.filter-dropdown');
108
+ dropdowns.forEach(dropdown => {
109
+ dropdown.classList.add('hidden');
110
+ });
111
+ }
112
+ });
113
+ });
114
+
115
+ // Notification system
116
+ function showNotification(message, type = 'info') {
117
+ const notification = document.createElement('div');
118
+ notification.className = `fixed top-4 right-4 z-50 px-6 py-4 rounded-lg shadow-lg flex items-center ${type === 'success' ? 'bg-green-800' : type === 'error' ? 'bg-red-800' : 'bg-primary-700'}`;
119
+ notification.innerHTML = `
120
+ <i data-feather="${type === 'success' ? 'check-circle' : type === 'error' ? 'alert-circle' : 'info'}" class="mr-3"></i>
121
+ <span>${message}</span>
122
+ `;
123
+ document.body.appendChild(notification);
124
+ feather.replace();
125
+
126
+ setTimeout(() => {
127
+ notification.classList.add('opacity-0', 'transition-opacity', 'duration-300');
128
+ setTimeout(() => notification.remove(), 300);
129
+ }, 3000);
130
+ }
style.css CHANGED
@@ -1,28 +1,91 @@
 
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ /* Base styles */
3
  body {
4
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
5
+ -webkit-tap-highlight-color: transparent;
6
+ }
7
+
8
+ /* Dark mode optimized colors */
9
+ .dark {
10
+ --bg-primary: #111827;
11
+ --bg-secondary: #1F2937;
12
+ --text-primary: #F3F4F6;
13
+ --text-secondary: #9CA3AF;
14
+ --highlight-green: #10B981;
15
+ --highlight-red: #EF4444;
16
+ --highlight-yellow: #F59E0B;
17
+ --highlight-purple: #8B5CF6;
18
  }
19
 
20
+ /* Touch-friendly elements */
21
+ button, a {
22
+ -webkit-user-select: none;
23
+ user-select: none;
24
  }
25
 
26
+ .note-btn {
27
+ transition: transform 0.1s ease;
 
 
 
28
  }
29
 
30
+ .note-btn:active {
31
+ transform: scale(0.9);
 
 
 
 
32
  }
33
 
34
+ .stat-card {
35
+ transition: all 0.3s ease;
36
  }
37
+
38
+ .stat-card:hover {
39
+ transform: translateY(-2px);
40
+ }
41
+ /* Room card animations */
42
+ .room-card {
43
+ transition: all 0.2s ease;
44
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
45
+ }
46
+
47
+ .room-card:hover {
48
+ transform: translateY(-2px);
49
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15);
50
+ }
51
+
52
+ /* Status indicators */
53
+ .status-clean {
54
+ border-left-color: #10B981;
55
+ }
56
+
57
+ .status-dirty {
58
+ border-left-color: #EF4444;
59
+ }
60
+
61
+ .status-in-progress {
62
+ border-left-color: #F59E0B;
63
+ }
64
+
65
+ .status-maintenance {
66
+ border-left-color: #8B5CF6;
67
+ }
68
+
69
+ /* Dark mode overrides */
70
+ .dark .status-clean {
71
+ border-left-color: #10B981;
72
+ }
73
+
74
+ .dark .status-dirty {
75
+ border-left-color: #EF4444;
76
+ }
77
+
78
+ .dark .status-in-progress {
79
+ border-left-color: #F59E0B;
80
+ }
81
+
82
+ .dark .status-maintenance {
83
+ border-left-color: #8B5CF6;
84
+ }
85
+
86
+ /* Responsive adjustments */
87
+ @media (max-width: 640px) {
88
+ .room-card {
89
+ padding: 0.75rem;
90
+ }
91
+ }