@uptrademedia/site-kit 1.0.19 → 1.0.20

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.
@@ -54,6 +54,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
54
54
  const [pendingFiles, setPendingFiles] = React2.useState([]);
55
55
  const [lastFailedSend, setLastFailedSend] = React2.useState(null);
56
56
  const [showWelcome, setShowWelcome] = React2.useState(true);
57
+ const [checkingAvailability, setCheckingAvailability] = React2.useState(false);
57
58
  React2.useRef(null);
58
59
  const messagesEndRef = React2.useRef(null);
59
60
  const inputRef = React2.useRef(null);
@@ -74,7 +75,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
74
75
  const fetchWidgetConfig = React2.useCallback(async () => {
75
76
  try {
76
77
  const { apiKey } = getApiConfig();
77
- const response = await fetch(`${baseUrl}/api/engage/widget/config?projectId=${projectId}`, {
78
+ const response = await fetch(`${baseUrl}/engage/widget/config?projectId=${projectId}`, {
78
79
  headers: apiKey ? { "x-api-key": apiKey } : {}
79
80
  });
80
81
  if (response.ok) {
@@ -88,25 +89,23 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
88
89
  const checkAvailability = React2.useCallback(async () => {
89
90
  try {
90
91
  const { apiKey } = getApiConfig();
91
- const response = await fetch(`${baseUrl}/api/engage/widget/availability?projectId=${projectId}`, {
92
+ const response = await fetch(`${baseUrl}/engage/widget/availability?projectId=${projectId}`, {
92
93
  headers: apiKey ? { "x-api-key": apiKey } : {}
93
94
  });
94
95
  if (response.ok) {
95
96
  const { data } = await response.json();
96
97
  setAvailability(data);
97
- if (data.mode === "offline" && !sessionId) {
98
- setShowOfflineForm(true);
99
- setShowWelcome(false);
100
- }
98
+ return data;
101
99
  }
102
100
  } catch (error) {
103
101
  console.error("[ChatWidget] Availability check failed:", error);
104
102
  }
105
- }, [projectId, baseUrl, sessionId]);
103
+ return null;
104
+ }, [projectId, baseUrl]);
106
105
  const initSession = React2.useCallback(async () => {
107
106
  try {
108
107
  const { apiKey } = getApiConfig();
109
- const response = await fetch(`${baseUrl}/api/engage/widget/session`, {
108
+ const response = await fetch(`${baseUrl}/engage/widget/session`, {
110
109
  method: "POST",
111
110
  headers: { "Content-Type": "application/json", ...apiKey && { "x-api-key": apiKey } },
112
111
  body: JSON.stringify({
@@ -209,7 +208,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
209
208
  console.log("[ChatWidget] Socket.io connected");
210
209
  if (currentSessionId) {
211
210
  const { apiKey } = getApiConfig();
212
- fetch(`${baseUrl}/api/engage/widget/messages?sessionId=${currentSessionId}`, {
211
+ fetch(`${baseUrl}/engage/widget/messages?sessionId=${currentSessionId}`, {
213
212
  headers: apiKey ? { "x-api-key": apiKey } : {}
214
213
  }).then((res) => res.ok ? res.json() : null).then((json) => {
215
214
  const data = json?.data ?? json;
@@ -272,7 +271,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
272
271
  pollingIntervalRef.current = setInterval(async () => {
273
272
  try {
274
273
  const { apiKey } = getApiConfig();
275
- const response = await fetch(`${baseUrl}/api/engage/widget/messages?sessionId=${currentSessionId}`, {
274
+ const response = await fetch(`${baseUrl}/engage/widget/messages?sessionId=${currentSessionId}`, {
276
275
  headers: apiKey ? { "x-api-key": apiKey } : {}
277
276
  });
278
277
  if (response.ok) {
@@ -321,7 +320,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
321
320
  };
322
321
  }, [fetchWidgetConfig, checkAvailability]);
323
322
  React2.useEffect(() => {
324
- if (isOpen && !showWelcome && !sessionId && availability?.mode !== "offline") {
323
+ if (isOpen && !showWelcome && !checkingAvailability && !showOfflineForm && !sessionId && availability?.mode !== "offline") {
325
324
  initSession().then((id) => {
326
325
  if (id && (availability?.mode === "live" || availability?.mode === "ai")) {
327
326
  setConnectionStatus("connecting");
@@ -332,26 +331,47 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
332
331
  return () => {
333
332
  if (pollingIntervalRef.current) clearInterval(pollingIntervalRef.current);
334
333
  };
335
- }, [isOpen, showWelcome, sessionId, availability?.mode, initSession, connectSocket]);
334
+ }, [isOpen, showWelcome, checkingAvailability, showOfflineForm, sessionId, availability?.mode, initSession, connectSocket]);
336
335
  const handleToggle = React2.useCallback(() => {
337
336
  setIsOpen((prev) => !prev);
338
337
  }, []);
339
338
  const startChat = React2.useCallback(
340
- (initialMessage) => {
339
+ async (initialMessage) => {
341
340
  setShowWelcome(false);
342
- setMessages([{ id: "welcome", role: "assistant", content: welcomeMessage, timestamp: /* @__PURE__ */ new Date() }]);
343
- if (initialMessage) {
344
- setInputValue(initialMessage);
345
- setTimeout(() => {
346
- setInputValue("");
347
- const userMsg = { id: `user-${Date.now()}`, role: "user", content: initialMessage, timestamp: /* @__PURE__ */ new Date() };
348
- setMessages((prev) => [...prev, userMsg]);
349
- setIsLoading(true);
350
- setLastFailedSend({ content: initialMessage, attachments: [] });
351
- }, 100);
341
+ const beginChatSession = () => {
342
+ setMessages([{ id: "welcome", role: "assistant", content: welcomeMessage, timestamp: /* @__PURE__ */ new Date() }]);
343
+ if (initialMessage) {
344
+ setInputValue(initialMessage);
345
+ setTimeout(() => {
346
+ setInputValue("");
347
+ const userMsg = { id: `user-${Date.now()}`, role: "user", content: initialMessage, timestamp: /* @__PURE__ */ new Date() };
348
+ setMessages((prev) => [...prev, userMsg]);
349
+ setIsLoading(true);
350
+ setLastFailedSend({ content: initialMessage, attachments: [] });
351
+ }, 100);
352
+ }
353
+ };
354
+ if (availability?.mode === "ai") {
355
+ beginChatSession();
356
+ return;
357
+ }
358
+ setCheckingAvailability(true);
359
+ const firstCheck = await checkAvailability();
360
+ if (firstCheck?.available && firstCheck.agentsOnline > 0) {
361
+ setCheckingAvailability(false);
362
+ beginChatSession();
363
+ return;
364
+ }
365
+ await new Promise((resolve) => setTimeout(resolve, 5e3));
366
+ const secondCheck = await checkAvailability();
367
+ setCheckingAvailability(false);
368
+ if (secondCheck?.available && secondCheck.agentsOnline > 0) {
369
+ beginChatSession();
370
+ } else {
371
+ setShowOfflineForm(true);
352
372
  }
353
373
  },
354
- [welcomeMessage]
374
+ [availability, welcomeMessage, checkAvailability]
355
375
  );
356
376
  const uploadWidgetFile = React2.useCallback(
357
377
  async (file) => {
@@ -361,7 +381,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
361
381
  form.append("file", file);
362
382
  form.append("sessionId", sessionId);
363
383
  form.append("visitorId", visitorId);
364
- const res = await fetch(`${baseUrl}/api/engage/widget/upload`, {
384
+ const res = await fetch(`${baseUrl}/engage/widget/upload`, {
365
385
  method: "POST",
366
386
  headers: apiKey ? { "x-api-key": apiKey } : {},
367
387
  body: form
@@ -439,7 +459,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
439
459
  if (!sessionId) return;
440
460
  try {
441
461
  const { apiKey } = getApiConfig();
442
- const availRes = await fetch(`${baseUrl}/api/engage/widget/availability?projectId=${projectId}`, {
462
+ const availRes = await fetch(`${baseUrl}/engage/widget/availability?projectId=${projectId}`, {
443
463
  headers: apiKey ? { "x-api-key": apiKey } : {}
444
464
  });
445
465
  const avail = availRes.ok ? (await availRes.json()).data : null;
@@ -452,7 +472,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
452
472
  ]);
453
473
  return;
454
474
  }
455
- await fetch(`${baseUrl}/api/engage/widget/handoff`, {
475
+ await fetch(`${baseUrl}/engage/widget/handoff`, {
456
476
  method: "POST",
457
477
  headers: { "Content-Type": "application/json", ...apiKey && { "x-api-key": apiKey } },
458
478
  body: JSON.stringify({ sessionId })
@@ -472,7 +492,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
472
492
  setIsLoading(true);
473
493
  try {
474
494
  const { apiKey } = getApiConfig();
475
- const response = await fetch(`${baseUrl}/api/engage/widget/offline-form`, {
495
+ const response = await fetch(`${baseUrl}/engage/widget/offline-form`, {
476
496
  method: "POST",
477
497
  headers: { "Content-Type": "application/json", ...apiKey && { "x-api-key": apiKey } },
478
498
  body: JSON.stringify({
@@ -509,6 +529,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
509
529
  }, []);
510
530
  const statusLabel = (() => {
511
531
  if (showOfflineForm) return null;
532
+ if (checkingAvailability) return { dot: "#f59e0b", text: "Checking availability..." };
512
533
  if (availability?.mode === "live" && availability.agentsOnline > 0) return { dot: "#22c55e", text: "Online" };
513
534
  if (availability?.mode === "ai") return { dot: "#a78bfa", text: "AI Assistant" };
514
535
  return { dot: "#9ca3af", text: "We'll respond soon" };
@@ -705,6 +726,75 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
705
726
  }
706
727
  )
707
728
  ] }) });
729
+ const CheckingScreen = /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 32, gap: 20, textAlign: "center" }, children: [
730
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", width: 64, height: 64 }, children: [
731
+ /* @__PURE__ */ jsxRuntime.jsx(
732
+ "div",
733
+ {
734
+ style: {
735
+ position: "absolute",
736
+ inset: 0,
737
+ borderRadius: "50%",
738
+ backgroundColor: `${primaryColor}15`,
739
+ animation: "checkPulse 2s infinite ease-out"
740
+ }
741
+ }
742
+ ),
743
+ /* @__PURE__ */ jsxRuntime.jsx(
744
+ "div",
745
+ {
746
+ style: {
747
+ position: "absolute",
748
+ inset: 8,
749
+ borderRadius: "50%",
750
+ backgroundColor: `${primaryColor}25`,
751
+ animation: "checkPulse 2s infinite ease-out 0.4s"
752
+ }
753
+ }
754
+ ),
755
+ /* @__PURE__ */ jsxRuntime.jsx(
756
+ "div",
757
+ {
758
+ style: {
759
+ position: "absolute",
760
+ inset: 16,
761
+ borderRadius: "50%",
762
+ backgroundColor: primaryColor,
763
+ display: "flex",
764
+ alignItems: "center",
765
+ justifyContent: "center"
766
+ },
767
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: isLightColor(primaryColor) ? "#1a1a1a" : "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
768
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
769
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8.5", cy: "7", r: "4" }),
770
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "20", y1: "8", x2: "20", y2: "14" }),
771
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "23", y1: "11", x2: "17", y2: "11" })
772
+ ] })
773
+ }
774
+ )
775
+ ] }),
776
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
777
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 16, fontWeight: 600, color: "#111827", marginBottom: 6 }, children: "Checking if any agents are available" }),
778
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 14, color: "#6b7280", lineHeight: 1.5 }, children: [
779
+ "One moment please",
780
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "inline-flex", width: 20 }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { animation: "checkDots 1.5s infinite steps(4, end)" }, children: "..." }) })
781
+ ] })
782
+ ] }),
783
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "80%", height: 3, backgroundColor: "#e5e7eb", borderRadius: 2, overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(
784
+ "div",
785
+ {
786
+ style: {
787
+ width: "100%",
788
+ height: "100%",
789
+ backgroundColor: primaryColor,
790
+ borderRadius: 2,
791
+ animation: "checkProgress 5s linear forwards",
792
+ transformOrigin: "left"
793
+ }
794
+ }
795
+ ) }),
796
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 12, color: "#9ca3af" }, children: "This usually takes just a few seconds" })
797
+ ] });
708
798
  const MessagesView = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
709
799
  /* @__PURE__ */ jsxRuntime.jsxs(
710
800
  "div",
@@ -887,7 +977,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
887
977
  },
888
978
  children: [
889
979
  Header,
890
- showOfflineForm ? OfflineFormView : showWelcome && welcomeEnabled && messages.length === 0 ? WelcomeScreen : MessagesView,
980
+ checkingAvailability ? CheckingScreen : showOfflineForm ? OfflineFormView : showWelcome && welcomeEnabled && messages.length === 0 ? WelcomeScreen : MessagesView,
891
981
  showPoweredBy && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "6px 0", textAlign: "center", fontSize: 11, color: "#9ca3af", backgroundColor: "#ffffff", borderTop: "1px solid #f3f4f6" }, children: [
892
982
  "Powered by",
893
983
  " ",
@@ -902,6 +992,20 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
902
992
  0%, 80%, 100% { opacity: 0.3; }
903
993
  40% { opacity: 1; }
904
994
  }
995
+ @keyframes checkPulse {
996
+ 0% { transform: scale(1); opacity: 1; }
997
+ 100% { transform: scale(1.8); opacity: 0; }
998
+ }
999
+ @keyframes checkDots {
1000
+ 0% { content: ''; }
1001
+ 25% { content: '.'; }
1002
+ 50% { content: '..'; }
1003
+ 75% { content: '...'; }
1004
+ }
1005
+ @keyframes checkProgress {
1006
+ from { transform: scaleX(0); }
1007
+ to { transform: scaleX(1); }
1008
+ }
905
1009
  ` })
906
1010
  ]
907
1011
  }
@@ -1528,5 +1632,5 @@ function getDeviceType() {
1528
1632
  exports.ChatWidget = ChatWidget;
1529
1633
  exports.DesignRenderer = DesignRenderer;
1530
1634
  exports.EngageWidget = EngageWidget;
1531
- //# sourceMappingURL=chunk-AZUOQAV6.js.map
1532
- //# sourceMappingURL=chunk-AZUOQAV6.js.map
1635
+ //# sourceMappingURL=chunk-D5VBZVOE.js.map
1636
+ //# sourceMappingURL=chunk-D5VBZVOE.js.map