/* INTEGRATION NOTE:
// Custom script to add Mavenoid
;(function(m,a,v,e,n,o,i,d) {
d=m.createElement(a);d.async=true;d.src="https://widget-hosts.mavenoid.com/custom-embedding-scripts/"+n+".js";
i=m.getElementsByTagName(a)[0];i.parentNode.insertBefore(d,i);v[e]=v[e]||[];
})(document,"script",window,"mavenoid","husqvarna-north-america");
*/
// --- begin mavenoid embedded troubleshooter ---
(function (m, a, v, e, n, o, i, d) {
n = m.createElement(a);
n.async = true;
n.src = "https://husqvarna.mavenoid.com/embedded/embedded.js";
o = m.getElementsByTagName(a)[0];
o.parentNode.insertBefore(n, o);
v[e] = v[e] || [];
})(document, "script", window, "mavenoid");
// --- end mavenoid embedded troubleshooter ---
var baseUrl = "https://shop.husqvarna.com";
var regionRegex = /(?:husqvarna|husqvarnagroup)\.com\/(.+?)(?:\/|$)/;
var { href, search, hostname } = document.location;
var regionRegexMatch = regionRegex.exec(href);
var region = null;
if (regionRegexMatch) {
region = regionRegexMatch[1];
} else if (href.includes("husqvarna.custhelp.com")) {
region = "us";
}
const INSTALLATION_PATHS = [
"/discover/epos-support",
"/discover/automower-installation-made-simple",
];
var regionLangMap = {
// --- French ---
"ca-fr": "fr",
// --- English ---
"ca-en": "en",
us: "en",
};
var currentLang = region ? regionLangMap[region] : "en";
var isPopOverShown = false;
var popOverElement = null;
var EXTERNAL_SCRIPTS = {
async openDirectly(input) {
await directlyEscalation(input);
return {
formData: [{ id: "result", value: { type: "string", value: "ok" } }],
};
},
async trackHQEvent() {
window.dataLayer.push({ event: "mavenoid_referral" });
return { formData: [] };
},
async navigateToUrl(url) {
window.location.href = url;
return { formData: [] };
},
async addToCart(input) {
const userContext = await getUserContext();
if (userContext?.error) return formDataError(userContext.error);
const res = await addPartNumberToCart(input);
if (!res.ok) return formDataError(await res.text());
return {
formData: [{ id: "result", value: { type: "string", value: "ok" } }],
};
},
};
function formDataError(msg) {
console.error(msg);
return {
formData: [
{
id: "error",
value: { type: "string", value: msg },
},
],
};
}
async function getContext() {
// Get user context of shopper
// API details: https://help.hcltechsw.com/commerce/9.0.0/restapi/code/authentication_and_session_management.html
return await fetch(
`${baseUrl}/wcs/resources/store/11251/usercontext/@self/contextdata`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
},
);
}
async function createGuest() {
// Create a guest
// API details: https://help.hcltechsw.com/commerce/9.0.0/restapi/code/authentication_and_session_management.html
return await fetch(
`${baseUrl}/wcs/resources/store/11251/guestidentity?updateCookies=true`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
},
);
}
async function getUserContext() {
// callerId === -1002 means anonymous user.
// Create guest identity first to get WC tokens before calling cart API.
const contextResponse = await getContext();
if (!contextResponse.ok) return { error: await contextResponse.text() };
const userContext = await contextResponse.json();
if (userContext?.basicInfo?.runAsId === -1002) {
const guestResponse = await createGuest();
if (!guestResponse.ok) return { error: await guestResponse.text() };
}
}
async function addPartNumberToCart({ partNumber, quantity }) {
// Add order item to cart
// API details: https://help.hcltechsw.com/commerce/8.0.0/restapi/code/cart.html
return await fetch(`${baseUrl}/wcs/resources/store/11251/cart/`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
body: JSON.stringify({
orderItem: [
{
partNumber,
quantity,
},
],
}),
});
}
async function loadCSS() {
var cssId = "popOverStyle";
if (!document.getElementById(cssId)) {
var head = document.getElementsByTagName("head")[0];
var link = document.createElement("link");
link.id = cssId;
link.rel = "stylesheet";
link.type = "text/css";
link.href =
"https://widget-hosts.mavenoid.com/custom-embedding-scripts/stylesheets/husqvarna/popover.css";
head.appendChild(link);
}
}
function keydownEventListener(e) {
if (e.keyCode === 27) {
// ESC key handler
closeMinimodal();
}
}
function closePopOver() {
if (!isPopOverShown) return;
isPopOverShown = false;
document.body.style.overflow = null;
document.removeEventListener("keydown", keydownEventListener);
if (popOverElement) {
const m = popOverElement;
m.classList.add("closing");
setTimeout(() => {
document.body.removeChild(m);
popOverElement = null;
}, 100);
}
}
async function showPopOver() {
await loadCSS();
setTimeout(() => {
if (!isPopOverShown) {
isPopOverShown = true;
popOverElement = popOverElement || document.createElement("div");
popOverElement.id = "mavenoid-popover-container"; // MAVENOID_BUTTON_CONTAINER_DIV_ID
popOverElement.className = "mavenoid-speech-bubble";
popOverElement.innerHTML = `
${
currentLang === "fr"
? "En quoi pouvons-nous vous aider?"
: "How can we help you?"
}
`;
popOverElement.addEventListener("click", () => {
closePopOver();
mavenoid.push({ event: "troubleshooter-show" });
});
Array.from(
popOverElement.querySelectorAll(".js-mavenoid-close-speech-bubble"),
).forEach((elt) =>
elt.addEventListener("click", (ev) => {
ev.stopPropagation();
closePopOver();
}),
);
document.addEventListener("keydown", keydownEventListener);
document.body.appendChild(popOverElement);
}
}, 0);
}
function showPopoverOnHover() {
// TODO: load the font in advance and remove delay
document.documentElement.style.setProperty("--popOverTime", "0.5s");
try {
var floatingButton = document
.getElementsByTagName("mavenoid-assistant")[0]
.querySelector("#mavenoid-shadow-root")
.shadowRoot.querySelector(".floating-button-content");
floatingButton.addEventListener("click", function () {
closePopOver();
});
floatingButton.addEventListener("mouseenter", function () {
if (!isPopOverShown) {
showPopOver();
}
});
floatingButton.addEventListener("mouseleave", function () {
closePopOver();
});
} catch (err) {
//
}
}
function getDirectlySDK(product) {
if (window.DirectlyRTM) {
return window.DirectlyRTM;
}
(function (d, i, r, e, c, t, l, y) {
// @ts-expect-error
i[r] =
i[r] ||
function () {
(i[r].cq = i[r].cq || []).push(arguments);
};
// @ts-expect-error
l = d.createElement("script");
l.id = "directlyRTMScript";
l.src = e;
l.async = 1;
y = d.head || d.getElementsByTagName("head")[0];
// @ts-expect-error
if (
d.readyState === "complete" ||
d.readyState === "loaded" ||
d.readyState === "interactive"
) {
y.appendChild(l);
} else if (i.addEventListener) {
// @ts-expect-error
i.addEventListener("DOMContentLoaded", function () {
y.appendChild(l);
});
} else {
// @ts-expect-error
i.attachEvent("onload", function () {
y.appendChild(l);
});
}
})(
document,
window,
"DirectlyRTM",
"https://app.directly.com/widgets/rtm/embed.js",
);
window.DirectlyRTM("config", {
id: getDirectlyId(),
lang: getDirectlyLang(),
metadata: {
Brand: getDirectlyBrand(product),
rtm: getDirectlyRtmConfig(),
},
});
return window.DirectlyRTM;
}
function getDirectlyId() {
// Allow overriding Directly ID from `?mavenoid-directly-dev=1`
// RTM Name in Directly: Mavenoid RTM
var overrideUseDev =
new URLSearchParams(search).get("mavenoid-directly-dev") === "1" ||
hostname === "acc-stage.husqvarna.com";
return overrideUseDev
? "2c99829d89aa1933018a40e73cdb0825" // dev
: "2c9985ab8acaa066018afaa07ccf5e61"; // prod
}
function getDirectlyLang() {
switch (region) {
case "ca-fr":
return "fr";
default:
return "en";
}
}
function getDirectlyBrand(product) {
var isAutomower = product?.id === 6915264 || product?.id === 4017449;
var brand = isAutomower ? "Automower" : "Husqvarna";
if (region.includes("ca")) {
brand += "-CA";
}
return brand;
}
function getDirectlyRtmConfig() {
return {
returnUrl: `https://www.husqvarna.com/${
["us", "ca-en", "ca-fr"].includes(region) ? region : "us"
}/support/`,
URL: href,
};
}
function extractMetadata(transcript, product) {
var metadata = {
// The following metadata is recommended by Directly - removing them
// can break their integration.
Brand: getDirectlyBrand(product),
rtm: getDirectlyRtmConfig(),
source: "Mavenoid",
};
var index = 1;
var QA = transcript.filter(
(e) => e.type === "question" || e.type === "solution",
);
for (var element of QA) {
var question = element.title;
var answer = element.answer ? element.answer : "Unknown reply";
if (question) {
metadata[`Question ${index}: ${question}`] = answer;
index++;
}
}
return metadata;
}
async function directlyEscalation(input) {
var transcript = input.transcript;
var product = input.product;
var directlySDK = getDirectlySDK(product);
var metadata = extractMetadata(transcript, product);
console.log("[Mavenoid-Directly] Metadata", metadata);
// Track questionID
// Implementation note: due the the interactivity of Directly, it is possible
// that we receive more than 1 event per session (with similar, or different IDs)
directlySDK("onNavigate", function (path) {
if (path.path && path.path.includes("/question/")) {
console.log("[Mavenoid-Directly] Question navigate");
}
});
// The question needs to be filled for Directly to work correctly.
// We take the FTS inputed text by default, and if that was not filled
// in the session, then we just have a hardcoded english sentence to go.
// We could do something smarter like picking the first question card but
// that risks of having bad results.
var freeTextSearch = transcript.find(
(e) => e.type === "free-text-search" && e.searchTerm != "",
);
var questionForDirectly = input.question;
var questionText = questionForDirectly
? questionForDirectly
: freeTextSearch
? freeTextSearch.searchTerm
: `I have a question about my ${product.name}`;
var name = input.name;
var email = input.email;
if (name && email) {
directlySDK("askQuestion", {
name,
email,
questionText,
metadata,
});
} else {
directlySDK("set", "metadata", metadata);
directlySDK("openAskForm");
directlySDK("maximize");
}
// Wait for directly to be ready or the timeout to be resolved
// This is due to the production setup where there is a clashing DirectlyRTM
// instance.
await new Promise(function (resolve) {
directlySDK("onReady", function () {
resolve();
});
setTimeout(resolve, 200);
});
// Unmount the iframe a bit after the last call from the caller is made (in QuestionComponent)
// If the unmount call is done synchronously, the iframe will unload, resulting
// in the awaiting function to never resume.
setTimeout(function () {
window.mavenoid.push({ event: "troubleshooter-unmount" });
}, 100);
}
// Integrate with hash-based opening
function hashIntegration() {
function hashChange(hash) {
var allowedHashUrls = [
"mavenoid-run-time-tool",
"mavenoid-general-automower",
"mavenoid-main-menu",
"mavenoid-chat-with-us",
"mavenoid-automower-buying-guide",
];
if (!hash) return;
var hashparams = new URLSearchParams(hash.slice(1));
if (!allowedHashUrls.some((key) => hashparams.has(key))) return;
loadMavenoid(true);
closePopOver();
}
// First run and event listener
hashChange(window.location.hash);
window.addEventListener("hashchange", (e) => {
hashChange(window.location.hash);
});
}
function getMavenoidClientId(openByDefault = false) {
if (
INSTALLATION_PATHS.some((path) => window.location.pathname.includes(path))
)
return "ma_4vchgvdk45i_9o7krmg5r5g9av6hiossk7oqvq9dmof70som"; //Touchpoint: Husqvarna North America - Installation Flow (Wide Theme)
return openByDefault
? "ma_50d487uqp3q_ujh8h54ptf29l6f7dn0np9726njulglcos6m" // Touchpoint: Husqvarna North America - Open By Default
: "ma_50ugfsq91kn_54npomkmsumecaglghsng2osss8lkq8nf35u"; // Touchpoint: Husqvarna North America
}
function openMavenoidAt(flowPath) {
// Added Flow Paths:
// Run Time Tool: "run-time-tool"
// General Automower: "general-automower"
// Main Menu: "main-menu"
// Chat With Us: "chat-with-us"
// Automower Buying Guide: "automower-buying-guide"
mavenoid.push({
event: "assistant-mount",
clientId: "ma_50d487uqp3q_ujh8h54ptf29l6f7dn0np9726njulglcos6m",
defaultLang: currentLang,
initFormData: {
"country-code": region ? region.split("-")[0] : "",
"full-country-code": region ? region : "",
"flow-path": flowPath ? flowPath : "",
},
externalScripts: EXTERNAL_SCRIPTS,
});
closePopOver();
}
function loadMavenoid(openByDefault = false) {
mavenoid.push({
event: "assistant-mount",
clientId: getMavenoidClientId(openByDefault),
defaultLang: currentLang,
initFormData: {
"country-code": region ? region.split("-")[0] : "",
"full-country-code": region ? region : "",
},
externalScripts: EXTERNAL_SCRIPTS,
});
}
showPopOver();
setTimeout(function () {
showPopoverOnHover();
}, 3000);
loadMavenoid();
hashIntegration();