fix(support-chat): support legacy mobile browsers
This commit is contained in:
@@ -89,13 +89,13 @@
|
||||
const userId = (params.get("user_id") || "").trim();
|
||||
if (!external_id && userId) {
|
||||
external_id = `mall_user:${userId}`;
|
||||
external_name ||= `商城用户 ${userId}`;
|
||||
if (!external_name) external_name = `商城用户 ${userId}`;
|
||||
}
|
||||
if (!external_id) {
|
||||
const storageKey = "agent_desk_guest_id";
|
||||
external_id = localStorage.getItem(storageKey) || `guest_${randomId()}`;
|
||||
localStorage.setItem(storageKey, external_id);
|
||||
external_name ||= `访客${external_id.slice(-8)}`;
|
||||
if (!external_name) external_name = `访客${external_id.slice(-8)}`;
|
||||
}
|
||||
return {
|
||||
external_id,
|
||||
@@ -124,7 +124,7 @@
|
||||
}
|
||||
try {
|
||||
const stored = JSON.parse(readSessionStorage(accessTargetStorageKey()) || "null");
|
||||
if ((stored?.type === "card" || stored?.type === "device") && validAccessNumber(stored?.number)) {
|
||||
if (stored && (stored.type === "card" || stored.type === "device") && validAccessNumber(stored.number)) {
|
||||
return { type: stored.type, number: String(stored.number).trim() };
|
||||
}
|
||||
} catch (_) {
|
||||
@@ -176,10 +176,19 @@
|
||||
}
|
||||
|
||||
function randomId() {
|
||||
if (window.crypto?.randomUUID) return window.crypto.randomUUID().replaceAll("-", "");
|
||||
if (window.crypto && window.crypto.randomUUID) return window.crypto.randomUUID().replace(/-/g, "");
|
||||
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`;
|
||||
}
|
||||
|
||||
function lastItem(items) {
|
||||
return Array.isArray(items) && items.length ? items[items.length - 1] : undefined;
|
||||
}
|
||||
|
||||
function replaceChildrenCompat(element, children) {
|
||||
while (element.firstChild) element.removeChild(element.firstChild);
|
||||
(children || []).forEach((child) => element.appendChild(child));
|
||||
}
|
||||
|
||||
function clientMessageId(prefix = "support_chat") {
|
||||
return `${prefix}_${Date.now()}_${randomId().slice(0, 8)}`;
|
||||
}
|
||||
@@ -199,7 +208,11 @@
|
||||
}
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(`${apiBase}${path}`, { ...options, headers, cache: "no-store", credentials: "include" });
|
||||
response = await fetch(`${apiBase}${path}`, Object.assign({}, options, {
|
||||
headers,
|
||||
cache: "no-store",
|
||||
credentials: "include",
|
||||
}));
|
||||
} catch (_) {
|
||||
throw new Error("网络连接失败,请检查网络后重试");
|
||||
}
|
||||
@@ -209,8 +222,8 @@
|
||||
} catch (_) {
|
||||
throw new Error("客服服务暂时不可用,请稍后重试");
|
||||
}
|
||||
if (!response.ok || payload?.ok === false || payload?.success === false) {
|
||||
const value = payload?.msg || payload?.message || payload?.code;
|
||||
if (!response.ok || (payload && payload.ok === false) || (payload && payload.success === false)) {
|
||||
const value = payload && (payload.msg || payload.message || payload.code);
|
||||
if (accessTarget && isCustomerSessionError(value, response.status)) {
|
||||
clearChatBinding();
|
||||
window.location.reload();
|
||||
@@ -228,8 +241,8 @@
|
||||
|
||||
function targetQuery(target = accessTarget) {
|
||||
const query = new URLSearchParams();
|
||||
if (target?.type === "card") query.set("card_no", target.number);
|
||||
if (target?.type === "device") query.set("device_no", target.number);
|
||||
if (target && target.type === "card") query.set("card_no", target.number);
|
||||
if (target && target.type === "device") query.set("device_no", target.number);
|
||||
return query;
|
||||
}
|
||||
|
||||
@@ -243,12 +256,11 @@
|
||||
async function h5AccessRequest(path, options = {}) {
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(h5AccessURL(path), {
|
||||
...options,
|
||||
response = await fetch(h5AccessURL(path), Object.assign({}, options, {
|
||||
cache: "no-store",
|
||||
credentials: "include",
|
||||
headers: { Accept: "application/json", ...(options.headers || {}) },
|
||||
});
|
||||
headers: Object.assign({ Accept: "application/json" }, options.headers || {}),
|
||||
}));
|
||||
} catch (_) {
|
||||
throw new Error("网络连接失败,请检查网络后重试");
|
||||
}
|
||||
@@ -258,8 +270,8 @@
|
||||
} catch (_) {
|
||||
throw new Error("客服入口暂时不可用,请稍后重试");
|
||||
}
|
||||
if (!response.ok || payload?.ok === false || payload?.success === false) {
|
||||
throw new Error(chineseError(payload?.msg || payload?.message || payload?.code));
|
||||
if (!response.ok || (payload && payload.ok === false) || (payload && payload.success === false)) {
|
||||
throw new Error(chineseError(payload && (payload.msg || payload.message || payload.code)));
|
||||
}
|
||||
return Object.prototype.hasOwnProperty.call(payload || {}, "data") ? payload.data : payload;
|
||||
}
|
||||
@@ -272,8 +284,8 @@
|
||||
body: "{}",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
const ticket = String(entry?.ticket || "").trim();
|
||||
const binding = String(entry?.session_binding || "").trim();
|
||||
const ticket = String((entry && entry.ticket) || "").trim();
|
||||
const binding = String((entry && entry.session_binding) || "").trim();
|
||||
if (!ticket || !binding) throw new Error("客服入口无效,请重试");
|
||||
state.chatBinding = binding;
|
||||
writeSessionStorage(chatBindingStorageKey(accessTarget), binding);
|
||||
@@ -366,11 +378,11 @@
|
||||
}
|
||||
|
||||
async function loadMessages(initial = false) {
|
||||
if (!state.conversation?.id) return;
|
||||
if (!state.conversation || !state.conversation.id) return;
|
||||
const result = await request(`/message/list?conversation_id=${state.conversation.id}&limit=50`);
|
||||
const incoming = Array.isArray(result?.results) ? result.results : [];
|
||||
state.cursor = result?.cursor || "";
|
||||
state.hasMore = Boolean(result?.has_more) || incoming.length >= 50;
|
||||
const incoming = result && Array.isArray(result.results) ? result.results : [];
|
||||
state.cursor = (result && result.cursor) || "";
|
||||
state.hasMore = Boolean(result && result.has_more) || incoming.length >= 50;
|
||||
state.messages = mergeMessages(state.messages, incoming);
|
||||
if (initial) state.initialScrollSettling = true;
|
||||
renderMessages();
|
||||
@@ -382,16 +394,16 @@
|
||||
}
|
||||
|
||||
async function loadOlder() {
|
||||
if (!state.hasMore || state.loadingOlder || !state.cursor || !state.conversation?.id) return;
|
||||
if (!state.hasMore || state.loadingOlder || !state.cursor || !state.conversation || !state.conversation.id) return;
|
||||
state.loadingOlder = true;
|
||||
dom.loadMore.disabled = true;
|
||||
dom.loadMore.textContent = "正在加载…";
|
||||
const oldHeight = dom.scroller.scrollHeight;
|
||||
try {
|
||||
const result = await request(`/message/list?conversation_id=${state.conversation.id}&limit=50&cursor=${encodeURIComponent(state.cursor)}`);
|
||||
state.cursor = result?.cursor || "";
|
||||
state.hasMore = Boolean(result?.has_more);
|
||||
state.messages = mergeMessages(result?.results || [], state.messages);
|
||||
state.cursor = (result && result.cursor) || "";
|
||||
state.hasMore = Boolean(result && result.has_more);
|
||||
state.messages = mergeMessages((result && result.results) || [], state.messages);
|
||||
renderMessages();
|
||||
requestAnimationFrame(() => {
|
||||
dom.scroller.scrollTop = dom.scroller.scrollHeight - oldHeight;
|
||||
@@ -406,12 +418,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
function mergeMessages(...groups) {
|
||||
function mergeMessages(first, second) {
|
||||
const map = new Map();
|
||||
groups.flat().forEach((item) => {
|
||||
if (item?.id != null) map.set(String(item.id), item);
|
||||
});
|
||||
return [...map.values()].sort((a, b) => Number(a.id) - Number(b.id));
|
||||
[first, second].forEach((group) => (group || []).forEach((item) => {
|
||||
if (item && item.id != null) map.set(String(item.id), item);
|
||||
}));
|
||||
return Array.from(map.values()).sort((a, b) => Number(a.id) - Number(b.id));
|
||||
}
|
||||
|
||||
function renderMessages() {
|
||||
@@ -428,7 +440,7 @@
|
||||
}
|
||||
fragment.append(createMessageElement(message));
|
||||
});
|
||||
dom.list.replaceChildren(fragment);
|
||||
replaceChildrenCompat(dom.list, [fragment]);
|
||||
dom.empty.hidden = state.messages.length > 0;
|
||||
}
|
||||
|
||||
@@ -466,15 +478,20 @@
|
||||
function avatar(message) {
|
||||
const node = document.createElement("span");
|
||||
node.className = "message-avatar";
|
||||
const name = senderName(message);
|
||||
const fallback = (name || "客服").slice(0, 1).toUpperCase();
|
||||
if (message.sender_avatar) {
|
||||
const image = document.createElement("img");
|
||||
image.src = message.sender_avatar;
|
||||
image.alt = "";
|
||||
image.addEventListener("error", () => {
|
||||
image.remove();
|
||||
node.textContent = fallback;
|
||||
}, { once: true });
|
||||
node.append(image);
|
||||
return node;
|
||||
}
|
||||
const name = senderName(message);
|
||||
node.textContent = (name || "客服").slice(0, 1).toUpperCase();
|
||||
node.textContent = fallback;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -500,8 +517,8 @@
|
||||
gallery.className = `message-image-grid count-${Math.min(assets.length, 9)}`;
|
||||
assets.slice(0, 9).forEach((asset) => {
|
||||
const image = document.createElement("img");
|
||||
image.src = asset?.url || "";
|
||||
image.alt = asset?.filename || "聊天图片";
|
||||
image.src = (asset && asset.url) || "";
|
||||
image.alt = (asset && asset.filename) || "聊天图片";
|
||||
image.loading = "eager";
|
||||
image.addEventListener("load", () => {
|
||||
if (state.initialScrollSettling) scrollToBottom(false);
|
||||
@@ -557,23 +574,28 @@
|
||||
"EMBED", "FORM", "IFRAME", "INPUT", "LINK", "META", "OBJECT",
|
||||
"SCRIPT", "STYLE", "TEMPLATE",
|
||||
]);
|
||||
[...root.querySelectorAll("*")].forEach((node) => {
|
||||
Array.from(root.querySelectorAll("*")).forEach((node) => {
|
||||
if (blockedTags.has(node.tagName)) {
|
||||
node.remove();
|
||||
if (node.parentNode) node.parentNode.removeChild(node);
|
||||
return;
|
||||
}
|
||||
if (!allowedTags.has(node.tagName)) {
|
||||
node.replaceWith(...node.childNodes);
|
||||
const parent = node.parentNode;
|
||||
if (parent) {
|
||||
while (node.firstChild) parent.insertBefore(node.firstChild, node);
|
||||
parent.removeChild(node);
|
||||
}
|
||||
return;
|
||||
}
|
||||
[...node.attributes].forEach((attr) => {
|
||||
Array.from(node.attributes).forEach((attr) => {
|
||||
if (node.tagName !== "A" || !["href", "title"].includes(attr.name.toLowerCase())) {
|
||||
node.removeAttribute(attr.name);
|
||||
}
|
||||
});
|
||||
if (node.tagName === "A") {
|
||||
const href = String(node.getAttribute("href") || "").trim();
|
||||
const scheme = href.match(/^([a-z][a-z0-9+.-]*):/i)?.[1]?.toLowerCase();
|
||||
const schemeMatch = href.match(/^([a-z][a-z0-9+.-]*):/i);
|
||||
const scheme = schemeMatch && schemeMatch[1] ? schemeMatch[1].toLowerCase() : "";
|
||||
if (scheme && !["http", "https", "mailto", "tel"].includes(scheme)) {
|
||||
node.removeAttribute("href");
|
||||
}
|
||||
@@ -584,7 +606,7 @@
|
||||
}
|
||||
});
|
||||
const fragment = document.createDocumentFragment();
|
||||
[...root.childNodes].forEach((node) => fragment.append(document.importNode(node, true)));
|
||||
Array.from(root.childNodes).forEach((node) => fragment.appendChild(document.importNode(node, true)));
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@@ -667,17 +689,19 @@
|
||||
}
|
||||
const remaining = kind === "image" ? Math.max(0, 9 - state.pendingUploads.length) : 1;
|
||||
if (accepted.length > remaining) toast("每次最多发送 9 张图片", true);
|
||||
state.pendingUploads.push(...accepted.slice(0, remaining).map((file) => ({
|
||||
file,
|
||||
kind,
|
||||
previewUrl: kind === "image" ? URL.createObjectURL(file) : "",
|
||||
})));
|
||||
accepted.slice(0, remaining).forEach((file) => {
|
||||
state.pendingUploads.push({
|
||||
file,
|
||||
kind,
|
||||
previewUrl: kind === "image" ? URL.createObjectURL(file) : "",
|
||||
});
|
||||
});
|
||||
renderPendingUploads();
|
||||
updateAvailability();
|
||||
}
|
||||
|
||||
function renderPendingUploads() {
|
||||
dom.pendingUploads.replaceChildren();
|
||||
replaceChildrenCompat(dom.pendingUploads, []);
|
||||
dom.pendingUploads.hidden = state.pendingUploads.length === 0;
|
||||
state.pendingUploads.forEach((pending) => {
|
||||
const image = pending.kind === "image";
|
||||
@@ -740,7 +764,7 @@
|
||||
if (pending.previewUrl) URL.revokeObjectURL(pending.previewUrl);
|
||||
});
|
||||
state.pendingUploads = [];
|
||||
dom.pendingUploads.replaceChildren();
|
||||
replaceChildrenCompat(dom.pendingUploads, []);
|
||||
dom.pendingUploads.hidden = true;
|
||||
dom.imageInput.value = "";
|
||||
dom.fileInput.value = "";
|
||||
@@ -779,7 +803,7 @@
|
||||
|
||||
async function sendComposer() {
|
||||
const content = dom.input.value.trim();
|
||||
const pending = [...state.pendingUploads];
|
||||
const pending = state.pendingUploads.slice();
|
||||
if ((!content && !pending.length) || state.sending || !canSend()) return;
|
||||
|
||||
state.sending = true;
|
||||
@@ -823,7 +847,7 @@
|
||||
}
|
||||
|
||||
function renderQuickActions() {
|
||||
dom.quickList.replaceChildren(...state.quickActions.map((action) => {
|
||||
replaceChildrenCompat(dom.quickList, state.quickActions.map((action) => {
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "quick-item";
|
||||
@@ -850,7 +874,7 @@
|
||||
client_msg_id: clientMessageId("support_chat_quick"),
|
||||
}),
|
||||
});
|
||||
state.messages = mergeMessages(state.messages, [result?.customer_message, result?.reply_message].filter(Boolean));
|
||||
state.messages = mergeMessages(state.messages, [result && result.customer_message, result && result.reply_message].filter(Boolean));
|
||||
renderMessages();
|
||||
scrollToBottom();
|
||||
} catch (error) {
|
||||
@@ -862,8 +886,8 @@
|
||||
}
|
||||
|
||||
async function markLatestRead() {
|
||||
const latest = state.messages.at(-1);
|
||||
if (!latest || !state.conversation?.id) return;
|
||||
const latest = lastItem(state.messages);
|
||||
if (!latest || !state.conversation || !state.conversation.id) return;
|
||||
try {
|
||||
await request("/message/read", {
|
||||
method: "POST",
|
||||
@@ -875,7 +899,7 @@
|
||||
}
|
||||
|
||||
function canSend() {
|
||||
return Boolean(state.conversation?.id) && Number(state.conversation.status) !== 4;
|
||||
return Boolean(state.conversation && state.conversation.id) && Number(state.conversation.status) !== 4;
|
||||
}
|
||||
|
||||
function updateAvailability() {
|
||||
@@ -897,7 +921,7 @@
|
||||
|
||||
function updateQueueStatus() {
|
||||
const conversation = state.conversation;
|
||||
const queued = Number(conversation?.status) === 2 && Number(conversation?.current_assignee_id || 0) === 0;
|
||||
const queued = Number(conversation && conversation.status) === 2 && Number((conversation && conversation.current_assignee_id) || 0) === 0;
|
||||
dom.queueStatus.hidden = !queued;
|
||||
if (!queued) return;
|
||||
|
||||
@@ -924,7 +948,7 @@
|
||||
}
|
||||
|
||||
function currentQueueWaitSeconds() {
|
||||
const baseline = Math.max(0, Number(state.conversation?.queue_wait_seconds || 0));
|
||||
const baseline = Math.max(0, Number((state.conversation && state.conversation.queue_wait_seconds) || 0));
|
||||
if (!state.queueSyncedAt) return baseline;
|
||||
return baseline + Math.max(0, Math.floor((Date.now() - state.queueSyncedAt) / 1000));
|
||||
}
|
||||
@@ -939,7 +963,7 @@
|
||||
}
|
||||
|
||||
function syncQueueTimers() {
|
||||
const queued = Number(state.conversation?.status) === 2 && Number(state.conversation?.current_assignee_id || 0) === 0;
|
||||
const queued = Number(state.conversation && state.conversation.status) === 2 && Number((state.conversation && state.conversation.current_assignee_id) || 0) === 0;
|
||||
if (!queued) {
|
||||
clearQueueTimers();
|
||||
return;
|
||||
@@ -960,10 +984,10 @@
|
||||
}
|
||||
|
||||
async function refreshConversationQueue() {
|
||||
if (!state.conversation?.id || Number(state.conversation.status) !== 2) return;
|
||||
if (!state.conversation || !state.conversation.id || Number(state.conversation.status) !== 2) return;
|
||||
try {
|
||||
const latest = await request(`/conversation/${state.conversation.id}`);
|
||||
state.conversation = { ...state.conversation, ...latest };
|
||||
state.conversation = Object.assign({}, state.conversation, latest);
|
||||
state.queueSyncedAt = Date.now();
|
||||
updateAvailability();
|
||||
} catch (_) {
|
||||
@@ -982,7 +1006,8 @@
|
||||
const base = apiBase.startsWith("http://") || apiBase.startsWith("https://")
|
||||
? apiBase.replace(/^http/, "ws")
|
||||
: `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}${apiBase.startsWith("/") ? "" : "/"}${apiBase}`;
|
||||
const query = new URLSearchParams({ channel_id: channelId });
|
||||
const query = new URLSearchParams();
|
||||
query.set("channel_id", channelId);
|
||||
if (accessTarget) {
|
||||
query.set("h5_chat_session", "required");
|
||||
query.set("h5_chat_binding", state.chatBinding);
|
||||
@@ -993,7 +1018,7 @@
|
||||
}
|
||||
|
||||
function connectSocket() {
|
||||
if (!state.conversation?.id || Number(state.conversation.status) === 4) return;
|
||||
if (!state.conversation || !state.conversation.id || Number(state.conversation.status) === 4) return;
|
||||
clearRealtimeTimers();
|
||||
if (state.socket) {
|
||||
const oldSocket = state.socket;
|
||||
@@ -1043,33 +1068,35 @@
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
const payload = event?.data;
|
||||
if (event?.type === "resyncRequired") {
|
||||
const payload = event && event.data;
|
||||
if (event && event.type === "resyncRequired") {
|
||||
loadMessages(false).catch(() => {});
|
||||
return;
|
||||
}
|
||||
if (!payload || Number(payload.conversation_id) !== Number(state.conversation?.id)) return;
|
||||
if (!payload || Number(payload.conversation_id) !== Number(state.conversation && state.conversation.id)) return;
|
||||
if (event.type === "message.created") {
|
||||
const message = normalizeRealtimeMessage(payload);
|
||||
if (!message) {
|
||||
loadMessages(false).catch(() => {});
|
||||
return;
|
||||
}
|
||||
const previousLastId = state.messages.at(-1)?.id;
|
||||
const previousLast = lastItem(state.messages);
|
||||
const previousLastId = previousLast && previousLast.id;
|
||||
state.messages = mergeMessages(state.messages, [message]);
|
||||
state.conversation.last_message_id = message.id;
|
||||
state.conversation.last_message_at = message.sent_at || state.conversation.last_message_at;
|
||||
renderMessages();
|
||||
if (state.messages.at(-1)?.id !== previousLastId) {
|
||||
const currentLast = lastItem(state.messages);
|
||||
if ((currentLast && currentLast.id) !== previousLastId) {
|
||||
scrollToBottom();
|
||||
markLatestRead();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (String(event.type || "").startsWith("conversation.")) {
|
||||
const patch = { ...payload };
|
||||
const patch = Object.assign({}, payload);
|
||||
delete patch.conversation_id;
|
||||
state.conversation = { ...state.conversation, ...patch };
|
||||
state.conversation = Object.assign({}, state.conversation, patch);
|
||||
state.queueSyncedAt = Date.now();
|
||||
applyReadState(payload);
|
||||
renderMessages();
|
||||
@@ -1082,7 +1109,7 @@
|
||||
}
|
||||
|
||||
function normalizeRealtimeMessage(payload) {
|
||||
if (payload.message?.id) return payload.message;
|
||||
if (payload.message && payload.message.id) return payload.message;
|
||||
const id = Number(payload.message_id || 0);
|
||||
const conversationId = Number(payload.conversation_id || 0);
|
||||
if (!id || !conversationId) return null;
|
||||
@@ -1106,15 +1133,14 @@
|
||||
function applyReadState(payload) {
|
||||
const agentReadId = Number(payload.agent_last_read_message_id || 0);
|
||||
const customerReadId = Number(payload.customer_last_read_message_id || 0);
|
||||
state.messages = state.messages.map((message) => ({
|
||||
...message,
|
||||
state.messages = state.messages.map((message) => Object.assign({}, message, {
|
||||
agent_read: message.agent_read || (agentReadId > 0 && Number(message.id) <= agentReadId),
|
||||
customer_read: message.customer_read || (customerReadId > 0 && Number(message.id) <= customerReadId),
|
||||
}));
|
||||
}
|
||||
|
||||
function scheduleReconnect() {
|
||||
if (!state.allowReconnect || state.reconnectTimer || !state.conversation?.id || Number(state.conversation.status) === 4) return;
|
||||
if (!state.allowReconnect || state.reconnectTimer || !state.conversation || !state.conversation.id || Number(state.conversation.status) === 4) return;
|
||||
const delay = Math.min(2000 * 2 ** state.reconnectAttempt, 30000);
|
||||
state.reconnectTimer = window.setTimeout(() => {
|
||||
state.reconnectTimer = null;
|
||||
@@ -1144,7 +1170,7 @@
|
||||
}
|
||||
|
||||
async function retry() {
|
||||
if (!state.initialized || !state.conversation?.id) {
|
||||
if (!state.initialized || !state.conversation || !state.conversation.id) {
|
||||
dom.loading.hidden = false;
|
||||
dom.empty.hidden = true;
|
||||
await init();
|
||||
@@ -1161,7 +1187,7 @@
|
||||
|
||||
async function closeConversation() {
|
||||
if (state.closing) return;
|
||||
if (!state.conversation?.id) {
|
||||
if (!state.conversation || !state.conversation.id) {
|
||||
closeCloseDialog();
|
||||
closePage();
|
||||
return;
|
||||
@@ -1175,7 +1201,7 @@
|
||||
method: "POST",
|
||||
body: JSON.stringify({ conversation_id: state.conversation.id }),
|
||||
});
|
||||
state.conversation = { ...state.conversation, status: 4 };
|
||||
state.conversation = Object.assign({}, state.conversation, { status: 4 });
|
||||
disconnectSocket(false);
|
||||
clearCustomerAccessState();
|
||||
clearPendingUploads();
|
||||
@@ -1229,7 +1255,7 @@
|
||||
const height = dom.scroller.scrollHeight;
|
||||
stableTicks = height === lastHeight ? stableTicks + 1 : 0;
|
||||
lastHeight = height;
|
||||
const imagesReady = [...dom.list.querySelectorAll("img")].every((image) => image.complete);
|
||||
const imagesReady = Array.from(dom.list.querySelectorAll("img")).every((image) => image.complete);
|
||||
if ((imagesReady && stableTicks >= 4) || Date.now() - startedAt >= 6000) {
|
||||
dom.scroller.scrollTop = dom.scroller.scrollHeight;
|
||||
state.initialScrollSettling = false;
|
||||
@@ -1323,7 +1349,7 @@
|
||||
}
|
||||
});
|
||||
window.addEventListener("message", (event) => {
|
||||
const type = event.data?.type;
|
||||
const type = event.data && event.data.type;
|
||||
if (type === "agent-desk:open" && state.initialized && !state.socket) connectSocket();
|
||||
if (type === "agent-desk:minimize") disconnectSocket(false);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user