class Chatbox {
constructor() {
this.args = {
openButton: document.querySelector("#Ch12"),
chatBox: document.querySelector(".chatbox__support"),
questionBox : document.querySelector('#questionBox'),
sendButton : document.querySelector('.send__button'),
minimizeButton: document.querySelector(".minimize__button"),
maxButton: document.querySelector(".chatbox__maxbutton"),
minButton: document.querySelector(".chatbox__minbutton"),
resetButton: document.querySelector(".chatbox__resetbutton"),
overlayBot: document.querySelector(".overlayBot"),
container: document.querySelector('.container2'),
soundButton : document.getElementById('soundButton'),
// <---------------------- Custom buttons -------------------->
customButtons: document.querySelectorAll(".custom_button_welcome"),
};
this.botSound = document.getElementById('botSound');
this.chatboxButton= document.getElementById('chatbox__button');
this.questionBox = document.querySelector('#questionBox');
this.sendButton = document.querySelector('.send__button');
this.darkSendIcon = this.sendButton.querySelector('img[src*="dark"]');
this.whiteSendIcon = this.sendButton.querySelector('img[src*="white"]');
this.updateSendButtonState();
this.setupInputListener();
this.isSoundOn=false;
this.buttonAnimationDelay = 100;
this.state = false;
this.isMaximized = false;
this.isSendButtonDisabled=true;
this.messages = [];
this.user_messages_count = 0;
this.bot_messages_count = 0;
this.clieked_id = '';
this.response = '';
// Text to be typed
this.txt = "";
this.instructions = [];
this.i = 0;
this.j = 0;
this.speed = 20;
this.parser = new DOMParser();
this.allButtons = new Set();
this.loadingIndicator = document.createElement("div");
// this.loadingIndicator.className = "loading-indicator";
this.loadingIndicator.innerHTML = ChatBotHTMLTemplates.animationContainer;
this.loadingIndicator.style.display = "none";
this.args.chatBox
.querySelector(".chatbox__messages")
.appendChild(this.loadingIndicator);
this.initializeChatbox();
}
//initail response from bot
initializeChatbox() {
const chatboxMessages = this.args.chatBox.querySelector(".chatbox__messages");
chatboxMessages.innerHTML = `
<div id="chat-message"></div>
`;
//append loading indicator inside chat-message
chatboxMessages.appendChild(this.loadingIndicator);
// Show loading indicator
this.showLoadingIndicator();
// show loading indicator for 1.5second then display welcome message
setTimeout(() => {
this.hideLoadingIndicator();
if (this.isSoundOn) {
this.botSound.play();
}
this.displayWelcomeMessage();
}, 1500); // 1.5 seconds delay
}
//contents of welcome message
displayWelcomeMessage() {
this.bot_messages_count += 1;
const chatmessage = document.querySelector("#chat-message");
const divId = "welcomeMessage" + this.bot_messages_count;
const html = `
<div class="response_message">
<div class="chatbox__image--header">
<div class="header-avatar-2"></div>
</div>
<div id="${divId}" class="messages__item messages__item--visitor" style="text-align:left !important; padding:10px; line-height:1.3"></div>
<div id="buttonContainer-${divId}"></div>
</div>
<div id="timestamp-${divId}" class="message-time-bot"></div>
`;
chatmessage.innerHTML += html;
const responseElement = document.getElementById(divId);
const welcomeMessage = "Muhtaram/Muhtarama, Assalamu Alaikum. I am Smart Connect your banking assistant from FSIB. How can I help you?";
//type content then show buttons and timestamps
this.typeContent(responseElement, welcomeMessage)
.then(() => {
this.renderButtonsAndTimestamp(divId);
});
// Add welcome buttons
this.ButtonHtml = ChatbotButtonTemplates.mainMenuOptionHtml;
}
convertMillisecToHrMinSec(milisectime) {
return ChatbotUtils.convertMillisecToHrMinSec(milisectime);
}
display() {
const {
openButton,
chatBox,
sendButton,
minimizeButton,
maxButton,
minButton,
resetButton,
customButtons,
soundButton
} = this.args;
openButton.addEventListener("click", () => this.toggleState());
sendButton.addEventListener("click", () => {
this.onSendButton(chatBox);
this.scrollToBottom();
});
minimizeButton.addEventListener("click", () => {
this.toggleState();
document.getElementById('overlay').style.display = 'none'; //hide overlay during minimization
});
maxButton.addEventListener("click", () => {
this.maximizeChatbox();
this.scrollToBottom();
});
minButton.addEventListener("click", () => {
this.minimizeChatbox();
this.scrollToBottom();
});
//conditionally play sound
soundButton.addEventListener('click', () => {
this.isSoundOn = !this.isSoundOn;
soundButton.innerText = this.isSoundOn ? '🔊' : '🔈';
});
if (resetButton) {
resetButton.addEventListener("click", () => {
this.resetChatbox();
this.scrollToBottom();
});
}
//attach event listener to every custom button
customButtons.forEach((button) => {
button.addEventListener("click", () => {
this.onCustomSendButton(chatBox, button.id);
this.scrollToBottom();
});
});
const node = document.querySelector('input[id="questionBox"]');
node.addEventListener("keyup", ({ key }) => {
if (key === "Enter") {
this.onSendButton(chatBox);
this.scrollToBottom();
}
});
this.sendButton.addEventListener('click', () => {
if (!this.sendButton.disabled) {
this.onSendButton(this.args.chatBox);
this.scrollToBottom();
this.updateSendButtonState(); // Reset button state after sending
}
});
this.updateIcons();
}
toggleState() {
this.state = !this.state;
if (this.state) {
this.args.chatBox.classList.add("chatbox--active");
this.args.overlayBot.style.display="block";
this.args.container.style.display="block";
this.chatboxButton.style.animation="none";
} else {
this.args.chatBox.classList.remove("chatbox--active");
this.args.container.style.display="none"
this.args.overlayBot.style.display="none";
this.chatboxButton.style.animation="pulse2 2s infinite";
}
}
maximizeChatbox() {
this.isMaximized = true;
this.args.chatBox.style.height = "90vh"; // Set the height to full screen
this.args.chatBox.style.width = "90vw"; // Set the width to full screen
this.updateIcons();
}
minimizeChatbox() {
this.isMaximized = false;
this.args.chatBox.style.height = "510px"; // Set the height to default
this.args.chatBox.style.width = "490px"; // Set the width to default, normal size
this.updateIcons();
}
updateIcons() {
if (this.isMaximized) {
this.args.maxButton.style.display = "none";
this.args.minButton.style.display = "inline-block";
} else {
this.args.maxButton.style.display = "inline-block";
this.args.minButton.style.display = "none";
}
}
resetChatbox() {
// Clear the messages array
this.messages = [];
// Reset user and bot message counts
this.user_messages_count = 0;
this.bot_messages_count = 0;
// Re-initialize the chatbox
this.initializeChatbox();
}
onCustomSendButton(chatbox, buttonId) {
this.clieked_id = buttonId;
const buttonText = document.querySelector("#" + buttonId).innerText;
// alert("inside onCustomSendButton. button id = " + buttonId +" and button text = " + buttonText);
if (buttonText === "") {
return;
}
//------------------ Printing User Question -------------------
this.user_messages_count += 1;
this.updateChatUserText(chatbox, buttonText);
this.messages.push({ name: "User", message: buttonText });
//------------------ Custom Response generation -------------------
if (buttonId == "depositSchemeBtn") {
this.answerText =
"Muhtaram/Muhtarama, FSIB Savings Account provides you for more saving with attractive profit rate." +
"what do you want to know from the following? ";
this.ButtonHtml = ChatbotButtonTemplates.depositSchemeOptionHtml;
this.normalHTML = ``;
} else if (buttonId == "address") {
this.answerText = `Rangs RD Center, Block: SE (F), Plot:03, Gulshan Ave, Dhaka 1212 `;
this.normalHTML = ``;
this.ButtonHtml = ChatbotButtonTemplates.addressOptionHtml;
}
//other buttons
// this.messages.push({ name: "Bot", message: this.answerText });
// this.bot_messages_count += 1;
// this.updateChatResponseText(chatbox, this.answerText);
this.showLoadingIndicator();
// Simulate a delay to make the typing indicator visible (you can adjust the delay as needed)
setTimeout(() => {
this.hideLoadingIndicator(); // Hide typing indicator
this.messages.push({ name: "Bot", message: this.answerText });
this.bot_messages_count += 1;
this.updateChatResponseText(chatbox, this.answerText);
}, 1500); // 1 second delay
}
onSendButton(chatbox) {
// var textField = chatbox.querySelector('input');
const questionField = document.querySelector('input[id="questionBox"]');
let question = questionField.value;
if (question === "") {
return;
}
this.user_messages_count += 1;
this.updateChatUserText(chatbox, question);
this.messages.push({ name: "User", message: question });
questionField.value = "";
let headers = new Headers();
headers.append("Content-Type", "application/json"); //headers.append('GET', 'POST', 'OPTIONS'); //headers.append('Access-Control-Allow-Origin', '*');
//let predict_url = "http://127.0.0.1:5000/predict"; //let predict_url ='http://10.20.42.26:5000/predict'; //let predict_url ='https://bot.fsiblbd.com/predict';
let predict_url =''
if(this.clieked_id =='customerYes' || this.clieked_id == 'customerNo'){
predict_url = "bot_function.php";
var req_start_time = new Date().getTime(); // console.log("req_start_time == "+ req_start_time);
console.log("Req start time == " + this.convertMillisecToHrMinSec(req_start_time));
//let dateInWords = new Date(start_time); console.log("/n dateInWords =="+ dateInWords);
//this.showTypingIndicator();
fetch(predict_url, {
method: "POST",
body: JSON.stringify({ message: question, currentCustomer:this.clieked_id}),
mode: "cors",
headers: headers,
})
.then((r) => r.json())
.then((r) => {
//let response_time = new Date().getTime(); // console.log("request_time=="+request_time);
//console.log("/n response_time = " + this.convertMillisecToHrMinSec(response_time));
//let dateInWords2 = new Date(response_time); console.log("/n dateInWords =="+ dateInWords2);
//let total_duration = response_time - req_start_time;
//console.log( "/n total_duration = " +this.convertMillisecToHrMinSec(total_duration));
//console.log(" bot response = " + r.answer);
this.messages.push({ name: "Bot", message: r.answer });
this.bot_messages_count += 1;
this.updateChatResponseText(chatbox, r.answer);
this.setupInputListener();
})
.catch((error) => {
console.error("Error:", error);
this.updateChatResponseText(chatbox, "");
this.setupInputListener();
});
}else
{
console.log(this.clieked_id + " in else " );
//this.normalHTML = "<p> </p> "
this.response = "This part is still under development. Please have patience. We will get back to you soon.";
console.log(" bot response = " + this.response);
this.messages.push({ name: "Bot", message: this.response });
this.bot_messages_count += 1;
this.updateChatResponseText(chatbox, this.response);
this.setupInputListener();
}
}
/* -------------------------------------------Old function before adding QuestionButton----------------------------------------------
onSendButton(chatbox) {
// var textField = chatbox.querySelector('input');
questionField.value = "";
this.updateSendButtonState();
const questionField = document.querySelector('input[id="questionBox"]');
let question = questionField.value.trim();
if (question === "") {
return;
}
this.user_messages_count += 1;
this.updateChatUserText(chatbox, question);
this.messages.push({ name: "User", message: question });
questionField.value = "";
let headers = new Headers();
headers.append("Content-Type", "application/json"); //headers.append('GET', 'POST', 'OPTIONS'); //headers.append('Access-Control-Allow-Origin', '*');
let predict_url = "http://127.0.0.1:5000/predict"; //let predict_url ='http://10.20.42.26:5000/predict'; //let predict_url ='https://bot.fsiblbd.com/predict';
var req_start_time = new Date().getTime(); //console.log("req_start_time=="+ req_start_time);
console.log(
"Req start time == " + this.convertMillisecToHrMinSec(req_start_time)
);
//let dateInWords = new Date(start_time); console.log("/n dateInWords =="+ dateInWords);
this.showLoadingIndicator();
fetch(predict_url, {
method: "POST",
body: JSON.stringify({ message: question }),
mode: "cors",
headers: headers,
})
.then((r) => r.json())
.then((r) => {
this.hideLoadingIndicator();
let response_time = new Date().getTime(); // console.log("request_time=="+request_time);
console.log(
"/n response_time = " + this.convertMillisecToHrMinSec(response_time)
);
//let dateInWords2 = new Date(response_time); console.log("/n dateInWords =="+ dateInWords2);
let total_duration = response_time - req_start_time;
console.log(
"/n total_duration = " +
this.convertMillisecToHrMinSec(total_duration)
);
console.log(" bot response = " + r.answer);
this.messages.push({ name: "Bot", message: r.answer });
this.bot_messages_count += 1;
this.updateChatResponseText(chatbox, r.answer);
})
.catch((error) => {
this.hideLoadingIndicator();
console.error("Error:", error);
this.updateChatResponseText(chatbox, "");
});
} */
//text and timestamp from user
updateChatUserText(chatbox, userMessage) {
var divId = "userMessage" + this.user_messages_count;
var timestamp = this.getCurrentTimestamp();
const chatmessage = document.querySelector("#chat-message");
var html =
'<img class="" src="./bot-images/user-icon-dark.png" alt="image" style=" width: 30px; height: 28px; float: right; margin-right: -20px; margin-top: 12px; margin-bottom:1rem">' +
'<div id= "' +
divId +
'" class="messages__item messages__item--operator"> </div>' +
'<div class="message-time-user">' +
timestamp +
"</div>";
chatmessage.innerHTML += html;
var i = 0;
var timer = setInterval(function () {
//document.getElementsByClassName("messages__item--operator").innerHTML += userMessage.charAt(i);
document.getElementById(divId).innerHTML += userMessage.charAt(i);
i++;
if (i > userMessage.length - 1) {
clearInterval(timer);
}
}, 30);
}
//sending response
updateChatResponseText(chatbox, botResponse) {
if (this.isSoundOn) { this.botSound.play(); }
const chatmessage = document.querySelector("#chat-message");
var divId = "responseMessage" + this.bot_messages_count;
const html = `
<div class="response_message">
<div class="chatbox__image--header">
<div class="header-avatar-2"></div>
</div>
<div id="${divId}" class="messages__item messages__item--visitor" style="text-align:left !important; padding:10px; line-height:1.3"></div>
<div id="buttonContainer-${divId}"></div>
</div>
<div id="timestamp-${divId}" class="message-time-bot"></div>
`;
chatmessage.innerHTML += html;
const responseElement = document.getElementById(divId);
this.typeContent(responseElement, botResponse)
.then(() => {
if (this.normalHTML) {
this.txt = this.normalHTML;
this.instructions = [];
this.i = 0;
this.j = 0;
this.recreateNode(this.txt, responseElement);
return new Promise((resolve) =>
this.typeWriter(responseElement, resolve)
);
}
})
.then(() => {
// Render buttons and timestamp after all typing is complete
this.renderButtonsAndTimestamp(divId);
});
}
//
//
typeContent(element, content) {
return new Promise((resolve) => {
this.typeText(element, content, resolve);
});
}
//
//
attachButtonEventListeners(container) {
const buttons = container.querySelectorAll(".custom_button");
buttons.forEach((button) => {
// Only add event listener if it hasn't been added before
if (!this.allButtons.has(button)) {
button.addEventListener("click", () => {
this.onCustomSendButton(this.args.chatBox, button.id);
this.scrollToBottom();
});
// Add button to the set of all buttons
this.allButtons.add(button);
}
});
}
//typing normal text
typeText(element, text, callback) {
let i = 0;
const timer = setInterval(() => {
if (i < text.length) {
element.innerHTML += text.charAt(i);
i++;
} else {
clearInterval(timer);
callback();
}
this.scrollToBottom();
}, this.speed);
}
showLoadingIndicator() {
this.loadingIndicator.style.display = "flex";
this.scrollToBottom();
}
hideLoadingIndicator() {
this.loadingIndicator.style.display = "none";
this.scrollToBottom();
}
//function for auto scroll to bottom
scrollToBottom() {
const chatMessages = document.querySelector(".chatbox__messages");
chatMessages.scrollTop = chatMessages.scrollHeight;
}
//render buttons from html
renderButtonHtml() {
const chatmessage = document.querySelector("#chat-message");
const timestamp = this.getCurrentTimestamp();
if (this.ButtonHtml) {
chatmessage.innerHTML += `${this.ButtonHtml}<div class="message-time-bot">${timestamp}</div>`;
// Attach event listeners to all buttons in the chat message
this.attachButtonEventListeners(chatmessage);
this.ButtonHtml = null;
} else {
chatmessage.innerHTML += `<div class="message-time-bot">${timestamp}</div>`;
}
this.scrollToBottom();
}
getCurrentTimestamp() {
return ChatbotUtils.getCurrentTimestamp();
}
//type normal html content
typeWriter(container, callback) {
if (this.j < this.instructions.length) {
if (typeof this.instructions[this.j][1] === "string") {
if (this.i < this.instructions[this.j][1].length) {
this.instructions[this.j][0].innerHTML += this.instructions[
this.j
][1].charAt(this.i);
this.i++;
setTimeout(() => this.typeWriter(container, callback), this.speed);
} else {
this.j++;
this.i = 0;
setTimeout(() => this.typeWriter(container, callback), this.speed);
}
} else if (typeof this.instructions[this.j][1] === "object") {
this.instructions[this.j][0].appendChild(this.instructions[this.j][1]);
this.j++;
this.i = 0;
this.typeWriter(container, callback);
}
this.scrollToBottom();
} else {
// Typing is complete
this.normalHTML = null;
if (callback) callback();
}
}
renderButtonsAndTimestamp(divId) {
const buttonContainer = document.querySelector("#buttonContainer-" + divId);
const timestampElement = document.getElementById(`timestamp-${divId}`);
if (this.ButtonHtml) {
buttonContainer.innerHTML = this.ButtonHtml;
// Animate the appearance of each button
const buttons = buttonContainer.querySelectorAll(".custom_button");
buttons.forEach((button, index) => {
// Initially hide the button
button.style.opacity = "0";
button.style.transform = "translateY(20px)";
button.style.transition =
"opacity 0.3s ease-out, transform 0.3s ease-out";
// Animate the button after a delay
setTimeout(() => {
button.style.opacity = "1";
button.style.transform = "translateY(0)";
}, index * this.buttonAnimationDelay);
});
// Attach event listeners to all buttons in the entire chat box
this.attachButtonEventListeners(this.args.chatBox);
this.ButtonHtml = null;
}
const timestamp = this.getCurrentTimestamp();
timestampElement.textContent = timestamp;
this.scrollToBottom();
}
//a function required for typing html
recreateNode(list, container) {
const doc = this.parser.parseFromString(list, "text/html");
doc.body.childNodes.forEach((a) => {
if (a.nodeName === "#text") {
this.instructions.push([container, a.nodeValue]);
} else {
const b = a.cloneNode(true);
const c = a.cloneNode(false);
this.instructions.push([container, c]);
this.recreateNode(b.innerHTML, c);
}
});
}
setupInputListener() {
this.questionBox.addEventListener('input', () => {
this.updateSendButtonState();
});
}
//changing send button based on input field
updateSendButtonState() {
const hasText = this.questionBox.value.trim() !== '';
this.sendButton.disabled = !hasText;
this.whiteSendIcon.style.display = hasText ? 'inline' : 'none';
this.darkSendIcon.style.display = hasText ? 'none' : 'inline';
}
}
document.addEventListener("DOMContentLoaded", () => {
const chatbox = new Chatbox();
chatbox.display();
});