import { Observer } from "../observe/Observer"; import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel"; import { ChatModel } from "../model/ChatModel"; import log = require("loglevel"); import * as DOMPurify from "dompurify"; import { SearchService } from "../service/SearchService"; import { UserModel } from "../model/UserModel"; import { UserViewDeps } from "./UserViewDeps"; import { ObserverData } from "../observe/ObserverData"; import { JsonAPI } from "../singleton/JsonAPI"; import { NotificationService } from "../service/NotificationService"; import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel"; export class UserView implements Observer { private readonly _model: UserModel; private readonly _chatModel: ChatModel; private readonly _usersListElement: HTMLElement; private readonly _userSearchInputElement: HTMLInputElement; private readonly _userSearchButton: HTMLElement; private readonly _userSearchCancelButton: HTMLElement; private readonly _searchService: SearchService; private readonly _userContactOnlineTemplate: Handlebars.TemplateDelegate< ActiveUserViewModel >; private readonly _userContactOfflineTemplate: Handlebars.TemplateDelegate< ActiveUserViewModel >; private readonly _notificationService: NotificationService; private _newMessagesLoop: any; constructor(deps: UserViewDeps) { this._model = deps.model; this._chatModel = deps.chatModel; this._usersListElement = deps.usersListElement; this._userSearchInputElement = deps.userSearchInputElement; this._userSearchButton = deps.userSearchButton; this._userSearchCancelButton = deps.userSearchCancelButton; this._searchService = deps.searchService; this._userContactOnlineTemplate = deps.userContactOnlineTemplate; this._userContactOfflineTemplate = deps.userContactOfflineTemplate; this._notificationService = deps.notificationService; this._addSearchEventListeners(); } update(d: ObserverData): void { let html: string = ""; d.data.forEach((element: ActiveUserViewModel) => { element.online ? (html += this._userContactOnlineTemplate(element)) : (html += this._userContactOfflineTemplate(element)); }); $(this._usersListElement).html(DOMPurify.sanitize(html)); this._addUserCallBacks(); } private _addSearchEventListeners(): void { this._addSearchButtonEL(); this._addSearchCancelEL(); this._addSearchInputEL(); } private _addUserCallBacks(): void { let userBoxes = document.getElementsByClassName("user-box"); Array.from(userBoxes).forEach((ub: Element) => ub.addEventListener("click", this._userCallBack.bind(this, ub)) ); } private _userCallBack(el: Element): void { this._chatModel.clear(); clearInterval(this._newMessagesLoop); let current = document.getElementsByClassName("user-box active"); if (current.length > 0) { current[0].className = current[0].className.replace(" active", ""); } // Add the active class to the current/clicked button else if (current.length == 0) { // @ts-ignore: Object is possibly 'null'. document.getElementById("no-user-selected").hidden = true; // @ts-ignore: Object is possibly 'null'. document.getElementById("chat-card").hidden = false; } // console.log(this.getElementsByClassName('to-user-span')); let elem = el.getElementsByClassName("to-user-span")[0] as HTMLElement; let userName = elem.innerText; JsonAPI.contactName = userName; // @ts-ignore: Object is possibly 'null'. document.getElementById("user-name-span").innerText = userName; let currentUser = this._model.activeUsersList.find((vm) => vm.userName === userName) || new ActiveUserViewModel(); currentUser.userName = userName; if (!currentUser?.passphrase) { this._notificationService.passphrasePrompt( async (result) => { if (result) { const valid = await this._chatModel.isPassphraseValid(result, currentUser.userName!); if (!valid) { bootbox.alert("Some error occured. Please check your password"); log.error("invalid password"); return; } currentUser.unlocked = true; currentUser.passphrase = result; const chatMessages: ChatMessageViewModel[] = await this._chatModel.getMessages(currentUser, "new"); this._model.activeUsersList .filter((v) => v.userName == currentUser!.userName) .forEach((v) => { v.passphrase = result; v.unlocked = true; if (chatMessages.length > 0) { v.lastMessageTime = new Date( chatMessages[chatMessages.length - 1].messageTime ); const lastMessageText = (v.lastMessageText = chatMessages[chatMessages.length - 1].message); if (lastMessageText.length > 15) { v.lastMessageText = chatMessages[chatMessages.length - 1].message.slice( 0, 15 ) + "..."; } } }); this._promptHandler(currentUser); } } ); } else { this._chatModel.getMessages(currentUser, "new"); } el.className += " active"; if (currentUser.unlocked && currentUser.lastMessageTime) { this._newMessagesLoop = setInterval( this._chatModel.getMessages.bind(this._chatModel, currentUser, "update"), 10_000 ); this._model.notify(); } } private _promptHandler(vm: ActiveUserViewModel) { // vms.filter(v => v.userName == vm.userName).map(v => v.userName = vm.userName) // log.debug(vms); if (vm.lastMessageTime) { this._newMessagesLoop = setInterval( this._chatModel.getMessages.bind(this._chatModel, vm, "update"), 10_000 ); this._model.notify(); } } private _addSearchButtonEL() { this._userSearchButton.addEventListener("submit", (e) => { e.preventDefault(); // log.trace(temp); const searchTerm = this._userSearchInputElement.value; if (searchTerm.length > 0) { log.debug("search term value = " + searchTerm); const list = this._model.activeUsersList; log.debug("active users"); log.debug(list); if (!list) { log.error("Users list is null"); return; } let searchResult = this._searchService.search(list, searchTerm); this.update({ data: searchResult, op: "" }); log.debug(searchResult); } else { this._notificationService.error("Please enter a name") } }); } private _addSearchInputEL() { this._userSearchInputElement.addEventListener("input", (e) => { e.preventDefault(); if (this._userSearchInputElement.value.length < 2) { this._userSearchCancelButton.hidden = false; } }); } private _addSearchCancelEL() { this._userSearchCancelButton.addEventListener("click", (e) => { e.preventDefault(); this._userSearchInputElement.value = ""; this._userSearchCancelButton.hidden = true; let list = this._model.activeUsersList; this.update({ data: list, op: "" }); }); } }