copilot-chat-widget 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -45
- package/dist/chat-widget.min.js +3 -3
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +43 -50
- package/package.json +1 -1
- package/src/index.d.ts +3 -4
- package/src/index.js +310 -326
- package/src/widget-runtime.js +101 -156
package/src/index.js
CHANGED
|
@@ -1,338 +1,322 @@
|
|
|
1
|
-
const BUILD_BASE_URL =
|
|
2
|
-
typeof __WIDGET_BASE_URL__ !== "undefined" && __WIDGET_BASE_URL__
|
|
3
|
-
? __WIDGET_BASE_URL__
|
|
4
|
-
: undefined;
|
|
5
|
-
|
|
6
|
-
const BUTTON_SIZE = 64;
|
|
7
|
-
const IFRAME_SIZE = 720;
|
|
8
|
-
|
|
9
|
-
const buildWidget = ({ iframeUrl, launcherIcon }) => {
|
|
10
|
-
const existingRoot = document.querySelector("[data-copilot-widget-root]");
|
|
11
|
-
if (existingRoot) {
|
|
12
|
-
existingRoot.remove();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const showCheckoutToast = (message) => {
|
|
16
|
-
const existingToast = document.querySelector("[data-copilot-checkout-toast]");
|
|
17
|
-
if (existingToast) {
|
|
18
|
-
existingToast.remove();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const toast = document.createElement("div");
|
|
22
|
-
toast.setAttribute("data-copilot-checkout-toast", "true");
|
|
23
|
-
toast.innerText = message;
|
|
24
|
-
|
|
25
|
-
Object.assign(toast.style, {
|
|
26
|
-
position: "fixed",
|
|
27
|
-
top: "20px",
|
|
28
|
-
left: "50%",
|
|
29
|
-
transform: "translateX(-50%)",
|
|
30
|
-
padding: "12px 16px",
|
|
31
|
-
background: "#0f172a",
|
|
32
|
-
color: "white",
|
|
33
|
-
borderRadius: "12px",
|
|
34
|
-
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
35
|
-
zIndex: 2147483647,
|
|
36
|
-
fontSize: "14px",
|
|
37
|
-
fontWeight: "600",
|
|
38
|
-
maxWidth: "420px",
|
|
39
|
-
lineHeight: "1.4",
|
|
40
|
-
textAlign: "center",
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
document.body.appendChild(toast);
|
|
44
|
-
|
|
45
|
-
setTimeout(() => {
|
|
46
|
-
toast.remove();
|
|
47
|
-
}, 4500);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// Shadow DOM container
|
|
51
|
-
const containerHost = document.createElement("div");
|
|
52
|
-
containerHost.setAttribute("data-copilot-widget-root", "true");
|
|
53
|
-
const shadow = containerHost.attachShadow({ mode: "open" });
|
|
54
|
-
document.body.appendChild(containerHost);
|
|
55
|
-
|
|
56
|
-
// Button
|
|
57
|
-
const btn = document.createElement("button");
|
|
58
|
-
btn.type = "button";
|
|
59
|
-
btn.setAttribute("aria-label", "Open Copilot chat");
|
|
60
|
-
btn.innerHTML = `
|
|
61
|
-
<img
|
|
62
|
-
src="${launcherIcon}"
|
|
63
|
-
alt="Copilot chat launcher"
|
|
64
|
-
style="width: 38px; height: 38px; object-fit: contain; border-radius: 50%; pointer-events: none;"
|
|
65
|
-
/>
|
|
66
|
-
`;
|
|
67
|
-
|
|
68
|
-
Object.assign(btn.style, {
|
|
69
|
-
position: "fixed",
|
|
70
|
-
bottom: "24px",
|
|
71
|
-
right: "24px",
|
|
72
|
-
width: `${BUTTON_SIZE}px`,
|
|
73
|
-
height: `${BUTTON_SIZE}px`,
|
|
74
|
-
borderRadius: "50%",
|
|
75
|
-
border: "none",
|
|
76
|
-
background: "linear-gradient(135deg, #0078ff, #00c6ff)",
|
|
77
|
-
color: "white",
|
|
78
|
-
cursor: "pointer",
|
|
79
|
-
zIndex: 999998,
|
|
80
|
-
display: "flex",
|
|
81
|
-
alignItems: "center",
|
|
82
|
-
justifyContent: "center",
|
|
83
|
-
boxShadow: "0 6px 14px rgba(0,0,0,0.25)",
|
|
84
|
-
transition: "all 0.25s ease",
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
btn.onmouseover = () => {
|
|
88
|
-
btn.style.transform = "scale(1.12)";
|
|
89
|
-
btn.style.boxShadow = "0 10px 25px rgba(0,0,0,0.3)";
|
|
90
|
-
};
|
|
91
|
-
btn.onmouseout = () => {
|
|
92
|
-
btn.style.transform = "scale(1)";
|
|
93
|
-
btn.style.boxShadow = "0 6px 14px rgba(0,0,0,0.25)";
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const container = document.createElement("div");
|
|
97
|
-
container.setAttribute("data-copilot-widget-root", "true");
|
|
98
|
-
Object.assign(container.style, {
|
|
99
|
-
display: "none",
|
|
100
|
-
position: "fixed",
|
|
101
|
-
bottom: `${BUTTON_SIZE + 36}px`,
|
|
102
|
-
right: "24px",
|
|
103
|
-
zIndex: "999999",
|
|
104
|
-
transformOrigin: "bottom right",
|
|
105
|
-
transform: "scale(0.8) translateY(20px)",
|
|
106
|
-
opacity: "0",
|
|
107
|
-
transition: "all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)",
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const arrow = document.createElement("div");
|
|
111
|
-
const arrowBorder = document.createElement("div");
|
|
112
|
-
const arrowFill = document.createElement("div");
|
|
113
|
-
|
|
114
|
-
Object.assign(arrow.style, {
|
|
115
|
-
position: "absolute",
|
|
116
|
-
bottom: "-14px",
|
|
117
|
-
right: "28px",
|
|
118
|
-
width: "30px",
|
|
119
|
-
height: "20px",
|
|
120
|
-
pointerEvents: "none",
|
|
121
|
-
display: "none",
|
|
122
|
-
zIndex: "1",
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
Object.assign(arrowBorder.style, {
|
|
126
|
-
position: "absolute",
|
|
127
|
-
bottom: "0",
|
|
128
|
-
left: "0",
|
|
129
|
-
right: "0",
|
|
130
|
-
margin: "0 auto",
|
|
131
|
-
width: "0",
|
|
132
|
-
height: "0",
|
|
133
|
-
borderLeft: "15px solid transparent",
|
|
134
|
-
borderRight: "15px solid transparent",
|
|
135
|
-
borderTop: "15px solid rgba(15,23,42,0.1)",
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
Object.assign(arrowFill.style, {
|
|
139
|
-
position: "absolute",
|
|
140
|
-
bottom: "2px",
|
|
141
|
-
left: "0",
|
|
142
|
-
right: "0",
|
|
143
|
-
margin: "0 auto",
|
|
144
|
-
width: "0",
|
|
145
|
-
height: "0",
|
|
146
|
-
borderLeft: "13px solid transparent",
|
|
147
|
-
borderRight: "13px solid transparent",
|
|
148
|
-
borderTop: "13px solid white",
|
|
149
|
-
boxShadow: "0 6px 16px rgba(15,23,42,0.12)",
|
|
150
|
-
borderRadius: "2px",
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
arrow.appendChild(arrowBorder);
|
|
154
|
-
arrow.appendChild(arrowFill);
|
|
155
|
-
|
|
156
|
-
const frameWrapper = document.createElement("div");
|
|
157
|
-
Object.assign(frameWrapper.style, {
|
|
158
|
-
width: `${IFRAME_SIZE}px`,
|
|
159
|
-
maxWidth: "calc(100vw - 48px)",
|
|
160
|
-
height: `${Math.min(IFRAME_SIZE, Math.max(320, window.innerHeight - 140))}px`,
|
|
161
|
-
maxHeight: "calc(100vh - 150px)",
|
|
162
|
-
borderRadius: "20px",
|
|
163
|
-
background: "white",
|
|
164
|
-
border: "1px solid rgba(15,23,42,0.12)",
|
|
165
|
-
boxShadow: "0 18px 45px rgba(15,23,42,0.16)",
|
|
166
|
-
overflow: "hidden",
|
|
167
|
-
});
|
|
168
|
-
shadow.appendChild(frameWrapper);
|
|
169
|
-
|
|
170
|
-
const iframe = document.createElement("iframe");
|
|
171
|
-
iframe.src = iframeUrl;
|
|
172
|
-
iframe.title = "Copilot chat widget";
|
|
173
|
-
iframe.allow = "clipboard-read; clipboard-write; microphone; camera; display-capture";
|
|
174
|
-
iframe.setAttribute("scrolling", "no");
|
|
175
|
-
Object.assign(iframe.style, {
|
|
176
|
-
width: "100%",
|
|
177
|
-
height: "100%",
|
|
178
|
-
border: "none",
|
|
179
|
-
display: "block",
|
|
180
|
-
background: "transparent",
|
|
181
|
-
overflow: "hidden",
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
shadow.appendChild(frameWrapper);
|
|
185
|
-
frameWrapper.appendChild(iframe);
|
|
186
|
-
|
|
187
|
-
container.appendChild(arrow);
|
|
188
|
-
container.appendChild(frameWrapper);
|
|
189
|
-
document.body.appendChild(btn);
|
|
190
|
-
document.body.appendChild(container);
|
|
191
|
-
|
|
192
|
-
let isOpen = false;
|
|
193
|
-
|
|
194
|
-
const closeChat = () => {
|
|
195
|
-
if (!isOpen) return;
|
|
196
|
-
isOpen = false;
|
|
197
|
-
container.style.opacity = "0";
|
|
198
|
-
container.style.transform = "scale(0.8) translateY(20px)";
|
|
199
|
-
arrow.style.display = "none";
|
|
200
|
-
setTimeout(() => {
|
|
201
|
-
container.style.display = "none";
|
|
202
|
-
}, 250);
|
|
203
|
-
btn.style.transform = "scale(1)";
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
const handleWidgetMessage = (event) => {
|
|
207
|
-
const { data, source } = event || {};
|
|
208
|
-
if (!data?.type) return;
|
|
209
|
-
|
|
210
|
-
if (data.type === "CART_CHECKOUT" && source === iframe.contentWindow) {
|
|
211
|
-
console.log("[CopilotChat] Received checkout payload from widget:", data);
|
|
212
|
-
showCheckoutToast("Checkout message received from chat widget. Check console for payload.");
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (data.type === "WIDGET_READY" && source === iframe.contentWindow) {
|
|
217
|
-
iframe.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (data.type === "CHAT_CLOSED") {
|
|
222
|
-
closeChat();
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
window.addEventListener("message", handleWidgetMessage);
|
|
227
|
-
|
|
228
|
-
btn.onclick = (event) => {
|
|
229
|
-
event.stopPropagation();
|
|
230
|
-
isOpen = !isOpen;
|
|
231
|
-
if (isOpen) {
|
|
232
|
-
container.style.display = "block";
|
|
233
|
-
arrow.style.display = "block";
|
|
234
|
-
requestAnimationFrame(() => {
|
|
235
|
-
container.style.opacity = "1";
|
|
236
|
-
container.style.transform = "scale(1) translateY(0)";
|
|
237
|
-
});
|
|
238
|
-
} else {
|
|
239
|
-
closeChat();
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
document.addEventListener("click", (event) => {
|
|
244
|
-
const target = event.target;
|
|
245
|
-
if (!target) return;
|
|
246
|
-
if (isOpen && !container.contains(target) && target !== btn) {
|
|
247
|
-
closeChat();
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
const controls = {
|
|
252
|
-
close: closeChat,
|
|
253
|
-
open: () => {
|
|
254
|
-
if (!isOpen) {
|
|
255
|
-
btn.click();
|
|
256
|
-
}
|
|
257
|
-
},
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
window.CopilotChat = window.CopilotChat || {};
|
|
261
|
-
window.CopilotChat.close = controls.close;
|
|
262
|
-
window.CopilotChat.open = controls.open;
|
|
263
|
-
window.CopilotChat.controls = controls;
|
|
264
|
-
|
|
265
|
-
return controls;
|
|
266
|
-
};
|
|
267
|
-
|
|
1
|
+
const BUILD_BASE_URL =
|
|
2
|
+
typeof __WIDGET_BASE_URL__ !== "undefined" && __WIDGET_BASE_URL__
|
|
3
|
+
? __WIDGET_BASE_URL__
|
|
4
|
+
: undefined;
|
|
5
|
+
|
|
6
|
+
const BUTTON_SIZE = 64;
|
|
7
|
+
const IFRAME_SIZE = 720;
|
|
8
|
+
|
|
9
|
+
const buildWidget = ({ iframeUrl, launcherIcon }) => {
|
|
10
|
+
const existingRoot = document.querySelector("[data-copilot-widget-root]");
|
|
11
|
+
if (existingRoot) {
|
|
12
|
+
existingRoot.remove();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const showCheckoutToast = (message) => {
|
|
16
|
+
const existingToast = document.querySelector("[data-copilot-checkout-toast]");
|
|
17
|
+
if (existingToast) {
|
|
18
|
+
existingToast.remove();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const toast = document.createElement("div");
|
|
22
|
+
toast.setAttribute("data-copilot-checkout-toast", "true");
|
|
23
|
+
toast.innerText = message;
|
|
24
|
+
|
|
25
|
+
Object.assign(toast.style, {
|
|
26
|
+
position: "fixed",
|
|
27
|
+
top: "20px",
|
|
28
|
+
left: "50%",
|
|
29
|
+
transform: "translateX(-50%)",
|
|
30
|
+
padding: "12px 16px",
|
|
31
|
+
background: "#0f172a",
|
|
32
|
+
color: "white",
|
|
33
|
+
borderRadius: "12px",
|
|
34
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
35
|
+
zIndex: 2147483647,
|
|
36
|
+
fontSize: "14px",
|
|
37
|
+
fontWeight: "600",
|
|
38
|
+
maxWidth: "420px",
|
|
39
|
+
lineHeight: "1.4",
|
|
40
|
+
textAlign: "center",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
document.body.appendChild(toast);
|
|
44
|
+
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
toast.remove();
|
|
47
|
+
}, 4500);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Shadow DOM container
|
|
51
|
+
const containerHost = document.createElement("div");
|
|
52
|
+
containerHost.setAttribute("data-copilot-widget-root", "true");
|
|
53
|
+
const shadow = containerHost.attachShadow({ mode: "open" });
|
|
54
|
+
document.body.appendChild(containerHost);
|
|
55
|
+
|
|
56
|
+
// Button
|
|
57
|
+
const btn = document.createElement("button");
|
|
58
|
+
btn.type = "button";
|
|
59
|
+
btn.setAttribute("aria-label", "Open Copilot chat");
|
|
60
|
+
btn.innerHTML = `
|
|
61
|
+
<img
|
|
62
|
+
src="${launcherIcon}"
|
|
63
|
+
alt="Copilot chat launcher"
|
|
64
|
+
style="width: 38px; height: 38px; object-fit: contain; border-radius: 50%; pointer-events: none;"
|
|
65
|
+
/>
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
Object.assign(btn.style, {
|
|
69
|
+
position: "fixed",
|
|
70
|
+
bottom: "24px",
|
|
71
|
+
right: "24px",
|
|
72
|
+
width: `${BUTTON_SIZE}px`,
|
|
73
|
+
height: `${BUTTON_SIZE}px`,
|
|
74
|
+
borderRadius: "50%",
|
|
75
|
+
border: "none",
|
|
76
|
+
background: "linear-gradient(135deg, #0078ff, #00c6ff)",
|
|
77
|
+
color: "white",
|
|
78
|
+
cursor: "pointer",
|
|
79
|
+
zIndex: 999998,
|
|
80
|
+
display: "flex",
|
|
81
|
+
alignItems: "center",
|
|
82
|
+
justifyContent: "center",
|
|
83
|
+
boxShadow: "0 6px 14px rgba(0,0,0,0.25)",
|
|
84
|
+
transition: "all 0.25s ease",
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
btn.onmouseover = () => {
|
|
88
|
+
btn.style.transform = "scale(1.12)";
|
|
89
|
+
btn.style.boxShadow = "0 10px 25px rgba(0,0,0,0.3)";
|
|
90
|
+
};
|
|
91
|
+
btn.onmouseout = () => {
|
|
92
|
+
btn.style.transform = "scale(1)";
|
|
93
|
+
btn.style.boxShadow = "0 6px 14px rgba(0,0,0,0.25)";
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const container = document.createElement("div");
|
|
97
|
+
container.setAttribute("data-copilot-widget-root", "true");
|
|
98
|
+
Object.assign(container.style, {
|
|
99
|
+
display: "none",
|
|
100
|
+
position: "fixed",
|
|
101
|
+
bottom: `${BUTTON_SIZE + 36}px`,
|
|
102
|
+
right: "24px",
|
|
103
|
+
zIndex: "999999",
|
|
104
|
+
transformOrigin: "bottom right",
|
|
105
|
+
transform: "scale(0.8) translateY(20px)",
|
|
106
|
+
opacity: "0",
|
|
107
|
+
transition: "all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const arrow = document.createElement("div");
|
|
111
|
+
const arrowBorder = document.createElement("div");
|
|
112
|
+
const arrowFill = document.createElement("div");
|
|
113
|
+
|
|
114
|
+
Object.assign(arrow.style, {
|
|
115
|
+
position: "absolute",
|
|
116
|
+
bottom: "-14px",
|
|
117
|
+
right: "28px",
|
|
118
|
+
width: "30px",
|
|
119
|
+
height: "20px",
|
|
120
|
+
pointerEvents: "none",
|
|
121
|
+
display: "none",
|
|
122
|
+
zIndex: "1",
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
Object.assign(arrowBorder.style, {
|
|
126
|
+
position: "absolute",
|
|
127
|
+
bottom: "0",
|
|
128
|
+
left: "0",
|
|
129
|
+
right: "0",
|
|
130
|
+
margin: "0 auto",
|
|
131
|
+
width: "0",
|
|
132
|
+
height: "0",
|
|
133
|
+
borderLeft: "15px solid transparent",
|
|
134
|
+
borderRight: "15px solid transparent",
|
|
135
|
+
borderTop: "15px solid rgba(15,23,42,0.1)",
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
Object.assign(arrowFill.style, {
|
|
139
|
+
position: "absolute",
|
|
140
|
+
bottom: "2px",
|
|
141
|
+
left: "0",
|
|
142
|
+
right: "0",
|
|
143
|
+
margin: "0 auto",
|
|
144
|
+
width: "0",
|
|
145
|
+
height: "0",
|
|
146
|
+
borderLeft: "13px solid transparent",
|
|
147
|
+
borderRight: "13px solid transparent",
|
|
148
|
+
borderTop: "13px solid white",
|
|
149
|
+
boxShadow: "0 6px 16px rgba(15,23,42,0.12)",
|
|
150
|
+
borderRadius: "2px",
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
arrow.appendChild(arrowBorder);
|
|
154
|
+
arrow.appendChild(arrowFill);
|
|
155
|
+
|
|
156
|
+
const frameWrapper = document.createElement("div");
|
|
157
|
+
Object.assign(frameWrapper.style, {
|
|
158
|
+
width: `${IFRAME_SIZE}px`,
|
|
159
|
+
maxWidth: "calc(100vw - 48px)",
|
|
160
|
+
height: `${Math.min(IFRAME_SIZE, Math.max(320, window.innerHeight - 140))}px`,
|
|
161
|
+
maxHeight: "calc(100vh - 150px)",
|
|
162
|
+
borderRadius: "20px",
|
|
163
|
+
background: "white",
|
|
164
|
+
border: "1px solid rgba(15,23,42,0.12)",
|
|
165
|
+
boxShadow: "0 18px 45px rgba(15,23,42,0.16)",
|
|
166
|
+
overflow: "hidden",
|
|
167
|
+
});
|
|
168
|
+
shadow.appendChild(frameWrapper);
|
|
169
|
+
|
|
170
|
+
const iframe = document.createElement("iframe");
|
|
171
|
+
iframe.src = iframeUrl;
|
|
172
|
+
iframe.title = "Copilot chat widget";
|
|
173
|
+
iframe.allow = "clipboard-read; clipboard-write; microphone; camera; display-capture";
|
|
174
|
+
iframe.setAttribute("scrolling", "no");
|
|
175
|
+
Object.assign(iframe.style, {
|
|
176
|
+
width: "100%",
|
|
177
|
+
height: "100%",
|
|
178
|
+
border: "none",
|
|
179
|
+
display: "block",
|
|
180
|
+
background: "transparent",
|
|
181
|
+
overflow: "hidden",
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
shadow.appendChild(frameWrapper);
|
|
185
|
+
frameWrapper.appendChild(iframe);
|
|
186
|
+
|
|
187
|
+
container.appendChild(arrow);
|
|
188
|
+
container.appendChild(frameWrapper);
|
|
189
|
+
document.body.appendChild(btn);
|
|
190
|
+
document.body.appendChild(container);
|
|
191
|
+
|
|
192
|
+
let isOpen = false;
|
|
193
|
+
|
|
194
|
+
const closeChat = () => {
|
|
195
|
+
if (!isOpen) return;
|
|
196
|
+
isOpen = false;
|
|
197
|
+
container.style.opacity = "0";
|
|
198
|
+
container.style.transform = "scale(0.8) translateY(20px)";
|
|
199
|
+
arrow.style.display = "none";
|
|
200
|
+
setTimeout(() => {
|
|
201
|
+
container.style.display = "none";
|
|
202
|
+
}, 250);
|
|
203
|
+
btn.style.transform = "scale(1)";
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const handleWidgetMessage = (event) => {
|
|
207
|
+
const { data, source } = event || {};
|
|
208
|
+
if (!data?.type) return;
|
|
209
|
+
|
|
210
|
+
if (data.type === "CART_CHECKOUT" && source === iframe.contentWindow) {
|
|
211
|
+
console.log("[CopilotChat] Received checkout payload from widget:", data);
|
|
212
|
+
showCheckoutToast("Checkout message received from chat widget. Check console for payload.");
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (data.type === "WIDGET_READY" && source === iframe.contentWindow) {
|
|
217
|
+
iframe.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (data.type === "CHAT_CLOSED") {
|
|
222
|
+
closeChat();
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
window.addEventListener("message", handleWidgetMessage);
|
|
227
|
+
|
|
228
|
+
btn.onclick = (event) => {
|
|
229
|
+
event.stopPropagation();
|
|
230
|
+
isOpen = !isOpen;
|
|
231
|
+
if (isOpen) {
|
|
232
|
+
container.style.display = "block";
|
|
233
|
+
arrow.style.display = "block";
|
|
234
|
+
requestAnimationFrame(() => {
|
|
235
|
+
container.style.opacity = "1";
|
|
236
|
+
container.style.transform = "scale(1) translateY(0)";
|
|
237
|
+
});
|
|
238
|
+
} else {
|
|
239
|
+
closeChat();
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
document.addEventListener("click", (event) => {
|
|
244
|
+
const target = event.target;
|
|
245
|
+
if (!target) return;
|
|
246
|
+
if (isOpen && !container.contains(target) && target !== btn) {
|
|
247
|
+
closeChat();
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const controls = {
|
|
252
|
+
close: closeChat,
|
|
253
|
+
open: () => {
|
|
254
|
+
if (!isOpen) {
|
|
255
|
+
btn.click();
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
window.CopilotChat = window.CopilotChat || {};
|
|
261
|
+
window.CopilotChat.close = controls.close;
|
|
262
|
+
window.CopilotChat.open = controls.open;
|
|
263
|
+
window.CopilotChat.controls = controls;
|
|
264
|
+
|
|
265
|
+
return controls;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
268
|
export async function loadCopilotChatWidget(options = {}) {
|
|
269
269
|
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
270
270
|
return null;
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
const globalConfig = window.CopilotChatConfig || {};
|
|
274
|
-
const token =
|
|
275
|
-
options.token ||
|
|
276
|
-
globalConfig.token ||
|
|
277
|
-
(typeof window !== "undefined"
|
|
278
|
-
? window.localStorage?.getItem("copilotChatToken") || null
|
|
279
|
-
: null);
|
|
280
|
-
|
|
281
|
-
if (!token) {
|
|
282
|
-
console.error(
|
|
283
|
-
"[CopilotChat] Missing token (provide via loadCopilotChatWidget({ token }) or window.CopilotChatConfig.token)."
|
|
284
|
-
);
|
|
285
|
-
return null;
|
|
286
|
-
}
|
|
287
274
|
|
|
288
275
|
const baseUrl =
|
|
289
276
|
options.baseUrl ||
|
|
290
277
|
globalConfig.baseUrl ||
|
|
291
278
|
BUILD_BASE_URL ||
|
|
292
|
-
(typeof window !== "undefined" && window.location?.origin) ||
|
|
293
|
-
null;
|
|
294
|
-
|
|
295
|
-
if (!baseUrl) {
|
|
296
|
-
console.error(
|
|
297
|
-
"[CopilotChat] Missing baseUrl (set via loadCopilotChatWidget({ baseUrl }), window.CopilotChatConfig.baseUrl, or WIDGET_BASE_URL)."
|
|
298
|
-
);
|
|
299
|
-
return null;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const url = `${baseUrl.replace(/\/$/, "")}/api/chat-widget/config
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
window.CopilotChat = window.CopilotChat || {};
|
|
322
|
-
window.CopilotChat.token = token;
|
|
279
|
+
(typeof window !== "undefined" && window.location?.origin) ||
|
|
280
|
+
null;
|
|
281
|
+
|
|
282
|
+
if (!baseUrl) {
|
|
283
|
+
console.error(
|
|
284
|
+
"[CopilotChat] Missing baseUrl (set via loadCopilotChatWidget({ baseUrl }), window.CopilotChatConfig.baseUrl, or WIDGET_BASE_URL)."
|
|
285
|
+
);
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const url = `${baseUrl.replace(/\/$/, "")}/api/chat-widget/config`;
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const response = await fetch(url, {
|
|
293
|
+
credentials: "omit",
|
|
294
|
+
mode: "cors",
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
if (!response.ok) {
|
|
298
|
+
throw new Error(`Server responded with ${response.status}`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const remoteConfig = await response.json();
|
|
302
|
+
if (!remoteConfig?.iframeUrl || !remoteConfig?.launcherIcon) {
|
|
303
|
+
throw new Error("Received incomplete widget configuration from server.");
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
window.CopilotChat = window.CopilotChat || {};
|
|
323
307
|
window.CopilotChat.baseUrl = baseUrl;
|
|
324
|
-
|
|
325
|
-
return buildWidget({
|
|
326
|
-
iframeUrl: remoteConfig.iframeUrl,
|
|
327
|
-
launcherIcon: remoteConfig.launcherIcon,
|
|
328
|
-
});
|
|
329
|
-
} catch (error) {
|
|
330
|
-
console.error(
|
|
331
|
-
"[CopilotChat] Error during widget bootstrap:",
|
|
332
|
-
error instanceof Error ? error.message : error
|
|
333
|
-
);
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
export default loadCopilotChatWidget;
|
|
308
|
+
|
|
309
|
+
return buildWidget({
|
|
310
|
+
iframeUrl: remoteConfig.iframeUrl,
|
|
311
|
+
launcherIcon: remoteConfig.launcherIcon,
|
|
312
|
+
});
|
|
313
|
+
} catch (error) {
|
|
314
|
+
console.error(
|
|
315
|
+
"[CopilotChat] Error during widget bootstrap:",
|
|
316
|
+
error instanceof Error ? error.message : error
|
|
317
|
+
);
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export default loadCopilotChatWidget;
|