685 lines
25 KiB
JavaScript

// START TEMPLATING
window.store = store;
window.checkCookieExists = (cookieName) => {
return document.cookie.includes(`${cookieName}=`);
}
function isMobile() {
return /Mobi|Android/i.test(navigator.userAgent);
}
window.mobileRedirectionCheck = () => {
if (isMobile()) {
store.main.hideMessenger();
}
}
function renderTemplate(template, data) {
// Replace variables like {{variable}} with their corresponding values in data
template = template.replace(/{{\s*(\w+)\s*}}/g, (_, key) => {
return data[key] || '';
});
// Handle v-if directives
template = template.replace(/<(\w+)\s*v-if="([^"]+)"\s*>([\s\S]*?)<\/\1>/g, (_, tag, condition, truePart) => {
// Evaluate the condition in the context of data
const conditionValue = eval(condition.replace(/\b(\w+)\b/g, (match) => data[match] !== undefined ? data[match] : match)); // Replace variables with their values
if (conditionValue) {
// If the condition is true, render the v-if block
return `<${tag}>${truePart}</${tag}>`;
}
return ''; // If the condition is false, render nothing
});
return template;
}
// store.isAuthenticated = checkCookieExists("PGXREGSITE_LOGIN");
// allows user to test authentication if they add &testAuth=1 onto the end of the url and refresh
store.isAuthenticated = checkCookieExists("PGXREGSITE_LOGIN") || (window.location.href.includes('ivastudio.ai') && window.location.href.includes('testAuth=1'));
const template = `${payload.settings.newConversationPlaceholder.code.html}`;
payload.settings.newConversationPlaceholder.code.html = renderTemplate(template, {
isAuthenticated: store.isAuthenticated
});
store.main.setSettings(payload.settings);
(() => {
let lastData = checkCookieExists("PGXREGSITE_LOGIN");
setInterval(() => {
let currentData = store.isAuthenticated = checkCookieExists("PGXREGSITE_LOGIN") || store.isAuthenticated;
payload.settings.newConversationPlaceholder.code.html = renderTemplate(template, {
isAuthenticated: store.isAuthenticated
});
if (store.isAuthenticated && !isLiveChat()) {
// disable
store.main.disableMessengerInput(); // 2-26-2025 commented out so Travis can test user inputs in Dev only
}
if (currentData !== lastData) {
lastData = currentData;
store.main.setSettings(payload.settings);
store.conversation.$reset();
store.conversationEvent.$reset();
store.main.setView("main");
}
}, 1000);
})();
// END TEMPLATING
//VERSION 1.1
store.random = true;
//console.log("payload", payload);
const liveChatOnLaunch = payload.settings.chatOnlyMode == true;
const closeBtns = payload.settings.desktopCloseBtn == true;
if (closeBtns) {
delete store.main.isCloseButtonVisible;
payload.settings.desktopCloseBtn = false;
}
store.main.setSettings(payload.settings);
const getCloseSVG = () => {
return `<svg fill="currentColor" height="12px" width="12px" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 492 492" xml:space="preserve"><g><g><path d="M300.188,246L484.14,62.04c5.06-5.064,7.852-11.82,7.86-19.024c0-7.208-2.792-13.972-7.86-19.028L468.02,7.872 c-5.068-5.076-11.824-7.856-19.036-7.856c-7.2,0-13.956,2.78-19.024,7.856L246.008,191.82L62.048,7.872 c-5.06-5.076-11.82-7.856-19.028-7.856c-7.2,0-13.96,2.78-19.02,7.856L7.872,23.988c-10.496,10.496-10.496,27.568,0,38.052 L191.828,246L7.872,429.952c-5.064,5.072-7.852,11.828-7.852,19.032c0,7.204,2.788,13.96,7.852,19.028l16.124,16.116 c5.06,5.072,11.824,7.856,19.02,7.856c7.208,0,13.968-2.784,19.028-7.856l183.96-183.952l183.952,183.952 c5.068,5.072,11.824,7.856,19.024,7.856h0.008c7.204,0,13.96-2.784,19.028-7.856l16.12-16.116 c5.06-5.064,7.852-11.824,7.852-19.028c0-7.204-2.792-13.96-7.852-19.028L300.188,246z"/></g></g></svg>`;
};
const getMinimizeSVG = () => {
return '<svg fill="currentColor" height="12px" width="12px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 492 492" xml:space="preserve"><g> <g><path d="M465.064,207.562H26.908C12.076,207.562,0,219.698,0,234.53v22.804c0,14.832,12.072,27.104,26.908,27.104h438.156 c14.84,0,26.936-12.272,26.936-27.104V234.53C492,219.698,479.904,207.562,465.064,207.562z"/></g></g></svg>';
};
const getCloseLiveChatSVG = () => {
return `<svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" width="32px" height="32px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve"><path d="M25.1,12.3v-3c4,0,7.2,3.2,7.2,7.2h-3l4.6,5.7c0.3,0.3,0.7,0.3,0.9,0l4.6-5.7h-3c0-6.3-5.2-11.4-11.4-11.4 v-3l-5.7,4.6C19,7,19.1,7.4,19.4,7.6L25.1,12.3z"/><path d="M26.3,33.6c-1.2-1.6-3.5-2.7-5.8-3.8c-2.4-1-2.7-2-2.7-3c0-1,0.6-2.1,1.4-2.8c1.3-1.3,2.1-3.2,2.1-5.3 c0-4-2.4-7.5-6.5-7.5h-0.4c-4.1,0-6.5,3.5-6.5,7.5c0,2.2,0.7,4,2.1,5.3c0.8,0.7,1.4,1.7,1.4,2.8c0,1-0.3,2-2.7,3 c-3.4,1.5-6.6,3.1-6.7,6.3C2.3,38.4,3.8,40,5.8,40h17.9c0.3,0,0.7-0.1,1-0.2C24.8,37.6,25.3,35.5,26.3,33.6z"/><path d="M31.8,34.6l6,6l-6,6c-0.6,0.6-0.6,1.6,0,2.1l0.7,0.7c0.6,0.6,1.6,0.6,2.1,0l6-6l6,6c0.6,0.6,1.6,0.6,2.1,0 l0.7-0.7c0.6-0.6,0.6-1.6,0-2.1l-6-6l6-6c0.6-0.6,0.6-1.6,0-2.1l-0.7-0.7c-0.6-0.6-1.6-0.6-2.1,0l-6,6l-6-6c-0.6-0.6-1.6-0.6-2.1,0 l-0.7,0.7C31.2,33,31.2,34,31.8,34.6z"/></svg>`;
};
const addScript = (url, root, callback) => {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
script.onload = callback;
root.appendChild(script);
};
const addLink = (url, root) => {
const link = document.createElement("link");
link.type = "text/css";
link.href = url;
link.rel = "stylesheet";
root.appendChild(link);
};
const waitForElm = function (selector) {
return new Promise((resolve) => {
const root = document.querySelector("body ivas-messenger-ui").shadowRoot;
if (root.querySelector(selector)) return resolve(root.querySelector(selector));
const observer = new MutationObserver((mutations) => {
if (root.querySelector(selector)) {
resolve(root.querySelector(selector));
observer.disconnect();
}
});
observer.observe(root, {
childList: true,
subtree: true,
});
});
};
const injectStyle = () => {
waitForElm("div.app").then((elem) => {
elem.insertAdjacentHTML(
"afterbegin",
`<style>
button#close {
position: absolute;
top: 10px;
right: 15px;
z-index: 11111;
color: #999
}
#close:hover {
color: #666
}
button#minimize {
position: absolute;
top: 10px;
right: 40px;
z-index: 11111;
color: #999
}
#minimize:hover {
color: #666
}
button#livechat {
z-index: 11111;
}
button#debug {
z-index: 11111;
}
.footer{
justify-self:normal !important;
}
</style>`
);
});
};
const sendLiveChatOnOff = (on) => {
let input = on ? "Connecting to live chat" : "Live chat ended";
if (on && !store.main.conversationId) {
store.conversationEvent.sendMessage({
input: input,
metadata: { liveChat: on, nluSupressDefaultAnswer: true },
});
} else if (store.main.conversationId) {
for (const webhook of payload.webhooks) {
if (webhook.enabled) {
axios({
method: 'post',
url: webhook.url,
data: {
event: {
conversationId: store.main.conversationId,
input,
external: true,
metadata: { liveChat: on }
}
}
});
}
}
}
};
const delayLiveChatOnOff = (on, msDelay) => {
setTimeout(() => {
console.log("livechat startup");
sendLiveChatOnOff(on);
}, msDelay);
};
let typingTimeout;
const TYPING_DELAY_MS = 500;
const handleTyping = () => {
clearTimeout(typingTimeout);
typingTimeout = setTimeout(() => {
console.log("TYPING");
console.log("store.main.conversationId");
console.log(store.main.conversationId);
try {
fetch("https://router.usw.ivastudio.ai/ProxyScript/run/66ce521b47ec88c50fb8adf4/current/userTyping", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"event": "TYPING",
"sessionId": store.main.conversationId
}),
});
}
catch (error) {
console.log("something errored when sending typing event");
}
}, TYPING_DELAY_MS);
}
const showHideLiveChat = (livechat) => {
const root = document.querySelector("body ivas-messenger-ui").shadowRoot;
const el = root.getElementById("livechat");
if (livechat === true) {
waitForElm(".footer").then(() => {
let textArea = root.querySelector(".footer textarea");
textArea.addEventListener("input", handleTyping);
});
if (!el) {
//store.main.enableMessengerInput();
// COMMENTING OUT THE FOLLOWING LINES TO HIDE END LIVE CHAT BUTTON PER CREDITS REQUEST
// waitForElm(".footer").then((el) => {
// const div = document.createElement("button");
// div.id = "livechat";
// div.setAttribute("aria-label", "End Live Chat");
// div.title = "End Live Chat";
// div.style.color = payload.settings.actionColor;
// div.innerHTML = getCloseLiveChatSVG();
// div.style.paddingRight = "10px";
// div.onclick = () => {
// sendLiveChatOnOff(false);
// if (store.isAuthenticated) {
// store.main.disableMessengerInput();
// }
// store.conversationEvent.sendMessage("Live Chat Session ended. Can I help you with anything else?");
// //Add a chip titled "Live Chat"
// div.remove();
// };
// el.appendChild(div);
// });
}
} else if (el) {
// livechat == false
el.remove();
}
};
const isLiveChat = () => {
let livechat = false;
for (const [id, participant] of Object.entries(store.conversationEvent.participants)) {
if (participant.type == "agent") livechat = true;
}
return livechat;
};
const debugButtons = (liveChatOn) => {
waitForElm(".footer").then((el) => {
const div = document.createElement("button");
div.id = "debug";
div.setAttribute("aria-label", "Start Live Chat");
div.innerHTML = "Connect to live chat";
div.title = "Connect to live chat";
div.onclick = () => {
store.conversationEvent.sendMessage({
input: "Connect to live chat",
metadata: { liveChat: true },
});
};
el.parentNode.insertBefore(div, el.nextSibling);
});
};
// state variables: connecting to live chat automatically in the messenger visibility event has a sequencing problem. It will get called before axios is loaded and error out.
// This delays the live chat connect until after axios is loaded.
let isAxiosLoaded = false;
let awaitingConnect = false;
addScript("https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js", document.head, () => {
if (awaitingConnect) {
awaitingConnect = false;
delayLiveChatOnOff(true, 1500);
}
isAxiosLoaded = true;
});
window.addEventListener("beforeunload", (event) => {
// doesn't work
if (liveChatOnLaunch && isLiveChat()) {
sendLiveChatOnOff(false);
}
});
// update the state of livechat based on the participants. If there is an "agent" participant type, it's a live chat.
vm.$watch(
() => store.conversationEvent.participants,
async (participants) => {
try {
showHideLiveChat(isLiveChat());
} catch (e) {
console.error(e);
}
}
);
vm.$watch(
() => store.main.isMessengerVisible,
async (isVisible) => {
try {
console.log("messenger visible =", isVisible, store.main.conversationId);
if (isVisible == true) {
const livechat = isLiveChat();
injectStyle();
showHideLiveChat(livechat);
//debugButtons(livechat);
if (closeBtns) {
waitForElm(".app").then((el) => {
const div = document.createElement("button");
div.id = "minimize";
div.title = "Minimize";
div.innerHTML = getMinimizeSVG();
div.onclick = () => {
store.main.hideMessenger();
};
el.appendChild(div);
});
waitForElm(".app").then((el) => {
const div = document.createElement("button");
div.id = "close";
div.title = "Close";
div.innerHTML = getCloseSVG();
div.onclick = () => {
//Added the following line and commented out the proceeding if statement at credit's request in order to ONLY minimize the UI when in live chat instead of closing the session
store.main.hideMessenger();
// if (!isLiveChat() || window.confirm("Live Chat is running. Are you sure you want to close?")) {
// store.main.hideMessenger();
// if (isLiveChat()) {
// sendLiveChatOnOff(false);
// }
// //store.main.setNewUserSession();
// store.conversation.$reset();
// store.conversationEvent.$reset();
// store.main.setView("chat");
// store.main.setNewConversation(true);
// }
};
el.appendChild(div);
});
}
if (liveChatOnLaunch) {
if (!livechat) {
if (isAxiosLoaded === true) {
delayLiveChatOnOff(true, 1500);
} else {
awaitingConnect = true;
}
}
}
}
} catch (e) {
console.error(e);
}
},
{
deep: true,
immediate: true
}
);
window.vm = vm;
window.store = store;
addScript("https://router.usw.ivastudio.ai/ProxyScript/run/66ce521b47ec88c50fb8adf4/current/adaptiveCardImplementation_64dbc87628bd839f69b0c962", document.head, () => {
// Uncomment the following line to load the optional host config script
// addScript('https://router.usw.ivastudio.ai/ProxyScript/run/66ce521b47ec88c50fb8adf4/current/adaptiveCardHostConfig_64dbc87628bd839f69b0c962', document.head);
});
//supplemental code for feedback functionality including waitForElm lines
// const waitForElm = function (selector) {
// return new Promise((resolve) => {
// const root = document.querySelector('body ivas-messenger-ui').shadowRoot;
// if (root.querySelector(selector)) return resolve(root.querySelector(selector));
// const observer = new MutationObserver((mutations) => {
// if (root.querySelector(selector)) {
// resolve(root.querySelector(selector));
// observer.disconnect();
// }
// });
// observer.observe(root, {
// childList: true,
// subtree: true
// });
// });
// };
//END GENERAL ON ENGAGEMENT LOAD CODE
//BEGIN FEEDBACK SPECIFIC CODE
vm.$watch(() => store.conversationEvent.messages, async (value) => {
value.forEach((message, index) => {
if (message.sentBy.hasOwnProperty('type')) {
if (localStorage.getItem(`feedback-${message._id}`) || message?.metadata?.feedbackable != true) {
} else {
window.showFeedback(message._id, message.conversationId, message?.metadata?.transactionId);
}
}
});
}, {
deep: true
});
window.showFeedback = (id, conversationId, transactionId) => {
waitForElm(`div#message-${id}`).then((wrap) => {
try {
// const wrap = document.querySelector("body > se-messenger").shadowRoot.querySelector("#se-messenger-app > div.se-messenger-frame > div > div.se-messenger-body > div");
const scrollToTop = () => {
wrap.scrollTop = wrap.scrollHeight;
};
let devWrap = wrap.querySelector(`div.feedback-wrap`);
if (!devWrap) {
devWrap = document.createElement('div');
devWrap.classList.add('feedback-wrap');
devWrap.innerHTML = `<div class="feedback" style="top: -10px; right: -20px; display: flex; flex-flow: row nowrap; padding-left: 35px; padding: 5px 0 5px 35px;"><a id="se-messenger-feedback-like-${id}" href="#" style=" display: block; padding: 5px;">👍</a><a id="se-messenger-feedback-dislike-${id}" href="#" style=" display: block; padding: 5px;">👎</a></div>`;
wrap.parentElement.querySelector(`div#message-${id} > div`).after(devWrap);
}
devWrap.querySelector(`a#se-messenger-feedback-like-${id}`).onclick = (e) => {
e.preventDefault();
console.log("like!");
devWrap.parentElement.removeChild(devWrap);
send("LIKE");
}
devWrap.querySelector(`a#se-messenger-feedback-dislike-${id}`).onclick = (e) => {
e.preventDefault();
console.log("dislike!");
devWrap.parentElement.removeChild(devWrap);
send("DISLIKE");
}
wrap.parentElement.parentElement.parentElement.scrollTop =
wrap.parentElement.parentElement.parentElement.scrollHeight;
const send = (event) => {
localStorage.setItem(`feedback-${id}`, true);
//update DQ_URL with the URL of the LTS version of your feedback query
fetch('https://router.usw.ivastudio.ai/DynamicQuery/run/66ce521b47ec88c50fb8adf4/current/Feedback_6529ac38d8f54e4b61bc0a99', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"event": event,
"_id": transactionId
}),
});
};
} catch (e) {
console.log(e);
}
});
};
//END FEEDBACK CODE
//Watcher to keep IVA Open When in LIVE CHAT
vm.$watch(() => store.conversationEvent.messages, async (value) => {
try {
console.log("Msg received");
const livechat = isLiveChat();
if (livechat) {
if (!store.main.isMessengerVisible) {
store.main.showMessenger();
}
}
console.log(livechat);
} catch (e) {
console.error(e);
}
}, {
deep: true
});
window.askIVA =
window.askSky =
window.askSkyWithData =
(input, postBack, configuration, isNew) => {
store.main.showMessenger();
if (isNew) {
store.conversation.$reset();
store.conversationEvent.$reset();
store.main.setView("chat");
store.main.setNewConversation(true);
} else {
store.main.setView("chat");
}
store.conversationEvent.sendMessage({
input,
postBack,
configuration
});
};
window.openChat = () => {
store.main.showMessenger();
// start new
store.conversation.$reset();
store.conversationEvent.$reset();
// start new
store.main.setView("chat");
// start new
store.main.setNewConversation(true);
};
window.closeChat = () => {
store.main.hideMessenger();
};
//BEGIN MASKING
const debounce = (func, timeout = 300) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => { func.apply(this, args); }, timeout);
};
};
const de = debounce((value) => {
value.forEach((message, index) => {
if (message.sentBy.hasOwnProperty('type')) {
if (localStorage.getItem(`feedback-${message._id}`) || message?.metadata?.feedbackable != true) {
} else {
window.showFeedback(message._id, message.conversationId, message?.metadata?.transactionId);
}
} else {
if (message.input) {
let matchRes = window.isMask(message.input);
if (matchRes.includes("####") || matchRes.includes("#%*!")) {
message.input = matchRes;
}
}
}
});
}, 1000);
vm.$watch(() => store.conversationEvent.messages, de, {
deep: true
});
// sendMessage(input, metadata, conversationId) {
// try {
// debugLogging(`Sending message ${input} and metadata: ${JSON.stringify(metadata)}`);
// window.liveChat.sendLiveChatMessage(input);
// const proxyEndpoint = `${store.main.settings.liveChat.apiBaseUrl}/recordUserMessage`;
// const id = window.liveChat.convoId;
// input = window.isMask(input);
// }
// }//abbreviated
// #region Masking
window.isMask = (message) => {
const ssnRegex = /\b(\d{3}[-. ]?\d{2}[-. ]?\d{4}|\d{2}[-. ]\d{4}|\d{9}|\d{3}-\d{2}-\d{4})\b/g;
const ssnRegex2 = /\b(\d{2}(.)\d{4}|\d{3}([- .])\d{3}\3\d{3})\b/g;
const ccRegex = /\b(\d{4}[-. ]?\d{6}[-. ]?\d{4,5}|\d{4}[-. ]?\d{4}[-. ]?\d{4}[-. ]?\d{4})\b/g;
const acctNoRegex = /\b(\d{4}[-.\s]?\d{4}[-.\s]?\d{4}[-.\s]?\d{4})\b/g;
const emailRegex = /\b[a-z0-9._%\+\-—|]+@[a-z0-9.\-—|]+\.[a-z|]{2,6}\b/g;
const birthDateRegex = /\b^(3[01]|[12][0-9]|0?[1-9])(\/|-)(1[0-2]|0?[1-9])\2([0-9]{2})?[0-9]{2}$\b/g;
const phoneNumberRegex = /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$\b/g;
let regexArr = [];
//regexArr.push(acctNoRegex);
regexArr.push(ccRegex);
regexArr.push(ssnRegex);
regexArr.push(ssnRegex2);
//regexArr.push(emailRegex);
//regexArr.push(birthDateRegex);
//regexArr.push(phoneNumberRegex);
regexArr.forEach((element) => {
message = message.replace(element, "####");
})
let badWords = [
"anal",
"anus",
"arse",
"ass",
"ballsack",
"bastard",
"bitch",
"biatch",
"blowjob",
"bollock",
"bollok",
"buttplug",
"clitoris",
"cock",
"coon",
"cunt",
"damn",
"dick",
"Dildo",
"dyke",
"fag",
"faggot",
"feck",
"fellate",
"fellatio",
"fuck",
"fucking",
"fucks",
"f u c k",
"Goddamn",
"God damn",
"hell",
"homo",
"jerk",
"jizz",
"knobend",
"knob end",
"labia",
"lmao",
"lmfao",
"nigger",
"nigga",
"prick",
"pube",
"pussy",
"queer",
"retard",
"sex",
"bullshit",
"shit",
"slut",
"tit",
"turd",
"twat",
"whore",
"wtf"
];
const regexbadWords = new RegExp(`\\b(?:${badWords.join('|')})\\b`, 'gi');
message = message.replace(regexbadWords, '#%*!');
return message;
};
//END Masking
// #region Response Link Click Handling
store.conversationEvent.chipOnClick = (data) => {
console.log(JSON.stringify(data));
if (data.url) {
window.open(data.url, '_blank');
} else if (data.action) {
switch (data.action) {
case "hideMessenger":
console.log('Got to hide messenger');
store.main.hideMessenger();
break;
}
}
else {
store.conversationEvent.sendMessage(data);
}
}
// endregion