Array.from(root.querySelectorAll(sel));
function getClientId(){
const k = "mg_client_id";
let v = localStorage.getItem(k);
if(!v){
v = "c" + Math.random().toString(36).slice(2) + Date.now().toString(36);
localStorage.setItem(k, v);
}
return v;
}
const voteKey = (sid, ver) => `mg_feedback_vote_${sid}_${ver}`;
const impKey = (sid, ver) => `mg_feedback_imp_${sid}_${ver}`;
function postJSON(url, payload){
try{
fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
credentials: "omit",
keepalive: true
}).catch(()=>{});
} catch(e){}
}
function renderWidget(root){
const sid = root.dataset.scenarioId;
const ver = root.dataset.scenarioVersion;
const weekLabel = (root.dataset.weekLabel || "").trim();
if(!sid || !ver){
console.warn("mg-feedback: missing data-scenario-id or data-scenario-version");
return;
}
root.style.setProperty("padding", "16px 0", "important");
root.style.setProperty("background", "transparent", "important");
root.style.setProperty("text-align", "center", "important");
root.innerHTML = `
`;
const glass = root.querySelector(".mg-glass");
const shine = root.querySelector(".mg-glass__shine");
const title = root.querySelector(".mg-feedback__title");
const row = root.querySelector(".mg-feedback__row");
const emojis = $all(".mg-feedback__emoji", root);
const thanks = root.querySelector(".mg-feedback__thanks");
title.textContent = TITLE_TEXT;
thanks.textContent = THANKS_TEXT;
// ===== Liquid Glass =====
glass.style.setProperty("position", "relative", "important");
glass.style.setProperty("overflow", "hidden", "important");
glass.style.setProperty("border-radius", "22px", "important");
glass.style.setProperty("padding", "16px 18px", "important");
glass.style.setProperty(
"background",
"linear-gradient(135deg, rgba(255,255,255,.22), rgba(255,255,255,.06))",
"important"
);
glass.style.setProperty("-webkit-backdrop-filter", "blur(18px) saturate(140%)", "important");
glass.style.setProperty("backdrop-filter", "blur(18px) saturate(140%)", "important");
glass.style.setProperty("border", "1px solid rgba(255,255,255,.28)", "important");
glass.style.setProperty(
"box-shadow",
"0 8px 30px rgba(0,0,0,.12), inset 0 1px 0 rgba(255,255,255,.25)",
"important"
);
shine.style.setProperty("position", "absolute", "important");
shine.style.setProperty("inset", "0", "important");
shine.style.setProperty("border-radius", "inherit", "important");
shine.style.setProperty("pointer-events", "none", "important");
shine.style.setProperty(
"background",
"radial-gradient(120% 120% at 10% 10%, rgba(255,255,255,.35), transparent 60%)",
"important"
);
// слой выше shine
[title, row, thanks].forEach(el => {
el.style.setProperty("position", "relative", "important");
el.style.setProperty("z-index", "1", "important");
});
// ===== Title =====
title.style.setProperty("opacity", ".9", "important");
title.style.setProperty("margin", "0 0 12px 0", "important");
// ===== Row =====
row.style.setProperty("display", "flex", "important");
row.style.setProperty("justify-content", "center", "important");
row.style.setProperty("align-items", "center", "important");
row.style.setProperty("gap", "26px", "important");
row.style.setProperty("font-size", "46px", "important");
row.style.setProperty("line-height", "1", "important");
emojis.forEach(e => {
e.style.setProperty("cursor", "pointer", "important");
e.style.setProperty("user-select", "none", "important");
e.style.setProperty("transition", "transform .12s ease, opacity .2s ease", "important");
e.style.setProperty("opacity", "1", "important");
e.style.setProperty("pointer-events", "auto", "important");
e.style.setProperty("transform", "scale(1)", "important");
e.style.setProperty("position", "relative", "important");
e.style.setProperty("z-index", "1", "important");
e.style.setProperty("-webkit-tap-highlight-color", "transparent", "important");
});
// ===== Thanks: постоянная высота + плавное появление =====
thanks.style.setProperty("display", "block", "important");
thanks.style.setProperty("min-height", "22px", "important");
thanks.style.setProperty("margin-top", "12px", "important");
thanks.style.setProperty("opacity", "0", "important");
thanks.style.setProperty("visibility", "hidden", "important");
thanks.style.setProperty("transform", "translateY(2px)", "important");
thanks.style.setProperty("transition", "opacity .18s ease, transform .18s ease", "important");
function lockUI(selectedValue){
emojis.forEach(e => {
const v = e.dataset.v;
e.style.setProperty("pointer-events", "none", "important");
e.style.setProperty("transform", "scale(1)", "important");
if(v === selectedValue){
e.style.setProperty("opacity", "1", "important");
e.style.setProperty("transform", "scale(1.10)", "important");
} else {
e.style.setProperty("opacity", ".35", "important");
}
});
thanks.style.setProperty("visibility", "visible", "important");
thanks.style.setProperty("opacity", ".92", "important");
thanks.style.setProperty("transform", "translateY(0)", "important");
}
// ===== Impression: 1 раз на client_id (локально) =====
const ik = impKey(sid, ver);
if(!localStorage.getItem(ik)){
localStorage.setItem(ik, "1");
postJSON(`${API_BASE}/api/feedback/impression`, {
scenario_id: sid,
scenario_version: ver,
week_label: weekLabel || null, // <-- название недели
client_id: getClientId(),
ts: Date.now(),
path: location.pathname,
ref: document.referrer || ""
});
}
// ===== Already voted? =====
const vk = voteKey(sid, ver);
const already = localStorage.getItem(vk);
if(already){
lockUI(already);
return;
}
// hover до голосования
emojis.forEach(e => {
e.addEventListener("mouseenter", () => e.style.setProperty("transform", "scale(1.12)", "important"));
e.addEventListener("mouseleave", () => e.style.setProperty("transform", "scale(1)", "important"));
});
// vote
emojis.forEach(el => {
el.addEventListener("click", () => {
const val = el.dataset.v;
localStorage.setItem(vk, val);
lockUI(val);
postJSON(`${API_BASE}/api/feedback/vote`, {
scenario_id: sid,
scenario_version: ver,
week_label: weekLabel || null, // <-- название недели
value: val,
client_id: getClientId(),
ts: Date.now(),
path: location.pathname
});
});
});
}
function init(){
document
.querySelectorAll(".mg-feedback[data-scenario-id][data-scenario-version]")
.forEach(renderWidget);
}
if(document.readyState === "loading") document.addEventListener("DOMContentLoaded", init);
else init();
})();