Modularize and fix code

This commit is contained in:
2025-08-20 22:25:27 +03:00
Unverified
parent ac4185ce82
commit 0db7d23e69
10 changed files with 210 additions and 199 deletions
+11 -5
View File
@@ -1,17 +1,20 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru" class="mdui-theme-dark"> <html lang="ru" class="mdui-theme-dark">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Loading...</title> <title>Loading...</title>
<link rel="icon" href="./src/images/logotip.png" viewBox='0 0 100% 100%'> <link rel="icon" href="./src/images/logo.png" />
</head> </head>
<body> <body>
<!-- Login Form --> <!-- Login Form -->
<div id="login-form" class="auth-container"> <div id="login-form" class="auth-container">
<div class="auth-card fade-in"> <div class="auth-card fade-in">
<div class="auth-header"> <div class="auth-header">
<h2><span class="material-symbols filled large">login</span> Добро пожаловать!</h2> <h2>
<span class="material-symbols filled large">login</span>
Добро пожаловать!
</h2>
<p>Войдите в свой аккаунт</p> <p>Войдите в свой аккаунт</p>
</div> </div>
<div class="auth-body"> <div class="auth-body">
@@ -40,7 +43,10 @@
<div id="register-form" class="auth-container" style="display: none;"> <div id="register-form" class="auth-container" style="display: none;">
<div class="auth-card fade-in"> <div class="auth-card fade-in">
<div class="auth-header"> <div class="auth-header">
<h2><span class="material-symbols filled large">person_add</span> Регистрация</h2> <h2>
<span class="material-symbols filled large">person_add</span>
Регистрация
</h2>
<p>Создайте новый аккаунт</p> <p>Создайте новый аккаунт</p>
</div> </div>
<div class="auth-body"> <div class="auth-body">
+1 -1
View File
@@ -1,4 +1,4 @@
import { loadMessages } from "./main"; import { loadMessages } from "./chat";
import type { Headers, ErrorResponse, User, LoginResponse, LoginRequest, RegisterRequest } from "./types"; import type { Headers, ErrorResponse, User, LoginResponse, LoginRequest, RegisterRequest } from "./types";
import { API_BASE_URL } from "./config"; import { API_BASE_URL } from "./config";
+111
View File
@@ -0,0 +1,111 @@
import { getAuthHeaders, currentUser, authToken } from "./auth";
import { API_BASE_URL } from "./config";
import { websocket } from "./websocket";
import type { Message, Messages, WebSocketMessage } from "./types";
import { formatTime } from "./utils";
export function addMessage(message: Message, isAuthor: boolean) {
const messagesContainer = document.querySelector('.chat-messages') as HTMLElement;
const messageDiv = document.createElement('div');
messageDiv.classList.add("message");
if (isAuthor) {
messageDiv.classList.add("sent");
} else {
messageDiv.classList.add("received");
}
messageDiv.dataset.id = `${message.id}`;
const messageInner = document.createElement('div');
messageInner.classList.add('message-inner');
if (!isAuthor) {
const usernameDiv = document.createElement('div');
usernameDiv.classList.add('message-username');
usernameDiv.textContent = message.username;
messageInner.appendChild(usernameDiv);
}
const contentDiv = document.createElement('div');
contentDiv.textContent = message.content;
messageInner.appendChild(contentDiv);
const timeDiv = document.createElement('div');
timeDiv.classList.add('message-time');
timeDiv.textContent = formatTime(message.timestamp);
if (isAuthor && message.is_read) {
const checkIcon = document.createElement('span');
checkIcon.classList.add("material-symbols", "outlined");
timeDiv.appendChild(checkIcon);
}
messageInner.appendChild(timeDiv);
messageDiv.appendChild(messageInner);
messagesContainer.appendChild(messageDiv);
// Прокрутка к новому сообщению
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
export function loadMessages() {
fetch(`${API_BASE_URL}/get_messages`, {
headers: getAuthHeaders()
})
.then(response => response.json())
.then((data: Messages) => {
if (data.messages && data.messages.length > 0) {
const messagesContainer = document.querySelector('.chat-messages') as HTMLElement;
const lastMessage = messagesContainer.lastElementChild as HTMLElement
let lastMessageId: number = 0
if (lastMessage) {
lastMessageId = Number(lastMessage.dataset.id)
}
// Добавляем только новые сообщения
data.messages.forEach(msg => {
if (msg.id > lastMessageId) {
addMessage(msg, msg.username == currentUser!.username);
}
});
}
});
}
export function sendMessage() {
const input = document.querySelector('.message-input') as HTMLInputElement;
const message = input.value.trim();
if (message) {
const payload: WebSocketMessage = {
data: {
content: message
},
credentials: {
scheme: "Bearer",
credentials: authToken!
},
type: "sendMessage"
}
let callback: ((e: MessageEvent) => void) | null = null
callback = (e) => {
websocket.removeEventListener("message", callback!);
const response: WebSocketMessage = JSON.parse(e.data)
console.log(response)
if (!response.error) {
input.value = "";
}
}
websocket.addEventListener("message", callback);
websocket.send(JSON.stringify(payload));
}
}
document.getElementById('message-form')!.addEventListener('submit', (e) => {
e.preventDefault();
sendMessage();
});

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

+7
View File
@@ -0,0 +1,7 @@
import { showLogin } from "./auth";
import { PRODUCT_NAME } from "./config";
showLogin();
document.getElementById("productname")!.textContent = PRODUCT_NAME;
document.title = PRODUCT_NAME;
+36
View File
@@ -0,0 +1,36 @@
import type { Dialog } from "mdui/components/dialog";
// сварачивание и разворачивание чата
const but = document.getElementById('chat-recrol')!;
const but_list1 = document.getElementById('chat1but')!;
const but_list2 = document.getElementById('chat1but2')!;
const cont1 = document.getElementById('conteinerchat')!;
const namechat = document.getElementById('namechat')!;
but.addEventListener('click', () => {
but.style.display = 'none';
cont1.style.display = 'none';
});
but_list1.addEventListener('click', () => {
but.style.display = 'flex';
cont1.style.display = 'flex';
namechat.textContent = 'общий чат';
});
but_list2.addEventListener('click', () => {
but.style.display = 'flex';
cont1.style.display = 'flex';
namechat.textContent = 'общий чат 2';
});
// открытие профиля
const butprofile = document.getElementById('profbut')!;
const dialog = document.getElementById("profile-dialog") as Dialog;
const dialogClose = document.getElementById("profile-dialog-close")!;
butprofile.addEventListener('click', () => {
dialog.open = true;
});
dialogClose.addEventListener("click", () => {
dialog.open = false;
});
+4 -183
View File
@@ -1,187 +1,8 @@
import './css/style.scss'; import './css/style.scss';
import "mdui/mdui.css"; import "mdui/mdui.css";
import { showLogin, getAuthHeaders, authToken, currentUser } from './auth';
import { API_BASE_URL, API_FULL_BASE_URL, PRODUCT_NAME } from './config';
import type { Message, Messages, WebSocketMessage } from './types';
import "./links"; import "./links";
import "./material"; import "./material";
import type { Dialog } from 'mdui/components/dialog.js'; import "./chat";
import "./leftpanel";
const websocket = new WebSocket(`ws://${API_FULL_BASE_URL}/chat/ws`); import "./init";
// Функция для форматирования времени
function formatTime(dateString: string) {
const date = new Date(dateString);
let hours = date.getHours();
let minutes = date.getMinutes();
const hoursString = hours < 10 ? '0' + hours : hours;
const minutesString = minutes < 10 ? '0' + minutes : minutes;
return hoursString + ':' + minutesString;
}
// Добавление нового сообщения в чат
export function addMessage(message: Message, isAuthor: boolean) {
const messagesContainer = document.querySelector('.chat-messages') as HTMLElement;
const messageDiv = document.createElement('div');
messageDiv.classList.add("message");
if (isAuthor) {
messageDiv.classList.add("sent");
} else {
messageDiv.classList.add("received");
}
messageDiv.dataset.id = `${message.id}`;
const messageInner = document.createElement('div');
messageInner.classList.add('message-inner');
if (!isAuthor) {
const usernameDiv = document.createElement('div');
usernameDiv.classList.add('message-username');
usernameDiv.textContent = message.username;
messageInner.appendChild(usernameDiv);
}
const contentDiv = document.createElement('div');
contentDiv.textContent = message.content;
messageInner.appendChild(contentDiv);
const timeDiv = document.createElement('div');
timeDiv.classList.add('message-time');
timeDiv.textContent = formatTime(message.timestamp);
if (isAuthor && message.is_read) {
const checkIcon = document.createElement('span');
checkIcon.classList.add("material-symbols", "outlined");
timeDiv.appendChild(checkIcon);
}
messageInner.appendChild(timeDiv);
messageDiv.appendChild(messageInner);
messagesContainer.appendChild(messageDiv);
// Прокрутка к новому сообщению
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
// Загрузка сообщений
export function loadMessages() {
fetch(`${API_BASE_URL}/get_messages`, {
headers: getAuthHeaders()
})
.then(response => response.json())
.then((data: Messages) => {
if (data.messages && data.messages.length > 0) {
const messagesContainer = document.querySelector('.chat-messages') as HTMLElement;
const lastMessage = messagesContainer.lastElementChild as HTMLElement
let lastMessageId: number = 0
if (lastMessage) {
lastMessageId = Number(lastMessage.dataset.id)
}
// Добавляем только новые сообщения
data.messages.forEach(msg => {
if (msg.id > lastMessageId) {
addMessage(msg, msg.username == currentUser!.username);
}
});
}
});
}
// Отправка сообщения
export function sendMessage() {
const input = document.querySelector('.message-input') as HTMLInputElement;
const message = input.value.trim();
if (message) {
const payload: WebSocketMessage = {
data: {
content: message
},
credentials: {
scheme: "Bearer",
credentials: authToken!
},
type: "sendMessage"
}
let callback: ((e: MessageEvent) => void) | null = null
callback = (e) => {
websocket.removeEventListener("message", callback!);
const response: WebSocketMessage = JSON.parse(e.data)
console.log(response)
if (!response.error) {
input.value = "";
}
}
websocket.addEventListener("message", callback);
websocket.send(JSON.stringify(payload));
}
}
// --------------
// Initialization
// --------------
websocket.addEventListener("message", (e) => {
const message: WebSocketMessage = JSON.parse(e.data);
switch (message.type) {
case "newMessage": {
const newMessage: Message = message.data;
addMessage(newMessage, newMessage.username == currentUser!.username);
break;
}
}
});
showLogin();
document.getElementById('message-form')!.addEventListener('submit', (e) => {
e.preventDefault();
sendMessage();
});
document.getElementById("productname")!.textContent = PRODUCT_NAME;
document.title = PRODUCT_NAME;
// сварачивание и разворачивание чата
const but = document.getElementById('chat-recrol')!;
const but_list1 = document.getElementById('chat1but')!;
const but_list2 = document.getElementById('chat1but2')!;
const cont1 = document.getElementById('conteinerchat')!;
const logout = document.getElementById('logouts')!;
const namechat = document.getElementById('namechat')!;
but.addEventListener('click',() => {
but.style.display = 'none';
cont1.style.display = 'none';
logout.style.display = 'flex';
});
but_list1.addEventListener('click',() => {
but.style.display = 'flex';
cont1.style.display = 'flex';
namechat.textContent = 'общий чат';
});
but_list2.addEventListener('click',() => {
but.style.display = 'flex';
cont1.style.display = 'flex';
namechat.textContent = 'общий чат 2';
});
// открытие профиля
const butprofile = document.getElementById('profbut')!;
const dialog = document.getElementById("profile-dialog") as Dialog;
const dialogClose = document.getElementById("profile-dialog-close")!;
butprofile.addEventListener('click', () => {
dialog.open = true;
});
dialogClose.addEventListener("click", () => {
dialog.open = false;
});
+10 -10
View File
@@ -1,13 +1,13 @@
import 'mdui/components/tabs.js'; import 'mdui/components/tabs';
import 'mdui/components/tab.js'; import 'mdui/components/tab';
import 'mdui/components/tab-panel.js'; import 'mdui/components/tab-panel';
import 'mdui/components/list.js'; import 'mdui/components/list';
import 'mdui/components/list-item.js'; import 'mdui/components/list-item';
import 'mdui/components/bottom-app-bar.js'; import 'mdui/components/bottom-app-bar';
import 'mdui/components/button-icon.js'; import 'mdui/components/button-icon';
import 'mdui/components/fab.js'; import 'mdui/components/fab';
import 'mdui/components/dialog.js'; import 'mdui/components/dialog';
import 'mdui/components/button.js'; import 'mdui/components/button';
import { setColorScheme } from 'mdui/functions/setColorScheme.js'; import { setColorScheme } from 'mdui/functions/setColorScheme.js';
+8
View File
@@ -0,0 +1,8 @@
export function formatTime(dateString: string) {
const date = new Date(dateString);
let hours = date.getHours();
let minutes = date.getMinutes();
const hoursString = hours < 10 ? '0' + hours : hours;
const minutesString = minutes < 10 ? '0' + minutes : minutes;
return hoursString + ':' + minutesString;
}
+22
View File
@@ -0,0 +1,22 @@
import { currentUser } from "./auth";
import { addMessage } from "./chat";
import { API_FULL_BASE_URL } from "./config";
import type { WebSocketMessage, Message } from "./types";
export const websocket = new WebSocket(`ws://${API_FULL_BASE_URL}/chat/ws`);
// --------------
// Initialization
// --------------
websocket.addEventListener("message", (e) => {
const message: WebSocketMessage = JSON.parse(e.data);
switch (message.type) {
case "newMessage": {
const newMessage: Message = message.data;
addMessage(newMessage, newMessage.username == currentUser!.username);
break;
}
}
});