// Single chat view
const ChatView = {
chatId: null,
otherId: null,
otherName: null,
ws: null,
async render(root, params) {
this.chatId = params.chatId;
this.otherId = params.otherId;
this.otherName = params.otherName;
root.innerHTML = `
${escapeHtml(this.otherName || '')}
Редактирование
`;
document.getElementById('chat-back').onclick = () => App.showView('chats');
document.getElementById('chat-profile').onclick = () => App.openUserProfile(this.otherId, this.otherName);
document.getElementById('chat-review').onclick = () => App.openReview(this.chatId, this.otherId, this.otherName);
this.loadMessages();
this.setupWS();
this.markRead();
},
async loadMessages() {
try {
const r = await API.ChatApi.listMessages(this.chatId);
const box = document.getElementById('messages');
box.innerHTML = '';
r.messages.forEach((m) => this.appendMessage(m));
box.scrollTop = box.scrollHeight;
} catch (e) {
console.warn(e);
}
},
appendMessage(m) {
const box = document.getElementById('messages');
const me = API.Store.user && m.sender_id === API.Store.user.id;
const div = document.createElement('div');
div.className = 'bubble ' + (me ? 'mine' : 'theirs');
div.dataset.id = m.id;
if (m.deleted) {
div.innerHTML = 'Удалено';
} else {
div.innerHTML = `
${escapeHtml(m.body)}
${formatTime(m.created_at)}
${m.edited ? 'ред.' : ''}
`;
if (me) {
div.onclick = () => this.onMessageClick(m);
}
}
box.appendChild(div);
box.scrollTop = box.scrollHeight;
},
onMessageClick(m) {
TG_APP.showConfirm('Удалить сообщение?').then((ok) => {
if (ok) this.deleteMessage(m);
});
},
async deleteMessage(m) {
try {
await API.ChatApi.deleteMessage(m.id);
const el = document.querySelector(`.bubble[data-id="${m.id}"]`);
if (el) el.innerHTML = 'Удалено';
} catch (e) {
TG_APP.showAlert('Ошибка: ' + e.message);
}
},
setupWS() {
if (!API.Store.access) return;
const url = (window.API_BASE || 'https://api.buhapp.mygoodservice.ru').replace(/^http/, 'ws') + '/ws?token=' + API.Store.access;
try {
this.ws = new WebSocket(url);
this.ws.onopen = () => console.log('WS connected');
this.ws.onmessage = (ev) => {
try {
const d = JSON.parse(ev.data);
if (d.type === 'message' && d.payload.chat_id === this.chatId) {
this.appendMessage(d.payload);
} else if (d.type === 'message_edited' && d.payload.chat_id === this.chatId) {
this.updateMessage(d.payload);
}
} catch {}
};
this.ws.onclose = () => setTimeout(() => this.setupWS(), 3000);
this.ws.onerror = (e) => console.warn('WS error', e);
} catch (e) {
console.warn(e);
}
},
updateMessage(p) {
const el = document.querySelector(`.bubble[data-id="${p.id}"]`);
if (el) {
el.querySelector('div:first-child') && (el.querySelector('div:first-child').textContent = p.body);
const meta = el.querySelector('.meta');
if (meta && !meta.querySelector('.edited')) {
const ed = document.createElement('span');
ed.className = 'edited';
ed.textContent = 'ред.';
meta.appendChild(ed);
}
}
},
async send() {
const inp = document.getElementById('msg-input');
const body = inp.value.trim();
if (!body) return;
inp.value = '';
try {
await API.ChatApi.sendMessage(this.chatId, body);
// WS пришлёт обратно
} catch (e) {
TG_APP.showAlert('Ошибка: ' + e.message);
}
},
async markRead() {
try { await API.ChatApi.markRead(this.chatId); } catch {}
},
cleanup() {
if (this.ws) { this.ws.close(); this.ws = null; }
},
};
window.ChatView = ChatView;