232 lines
6.6 KiB
TypeScript
232 lines
6.6 KiB
TypeScript
import { MsgData, Contact, Convo, Msg, LastMsg, Search, SearchResult, Typing, Pane, Redraw } from './interfaces';
|
|
import notify from 'common/notification';
|
|
import throttle from 'common/throttle';
|
|
import * as network from './network';
|
|
import { scroller } from './view/scroller';
|
|
|
|
export default class MsgCtrl {
|
|
data: MsgData;
|
|
search: Search = {
|
|
input: '',
|
|
};
|
|
pane: Pane;
|
|
loading = false;
|
|
connected = () => true;
|
|
msgsPerPage = 100;
|
|
canGetMoreSince?: Date;
|
|
typing?: Typing;
|
|
textStore?: LichessStorage;
|
|
|
|
constructor(data: MsgData, readonly trans: Trans, readonly redraw: Redraw) {
|
|
this.data = data;
|
|
this.pane = data.convo ? 'convo' : 'side';
|
|
this.connected = network.websocketHandler(this);
|
|
if (this.data.convo) this.onLoadConvo(this.data.convo);
|
|
window.addEventListener('focus', this.setRead);
|
|
}
|
|
|
|
openConvo = (userId: string) => {
|
|
if (this.data.convo?.user.id != userId) {
|
|
this.data.convo = undefined;
|
|
this.loading = true;
|
|
}
|
|
network.loadConvo(userId).then(data => {
|
|
this.data = data;
|
|
this.search.result = undefined;
|
|
this.loading = false;
|
|
if (data.convo) {
|
|
history.replaceState({ contact: userId }, '', `/inbox/${data.convo.user.name}`);
|
|
this.onLoadConvo(data.convo);
|
|
this.redraw();
|
|
} else this.showSide();
|
|
});
|
|
this.pane = 'convo';
|
|
this.redraw();
|
|
};
|
|
|
|
showSide = () => {
|
|
this.pane = 'side';
|
|
this.redraw();
|
|
};
|
|
|
|
getMore = () => {
|
|
if (this.data.convo && this.canGetMoreSince)
|
|
network.getMore(this.data.convo.user.id, this.canGetMoreSince).then(data => {
|
|
if (!this.data.convo || !data.convo || data.convo.user.id != this.data.convo.user.id || !data.convo.msgs[0])
|
|
return;
|
|
if (data.convo.msgs[0].date >= this.data.convo.msgs[this.data.convo.msgs.length - 1].date) return;
|
|
this.data.convo.msgs = this.data.convo.msgs.concat(data.convo.msgs);
|
|
this.onLoadMsgs(data.convo.msgs);
|
|
this.redraw();
|
|
});
|
|
this.canGetMoreSince = undefined;
|
|
this.redraw();
|
|
};
|
|
|
|
private onLoadConvo = (convo: Convo) => {
|
|
this.textStore = lichess.storage.make(`msg:area:${convo.user.id}`);
|
|
this.onLoadMsgs(convo.msgs);
|
|
if (this.typing) {
|
|
clearTimeout(this.typing.timeout);
|
|
this.typing = undefined;
|
|
}
|
|
setTimeout(this.setRead, 500);
|
|
};
|
|
private onLoadMsgs = (msgs: Msg[]) => {
|
|
const oldFirstMsg = msgs[this.msgsPerPage - 1];
|
|
this.canGetMoreSince = oldFirstMsg?.date;
|
|
};
|
|
|
|
post = (text: string) => {
|
|
if (this.data.convo) {
|
|
network.post(this.data.convo.user.id, text);
|
|
const msg: LastMsg = {
|
|
text,
|
|
user: this.data.me.id,
|
|
date: new Date(),
|
|
read: true,
|
|
};
|
|
this.data.convo.msgs.unshift(msg);
|
|
const contact = this.currentContact();
|
|
if (contact) this.addMsg(msg, contact);
|
|
else
|
|
setTimeout(
|
|
() =>
|
|
network.loadContacts().then(data => {
|
|
this.data.contacts = data.contacts;
|
|
this.redraw();
|
|
}),
|
|
1000
|
|
);
|
|
scroller.enable(true);
|
|
this.redraw();
|
|
}
|
|
};
|
|
|
|
receive = (msg: LastMsg) => {
|
|
const contact = this.findContact(msg.user);
|
|
this.addMsg(msg, contact);
|
|
if (contact) {
|
|
let redrawn = false;
|
|
if (msg.user == this.data.convo?.user.id) {
|
|
this.data.convo.msgs.unshift(msg);
|
|
if (document.hasFocus()) redrawn = this.setRead();
|
|
else this.notify(contact, msg);
|
|
this.receiveTyping(msg.user, true);
|
|
}
|
|
if (!redrawn) this.redraw();
|
|
} else
|
|
network.loadContacts().then(data => {
|
|
this.data.contacts = data.contacts;
|
|
this.notify(this.findContact(msg.user)!, msg);
|
|
this.redraw();
|
|
});
|
|
};
|
|
|
|
private addMsg = (msg: LastMsg, contact?: Contact) => {
|
|
if (contact) {
|
|
contact.lastMsg = msg;
|
|
this.data.contacts = [contact].concat(this.data.contacts.filter(c => c.user.id != contact.user.id));
|
|
}
|
|
};
|
|
|
|
private findContact = (userId: string): Contact | undefined => this.data.contacts.find(c => c.user.id == userId);
|
|
|
|
private currentContact = (): Contact | undefined => this.data.convo && this.findContact(this.data.convo.user.id);
|
|
|
|
private notify = (contact: Contact, msg: Msg) => {
|
|
notify(() => `${contact.user.name}: ${msg.text}`);
|
|
};
|
|
|
|
searchInput = (q: string) => {
|
|
this.search.input = q;
|
|
if (q.length > 2)
|
|
network.search(q).then((res: SearchResult) => {
|
|
this.search.result = this.search.input[1] ? res : undefined;
|
|
this.redraw();
|
|
});
|
|
else {
|
|
this.search.result = undefined;
|
|
this.redraw();
|
|
}
|
|
};
|
|
|
|
setRead = () => {
|
|
const msg = this.currentContact()?.lastMsg;
|
|
if (msg && msg.user != this.data.me.id) {
|
|
lichess.pubsub.emit('notify-app.set-read', msg.user);
|
|
if (msg.read) return false;
|
|
msg.read = true;
|
|
network.setRead(msg.user);
|
|
this.redraw();
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
delete = () => {
|
|
const userId = this.data.convo?.user.id;
|
|
if (userId)
|
|
network.del(userId).then(data => {
|
|
this.data = data;
|
|
this.redraw();
|
|
history.replaceState({}, '', '/inbox');
|
|
});
|
|
};
|
|
|
|
report = () => {
|
|
const user = this.data.convo?.user;
|
|
if (user) {
|
|
const text = this.reportableMsg()?.text.slice(0, 140);
|
|
if (text)
|
|
network
|
|
.report(user.name, text)
|
|
.then(_ => alert('Your report has been sent.'))
|
|
.catch(err => alert('Failed to send report: ' + err));
|
|
}
|
|
};
|
|
|
|
reportableMsg = (): Msg | undefined =>
|
|
this.data.convo?.msgs.find(m => m.user != this.data.me.id && m.text.length > 2);
|
|
|
|
block = () => {
|
|
const userId = this.data.convo?.user.id;
|
|
if (userId) network.block(userId).then(() => this.openConvo(userId));
|
|
};
|
|
|
|
unblock = () => {
|
|
const userId = this.data.convo?.user.id;
|
|
if (userId) network.unblock(userId).then(() => this.openConvo(userId));
|
|
};
|
|
|
|
changeBlockBy = (userId: string) => {
|
|
if (userId == this.data.convo?.user.id) this.openConvo(userId);
|
|
};
|
|
|
|
sendTyping = throttle(3000, (user: string) => {
|
|
if (this.textStore?.get()) network.typing(user);
|
|
});
|
|
|
|
receiveTyping = (userId: string, cancel?: any) => {
|
|
if (this.typing) {
|
|
clearTimeout(this.typing.timeout);
|
|
this.typing = undefined;
|
|
}
|
|
if (cancel !== true && this.data.convo?.user.id == userId) {
|
|
this.typing = {
|
|
user: userId,
|
|
timeout: setTimeout(() => {
|
|
if (this.data.convo?.user.id == userId) this.typing = undefined;
|
|
this.redraw();
|
|
}, 3000),
|
|
};
|
|
}
|
|
this.redraw();
|
|
};
|
|
|
|
onReconnect = () => {
|
|
this.data.convo && this.openConvo(this.data.convo.user.id);
|
|
this.redraw();
|
|
};
|
|
}
|