@getwidgets/live-chat-widget 1.0.7 → 1.0.9
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/dist/live-chat-widget.umd.js +197 -18
- package/package.json +1 -1
|
@@ -19710,14 +19710,16 @@
|
|
|
19710
19710
|
function LuSend(props) {
|
|
19711
19711
|
return GenIcon({ "attr": { "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "strokeWidth": "2", "strokeLinecap": "round", "strokeLinejoin": "round" }, "child": [{ "tag": "path", "attr": { "d": "m22 2-7 20-4-9-9-4Z" } }, { "tag": "path", "attr": { "d": "M22 2 11 13" } }] })(props);
|
|
19712
19712
|
}
|
|
19713
|
+
const API_BASE_URL = "https://api.getwidgets.app";
|
|
19714
|
+
const WS_BASE_URL = "wss://api.getwidgets.app";
|
|
19713
19715
|
const fetchWidgetConfig = async (widgetId) => {
|
|
19714
|
-
const res = await fetch(
|
|
19716
|
+
const res = await fetch(`${API_BASE_URL}/api/widgets/user-widgets/${widgetId}/config`);
|
|
19715
19717
|
if (!res.ok) throw new Error("Failed to fetch widget config");
|
|
19716
19718
|
return res.json();
|
|
19717
19719
|
};
|
|
19718
19720
|
const checkSessionStatus = async (widgetId, sessionId) => {
|
|
19719
19721
|
try {
|
|
19720
|
-
const url =
|
|
19722
|
+
const url = `${API_BASE_URL}/api/widgets/livechat/${widgetId}/status/?session_id=${sessionId}`;
|
|
19721
19723
|
const res = await fetch(url);
|
|
19722
19724
|
if (!res.ok) {
|
|
19723
19725
|
const txt = await res.text().catch(() => null);
|
|
@@ -19748,7 +19750,7 @@
|
|
|
19748
19750
|
}
|
|
19749
19751
|
return sessionId;
|
|
19750
19752
|
};
|
|
19751
|
-
const LiveChatWidget = ({ widgetId, apiKey }) => {
|
|
19753
|
+
const LiveChatWidget = ({ widgetId, apiKey, name: name2 = null, email = null, unique_id = null }) => {
|
|
19752
19754
|
var _a, _b;
|
|
19753
19755
|
const [config, setConfig] = reactExports.useState(null);
|
|
19754
19756
|
const [messages, setMessages] = reactExports.useState([]);
|
|
@@ -19773,6 +19775,23 @@
|
|
|
19773
19775
|
const [windowWidth, setWindowWidth] = reactExports.useState(typeof window !== "undefined" ? window.innerWidth : 1024);
|
|
19774
19776
|
const isOpenRef = reactExports.useRef(false);
|
|
19775
19777
|
const ICON_MAP = { IoIosSend, IoSendOutline, MdOutlineSend, LuSend };
|
|
19778
|
+
const [authToken, setAuthToken] = reactExports.useState(null);
|
|
19779
|
+
const [localStorageToken, setLocalStorageToken] = reactExports.useState(null);
|
|
19780
|
+
const [contactName, setContactName] = reactExports.useState("");
|
|
19781
|
+
const [contactEmail, setContactEmail] = reactExports.useState("");
|
|
19782
|
+
const [showContactFields, setShowContactFields] = reactExports.useState(false);
|
|
19783
|
+
const [showContactErrors, setShowContactErrors] = reactExports.useState(false);
|
|
19784
|
+
const base64UrlEncode = (value) => {
|
|
19785
|
+
const json = typeof value === "string" ? value : JSON.stringify(value);
|
|
19786
|
+
const base64 = btoa(unescape(encodeURIComponent(json)));
|
|
19787
|
+
return base64.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
19788
|
+
};
|
|
19789
|
+
const buildUnsignedJwt = (payload) => {
|
|
19790
|
+
const header2 = { alg: "none", typ: "JWT" };
|
|
19791
|
+
const encodedHeader = base64UrlEncode(header2);
|
|
19792
|
+
const encodedPayload = base64UrlEncode(payload);
|
|
19793
|
+
return `${encodedHeader}.${encodedPayload}`;
|
|
19794
|
+
};
|
|
19776
19795
|
const normalizeIncomingMessage = (m2) => {
|
|
19777
19796
|
if (!m2) return { id: void 0, role: "agent", content: "", timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }), created_at: Date.now() };
|
|
19778
19797
|
if (m2.sent_by) {
|
|
@@ -19818,6 +19837,55 @@
|
|
|
19818
19837
|
const id2 = getSessionId();
|
|
19819
19838
|
setSessionId(id2);
|
|
19820
19839
|
}, [widgetId]);
|
|
19840
|
+
reactExports.useEffect(() => {
|
|
19841
|
+
if (typeof window === "undefined") return;
|
|
19842
|
+
try {
|
|
19843
|
+
const stored = localStorage.getItem("widgetkraft_livechat_authtoken");
|
|
19844
|
+
setLocalStorageToken(stored);
|
|
19845
|
+
if (stored && !authToken) setAuthToken(stored);
|
|
19846
|
+
} catch (e) {
|
|
19847
|
+
}
|
|
19848
|
+
const handleStorageChange = (e) => {
|
|
19849
|
+
if (e.key === "widgetkraft_livechat_authtoken" || e.key === null) {
|
|
19850
|
+
try {
|
|
19851
|
+
const stored = localStorage.getItem("widgetkraft_livechat_authtoken");
|
|
19852
|
+
setLocalStorageToken(stored);
|
|
19853
|
+
if (stored && !authToken) setAuthToken(stored);
|
|
19854
|
+
} catch (err) {
|
|
19855
|
+
}
|
|
19856
|
+
}
|
|
19857
|
+
};
|
|
19858
|
+
window.addEventListener("storage", handleStorageChange);
|
|
19859
|
+
return () => window.removeEventListener("storage", handleStorageChange);
|
|
19860
|
+
}, [authToken]);
|
|
19861
|
+
reactExports.useEffect(() => {
|
|
19862
|
+
const buildAuthToken = async () => {
|
|
19863
|
+
const hasIdentity = Boolean(name2 || email || unique_id);
|
|
19864
|
+
if (!hasIdentity || typeof window === "undefined") {
|
|
19865
|
+
return;
|
|
19866
|
+
}
|
|
19867
|
+
try {
|
|
19868
|
+
const payload = { name: name2, email, unique_id };
|
|
19869
|
+
const token = buildUnsignedJwt(payload);
|
|
19870
|
+
if (token) {
|
|
19871
|
+
try {
|
|
19872
|
+
localStorage.setItem("widgetkraft_livechat_authtoken", token);
|
|
19873
|
+
} catch (e) {
|
|
19874
|
+
}
|
|
19875
|
+
setAuthToken(token);
|
|
19876
|
+
setShowContactFields(false);
|
|
19877
|
+
}
|
|
19878
|
+
} catch (e) {
|
|
19879
|
+
console.warn("Failed to create auth token", e);
|
|
19880
|
+
try {
|
|
19881
|
+
localStorage.removeItem("widgetkraft_livechat_authtoken");
|
|
19882
|
+
} catch (err) {
|
|
19883
|
+
}
|
|
19884
|
+
setAuthToken(null);
|
|
19885
|
+
}
|
|
19886
|
+
};
|
|
19887
|
+
buildAuthToken();
|
|
19888
|
+
}, [name2, email, unique_id]);
|
|
19821
19889
|
reactExports.useEffect(() => {
|
|
19822
19890
|
const dismissalKey = `live-chat-notification-dismissed/${widgetId}`;
|
|
19823
19891
|
const dismissalTime = localStorage.getItem(dismissalKey);
|
|
@@ -19877,11 +19945,12 @@
|
|
|
19877
19945
|
}, []);
|
|
19878
19946
|
const startLiveSession = async (widgetUuid, currentSessionId) => {
|
|
19879
19947
|
try {
|
|
19880
|
-
const url =
|
|
19948
|
+
const url = `${API_BASE_URL}/api/widgets/livechat/start/${widgetUuid}/`;
|
|
19949
|
+
const storedAuthToken = authToken || (typeof window !== "undefined" ? localStorage.getItem("widgetkraft_livechat_authtoken") : null);
|
|
19881
19950
|
const res = await fetch(url, {
|
|
19882
19951
|
method: "POST",
|
|
19883
19952
|
headers: { "Content-Type": "application/json" },
|
|
19884
|
-
body: JSON.stringify({ session_id: currentSessionId })
|
|
19953
|
+
body: JSON.stringify({ session_id: currentSessionId, auth_token: storedAuthToken || null })
|
|
19885
19954
|
});
|
|
19886
19955
|
if (!res.ok) {
|
|
19887
19956
|
const txt = await res.text().catch(() => null);
|
|
@@ -19904,7 +19973,7 @@
|
|
|
19904
19973
|
}
|
|
19905
19974
|
wsRef.current = null;
|
|
19906
19975
|
}
|
|
19907
|
-
const url =
|
|
19976
|
+
const url = `${WS_BASE_URL}/ws/livechat/${sid}`;
|
|
19908
19977
|
const ws = new WebSocket(url);
|
|
19909
19978
|
wsRef.current = ws;
|
|
19910
19979
|
ws.onopen = () => {
|
|
@@ -20141,8 +20210,8 @@
|
|
|
20141
20210
|
localStorage.setItem(dismissalKey, Date.now().toString());
|
|
20142
20211
|
setShowNotificationPreview(false);
|
|
20143
20212
|
};
|
|
20144
|
-
|
|
20145
|
-
const { header, chat_area, input_area, appearance } =
|
|
20213
|
+
const widgetConfig = ((_a = config == null ? void 0 : config.config) == null ? void 0 : _a.chat_widget) || {};
|
|
20214
|
+
const { header, chat_area, input_area, appearance } = widgetConfig;
|
|
20146
20215
|
const headerConfig = header || {};
|
|
20147
20216
|
const appearanceConfig = appearance || {};
|
|
20148
20217
|
const chatAreaConfig = chat_area || {};
|
|
@@ -20229,6 +20298,44 @@
|
|
|
20229
20298
|
};
|
|
20230
20299
|
const timeTextColor = getContrastColor(appearanceConfig.background_color || "#F9FAFB");
|
|
20231
20300
|
const isMobile = windowWidth < 768;
|
|
20301
|
+
reactExports.useEffect(() => {
|
|
20302
|
+
if (inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email) {
|
|
20303
|
+
let hasToken = false;
|
|
20304
|
+
try {
|
|
20305
|
+
hasToken = !!(authToken || localStorage.getItem("widgetkraft_livechat_authtoken"));
|
|
20306
|
+
} catch (e) {
|
|
20307
|
+
hasToken = !!authToken;
|
|
20308
|
+
}
|
|
20309
|
+
setShowContactFields(!hasToken);
|
|
20310
|
+
} else {
|
|
20311
|
+
setShowContactFields(false);
|
|
20312
|
+
}
|
|
20313
|
+
}, [inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email, authToken, isOpen]);
|
|
20314
|
+
const isContactValid = !(inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email) || (!showContactFields ? true : contactName.trim() && contactEmail.trim());
|
|
20315
|
+
const createAndStoreAuthToken = () => {
|
|
20316
|
+
const payload = { name: contactName.trim(), email: contactEmail.trim(), unique_id };
|
|
20317
|
+
const token = buildUnsignedJwt(payload);
|
|
20318
|
+
try {
|
|
20319
|
+
localStorage.setItem("widgetkraft_livechat_authtoken", token);
|
|
20320
|
+
} catch (e) {
|
|
20321
|
+
}
|
|
20322
|
+
setAuthToken(token);
|
|
20323
|
+
return token;
|
|
20324
|
+
};
|
|
20325
|
+
const performSendWithContact = async () => {
|
|
20326
|
+
if ((inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email) && !authToken) {
|
|
20327
|
+
const missingName = !contactName.trim();
|
|
20328
|
+
const missingEmail = !contactEmail.trim();
|
|
20329
|
+
if (missingName || missingEmail) {
|
|
20330
|
+
setShowContactErrors(true);
|
|
20331
|
+
return;
|
|
20332
|
+
}
|
|
20333
|
+
createAndStoreAuthToken();
|
|
20334
|
+
setShowContactFields(false);
|
|
20335
|
+
}
|
|
20336
|
+
await performSend();
|
|
20337
|
+
};
|
|
20338
|
+
if (!config) return null;
|
|
20232
20339
|
return /* @__PURE__ */ React.createElement("div", { style: getPositionStyles() }, !isOpen && showNotificationPreview && /* @__PURE__ */ React.createElement(
|
|
20233
20340
|
"div",
|
|
20234
20341
|
{
|
|
@@ -20481,7 +20588,7 @@
|
|
|
20481
20588
|
/* @__PURE__ */ React.createElement(
|
|
20482
20589
|
"div",
|
|
20483
20590
|
{
|
|
20484
|
-
className: "flex
|
|
20591
|
+
className: "flex flex-col gap-2 border-t flex-shrink-0",
|
|
20485
20592
|
style: {
|
|
20486
20593
|
backgroundColor: inputAreaConfig.background_color || "#FFF",
|
|
20487
20594
|
borderColor: inputAreaConfig.border_color || "#D1D5DB",
|
|
@@ -20491,7 +20598,7 @@
|
|
|
20491
20598
|
gap: isMobile ? "8px" : "12px"
|
|
20492
20599
|
}
|
|
20493
20600
|
},
|
|
20494
|
-
/* @__PURE__ */ React.createElement(
|
|
20601
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 w-full" }, /* @__PURE__ */ React.createElement(
|
|
20495
20602
|
"input",
|
|
20496
20603
|
{
|
|
20497
20604
|
ref: inputRef,
|
|
@@ -20511,11 +20618,10 @@
|
|
|
20511
20618
|
},
|
|
20512
20619
|
placeholder: inputAreaConfig.placeholder_text || "Type your message..."
|
|
20513
20620
|
}
|
|
20514
|
-
),
|
|
20515
|
-
/* @__PURE__ */ React.createElement(
|
|
20621
|
+
), /* @__PURE__ */ React.createElement(
|
|
20516
20622
|
"button",
|
|
20517
20623
|
{
|
|
20518
|
-
onClick:
|
|
20624
|
+
onClick: performSendWithContact,
|
|
20519
20625
|
disabled: localLoading || !inputMessage.trim(),
|
|
20520
20626
|
className: "rounded-full flex items-center justify-center flex-shrink-0 hover:opacity-90 transition-opacity",
|
|
20521
20627
|
style: {
|
|
@@ -20524,7 +20630,7 @@
|
|
|
20524
20630
|
height: `${sendButtonSize}px`,
|
|
20525
20631
|
minWidth: `${sendButtonSize}px`,
|
|
20526
20632
|
minHeight: `${sendButtonSize}px`,
|
|
20527
|
-
opacity: localLoading || !inputMessage.trim() ? 0.5 : 1,
|
|
20633
|
+
opacity: localLoading || !inputMessage.trim() || !isContactValid ? 0.5 : 1,
|
|
20528
20634
|
transition: "opacity 0.2s",
|
|
20529
20635
|
border: "none",
|
|
20530
20636
|
cursor: "pointer"
|
|
@@ -20553,7 +20659,47 @@
|
|
|
20553
20659
|
if (iconUrl) return /* @__PURE__ */ React.createElement("img", { src: iconUrl, alt: "send", style: { width: "60%", height: "60%" } });
|
|
20554
20660
|
return /* @__PURE__ */ React.createElement(Send, { className: "w-4 h-4", style: { color: "#FFFFFF" } });
|
|
20555
20661
|
})()
|
|
20556
|
-
)
|
|
20662
|
+
)),
|
|
20663
|
+
showContactFields && /* @__PURE__ */ React.createElement("div", { className: "p-3 border rounded-lg mt-2", style: {
|
|
20664
|
+
borderColor: showContactErrors && (!contactName.trim() || !contactEmail.trim()) ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
|
|
20665
|
+
backgroundColor: inputAreaConfig.background_color || "#FFF"
|
|
20666
|
+
} }, /* @__PURE__ */ React.createElement("div", { className: "text-sm font-semibold mb-2", style: { color: inputAreaConfig.text_color || "#111827" } }, "How should we reach you?"), /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement(
|
|
20667
|
+
"input",
|
|
20668
|
+
{
|
|
20669
|
+
type: "text",
|
|
20670
|
+
placeholder: "Name",
|
|
20671
|
+
value: contactName,
|
|
20672
|
+
onChange: (e) => {
|
|
20673
|
+
setContactName(e.target.value);
|
|
20674
|
+
if (showContactErrors) setShowContactErrors(false);
|
|
20675
|
+
},
|
|
20676
|
+
className: "w-full px-3 py-1.5 border rounded-md",
|
|
20677
|
+
style: {
|
|
20678
|
+
borderColor: showContactErrors && !contactName.trim() ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
|
|
20679
|
+
color: inputAreaConfig.text_color || "#111827",
|
|
20680
|
+
fontSize: "13px",
|
|
20681
|
+
backgroundColor: inputAreaConfig.background_color || "#FFF"
|
|
20682
|
+
}
|
|
20683
|
+
}
|
|
20684
|
+
), /* @__PURE__ */ React.createElement(
|
|
20685
|
+
"input",
|
|
20686
|
+
{
|
|
20687
|
+
type: "email",
|
|
20688
|
+
placeholder: "Email address",
|
|
20689
|
+
value: contactEmail,
|
|
20690
|
+
onChange: (e) => {
|
|
20691
|
+
setContactEmail(e.target.value);
|
|
20692
|
+
if (showContactErrors) setShowContactErrors(false);
|
|
20693
|
+
},
|
|
20694
|
+
className: "w-full px-3 py-1.5 border rounded-md",
|
|
20695
|
+
style: {
|
|
20696
|
+
borderColor: showContactErrors && !contactEmail.trim() ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
|
|
20697
|
+
color: inputAreaConfig.text_color || "#111827",
|
|
20698
|
+
fontSize: "13px",
|
|
20699
|
+
backgroundColor: inputAreaConfig.background_color || "#FFF"
|
|
20700
|
+
}
|
|
20701
|
+
}
|
|
20702
|
+
), showContactErrors && (!contactName.trim() || !contactEmail.trim()) && /* @__PURE__ */ React.createElement("div", { className: "text-xs", style: { color: "#EF4444" } }, `${!contactName.trim() ? "Name is required. " : ""}${!contactEmail.trim() ? "Email is required." : ""}`)))
|
|
20557
20703
|
),
|
|
20558
20704
|
inputAreaConfig.show_branding !== false && /* @__PURE__ */ React.createElement(
|
|
20559
20705
|
"div",
|
|
@@ -20649,7 +20795,7 @@
|
|
|
20649
20795
|
}
|
|
20650
20796
|
`));
|
|
20651
20797
|
};
|
|
20652
|
-
function init({ widgetId, apiKey, mode = "inline" }) {
|
|
20798
|
+
function init({ widgetId, apiKey, mode = "inline", name: name2 = null, email = null, unique_id = null }) {
|
|
20653
20799
|
const container = document.getElementById("livechat-root");
|
|
20654
20800
|
if (!container) {
|
|
20655
20801
|
console.error("Live Chat Widget root element (#livechat-root) not found.");
|
|
@@ -20669,7 +20815,16 @@
|
|
|
20669
20815
|
const root2 = client.createRoot(mountPoint);
|
|
20670
20816
|
try {
|
|
20671
20817
|
root2.render(
|
|
20672
|
-
/* @__PURE__ */ React.createElement(React.StrictMode, null, /* @__PURE__ */ React.createElement(
|
|
20818
|
+
/* @__PURE__ */ React.createElement(React.StrictMode, null, /* @__PURE__ */ React.createElement(
|
|
20819
|
+
LiveChatWidget,
|
|
20820
|
+
{
|
|
20821
|
+
widgetId,
|
|
20822
|
+
apiKey,
|
|
20823
|
+
name: name2,
|
|
20824
|
+
email,
|
|
20825
|
+
unique_id
|
|
20826
|
+
}
|
|
20827
|
+
))
|
|
20673
20828
|
);
|
|
20674
20829
|
container.__livechat_mounted = true;
|
|
20675
20830
|
} catch (err) {
|
|
@@ -20684,7 +20839,31 @@
|
|
|
20684
20839
|
mountPoint.appendChild(errDiv);
|
|
20685
20840
|
}
|
|
20686
20841
|
}
|
|
20687
|
-
|
|
20842
|
+
function setUser({ name: name2, email, unique_id }) {
|
|
20843
|
+
const container = document.getElementById("livechat-root");
|
|
20844
|
+
if (container && container.__livechat_mounted) {
|
|
20845
|
+
const shadowRoot = container.shadowRoot;
|
|
20846
|
+
if (shadowRoot) {
|
|
20847
|
+
const mountPoint = shadowRoot.getElementById("live-chat-widget-mount") || shadowRoot.querySelector("#live-chat-widget-mount");
|
|
20848
|
+
if (mountPoint) {
|
|
20849
|
+
const root2 = client.createRoot(mountPoint);
|
|
20850
|
+
root2.render(
|
|
20851
|
+
/* @__PURE__ */ React.createElement(React.StrictMode, null, /* @__PURE__ */ React.createElement(
|
|
20852
|
+
LiveChatWidget,
|
|
20853
|
+
{
|
|
20854
|
+
widgetId: container.dataset.widgetId,
|
|
20855
|
+
apiKey: container.dataset.apiKey,
|
|
20856
|
+
name: name2,
|
|
20857
|
+
email,
|
|
20858
|
+
unique_id
|
|
20859
|
+
}
|
|
20860
|
+
))
|
|
20861
|
+
);
|
|
20862
|
+
}
|
|
20863
|
+
}
|
|
20864
|
+
}
|
|
20865
|
+
}
|
|
20866
|
+
window.LiveChatWidget = { init, setUser };
|
|
20688
20867
|
exports2.init = init;
|
|
20689
20868
|
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
20690
20869
|
});
|