Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Отправка сообщений #22

Merged
merged 21 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c4a45cd
фикс роутера
oFem1m Apr 6, 2024
3d7a9fe
Заготовка под вебсокеты
oFem1m Apr 6, 2024
dcbae6f
Включение/отключение вебсокета при авторизации/выходе
oFem1m Apr 6, 2024
b526e74
Работает отправка сообщений через вебсокеты
oFem1m Apr 6, 2024
9d276e2
Правка config.js
oFem1m Apr 7, 2024
f93726c
Правка config.js
oFem1m Apr 7, 2024
b1dbac3
Правка ws/wss
oFem1m Apr 7, 2024
ffd6ccf
фикс конфига
oFem1m Apr 7, 2024
9670795
Сообщения пользователя и его собеседника находятся в разных сторонах …
oFem1m Apr 7, 2024
eaa59aa
фикс стрелочки
oFem1m Apr 7, 2024
ab93ba5
UserId → userId
oFem1m Apr 7, 2024
2e0a2d0
добавил trim и удаление xss
oFem1m Apr 7, 2024
59a06ac
перенес санитазйер в valid.js
oFem1m Apr 8, 2024
fac7a82
Изменена обработка страниц
oFem1m Apr 8, 2024
a40ba4f
вебсокеты работают!
oFem1m Apr 8, 2024
9e69a3c
фикс бага с черновиками сообщений, обновлением сообщений при переходе…
oFem1m Apr 9, 2024
883a2dc
добавил обработку нажатия enter для отправки сообщения
oFem1m Apr 9, 2024
a702335
теперь браузер не "подсказывает" при вводе сообщения
oFem1m Apr 9, 2024
4e982fb
Merge branch 'develop' into sending_messages
oFem1m Apr 9, 2024
7383ac8
фикс для сливания веток
oFem1m Apr 9, 2024
0027199
prettier fix
oFem1m Apr 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Components/Chat/Chat.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
placeholder='Сообщение...'
value='{{inputMessageValue}}'
/>
<button class='input_send chat-input' disabled>-></button>
<button class='input_send chat-input'>→</button>
</div>
</div>
</main>
6 changes: 5 additions & 1 deletion src/Components/Chat/Chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ export default class Chat extends BaseComponent {

this.getParent()
.querySelector('#input_message')
.addEventListener('input', this.getConfig().inputMessaegHandler);
.addEventListener('input', this.getConfig().inputMessageHandler);

this.getParent()
.querySelector('.input_send')
.addEventListener('click', this.getConfig().sendMessageHandler);
}

setInputMessageValue(value) {
Expand Down
4 changes: 2 additions & 2 deletions src/Components/ChatList/ChatList.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ export default class ChatList extends BaseComponent {
this.getParent()
.querySelector('#profile_btn')
.addEventListener('click', () => {
goToPage('/profile');
goToPage('/profile', true);
});
this.getParent()
.querySelector('#contacts_btn')
.addEventListener('click', () => {
goToPage('/contacts');
goToPage('/contacts', true);
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/Components/Contacts/Contacts.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default class Contacts extends BaseComponent {
.querySelector('#backButton')
.addEventListener('click', () => {
// TODO: Возврат назад
goToPage('/chat');
goToPage('/chat', true);
});
}

Expand Down
7 changes: 5 additions & 2 deletions src/Components/Message/Message.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
:root {
--message-color: var(--white);
--my-message-color: var(--green-light);
--my-message-color: var(--blue-light);
}

.message {
Expand All @@ -14,8 +14,11 @@
}

.my_message {
border-radius: var(--border-radius) var(--border-radius) 1px var(--border-radius);
border-radius: var(--border-radius) var(--border-radius) 1px var(--border-radius);
background-color: var(--my-message-color);
padding: 10px;
max-width: 75%;
margin-left: auto;
margin-right: 0;
margin-bottom: 5px;
}
2 changes: 1 addition & 1 deletion src/Components/Message/Message.hbs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div class="message">
<div class="{{message_owner}}">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вот тут нет ошибки?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Там теперь логика такая, что если id пользователя совпадает с id отправителя сообщения, то используется класс my_message, для которого уже заготовлены стили

Copy link
Collaborator

@johnSamilin johnSamilin Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

так это можно прямо в шаблоне проверить типа через class="{{isCurrentUserOwner ? 'owner' : 'noOwner'}}"

{{message_text}}
</div>
6 changes: 3 additions & 3 deletions src/Components/Profile/Profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ export default class Profile extends BaseComponent {
.querySelector('#backButton')
.addEventListener('click', () => {
// TODO: Возврат назад
goToPage('/chat');
goToPage('/chat', true);
});
this.getParent()
.querySelector('#editButton')
.addEventListener('click', () => {
goToPage('/edit');
goToPage('/edit', true);
});
this.getParent()
.querySelector('#changePasswordButton')
.addEventListener('click', () => {
goToPage('/password');
goToPage('/password', true);
});
}
}
13 changes: 13 additions & 0 deletions src/Pages/BasePage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export class BasePage {
#parent;

constructor(parent) {
this.#parent = parent;
}

render() {
throw new Error('Метод render не определен');
}

async getData() {}
}
7 changes: 5 additions & 2 deletions src/Pages/ChangePasswordPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import Form from '../Components/Form/Form.js';
import { validatePassword } from '../utils/valid.js';
import { ProfileAPI } from '../utils/API/ProfileAPI.js';
import { goToPage } from '../utils/router.js';
import { BasePage } from './BasePage.js';

/**
* Рендерит страницу изменения пароля
* @class Класс страницы изменения пароля
*/
export default class ChangePasswordPage {
export default class ChangePasswordPage extends BasePage {
#parent;

constructor(parent) {
super(parent);
this.#parent = parent;
this.render();
}

formCallback(event) {
Expand Down Expand Up @@ -57,7 +60,7 @@ export default class ChangePasswordPage {
header: 'Изменение пароля',
onSubmit: this.formCallback,
onAdditionButtonClick: () => {
goToPage('/profile');
goToPage('/profile', true);
},
inputs: [
{
Expand Down
160 changes: 115 additions & 45 deletions src/Pages/ChatPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,58 @@ import Chat from '../Components/Chat/Chat.js';
import ChatList from '../Components/ChatList/ChatList.js';
import Message from '../Components/Message/Message.js';
import { ProfileAPI } from '../utils/API/ProfileAPI.js';
import { websocketManager } from '../utils/WebSocket.js';
import { sanitizer } from '../utils/valid.js';
import { BasePage } from './BasePage.js';

/**
/*
* Рендерит страницу чатов
* @class Класс страницы чатов
*/
export default class ChatPage {
export default class ChatPage extends BasePage {
#parent;
#chat;
#chatList;
#messageDrafts = {};
#currentChatId;
#profile;
#chats;

constructor(parent, urlParams) {
super(parent);
this.#parent = parent;
this.#currentChatId = parseInt(urlParams.get('id'));
websocketManager.connect();
websocketManager.setMessageHandler(this.handleWebSocketMessage);
this.getData().then(() => this.render());
}

getData = async () => {
try {
const chatAPI = new ChatAPI();
const profileAPI = new ProfileAPI();

const [chatsResponse, profileResponse] = await Promise.all([
chatAPI.getChats(),
profileAPI.getProfile(),
]);

this.#chats = chatsResponse.body.chats;
if (profileResponse.status !== 200) {
throw new Error('Пришел не 200 статус');
}
this.#profile = profileResponse.body.user;

return {
chats: this.#chats,
profile: this.#profile,
};
} catch (error) {
console.error('Ошибка при получении данных:', error);
throw error;
}
};

render() {
const wrapper = document.createElement('div');
wrapper.classList = 'full-screen';
Expand All @@ -30,60 +65,88 @@ export default class ChatPage {
logoutHandler: this.handleLogout,
});
this.#chatList.render();
this.#chatList.setUserName(`${this.#profile.username}`);

this.#chat = new Chat(wrapper, {
inputMessaegHandler: this.messageDraftHandler,
inputMessageHandler: this.messageDraftHandler,
sendMessageHandler: this.messageSendHandler,
});
this.#chat.render();

this.#parent.appendChild(wrapper);
let checkChatId = false;

const chatAPI = new ChatAPI();
chatAPI
.getChats()
.then((chats) => {
chats.body.chats.forEach((chatConfig) => {
if (chatConfig.id === this.#currentChatId) {
checkChatId = true;
this.displayActiveChat(chatConfig);
}
this.#chatList.addChat(chatConfig, () => {
this.#chat.setInputMessageValue(
this.#messageDrafts[chatConfig.id] || '',
);
this.displayActiveChat(chatConfig);
goToPage('/chat?id=' + chatConfig.id);
});
});
if (!checkChatId && !isNaN(this.#currentChatId)) {
goToPage('/chat');
this.#currentChatId = null;
}
})
.catch((error) => {
console.error('Ошибка при получении чатов:', error);
});

const profileAPI = new ProfileAPI();
profileAPI
.getProfile()
.then((response) => {
if (response.status !== 200) {
throw new Error('Пришел не 200 статус');
}
const profile = response.body.user;
this.#chatList.setUserName(`${profile.username}`);
})
.catch((error) => {
console.error('Ошибка при получении профиля:', error);
});
this.displayChats(this.#chats);
}

messageDraftHandler = (event) => {
this.#messageDrafts[this.#currentChatId] = event.target.value;
};

messageSendHandler = () => {
// Контейнер активного чата
const inputMessage = this.#parent
.querySelector('#input_message')
.value.trim();
const urlParams = new URLSearchParams(window.location.search);
const chatId = parseInt(urlParams.get('id'));
if (inputMessage && chatId) {
// Проверяем, что есть сообщение и ID чата
const sanitizedInputMessage = sanitizer(inputMessage);
websocketManager.sendMessage(chatId, sanitizedInputMessage);
document.querySelector('#input_message').value = '';
} else {
console.error('Нет текста сообщения или ID чата.');
}
};

handleWebSocketMessage = (message) => {
const chatIndex = this.#chats.findIndex(
(chat) => chat.id === message.chat_id,
);
if (chatIndex !== -1) {
const chat = this.#chats.splice(chatIndex, 1)[0];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

проще сделать сортировку через css (свойство order)

this.#chats.unshift(chat);
const activeChatContainer = document.getElementById(
'active-chat-container',
);
const owner =
message.user_id === this.#profile.id ? 'my_message' : 'message';
const messageElement = new Message(activeChatContainer, {
message_owner: owner,
message_text: message.message_text,
});
messageElement.render();
this.#chats[0].messages.push(message); // Добавляем сообщение в начало массива сообщений
this.displayChats(this.#chats); // Обновляем отображение чатов
}
};

displayChats(chats) {
const chatListContainer = document.getElementById(
'chat-list-container',
);
chatListContainer.innerHTML = '';
let checkChatId = false;
chats.forEach((chatConfig) => {
if (chatConfig.id === this.#currentChatId) {
checkChatId = true;
this.displayActiveChat(chatConfig);
}
this.#chatList.addChat(chatConfig, () => {
this.#chat.setInputMessageValue(
this.#messageDrafts[chatConfig.id] || '',
);
this.displayActiveChat(chatConfig);
this.#currentChatId = chatConfig.id;
goToPage('/chat?id=' + chatConfig.id, false);
});
});
this.#messageDrafts[this.#currentChatId] = '';
if (!checkChatId && !isNaN(this.#currentChatId)) {
goToPage('/chat', false);
this.#currentChatId = null;
}
}

displayActiveChat(chat) {
// Очищаем контейнер активного чата
const activeChatContainer = document.getElementById(
Expand Down Expand Up @@ -113,7 +176,13 @@ export default class ChatPage {

// Отображаем сообщения в чате
chat.messages.forEach((message) => {
// Если сообщение от акитивного юзера, то
let owner = 'message';
if (this.#profile.id === message.user_id) {
owner = 'my_message';
}
const messageElement = new Message(activeChatContainer, {
message_owner: owner,
message_text: message.message_text,
});
messageElement.render();
Expand All @@ -129,7 +198,8 @@ export default class ChatPage {
if (data.status === 200) {
// Обработка успешной авторизации
console.log('Successfully logged out');
goToPage('/login');
websocketManager.close();
goToPage('/login', true);
} else {
console.log('Error logged out');
}
Expand Down
Loading