const Card = { socket: null, reconnectTimeout: null, reconnectNumber: 0, username: null, listEntrances: [], listApartment: [], color_status: [ ["var(--ColorThemes2)", "var(--ColorThemes3)"], ["#fbf1e0", "#ff8300"], ["#fce3e2", "#ff0000"], ["#d7ddec", "#2919bd"], ["#d5e9dd", "#11a568"], ["#d7ebfa", "#3fb4fc"], ["#e8dbf5", "#b381eb"] ], init: async (type, id) => { let html = await fetch('/lib/pages/card/index.html').then((response) => response.text()); app.innerHTML = html; house = id; if (Card.socket) Card.socket.close(1000, "Перезапуск соединения"); Card.sort(localStorage.getItem('sort_mode'), false) if (type == "house") { Card.getEntrances({ update: false }); Card.cloud.start(makeid(6)); } // Закриття вікно popup при натисканні за його межі const block_card = document.getElementById('card-new-date'); const mess = block_card.querySelector('.mess'); if (!block_card.dataset.listenerAdded) { block_card.addEventListener('click', function (event) { if (!mess.contains(event.target)) { Card.dateEditor.close(); } }); block_card.dataset.listenerAdded = 'true'; } }, cloud: { status: (mode) => { let cloud_1 = document.getElementById('cloud_1'); let cloud_2 = document.getElementById('cloud_2'); let cloud_3 = document.getElementById('cloud_3'); switch (mode) { case 'sync': cloud_1.setAttribute('data-state', 'active'); cloud_2.setAttribute('data-state', ''); cloud_3.setAttribute('data-state', ''); break; case 'ok': cloud_1.setAttribute('data-state', ''); cloud_2.setAttribute('data-state', 'active'); cloud_3.setAttribute('data-state', ''); break; case 'err': cloud_1.setAttribute('data-state', ''); cloud_2.setAttribute('data-state', ''); cloud_3.setAttribute('data-state', 'active'); break; } }, start: (name) => { if (!name) return; Card.username = name; let uuid = localStorage.getItem("uuid"); Card.socket = new WebSocket(`${CONFIG.wss}?uuid=${uuid}`); Card.socket.onopen = function (e) { console.log("[WebSocket | open] З'єднання встановлено"); Card.cloud.status('ok'); const message = { event: 'connection', id: getTimeInSeconds(), date: getTimeInSeconds(), uuid: uuid, username: name, data: { id: 1, entrance_id: 1, apartment_number: 1, title: "1", group_number: 1, status: 1, description: "", created_at: 1727541827, updated_at: 1727541827 } } Card.socket.send(JSON.stringify(message)); Card.reconnectNumber = 0; clearTimeout(Card.reconnectTimeout); }; Card.socket.onmessage = function (event) { let data = JSON.parse(event.data) if (data.event == 'connection') { if (data.username == Card.username) return console.log(`Доданий новий користувач на ім'я ${data.username}`); } else if (data.event == 'message') { Card.cloud.update(data); if (data.username == Card.username) return console.log(`${data.username} пише: `, data.data); } }; Card.socket.onclose = function (event) { if (event.wasClean) { console.log(`[WebSocket | close] З'єднання закрито чисто, код =${event.code} причина=${event.reason}`); Card.cloud.status('err'); } else { console.log(`[WebSocket | close] З'єднання перервано`); Card.cloud.status('err'); Card.reconnectTimeout = setTimeout(function () { Card.reconnectNumber++; if (Card.reconnectNumber > 5) { Card.reconnectNumber = 0; clearTimeout(Card.reconnectTimeout); const result = confirm(`З'єднання розірвано! Перепідключитись?`); if (result) { Card.getEntrances({ update: true }); Card.cloud.start(Card.username); } } else { Card.getEntrances({ update: true }); Card.cloud.start(Card.username); } }, 500); } }; Card.socket.onerror = function (error) { console.log(`[WebSocket | error]`); Card.cloud.status('err'); }; }, mess: ({ number, id, update, time }) => { const pos = Card.listApartment[number].map(e => e.id).indexOf(id); let apartment = Card.listApartment[number][pos]; let status = document.getElementById(`status_${id}`); let description = document.getElementById(`description_${id}`); let date = () => { if (!update && !time) { return apartment.updated_at; } else if (update && !time) { return getTimeInSeconds(); } else if (update && time) { return getTimeInSeconds(time); } } apartment.description = description.value; apartment.status = Number(status.value); apartment.updated_at = date(); status.style.backgroundColor = Card.color_status[status.value][0]; status.style.color = Card.color_status[status.value][1]; status.style.border = `1px solid ${Card.color_status[status.value][1]}`; let message = { event: 'message', id: getTimeInSeconds(), date: getTimeInSeconds(), username: Card.username, data: { id: apartment.id, entrance_id: apartment.entrance_id, apartment_number: apartment.apartment_number, title: apartment.title, group_number: apartment.group_number, status: apartment.status, description: apartment.description, updated_at: apartment.updated_at, sheep_id: USER.id } } if (Card.socket && Card.socket.readyState === WebSocket.OPEN) { Card.socket.send(JSON.stringify(message)); } else { console.warn("WebSocket не підключено. Повідомлення не надіслано."); const result = confirm(`З'єднання розірвано! Перепідключитись?`); if (result) { Card.getEntrances({ update: true }); Card.start(Card.username); } } if (update) { let sort_mode = localStorage.getItem('sort_mode') ?? '1'; if (sort_mode == '3') { let child = document.getElementById(`card_${apartment.id}`); document.getElementById(`apartments_${apartment.entrance_id}`).removeChild(child); document.getElementById(`apartments_${apartment.entrance_id}`).append(child); child.style.border = "1px solid var(--PrimaryColor)"; } else if (sort_mode == '4') { let child = document.getElementById(`card_${apartment.id}`); document.getElementById(`apartments_${apartment.entrance_id}`).removeChild(child); document.getElementById(`apartments_${apartment.entrance_id}`).prepend(child); child.style.border = "1px solid var(--PrimaryColor)"; } } }, update: (message) => { if (!document.getElementById(`status_${message.data.id}`)) return; document.getElementById(`card_${message.data.id}`).style.backgroundColor = Card.color_status[message.data.status][0]; document.getElementById(`card_${message.data.id}`).style.color = Card.color_status[message.data.status][1]; document.getElementById(`card_${message.data.id}`).style.border = `1px solid ${Card.color_status[message.data.status][1]}`; document.getElementById(`status_${message.data.id}`).style.backgroundColor = Card.color_status[message.data.status][0]; document.getElementById(`status_${message.data.id}`).style.color = Card.color_status[message.data.status][1]; document.getElementById(`status_${message.data.id}`).style.border = `1px solid ${Card.color_status[message.data.status][1]}`; document.getElementById(`status_${message.data.id}`).value = message.data.status; document.getElementById(`description_${message.data.id}`).value = message.data.description; document.getElementById(`date_text_${message.data.id}`).innerText = formattedDateTime(message.data.updated_at); } }, getEntrances: ({ house_id = house, update = false }) => { const uuid = localStorage.getItem('uuid'); const URL = `${CONFIG.api}/house/${house_id}/entrances`; fetch(URL, { method: 'GET', headers: { "Content-Type": "application/json", "Authorization": uuid } }) .then(function (response) { return response.json(); }) .then(function (data) { Card.listEntrances = data; const element_list = document.getElementById('list'); if (update) { for (let i = 0; i < Card.listEntrances.length; i++) { const element = Card.listEntrances[i]; Card.getApartment({ id: element.id, number: element.entrance_number, update: update }); } } else { element_list.innerHTML = ""; for (let i = 0; i < Card.listEntrances.length; i++) { const element = Card.listEntrances[i]; let status = () => { if ((element.history.name == "Групова" || element.history.name == USER.name) && element.working) return "open"; else if (USER.mode == 2 || (USER.mode == 1 && USER.possibilities.can_manager_territory)) return "close"; else return "style='display: none;'" } let statusIcon = () => { if ((element.history.name == "Групова" || element.history.name == USER.name) && element.working) return '' else return ' ' } element_list.innerHTML += `

${element.title}

${statusIcon()}
`; Card.getApartment({ id: element.id, number: element.entrance_number, update: false }); } } }) }, getApartment: ({ id, number, update }) => { const uuid = localStorage.getItem('uuid'); const URL = `${CONFIG.api}/apartment/${id}`; fetch(URL, { method: 'GET', headers: { "Content-Type": "application/json", "Authorization": uuid } }) .then(function (response) { return response.json(); }) .then(function (data) { Card.listApartment[number] = data; if (update) { for (let i = 0; i < data.length; i++) { const element = data[i]; let now = new Date(element.updated_at); now.setMinutes(now.getMinutes() - now.getTimezoneOffset()); now = now.toISOString().slice(0, 16) document.getElementById(`card_${element.id}`).setAttribute('style', `border: 1px solid ${Card.color_status[element.status][1]};background: ${Card.color_status[element.status][0]};color: ${Card.color_status[element.status][1]};`); document.getElementById(`status_${element.id}`).value = element.status; document.getElementById(`status_${element.id}`).setAttribute('style', `background-color: ${Card.color_status[element.status][0]}; color: ${Card.color_status[element.status][1]}; border: 1px solid ${Card.color_status[element.status][1]};`); document.getElementById(`date_${element.id}`).setAttribute('onclick', `Card.dateEditor.open({id: ${element.id}, number: ${number}, updated_at: ${element.updated_at}})`); document.getElementById(`date_text_${element.id}`).innerText = element.updated_at ? formattedDateTime(element.updated_at) : "0.0.0000 00:00"; document.getElementById(`description_${element.id}`).innerText = element.description ?? ""; } } else { let sort_mode = localStorage.getItem('sort_mode') ?? 1; if (sort_mode == "1") data.sort((a, b) => a.apartment_number - b.apartment_number); else if (sort_mode == "2") data.sort((a, b) => b.apartment_number - a.apartment_number); else if (sort_mode == "3") data.sort((a, b) => a.updated_at - b.updated_at); else if (sort_mode == "4") data.sort((a, b) => b.updated_at - a.updated_at); else data.sort((a, b) => a.apartment_number - b.apartment_number); for (let i = 0; i < data.length; i++) { const element = data[i]; let now = new Date(element.updated_at); now.setMinutes(now.getMinutes() - now.getTimezoneOffset()); now = now.toISOString().slice(0, 16) let disabled = () => { if (USER.possibilities.can_manager_territory) return ''; else if (element.status == 2) return "disabled"; } document.getElementById(`apartments_${id}`).innerHTML += `
кв.${element.title}
`; } } }) }, sort: (mode, load) => { const sortIds = ['sort_1', 'sort_2', 'sort_3', 'sort_4']; sortIds.forEach(id => { const el = document.getElementById(id); if (el) el.setAttribute('data-state', ''); }); let index = parseInt(mode, 10); if (isNaN(index) || index < 1 || index > 4) index = 1; const activeEl = document.getElementById(`sort_${index}`); if (activeEl) activeEl.setAttribute('data-state', 'active'); localStorage.setItem('sort_mode', index.toString()); if (!load) Card.getEntrances({ update: false }); }, dateEditor: { open: ({ id, number, updated_at }) => { const block = document.getElementById('card-new-date'); const card_new_date_input = document.getElementById('card-new-date-input'); const card_new_date_button = document.getElementById('card-new-date-button'); let now = new Date(updated_at); now.setMinutes(now.getMinutes() - now.getTimezoneOffset()); now = now.toISOString().slice(0, 16) card_new_date_input.value = now; card_new_date_input.setAttribute("onchange", `Card.dateEditor.edit({ id: ${id}, number: ${number} })`) card_new_date_button.setAttribute("onclick", `Card.dateEditor.edit({ id: ${id}, number: ${number}, type: 'now'})`) block.style.display = ""; setTimeout(() => { block.style.opacity = "1"; }, 100) }, close: () => { const block = document.getElementById('card-new-date'); block.style.opacity = "0"; setTimeout(() => { block.style.display = "none"; }, 200) }, edit: ({ id, number, type }) => { const card_new_date_input = document.getElementById('card-new-date-input'); if (type == "now") { Card.cloud.mess({ number: number, id: id, update: true }); } else { if (card_new_date_input.value) { let date = new Date(card_new_date_input.value); const timestamp = date.getTime(); Card.cloud.mess({ number: number, id: id, update: true, time: timestamp }); } else { Card.cloud.mess({ number: number, id: id }); } } Card.dateEditor.close(); } } }