diff --git a/src/js/app.js b/src/js/app.js index 2cf299d..c8f42ab 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -5,6 +5,7 @@ import { launchSSE, launchWS } from './services'; import { SUBSCRIPTION, WS } from './constants'; document.addEventListener('DOMContentLoaded', () => { + // TODO: Переместить все handlers в отдельные файлы??? const submitNickname = (e) => { e.preventDefault(); const modal = document.querySelector('.modal'); @@ -66,13 +67,15 @@ document.addEventListener('DOMContentLoaded', () => { return; } - const messageItem = { + const data = { message, client: GLOBAL_STATE.userName, date: new Date().getTime(), }; - - WS.send(JSON.stringify(messageItem)); + WS.send(JSON.stringify({ + type: 'add', + data, + })); e.target.reset(); }; @@ -98,7 +101,7 @@ document.addEventListener('DOMContentLoaded', () => { input.addEventListener('click', hideError); }; - function handleCreateMessage() { + const handleCreateMessage = () => { const form = document.forms['create-message']; const input = form.querySelector('.form__input'); const errorContainer = form.querySelector('.form__validator-container'); @@ -114,7 +117,7 @@ document.addEventListener('DOMContentLoaded', () => { form.addEventListener('submit', submitMessage); input.addEventListener('click', hideError); - } + }; try { if (document.forms.length === 0) throw new Error('отсутствуют формы на странице'); diff --git a/src/js/constants.js b/src/js/constants.js index dedd360..4737e8c 100644 --- a/src/js/constants.js +++ b/src/js/constants.js @@ -1,6 +1,7 @@ import SubscriptionApi from '../api/SubscriptionApi'; export const SERVER_URL = 'http://localhost:7070/'; +// export const SERVER_URL = 'http://192.168.14.55:9000/'; export const SERVER_URL_WS = `${SERVER_URL}ws`; export const SERVER_URL_SSE = `${SERVER_URL}sse`; export const SSE = new EventSource(SERVER_URL_SSE); diff --git a/src/js/creatingElements.js b/src/js/creatingElements.js index 6b05444..5321128 100644 --- a/src/js/creatingElements.js +++ b/src/js/creatingElements.js @@ -1,3 +1,4 @@ +import { handleRemoveMessage } from './handlers'; import { formatDate } from './helpers'; import { GLOBAL_STATE } from './store'; @@ -11,15 +12,47 @@ export function createNewSubscriber(name) { subscriptions.appendChild(subscriber); } -export function createMessage({ message, date, client }) { - const chat = document.querySelector('.chat__messages'); - const container = document.querySelector('.chat__container'); +const createRemoveButton = ({ parent, id }) => { + const remove = document.createElement('button'); + remove.setAttribute('type', 'button'); + remove.classList.add('chat__message-remove'); + remove.dataset.id = id; + remove.textContent = 'Удалить'; + remove.addEventListener('click', handleRemoveMessage); + parent.appendChild(remove); +}; + +const createMessageText = ({ + deleted, message, id, parent, client, +}) => { + const paragraph = document.createElement('p'); + paragraph.classList.add('chat__message'); + + if (deleted) { + paragraph.classList.add('chat__message_italic'); + paragraph.textContent = 'Сообщение удалено'; + return paragraph; + } + + if (client === GLOBAL_STATE.userName) createRemoveButton({ parent, id }); + paragraph.textContent = message; + + return paragraph; +}; +export const createMessage = ({ + id, + message, + client, + date, + deleted, +}) => { const itemMessage = document.createElement('li'); const nickname = document.createElement('h3'); nickname.classList.add('chat__message-nickname'); itemMessage.classList.add('chat__message-item'); + itemMessage.dataset.id = id; if (client !== GLOBAL_STATE.userName) nickname.textContent = client; if (client === GLOBAL_STATE.userName) { @@ -29,20 +62,33 @@ export function createMessage({ message, date, client }) { const time = document.createElement('time'); time.classList.add('chat__message-time'); - const timeSendingMessage = new Date(date); + const timeSendingMessage = new Date(parseInt(date, 10)); time.textContent = ` ${formatDate(timeSendingMessage)}`; nickname.appendChild(time); - const text = document.createElement('p'); - text.classList.add('chat__message'); - text.textContent = message; + const text = createMessageText({ + deleted, message, id, parent: nickname, client, + }); itemMessage.appendChild(nickname); itemMessage.appendChild(text); + return itemMessage; +}; + +export const removeMessage = (message) => { + const [id, messageData] = Object.entries(message)[0]; + const newMessage = createMessage({ id, ...messageData }); + const messages = document.querySelectorAll('.chat__message-item'); + const deletedMessage = [...messages].find((item) => item.dataset.id === id); + deletedMessage.replaceWith(newMessage); +}; - chat.appendChild(itemMessage); +export const insertInChat = ({ element }) => { + const chat = document.querySelector('.chat__messages'); + const container = document.querySelector('.chat__container'); + chat.appendChild(element); container.scrollTop = container.scrollHeight; -} +}; export const changeNickname = ({ userName }) => { if (GLOBAL_STATE.allUsers.every((i) => i !== userName)) throw new Error('юзера с данным именем нет в общем списке юзеров'); diff --git a/src/js/handlers.js b/src/js/handlers.js new file mode 100644 index 0000000..36c7e28 --- /dev/null +++ b/src/js/handlers.js @@ -0,0 +1,16 @@ +import { WS } from './constants'; + +export const handleRemoveMessage = (e) => { + const { id } = e.target.dataset; + WS.send(JSON.stringify({ + type: 'delete', + data: { id }, + })); +}; + +export const handleRemoveMessage1 = (id) => { + WS.send(JSON.stringify({ + type: 'delete', + data: id, + })); +}; diff --git a/src/js/services.js b/src/js/services.js index 6ccd458..2ecfaeb 100644 --- a/src/js/services.js +++ b/src/js/services.js @@ -1,7 +1,9 @@ import { SSE, SUBSCRIPTION, WS, } from './constants'; -import { createMessage, createNewSubscriber, removeSubscriber } from './creatingElements'; +import { + createMessage, createNewSubscriber, insertInChat, removeSubscriber, removeMessage, +} from './creatingElements'; import { deleteCompanion, setCompanion } from './store'; export const launchSSE = () => { @@ -87,16 +89,45 @@ export const launchWS = () => { }); WS.addEventListener('message', (e) => { - const data = JSON.parse(e.data); - - data.chat.forEach((item) => { - const { message, client, date } = item; - - createMessage({ - message, - client, - date, - }); - }); + const eventSocket = JSON.parse(e.data); + let element; + switch (eventSocket.type) { + case 'first-load': + Object.entries(eventSocket.data).forEach(([id, data]) => { + const { + message, client, date, deleted, + } = data; + element = createMessage({ + date, + id, + message, + client, + deleted, + }); + + insertInChat({ element }); + }); + break; + case 'add': + Object.entries(eventSocket.data).forEach(([id, data]) => { + const { + message, client, date, deleted, + } = data; + element = createMessage({ + date, + id, + message, + client, + deleted, + }); + insertInChat({ element }); + }); + break; + case 'delete': + removeMessage(eventSocket.data); + break; + default: + break; + } }); }; diff --git a/src/scss/style.scss b/src/scss/style.scss index 377db0b..f57f0b9 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -8,7 +8,7 @@ .chat { position: relative; box-sizing: border-box; - width: 908px; + width: 795px; height: 583px; padding: 64px; margin: auto; @@ -23,7 +23,36 @@ // .chat__container &__container { overflow-y: auto; - // max-height: 200px; + padding-right: 10px; + + &::-webkit-scrollbar-button { + width: 5px; + height: 0; + transform: translateX(-5px); + } + + &::-webkit-scrollbar-track { + background-color: $colorGrey4Cool; + } + + &::-webkit-scrollbar-thumb { + -webkit-border-radius: 0; + border-radius: 0; + background-color: $colorBlue1; + } + + &::-webkit-scrollbar-thumb:hover { + background-color: $colorBlue1; + } + + &::-webkit-resizer { + width: 4px; + height: 0; + } + + &::-webkit-scrollbar { + width: 4px; + } } // .chat__messages @@ -39,6 +68,7 @@ // .chat__message-item &__message-item { + min-width: 40%; width: fit-content; border-bottom: solid 1px $colorGrey3Cool; @@ -51,6 +81,8 @@ // .chat__message-nickname &__message-nickname { + display: flex; + column-gap: 10px; color: $colorGrey3Cool; } @@ -59,10 +91,27 @@ color: $colorGrey3Cool; } + // .chat__message-remove + &__message-remove{ + text-decoration: underline; + font-size: 14px; + color: $colorBlue1; + cursor: pointer; + background: none; + font-weight: 400; + margin-left: auto; + text-underline-position: under; + } + // .chat__message &__message { color: $colorBlackCool; font-weight: 500; + + // .chat__message_italic + &_italic{ + font-style: italic; + } } } diff --git a/src/scss/variables.scss b/src/scss/variables.scss index 127df81..917d110 100644 --- a/src/scss/variables.scss +++ b/src/scss/variables.scss @@ -2,6 +2,8 @@ $fontUbuntu: 'Ubuntu'; $colorUnwhite: #FBFBFB; $colorGrey2Cool: #364347; $colorGrey3Cool: #9AA0A8; +$colorGrey4Cool: #D7E1E7; +$colorTextGrey: #5D6878; $colorBlackCool: #0F1113; $colorBlue1: #285FAA; $colorError: #C71938;