school44s commited on
Commit
3e183cb
·
verified ·
1 Parent(s): f9bf3b2

Upload 4 files

Browse files
Files changed (4) hide show
  1. index.html +100 -19
  2. index2.html +96 -0
  3. script.js +589 -0
  4. style.css +399 -28
index.html CHANGED
@@ -1,19 +1,100 @@
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="vi">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>DB-chat</title>
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ font-family: Arial, sans-serif;
11
+ line-height: 1.6;
12
+ color: #333;
13
+ }
14
+
15
+ header {
16
+ background: #20232a;
17
+ color: #fff;
18
+ padding: 1rem 2rem;
19
+ display: flex;
20
+ justify-content: space-between;
21
+ align-items: center;
22
+ }
23
+
24
+ header h1 {
25
+ margin: 0;
26
+ font-size: 1.8rem;
27
+ }
28
+
29
+ nav a {
30
+ color: #61dafb;
31
+ margin-left: 20px;
32
+ text-decoration: none;
33
+ font-weight: bold;
34
+ }
35
+
36
+ .hero {
37
+ background: linear-gradient(to right, #00b4db, #0083b0);
38
+ color: white;
39
+ padding: 100px 20px;
40
+ text-align: center;
41
+ }
42
+
43
+ .hero h2 {
44
+ font-size: 2.5rem;
45
+ margin-bottom: 20px;
46
+ }
47
+
48
+ .hero p {
49
+ font-size: 1.2rem;
50
+ margin-bottom: 30px;
51
+ }
52
+
53
+ .hero a {
54
+ background-color: white;
55
+ color: #0083b0;
56
+ padding: 12px 24px;
57
+ text-decoration: none;
58
+ border-radius: 5px;
59
+ font-weight: bold;
60
+ transition: background-color 0.3s;
61
+ }
62
+
63
+ .hero a:hover {
64
+ background-color: #f0f0f0;
65
+ }
66
+
67
+ footer {
68
+ background: #20232a;
69
+ color: white;
70
+ text-align: center;
71
+ padding: 1rem 0;
72
+ position: relative;
73
+ bottom: 0;
74
+ width: 100%;
75
+ }
76
+ </style>
77
+ </head>
78
+ <body>
79
+
80
+ <header>
81
+ <h1>DB-chat</h1>
82
+ <nav>
83
+ <a href="index.html">Trang chủ</a>
84
+ <a href="chat.html">Trò chuyện</a>
85
+ <a href="#">Giới thiệu</a>
86
+ </nav>
87
+ </header>
88
+
89
+ <section class="hero">
90
+ <h2>Chào mừng bạn đến với DB-chat</h2>
91
+ <p>Trải nghiệm nền tảng trò chuyện thông minh và tiện lợi nhất.</p>
92
+ <a href="index2.html">Bắt đầu trò chuyện</a>
93
+ </section>
94
+
95
+ <footer>
96
+ &copy; 2025 DB-chat. Đã đăng ký bản quyền.
97
+ </footer>
98
+
99
+ </body>
100
+ </html>
index2.html ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="vi">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Chat App with Auth</title>
8
+ <script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-app-compat.js"></script>
9
+ <script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-auth-compat.js"></script>
10
+ <script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-database-compat.js"></script>
11
+ <link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet" />
12
+ <link rel="stylesheet" href="style.css" />
13
+ </head>
14
+
15
+ <body>
16
+ <div class="container">
17
+ <div id="auth-section">
18
+ <h2 id="auth-title">Đăng nhập</h2>
19
+ <form id="login-form">
20
+ <div class="form-group">
21
+ <label>Email</label>
22
+ <input type="email" id="login-email" required />
23
+ </div>
24
+ <div class="form-group">
25
+ <label>Mật khẩu</label>
26
+ <input type="password" id="login-password" required />
27
+ </div>
28
+ <button type="submit">Đăng nhập</button>
29
+ <button type="button" class="google-btn" id="google-login">Đăng nhập với Google</button>
30
+ </form>
31
+
32
+ <form id="register-form" class="hidden">
33
+ <div class="form-group">
34
+ <label>Tên tài khoản</label>
35
+ <input type="text" id="register-username" required />
36
+ </div>
37
+ <div class="form-group">
38
+ <label>Email</label>
39
+ <input type="email" id="register-email" required />
40
+ </div>
41
+ <div class="form-group">
42
+ <label>Mật khẩu</label>
43
+ <input type="password" id="register-password" required />
44
+ </div>
45
+ <button type="submit">Đăng ký</button>
46
+ </form>
47
+
48
+ <div class="switch">
49
+ <a href="#" id="toggle-auth">Chưa có tài khoản? Đăng ký</a>
50
+ </div>
51
+ </div>
52
+
53
+ <div id="chat-section" class="hidden">
54
+ <div class="chat-header">
55
+ <button id="roomListToggle" class="menu-btn">☰</button>
56
+ <h2>Xin chào, <span id="display-name"></span></h2>
57
+ <span id="current-room-name">Room chung</span>
58
+ </div>
59
+
60
+ <div class="chat-container">
61
+ <div id="room-sidebar" class="room-sidebar">
62
+ <div class="sidebar-header">
63
+ <h3>Danh sách Room</h3>
64
+ <input type="text" id="roomSearchInput" placeholder="Tìm kiếm phòng..." class="room-search-input">
65
+ <div class="room-actions">
66
+ <button id="createRoomBtn" class="create-room-btn">+ Tạo Room</button>
67
+ <button id="joinRoomBtn" class="join-room-btn">Tham gia Room</button>
68
+ </div>
69
+ </div>
70
+ <div id="room-list" class="room-list"></div>
71
+ <div id="search-results" class="search-results hidden">
72
+ <h4>Kết quả tìm kiếm:</h4>
73
+ <div id="search-room-list" class="room-list"></div>
74
+ </div>
75
+ </div>
76
+
77
+ <div class="chat-main">
78
+ <div class="chat-box" id="chat-box"></div>
79
+ <div id="mediaPreview"></div>
80
+ <div id="inputArea">
81
+ <button class="media-btn" onclick="document.getElementById('imageInput').click()" title="Gửi ảnh">📷</button>
82
+ <button class="media-btn" onclick="document.getElementById('videoInput').click()" title="Gửi video">🎥</button>
83
+ <input type="file" id="imageInput" multiple accept="image/*">
84
+ <input type="file" id="videoInput" accept="video/*">
85
+ <input type="text" id="chat-input" placeholder="Nhập tin nhắn..." />
86
+ <button onclick="sendMessage()">Gửi</button>
87
+ </div>
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+
93
+ <script src="script.js"></script>
94
+ </body>
95
+
96
+ </html>
script.js ADDED
@@ -0,0 +1,589 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Firebase configuration
2
+ const firebaseConfig = {
3
+ apiKey: "AIzaSyDN6tU7Ln3JgeFP7jTprAjSgXDfzunDGQI",
4
+ authDomain: "gay-db7b1.firebaseapp.com",
5
+ databaseURL: "https://gay-db7b1-default-rtdb.firebaseio.com",
6
+ projectId: "gay-db7b1",
7
+ storageBucket: "gay-db7b1.appspot.com",
8
+ messagingSenderId: "959507085021",
9
+ appId: "1:959507085021:web:755901093c2c81d0fb4d34",
10
+ measurementId: "G-1900F4D48J"
11
+ };
12
+
13
+ // Initialize Firebase
14
+ firebase.initializeApp(firebaseConfig);
15
+ const auth = firebase.auth();
16
+ const db = firebase.database();
17
+
18
+ // Global variables
19
+ let currentRoomId = "general";
20
+ let currentUser = null;
21
+
22
+ // DOM elements
23
+ const loginForm = document.getElementById("login-form");
24
+ const registerForm = document.getElementById("register-form");
25
+ const toggleAuth = document.getElementById("toggle-auth");
26
+ const authTitle = document.getElementById("auth-title");
27
+
28
+ // Toggle between login and register forms
29
+ toggleAuth.addEventListener("click", () => {
30
+ loginForm.classList.toggle("hidden");
31
+ registerForm.classList.toggle("hidden");
32
+ authTitle.textContent = loginForm.classList.contains("hidden") ? "Đăng ký" : "Đăng nhập";
33
+ toggleAuth.textContent = loginForm.classList.contains("hidden") ? "Đã có tài khoản? Đăng nhập" : "Chưa có tài khoản? Đăng ký";
34
+ });
35
+
36
+ // Register form handler
37
+ registerForm.addEventListener("submit", (e) => {
38
+ e.preventDefault();
39
+ const username = document.getElementById("register-username").value;
40
+ const email = document.getElementById("register-email").value;
41
+ const password = document.getElementById("register-password").value;
42
+
43
+ auth.createUserWithEmailAndPassword(email, password).then(userCredential => {
44
+ return userCredential.user.updateProfile({ displayName: username });
45
+ }).then(() => {
46
+ document.getElementById("display-name").textContent = auth.currentUser.displayName;
47
+ showChat();
48
+ }).catch(error => alert(error.message));
49
+ });
50
+
51
+ // Login form handler
52
+ loginForm.addEventListener("submit", (e) => {
53
+ e.preventDefault();
54
+ const email = document.getElementById("login-email").value;
55
+ const password = document.getElementById("login-password").value;
56
+
57
+ auth.signInWithEmailAndPassword(email, password).then(() => {
58
+ document.getElementById("display-name").textContent = auth.currentUser.displayName || auth.currentUser.email;
59
+ showChat();
60
+ }).catch(error => alert(error.message));
61
+ });
62
+
63
+ // Google login handler
64
+ document.getElementById("google-login").addEventListener("click", () => {
65
+ const provider = new firebase.auth.GoogleAuthProvider();
66
+ auth.signInWithPopup(provider).then(() => {
67
+ document.getElementById("display-name").textContent = auth.currentUser.displayName;
68
+ showChat();
69
+ }).catch(error => alert(error.message));
70
+ });
71
+
72
+ // Show chat section
73
+ function showChat() {
74
+ document.getElementById("auth-section").classList.add("hidden");
75
+ document.getElementById("chat-section").classList.remove("hidden");
76
+ currentUser = auth.currentUser;
77
+
78
+ // Initialize room functionality
79
+ initializeRooms();
80
+ loadUserRooms();
81
+ setupRoomListeners();
82
+ }
83
+
84
+ // Send message function
85
+ function sendMessage() {
86
+ const input = document.getElementById("chat-input");
87
+ const imageInput = document.getElementById("imageInput");
88
+ const videoInput = document.getElementById("videoInput");
89
+ const text = input.value.trim();
90
+ const images = imageInput.files;
91
+ const videos = videoInput.files;
92
+
93
+ if (!text && images.length === 0 && videos.length === 0) return;
94
+
95
+ // Send text message if exists
96
+ if (text) {
97
+ db.ref(`rooms/${currentRoomId}/messages`).push({
98
+ name: auth.currentUser.displayName || auth.currentUser.email,
99
+ text: text,
100
+ uid: auth.currentUser.uid,
101
+ timestamp: Date.now()
102
+ });
103
+
104
+ // Update room last message
105
+ updateRoomLastMessage(currentRoomId, text);
106
+ }
107
+
108
+ // Send images
109
+ if (images.length > 0) {
110
+ sendImages(images);
111
+ }
112
+
113
+ // Send videos
114
+ if (videos.length > 0) {
115
+ sendVideos(videos);
116
+ }
117
+
118
+ // Clear inputs
119
+ input.value = "";
120
+ imageInput.value = "";
121
+ videoInput.value = "";
122
+ document.getElementById("mediaPreview").innerHTML = "";
123
+ }
124
+
125
+ // Send images function
126
+ async function sendImages(files) {
127
+ for (const file of files) {
128
+ try {
129
+ const base64 = await toBase64(file);
130
+ const imageUrl = await uploadToImgbb(base64);
131
+ if (imageUrl) {
132
+ db.ref(`rooms/${currentRoomId}/messages`).push({
133
+ name: auth.currentUser.displayName || auth.currentUser.email,
134
+ text: "",
135
+ image: imageUrl,
136
+ uid: auth.currentUser.uid,
137
+ timestamp: Date.now()
138
+ });
139
+
140
+ // Update room last message
141
+ updateRoomLastMessage(currentRoomId, "📷 Hình ảnh");
142
+ }
143
+ } catch (error) {
144
+ console.error("Error uploading image:", error);
145
+ alert("Lỗi upload ảnh!");
146
+ }
147
+ }
148
+ }
149
+
150
+ // Send videos function
151
+ async function sendVideos(files) {
152
+ for (const file of files) {
153
+ try {
154
+ showUploadProgress("Đang upload video...");
155
+ const videoUrl = await uploadVideo(file);
156
+ hideUploadProgress();
157
+ if (videoUrl) {
158
+ db.ref(`rooms/${currentRoomId}/messages`).push({
159
+ name: auth.currentUser.displayName || auth.currentUser.email,
160
+ text: "",
161
+ video: videoUrl,
162
+ uid: auth.currentUser.uid,
163
+ timestamp: Date.now()
164
+ });
165
+
166
+ // Update room last message
167
+ updateRoomLastMessage(currentRoomId, "🎥 Video");
168
+ }
169
+ } catch (error) {
170
+ hideUploadProgress();
171
+ console.error("Error uploading video:", error);
172
+ alert("Lỗi upload video!");
173
+ }
174
+ }
175
+ }
176
+
177
+ // Convert file to base64
178
+ function toBase64(file) {
179
+ return new Promise((resolve, reject) => {
180
+ const reader = new FileReader();
181
+ reader.onloadend = () => resolve(reader.result.split(',')[1]);
182
+ reader.onerror = reject;
183
+ reader.readAsDataURL(file);
184
+ });
185
+ }
186
+
187
+ // Upload image to imgbb
188
+ async function uploadToImgbb(base64) {
189
+ const apiKey = "eb64cc8f94a115e3a412694f2a0f10b3";
190
+ const formData = new FormData();
191
+ formData.append("key", apiKey);
192
+ formData.append("image", base64);
193
+
194
+ try {
195
+ const response = await fetch("https://api.imgbb.com/1/upload", {
196
+ method: "POST",
197
+ body: formData
198
+ });
199
+ const result = await response.json();
200
+ return result.data.url;
201
+ } catch (error) {
202
+ console.error("Error uploading to imgbb:", error);
203
+ return null;
204
+ }
205
+ }
206
+
207
+ // Upload video to server
208
+ async function uploadVideo(file) {
209
+ const formData = new FormData();
210
+ formData.append("file", file);
211
+
212
+ try {
213
+ const response = await fetch("http://192.168.1.6:5000/upload", {
214
+ method: "POST",
215
+ body: formData,
216
+ });
217
+
218
+ const result = await response.json();
219
+
220
+ // Check if upload was successful
221
+ if (result.status === "success" && result.data && result.data.url) {
222
+ return result.data.url;
223
+ } else {
224
+ console.error("Upload failed:", result);
225
+ return null;
226
+ }
227
+ } catch (error) {
228
+ console.error("Error uploading video:", error);
229
+ return null;
230
+ }
231
+ }
232
+
233
+ // Show upload progress
234
+ function showUploadProgress(message) {
235
+ const preview = document.getElementById("mediaPreview");
236
+ preview.innerHTML = `
237
+ <div class="upload-progress">
238
+ <div class="upload-progress-bar" style="width: 100%">${message}</div>
239
+ </div>
240
+ `;
241
+ }
242
+
243
+ // Hide upload progress
244
+ function hideUploadProgress() {
245
+ document.getElementById("mediaPreview").innerHTML = "";
246
+ }
247
+
248
+ // Preview selected images
249
+ document.getElementById("imageInput").addEventListener("change", function() {
250
+ const files = this.files;
251
+ const preview = document.getElementById("mediaPreview");
252
+ preview.innerHTML = "";
253
+
254
+ for (const file of files) {
255
+ const reader = new FileReader();
256
+ reader.onload = () => {
257
+ const img = document.createElement("img");
258
+ img.src = reader.result;
259
+ img.title = file.name;
260
+ preview.appendChild(img);
261
+ };
262
+ reader.readAsDataURL(file);
263
+ }
264
+ });
265
+
266
+ // Preview selected videos
267
+ document.getElementById("videoInput").addEventListener("change", function() {
268
+ const files = this.files;
269
+ const preview = document.getElementById("mediaPreview");
270
+ preview.innerHTML = "";
271
+
272
+ for (const file of files) {
273
+ const reader = new FileReader();
274
+ reader.onload = () => {
275
+ const video = document.createElement("video");
276
+ video.src = reader.result;
277
+ video.title = file.name;
278
+ video.controls = true;
279
+ video.muted = true;
280
+ preview.appendChild(video);
281
+ };
282
+ reader.readAsDataURL(file);
283
+ }
284
+ });
285
+
286
+ // Allow Enter key to send message
287
+ document.getElementById("chat-input").addEventListener("keydown", function(event) {
288
+ if (event.key === "Enter") {
289
+ event.preventDefault();
290
+ sendMessage();
291
+ }
292
+ });
293
+
294
+ // Listen for new messages
295
+ const chatBox = document.getElementById("chat-box");
296
+ let messagesListener = null;
297
+
298
+ function listenToMessages() {
299
+ // Remove previous listener
300
+ if (messagesListener) {
301
+ messagesListener.off();
302
+ }
303
+
304
+ // Clear chat box
305
+ chatBox.innerHTML = "";
306
+
307
+ // Listen to current room messages
308
+ messagesListener = db.ref(`rooms/${currentRoomId}/messages`);
309
+ messagesListener.on("child_added", snapshot => {
310
+ const msg = snapshot.val();
311
+ const div = document.createElement("div");
312
+ div.className = "message " + (msg.uid === auth.currentUser?.uid ? "mine" : "other");
313
+
314
+ let content = `<strong>${msg.name}:</strong><br>`;
315
+
316
+ // Add text if exists
317
+ if (msg.text) {
318
+ content += `<span>${msg.text}</span>`;
319
+ }
320
+
321
+ // Add image if exists
322
+ if (msg.image) {
323
+ content += `<br><a href="${msg.image}" target="_blank">
324
+ <img src="${msg.image}" alt="Image" />
325
+ </a>`;
326
+ }
327
+
328
+ // Add video if exists
329
+ if (msg.video) {
330
+ content += `<br><video controls>
331
+ <source src="${msg.video}" type="video/mp4">
332
+ <source src="${msg.video}" type="video/webm">
333
+ Your browser does not support the video tag.
334
+ </video>`;
335
+ }
336
+
337
+ div.innerHTML = content;
338
+ chatBox.appendChild(div);
339
+ chatBox.scrollTop = chatBox.scrollHeight;
340
+ });
341
+ }
342
+
343
+ // Room management functions
344
+ function initializeRooms() {
345
+ // Create general room if not exists
346
+ db.ref('rooms/general').once('value', snapshot => {
347
+ if (!snapshot.exists()) {
348
+ db.ref('rooms/general').set({
349
+ name: "Room chung",
350
+ description: "Phòng chat chung cho tất cả mọi người",
351
+ createdBy: auth.currentUser.uid,
352
+ createdAt: Date.now(),
353
+ members: {
354
+ [auth.currentUser.uid]: {
355
+ name: auth.currentUser.displayName || auth.currentUser.email,
356
+ joinedAt: Date.now()
357
+ }
358
+ }
359
+ });
360
+ } else {
361
+ // Add current user to general room if not already member
362
+ db.ref(`rooms/general/members/${auth.currentUser.uid}`).set({
363
+ name: auth.currentUser.displayName || auth.currentUser.email,
364
+ joinedAt: Date.now()
365
+ });
366
+ }
367
+ });
368
+
369
+ // Switch to general room
370
+ switchToRoom("general", "Room chung");
371
+ }
372
+
373
+ function loadUserRooms() {
374
+ const roomList = document.getElementById("room-list");
375
+
376
+ // Listen for rooms where user is a member
377
+ db.ref('rooms').on('value', snapshot => {
378
+ roomList.innerHTML = "";
379
+ const rooms = snapshot.val();
380
+
381
+ if (rooms) {
382
+ Object.keys(rooms).forEach(roomId => {
383
+ const room = rooms[roomId];
384
+ if (room.members && room.members[auth.currentUser.uid]) {
385
+ createRoomListItem(roomId, room);
386
+ }
387
+ });
388
+ }
389
+ });
390
+ }
391
+
392
+ function createRoomListItem(roomId, room) {
393
+ const roomList = document.getElementById("room-list");
394
+ const roomItem = document.createElement("div");
395
+ roomItem.className = `room-item ${roomId === currentRoomId ? 'active' : ''}`;
396
+ roomItem.dataset.roomId = roomId;
397
+ roomItem.onclick = () => switchToRoom(roomId, room.name);
398
+
399
+ roomItem.innerHTML = `
400
+ <div class="room-info">
401
+ <div class="room-name">${room.name}</div>
402
+ <div class="room-last-message">${room.lastMessage || "Chưa có tin nhắn"}</div>
403
+ </div>
404
+ `;
405
+
406
+ roomList.appendChild(roomItem);
407
+ }
408
+
409
+ function switchToRoom(roomId, roomName) {
410
+ currentRoomId = roomId;
411
+ document.getElementById("current-room-name").textContent = roomName;
412
+
413
+ // Update active room in UI
414
+ document.querySelectorAll(".room-item").forEach(item => {
415
+ item.classList.remove("active");
416
+ });
417
+
418
+ // Find and activate current room by checking data attribute
419
+ document.querySelectorAll(".room-item").forEach(item => {
420
+ if (item.dataset.roomId === roomId) {
421
+ item.classList.add("active");
422
+ }
423
+ });
424
+
425
+ // Load messages for this room
426
+ listenToMessages();
427
+ }
428
+
429
+ function updateRoomLastMessage(roomId, message) {
430
+ db.ref(`rooms/${roomId}/lastMessage`).set(message);
431
+ db.ref(`rooms/${roomId}/lastMessageTime`).set(Date.now());
432
+ }
433
+
434
+ function createRoom() {
435
+ const roomName = prompt("Nhập tên phòng chat:");
436
+ if (!roomName || !roomName.trim()) return;
437
+
438
+ const roomDescription = prompt("Nhập mô tả phòng (tùy chọn):") || `Phòng chat ${roomName.trim()}`;
439
+
440
+ const roomId = 'room_' + Date.now();
441
+ db.ref(`rooms/${roomId}`).set({
442
+ name: roomName.trim(),
443
+ description: roomDescription.trim(),
444
+ createdBy: auth.currentUser.uid,
445
+ createdAt: Date.now(),
446
+ members: {
447
+ [auth.currentUser.uid]: {
448
+ name: auth.currentUser.displayName || auth.currentUser.email,
449
+ joinedAt: Date.now()
450
+ }
451
+ }
452
+ }).then(() => {
453
+ switchToRoom(roomId, roomName.trim());
454
+ alert(`Đã tạo phòng "${roomName.trim()}" thành công!`);
455
+ });
456
+ }
457
+
458
+ function setupRoomListeners() {
459
+ // Room list toggle
460
+ document.getElementById("roomListToggle").addEventListener("click", () => {
461
+ const sidebar = document.getElementById("room-sidebar");
462
+ sidebar.classList.toggle("show");
463
+ });
464
+
465
+ // Create room button
466
+ document.getElementById("createRoomBtn").addEventListener("click", createRoom);
467
+
468
+ // Join room button
469
+ document.getElementById("joinRoomBtn").addEventListener("click", showJoinRoomDialog);
470
+
471
+ // Room search functionality
472
+ const searchInput = document.getElementById("roomSearchInput");
473
+ searchInput.addEventListener("input", handleRoomSearch);
474
+ searchInput.addEventListener("focus", () => {
475
+ if (searchInput.value.trim()) {
476
+ document.getElementById("search-results").classList.remove("hidden");
477
+ }
478
+ });
479
+
480
+ // Hide search results when clicking outside
481
+ document.addEventListener("click", (event) => {
482
+ const sidebar = document.getElementById("room-sidebar");
483
+ const searchResults = document.getElementById("search-results");
484
+
485
+ if (!sidebar.contains(event.target)) {
486
+ searchResults.classList.add("hidden");
487
+ }
488
+ });
489
+ }
490
+
491
+ // Room search functionality
492
+ function handleRoomSearch() {
493
+ const searchTerm = document.getElementById("roomSearchInput").value.trim().toLowerCase();
494
+ const searchResults = document.getElementById("search-results");
495
+ const searchRoomList = document.getElementById("search-room-list");
496
+
497
+ if (!searchTerm) {
498
+ searchResults.classList.add("hidden");
499
+ return;
500
+ }
501
+
502
+ searchResults.classList.remove("hidden");
503
+ searchRoomList.innerHTML = "";
504
+
505
+ // Search all rooms in database
506
+ db.ref('rooms').once('value', snapshot => {
507
+ const rooms = snapshot.val();
508
+ let foundRooms = [];
509
+
510
+ if (rooms) {
511
+ Object.keys(rooms).forEach(roomId => {
512
+ const room = rooms[roomId];
513
+ if (room.name && room.name.toLowerCase().includes(searchTerm)) {
514
+ foundRooms.push({ id: roomId, ...room });
515
+ }
516
+ });
517
+ }
518
+
519
+ if (foundRooms.length === 0) {
520
+ searchRoomList.innerHTML = '<div class="no-results">Không tìm thấy phòng nào</div>';
521
+ } else {
522
+ foundRooms.forEach(room => {
523
+ createSearchResultItem(room.id, room);
524
+ });
525
+ }
526
+ });
527
+ }
528
+
529
+ function createSearchResultItem(roomId, room) {
530
+ const searchRoomList = document.getElementById("search-room-list");
531
+ const roomItem = document.createElement("div");
532
+ const isMember = room.members && room.members[auth.currentUser.uid];
533
+
534
+ roomItem.className = `room-item search-result`;
535
+ roomItem.dataset.roomId = roomId;
536
+
537
+ // Count members
538
+ const memberCount = room.members ? Object.keys(room.members).length : 0;
539
+
540
+ roomItem.innerHTML = `
541
+ <div class="room-info">
542
+ <div class="room-name">${room.name}</div>
543
+ <div class="room-last-message">${room.description || "Không có mô tả"}</div>
544
+ <div class="room-member-count">${memberCount} thành viên</div>
545
+ </div>
546
+ ${isMember ?
547
+ `<button class="room-join-btn" onclick="switchToRoom('${roomId}', '${room.name}'); hideSearchResults();">Vào phòng</button>` :
548
+ `<button class="room-join-btn" onclick="joinRoom('${roomId}', '${room.name}')">Tham gia</button>`
549
+ }
550
+ `;
551
+
552
+ searchRoomList.appendChild(roomItem);
553
+ }
554
+
555
+ function joinRoom(roomId, roomName) {
556
+ // Add user to room members
557
+ db.ref(`rooms/${roomId}/members/${auth.currentUser.uid}`).set({
558
+ name: auth.currentUser.displayName || auth.currentUser.email,
559
+ joinedAt: Date.now()
560
+ }).then(() => {
561
+ // Switch to the joined room
562
+ switchToRoom(roomId, roomName);
563
+ hideSearchResults();
564
+ alert(`Đã tham gia phòng "${roomName}" thành công!`);
565
+ }).catch(error => {
566
+ console.error("Error joining room:", error);
567
+ alert("Lỗi khi tham gia phòng!");
568
+ });
569
+ }
570
+
571
+ function hideSearchResults() {
572
+ document.getElementById("search-results").classList.add("hidden");
573
+ document.getElementById("roomSearchInput").value = "";
574
+ }
575
+
576
+ function showJoinRoomDialog() {
577
+ const roomId = prompt("Nhập ID phòng muốn tham gia:");
578
+ if (!roomId || !roomId.trim()) return;
579
+
580
+ // Check if room exists
581
+ db.ref(`rooms/${roomId}`).once('value', snapshot => {
582
+ if (snapshot.exists()) {
583
+ const room = snapshot.val();
584
+ joinRoom(roomId, room.name);
585
+ } else {
586
+ alert("Không tìm thấy phòng với ID này!");
587
+ }
588
+ });
589
+ }
style.css CHANGED
@@ -1,28 +1,399 @@
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
+ box-sizing: border-box;
3
+ font-family: 'Roboto', sans-serif;
4
+ }
5
+
6
+ body {
7
+ margin: 0;
8
+ background: #f0f2f5;
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ min-height: 100vh;
13
+ }
14
+
15
+ .container {
16
+ width: 100%;
17
+ max-width: 500px;
18
+ background: white;
19
+ padding: 1rem;
20
+ border-radius: 10px;
21
+ box-shadow: 0 4px 10px rgba(0,0,0,0.1);
22
+ }
23
+
24
+ .hidden {
25
+ display: none;
26
+ }
27
+
28
+ .form-group {
29
+ display: flex;
30
+ flex-direction: column;
31
+ margin-bottom: 1rem;
32
+ }
33
+
34
+ input {
35
+ padding: 10px;
36
+ margin-top: 4px;
37
+ border: 1px solid #ccc;
38
+ border-radius: 6px;
39
+ }
40
+
41
+ button {
42
+ padding: 10px;
43
+ background: #4CAF50;
44
+ color: white;
45
+ border: none;
46
+ border-radius: 6px;
47
+ cursor: pointer;
48
+ }
49
+
50
+ .chat-box {
51
+ height: 300px;
52
+ overflow-y: auto;
53
+ margin-bottom: 10px;
54
+ background: #f9f9f9;
55
+ padding: 10px;
56
+ border-radius: 6px;
57
+ }
58
+
59
+ .message {
60
+ margin: 5px 0;
61
+ max-width: 80%;
62
+ padding: 8px 12px;
63
+ border-radius: 12px;
64
+ clear: both;
65
+ }
66
+
67
+ .mine {
68
+ background-color: #d2f8d2;
69
+ float: right;
70
+ }
71
+
72
+ .other {
73
+ background-color: #f0d4d4;
74
+ float: left;
75
+ }
76
+
77
+ .switch {
78
+ text-align: center;
79
+ margin-top: 1rem;
80
+ }
81
+
82
+ .google-btn {
83
+ background-color: #4285f4;
84
+ margin-top: 5px;
85
+ }
86
+
87
+ /* Media upload styles */
88
+ #inputArea {
89
+ display: flex;
90
+ padding: 10px;
91
+ background: #fff;
92
+ border-top: 1px solid #ccc;
93
+ gap: 8px;
94
+ align-items: center;
95
+ }
96
+
97
+ #inputArea input[type="text"] {
98
+ flex: 1;
99
+ padding: 10px;
100
+ border-radius: 20px;
101
+ border: 1px solid #ccc;
102
+ }
103
+
104
+ input[type="file"] {
105
+ display: none;
106
+ }
107
+
108
+ .media-btn {
109
+ background: none;
110
+ border: none;
111
+ font-size: 20px;
112
+ cursor: pointer;
113
+ padding: 5px;
114
+ border-radius: 50%;
115
+ }
116
+
117
+ .media-btn:hover {
118
+ background: #f0f0f0;
119
+ }
120
+
121
+ #mediaPreview {
122
+ padding: 10px;
123
+ display: flex;
124
+ flex-wrap: wrap;
125
+ gap: 10px;
126
+ border-top: 1px solid #ccc;
127
+ background: #fafafa;
128
+ }
129
+
130
+ #mediaPreview img, #mediaPreview video {
131
+ max-width: 80px;
132
+ max-height: 80px;
133
+ border-radius: 8px;
134
+ cursor: pointer;
135
+ }
136
+
137
+ .message img {
138
+ max-width: 200px;
139
+ border-radius: 8px;
140
+ margin-top: 5px;
141
+ }
142
+
143
+ .message video {
144
+ max-width: 200px;
145
+ border-radius: 8px;
146
+ margin-top: 5px;
147
+ }
148
+
149
+ .upload-progress {
150
+ background: #e0e0e0;
151
+ border-radius: 10px;
152
+ overflow: hidden;
153
+ margin: 5px 0;
154
+ }
155
+
156
+ .upload-progress-bar {
157
+ height: 20px;
158
+ background: #4CAF50;
159
+ transition: width 0.3s ease;
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ color: white;
164
+ font-size: 12px;
165
+ }
166
+
167
+ /* Chat room styles */
168
+ .chat-header {
169
+ display: flex;
170
+ align-items: center;
171
+ padding: 10px;
172
+ background: #4CAF50;
173
+ color: white;
174
+ gap: 10px;
175
+ }
176
+
177
+ .chat-header h2 {
178
+ margin: 0;
179
+ flex: 1;
180
+ }
181
+
182
+ .menu-btn {
183
+ background: none;
184
+ border: none;
185
+ color: white;
186
+ font-size: 18px;
187
+ cursor: pointer;
188
+ padding: 5px;
189
+ border-radius: 3px;
190
+ }
191
+
192
+ .menu-btn:hover {
193
+ background: rgba(255,255,255,0.2);
194
+ }
195
+
196
+ #current-room-name {
197
+ font-size: 14px;
198
+ opacity: 0.8;
199
+ background: rgba(255,255,255,0.2);
200
+ padding: 4px 8px;
201
+ border-radius: 10px;
202
+ }
203
+
204
+ .chat-container {
205
+ display: flex;
206
+ height: 400px;
207
+ position: relative;
208
+ }
209
+
210
+ .room-sidebar {
211
+ width: 250px;
212
+ background: #f8f9fa;
213
+ border-right: 1px solid #ddd;
214
+ transform: translateX(-100%);
215
+ transition: transform 0.3s ease;
216
+ overflow-y: auto;
217
+ }
218
+
219
+ .room-sidebar.show {
220
+ transform: translateX(0);
221
+ }
222
+
223
+ .sidebar-header {
224
+ padding: 15px;
225
+ border-bottom: 1px solid #ddd;
226
+ background: white;
227
+ }
228
+
229
+ .sidebar-header h3 {
230
+ margin: 0 0 10px 0;
231
+ font-size: 16px;
232
+ }
233
+
234
+ .room-search-input {
235
+ width: 100%;
236
+ padding: 8px 12px;
237
+ border: 1px solid #ddd;
238
+ border-radius: 5px;
239
+ margin-bottom: 10px;
240
+ font-size: 14px;
241
+ }
242
+
243
+ .room-search-input:focus {
244
+ outline: none;
245
+ border-color: #4CAF50;
246
+ }
247
+
248
+ .room-actions {
249
+ display: flex;
250
+ gap: 5px;
251
+ }
252
+
253
+ .create-room-btn, .join-room-btn {
254
+ background: #007bff;
255
+ color: white;
256
+ border: none;
257
+ padding: 8px 12px;
258
+ border-radius: 5px;
259
+ cursor: pointer;
260
+ font-size: 12px;
261
+ flex: 1;
262
+ }
263
+
264
+ .join-room-btn {
265
+ background: #28a745;
266
+ }
267
+
268
+ .create-room-btn:hover {
269
+ background: #0056b3;
270
+ }
271
+
272
+ .join-room-btn:hover {
273
+ background: #1e7e34;
274
+ }
275
+
276
+ .search-results {
277
+ border-top: 1px solid #ddd;
278
+ margin-top: 10px;
279
+ padding-top: 10px;
280
+ }
281
+
282
+ .search-results h4 {
283
+ margin: 0 0 10px 10px;
284
+ font-size: 14px;
285
+ color: #666;
286
+ }
287
+
288
+ .search-results.hidden {
289
+ display: none;
290
+ }
291
+
292
+ .room-list {
293
+ padding: 10px;
294
+ }
295
+
296
+ .room-item {
297
+ display: flex;
298
+ align-items: center;
299
+ padding: 10px;
300
+ margin-bottom: 5px;
301
+ background: white;
302
+ border: 1px solid #e0e0e0;
303
+ border-radius: 8px;
304
+ cursor: pointer;
305
+ transition: all 0.2s;
306
+ }
307
+
308
+ .room-item:hover {
309
+ background: #f0f0f0;
310
+ border-color: #4CAF50;
311
+ }
312
+
313
+ .room-item.active {
314
+ background: #e8f5e8;
315
+ border-color: #4CAF50;
316
+ }
317
+
318
+ .room-info {
319
+ flex: 1;
320
+ }
321
+
322
+ .room-name {
323
+ font-weight: 500;
324
+ margin-bottom: 2px;
325
+ }
326
+
327
+ .room-last-message {
328
+ font-size: 12px;
329
+ color: #666;
330
+ white-space: nowrap;
331
+ overflow: hidden;
332
+ text-overflow: ellipsis;
333
+ }
334
+
335
+ .room-unread {
336
+ background: #ff4444;
337
+ color: white;
338
+ border-radius: 10px;
339
+ padding: 2px 6px;
340
+ font-size: 10px;
341
+ margin-left: 5px;
342
+ }
343
+
344
+ .room-item.search-result {
345
+ border-left: 3px solid #007bff;
346
+ }
347
+
348
+ .room-item.search-result .room-info {
349
+ position: relative;
350
+ }
351
+
352
+ .room-join-btn {
353
+ background: #28a745;
354
+ color: white;
355
+ border: none;
356
+ padding: 4px 8px;
357
+ border-radius: 3px;
358
+ font-size: 10px;
359
+ cursor: pointer;
360
+ margin-left: 5px;
361
+ }
362
+
363
+ .room-join-btn:hover {
364
+ background: #1e7e34;
365
+ }
366
+
367
+ .room-member-count {
368
+ font-size: 11px;
369
+ color: #888;
370
+ margin-top: 2px;
371
+ }
372
+
373
+ .no-results {
374
+ padding: 20px;
375
+ text-align: center;
376
+ color: #666;
377
+ font-style: italic;
378
+ }
379
+
380
+ .chat-main {
381
+ flex: 1;
382
+ display: flex;
383
+ flex-direction: column;
384
+ }
385
+
386
+ @media (max-width: 768px) {
387
+ .room-sidebar {
388
+ position: absolute;
389
+ top: 0;
390
+ left: 0;
391
+ height: 100%;
392
+ z-index: 1000;
393
+ box-shadow: 2px 0 5px rgba(0,0,0,0.1);
394
+ }
395
+
396
+ .chat-container {
397
+ height: 350px;
398
+ }
399
+ }