@uptrademedia/site-kit 1.0.19 → 1.0.23

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.
Files changed (81) hide show
  1. package/dist/analytics/index.js +6 -6
  2. package/dist/analytics/index.mjs +2 -2
  3. package/dist/{chunk-BZBJVG5Y.js → chunk-4KKQQRZV.js} +4 -4
  4. package/dist/{chunk-BZBJVG5Y.js.map → chunk-4KKQQRZV.js.map} +1 -1
  5. package/dist/{chunk-VDMZZL2O.mjs → chunk-ASVFZY6X.mjs} +4 -4
  6. package/dist/{chunk-VDMZZL2O.mjs.map → chunk-ASVFZY6X.mjs.map} +1 -1
  7. package/dist/chunk-EL5QTAA3.mjs +1 -0
  8. package/dist/{chunk-KBS3KW2U.js → chunk-GKABCBZE.js} +2 -2
  9. package/dist/{chunk-KBS3KW2U.js.map → chunk-GKABCBZE.js.map} +1 -1
  10. package/dist/{chunk-SQHDILBN.js → chunk-HGTTGJVZ.js} +4 -2
  11. package/dist/chunk-HGTTGJVZ.js.map +1 -0
  12. package/dist/{chunk-DOHML47I.mjs → chunk-HHAJAANV.mjs} +46 -4
  13. package/dist/chunk-HHAJAANV.mjs.map +1 -0
  14. package/dist/{chunk-IJVPYQAB.mjs → chunk-JTLOJLWQ.mjs} +4 -50
  15. package/dist/chunk-JTLOJLWQ.mjs.map +1 -0
  16. package/dist/{chunk-BV4YYSAZ.js → chunk-KUGMH4ZF.js} +2 -50
  17. package/dist/chunk-KUGMH4ZF.js.map +1 -0
  18. package/dist/chunk-M5VNAX5I.mjs +54 -0
  19. package/dist/chunk-M5VNAX5I.mjs.map +1 -0
  20. package/dist/chunk-MXBDMOVK.js +56 -0
  21. package/dist/chunk-MXBDMOVK.js.map +1 -0
  22. package/dist/{chunk-YHQHSM76.mjs → chunk-OW2C3ATV.mjs} +5 -2
  23. package/dist/chunk-OW2C3ATV.mjs.map +1 -0
  24. package/dist/chunk-QD66FTXZ.mjs +1 -0
  25. package/dist/{chunk-K2HWVOEO.js → chunk-RM4XFDE6.js} +46 -3
  26. package/dist/chunk-RM4XFDE6.js.map +1 -0
  27. package/dist/{chunk-IT6R5VAZ.mjs → chunk-VZHEJXDY.mjs} +2 -2
  28. package/dist/{chunk-IT6R5VAZ.mjs.map → chunk-VZHEJXDY.mjs.map} +1 -1
  29. package/dist/chunk-WPSRS352.mjs +1 -0
  30. package/dist/chunk-XFRPT5ZX.mjs +1 -0
  31. package/dist/{chunk-AZUOQAV6.js → chunk-XVYXOTWO.js} +176 -41
  32. package/dist/chunk-XVYXOTWO.js.map +1 -0
  33. package/dist/{chunk-XIF2CBLV.mjs → chunk-Y2FMP4QM.mjs} +176 -41
  34. package/dist/chunk-Y2FMP4QM.mjs.map +1 -0
  35. package/dist/cli/index.js +1 -1
  36. package/dist/cli/index.mjs +1 -1
  37. package/dist/commerce/index.d.mts +1 -1
  38. package/dist/commerce/index.d.ts +1 -1
  39. package/dist/commerce/index.js +42 -38
  40. package/dist/commerce/index.mjs +1 -1
  41. package/dist/engage/index.d.mts +1 -1
  42. package/dist/engage/index.d.ts +1 -1
  43. package/dist/engage/index.js +4 -4
  44. package/dist/engage/index.mjs +1 -1
  45. package/dist/images/index.d.mts +2 -54
  46. package/dist/images/index.d.ts +2 -54
  47. package/dist/images/index.js +13 -12
  48. package/dist/images/index.mjs +2 -1
  49. package/dist/images/server.d.mts +54 -0
  50. package/dist/images/server.d.ts +54 -0
  51. package/dist/images/server.js +13 -0
  52. package/dist/images/server.js.map +1 -0
  53. package/dist/images/server.mjs +4 -0
  54. package/dist/images/server.mjs.map +1 -0
  55. package/dist/index.d.mts +1 -1
  56. package/dist/index.d.ts +1 -1
  57. package/dist/index.js +43 -42
  58. package/dist/index.js.map +1 -1
  59. package/dist/index.mjs +6 -5
  60. package/dist/index.mjs.map +1 -1
  61. package/dist/redirects/index.js +5 -5
  62. package/dist/redirects/index.mjs +1 -1
  63. package/dist/setup/index.js +2 -2
  64. package/dist/setup/index.mjs +1 -1
  65. package/dist/setup/server.js +2 -2
  66. package/dist/setup/server.mjs +1 -1
  67. package/dist/socket-loader-3FWQWPDQ.js +16 -0
  68. package/dist/socket-loader-3FWQWPDQ.js.map +1 -0
  69. package/dist/socket-loader-N5ETWMXW.mjs +14 -0
  70. package/dist/socket-loader-N5ETWMXW.mjs.map +1 -0
  71. package/dist/{useEventModal-CaePVcfW.d.ts → useEventModal-DHO4-xhg.d.ts} +6 -1
  72. package/dist/{useEventModal-Dt6y1L0o.d.mts → useEventModal-Dbg2fYYk.d.mts} +6 -1
  73. package/package.json +6 -1
  74. package/dist/chunk-AZUOQAV6.js.map +0 -1
  75. package/dist/chunk-BV4YYSAZ.js.map +0 -1
  76. package/dist/chunk-DOHML47I.mjs.map +0 -1
  77. package/dist/chunk-IJVPYQAB.mjs.map +0 -1
  78. package/dist/chunk-K2HWVOEO.js.map +0 -1
  79. package/dist/chunk-SQHDILBN.js.map +0 -1
  80. package/dist/chunk-XIF2CBLV.mjs.map +0 -1
  81. package/dist/chunk-YHQHSM76.mjs.map +0 -1
@@ -1,5 +1,4 @@
1
1
  import React2, { useState, useRef, useCallback, useEffect, createElement } from 'react';
2
- import { io } from 'socket.io-client';
3
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
3
  import { usePathname } from 'next/navigation';
5
4
 
@@ -48,7 +47,9 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
48
47
  const [pendingFiles, setPendingFiles] = useState([]);
49
48
  const [lastFailedSend, setLastFailedSend] = useState(null);
50
49
  const [showWelcome, setShowWelcome] = useState(true);
50
+ const [checkingAvailability, setCheckingAvailability] = useState(false);
51
51
  useRef(null);
52
+ const pendingInitialMessageRef = useRef(null);
52
53
  const messagesEndRef = useRef(null);
53
54
  const inputRef = useRef(null);
54
55
  const socketRef = useRef(null);
@@ -66,9 +67,10 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
66
67
  const offlineSubheading = handoffOfflinePrompt ?? widgetConfig?.offline_subheading ?? widgetConfig?.form_description ?? widgetConfig?.offline_message ?? config?.offlineMessage ?? "Leave us a message and we'll get back to you!";
67
68
  const baseUrl = propApiUrl || getApiConfig().apiUrl;
68
69
  const fetchWidgetConfig = useCallback(async () => {
70
+ if (!projectId) return;
69
71
  try {
70
72
  const { apiKey } = getApiConfig();
71
- const response = await fetch(`${baseUrl}/api/engage/widget/config?projectId=${projectId}`, {
73
+ const response = await fetch(`${baseUrl}/engage/widget/config?projectId=${projectId}`, {
72
74
  headers: apiKey ? { "x-api-key": apiKey } : {}
73
75
  });
74
76
  if (response.ok) {
@@ -76,31 +78,34 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
76
78
  setWidgetConfig(data ?? null);
77
79
  }
78
80
  } catch (error) {
79
- console.error("[ChatWidget] Config fetch failed:", error);
81
+ if (process.env.NODE_ENV === "development") {
82
+ console.warn("[ChatWidget] Config fetch failed:", error instanceof Error ? error.message : error);
83
+ }
80
84
  }
81
85
  }, [projectId, baseUrl]);
82
86
  const checkAvailability = useCallback(async () => {
87
+ if (!projectId) return null;
83
88
  try {
84
89
  const { apiKey } = getApiConfig();
85
- const response = await fetch(`${baseUrl}/api/engage/widget/availability?projectId=${projectId}`, {
90
+ const response = await fetch(`${baseUrl}/engage/widget/availability?projectId=${projectId}`, {
86
91
  headers: apiKey ? { "x-api-key": apiKey } : {}
87
92
  });
88
93
  if (response.ok) {
89
94
  const { data } = await response.json();
90
95
  setAvailability(data);
91
- if (data.mode === "offline" && !sessionId) {
92
- setShowOfflineForm(true);
93
- setShowWelcome(false);
94
- }
96
+ return data;
95
97
  }
96
98
  } catch (error) {
97
- console.error("[ChatWidget] Availability check failed:", error);
99
+ if (process.env.NODE_ENV === "development") {
100
+ console.warn("[ChatWidget] Availability check failed:", error instanceof Error ? error.message : error);
101
+ }
98
102
  }
99
- }, [projectId, baseUrl, sessionId]);
103
+ return null;
104
+ }, [projectId, baseUrl]);
100
105
  const initSession = useCallback(async () => {
101
106
  try {
102
107
  const { apiKey } = getApiConfig();
103
- const response = await fetch(`${baseUrl}/api/engage/widget/session`, {
108
+ const response = await fetch(`${baseUrl}/engage/widget/session`, {
104
109
  method: "POST",
105
110
  headers: { "Content-Type": "application/json", ...apiKey && { "x-api-key": apiKey } },
106
111
  body: JSON.stringify({
@@ -181,14 +186,15 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
181
186
  }
182
187
  }, []);
183
188
  const connectSocket = useCallback(
184
- (currentSessionId) => {
189
+ async (currentSessionId) => {
185
190
  if (socketRef.current?.connected) return;
186
191
  if (socketRef.current) {
187
192
  socketRef.current.disconnect();
188
193
  socketRef.current = null;
189
194
  }
195
+ const { createSocket } = await import('./socket-loader-N5ETWMXW.mjs');
190
196
  const namespaceUrl = `${baseUrl.replace(/\/$/, "")}/engage/chat`;
191
- const socket = io(namespaceUrl, {
197
+ const socket = await createSocket(namespaceUrl, {
192
198
  query: { projectId, visitorId, sessionId: currentSessionId },
193
199
  transports: ["websocket", "polling"],
194
200
  // Auto-reconnect config
@@ -203,7 +209,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
203
209
  console.log("[ChatWidget] Socket.io connected");
204
210
  if (currentSessionId) {
205
211
  const { apiKey } = getApiConfig();
206
- fetch(`${baseUrl}/api/engage/widget/messages?sessionId=${currentSessionId}`, {
212
+ fetch(`${baseUrl}/engage/widget/messages?sessionId=${currentSessionId}`, {
207
213
  headers: apiKey ? { "x-api-key": apiKey } : {}
208
214
  }).then((res) => res.ok ? res.json() : null).then((json) => {
209
215
  const data = json?.data ?? json;
@@ -266,7 +272,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
266
272
  pollingIntervalRef.current = setInterval(async () => {
267
273
  try {
268
274
  const { apiKey } = getApiConfig();
269
- const response = await fetch(`${baseUrl}/api/engage/widget/messages?sessionId=${currentSessionId}`, {
275
+ const response = await fetch(`${baseUrl}/engage/widget/messages?sessionId=${currentSessionId}`, {
270
276
  headers: apiKey ? { "x-api-key": apiKey } : {}
271
277
  });
272
278
  if (response.ok) {
@@ -315,37 +321,71 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
315
321
  };
316
322
  }, [fetchWidgetConfig, checkAvailability]);
317
323
  useEffect(() => {
318
- if (isOpen && !showWelcome && !sessionId && availability?.mode !== "offline") {
319
- initSession().then((id) => {
320
- if (id && (availability?.mode === "live" || availability?.mode === "ai")) {
321
- setConnectionStatus("connecting");
322
- connectSocket(id);
324
+ if (isOpen && !showWelcome && !checkingAvailability && !showOfflineForm && !sessionId) {
325
+ initSession().then(async (id) => {
326
+ if (!id) return;
327
+ setConnectionStatus("connecting");
328
+ await connectSocket(id);
329
+ const pending = pendingInitialMessageRef.current;
330
+ if (pending) {
331
+ pendingInitialMessageRef.current = null;
332
+ const waitForSocket = () => new Promise((resolve) => {
333
+ const check = (attempts = 0) => {
334
+ if (socketRef.current?.connected || attempts > 20) {
335
+ resolve();
336
+ return;
337
+ }
338
+ setTimeout(() => check(attempts + 1), 150);
339
+ };
340
+ check();
341
+ });
342
+ await waitForSocket();
343
+ if (socketRef.current?.connected) {
344
+ socketRef.current.emit("visitor:message", { content: pending });
345
+ }
323
346
  }
324
347
  });
325
348
  }
326
349
  return () => {
327
350
  if (pollingIntervalRef.current) clearInterval(pollingIntervalRef.current);
328
351
  };
329
- }, [isOpen, showWelcome, sessionId, availability?.mode, initSession, connectSocket]);
352
+ }, [isOpen, showWelcome, checkingAvailability, showOfflineForm, sessionId, initSession, connectSocket]);
330
353
  const handleToggle = useCallback(() => {
331
354
  setIsOpen((prev) => !prev);
332
355
  }, []);
333
356
  const startChat = useCallback(
334
- (initialMessage) => {
357
+ async (initialMessage) => {
335
358
  setShowWelcome(false);
336
- setMessages([{ id: "welcome", role: "assistant", content: welcomeMessage, timestamp: /* @__PURE__ */ new Date() }]);
337
- if (initialMessage) {
338
- setInputValue(initialMessage);
339
- setTimeout(() => {
340
- setInputValue("");
359
+ const beginChatSession = () => {
360
+ setMessages([{ id: "welcome", role: "assistant", content: welcomeMessage, timestamp: /* @__PURE__ */ new Date() }]);
361
+ if (initialMessage) {
362
+ pendingInitialMessageRef.current = initialMessage;
341
363
  const userMsg = { id: `user-${Date.now()}`, role: "user", content: initialMessage, timestamp: /* @__PURE__ */ new Date() };
342
364
  setMessages((prev) => [...prev, userMsg]);
343
365
  setIsLoading(true);
344
- setLastFailedSend({ content: initialMessage, attachments: [] });
345
- }, 100);
366
+ }
367
+ };
368
+ if (widgetConfig?.signal_enabled) {
369
+ beginChatSession();
370
+ return;
371
+ }
372
+ setCheckingAvailability(true);
373
+ const firstCheck = await checkAvailability();
374
+ if (firstCheck?.available && firstCheck.agentsOnline > 0) {
375
+ setCheckingAvailability(false);
376
+ beginChatSession();
377
+ return;
378
+ }
379
+ await new Promise((resolve) => setTimeout(resolve, 5e3));
380
+ const secondCheck = await checkAvailability();
381
+ setCheckingAvailability(false);
382
+ if (secondCheck?.available && secondCheck.agentsOnline > 0) {
383
+ beginChatSession();
384
+ } else {
385
+ setShowOfflineForm(true);
346
386
  }
347
387
  },
348
- [welcomeMessage]
388
+ [widgetConfig?.signal_enabled, welcomeMessage, checkAvailability]
349
389
  );
350
390
  const uploadWidgetFile = useCallback(
351
391
  async (file) => {
@@ -355,7 +395,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
355
395
  form.append("file", file);
356
396
  form.append("sessionId", sessionId);
357
397
  form.append("visitorId", visitorId);
358
- const res = await fetch(`${baseUrl}/api/engage/widget/upload`, {
398
+ const res = await fetch(`${baseUrl}/engage/widget/upload`, {
359
399
  method: "POST",
360
400
  headers: apiKey ? { "x-api-key": apiKey } : {},
361
401
  body: form
@@ -433,7 +473,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
433
473
  if (!sessionId) return;
434
474
  try {
435
475
  const { apiKey } = getApiConfig();
436
- const availRes = await fetch(`${baseUrl}/api/engage/widget/availability?projectId=${projectId}`, {
476
+ const availRes = await fetch(`${baseUrl}/engage/widget/availability?projectId=${projectId}`, {
437
477
  headers: apiKey ? { "x-api-key": apiKey } : {}
438
478
  });
439
479
  const avail = availRes.ok ? (await availRes.json()).data : null;
@@ -446,7 +486,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
446
486
  ]);
447
487
  return;
448
488
  }
449
- await fetch(`${baseUrl}/api/engage/widget/handoff`, {
489
+ await fetch(`${baseUrl}/engage/widget/handoff`, {
450
490
  method: "POST",
451
491
  headers: { "Content-Type": "application/json", ...apiKey && { "x-api-key": apiKey } },
452
492
  body: JSON.stringify({ sessionId })
@@ -459,14 +499,16 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
459
499
  console.error("[ChatWidget] Handoff request failed:", error);
460
500
  }
461
501
  }, [sessionId, baseUrl, projectId, widgetConfig, offlineHeading]);
502
+ const [offlineError, setOfflineError] = useState(null);
462
503
  const handleOfflineSubmit = useCallback(
463
504
  async (e) => {
464
505
  e.preventDefault();
465
506
  if (!offlineForm.name || !offlineForm.email || !offlineForm.message) return;
466
507
  setIsLoading(true);
508
+ setOfflineError(null);
467
509
  try {
468
510
  const { apiKey } = getApiConfig();
469
- const response = await fetch(`${baseUrl}/api/engage/widget/offline-form`, {
511
+ const response = await fetch(`${baseUrl}/engage/widget/offline-form`, {
470
512
  method: "POST",
471
513
  headers: { "Content-Type": "application/json", ...apiKey && { "x-api-key": apiKey } },
472
514
  body: JSON.stringify({
@@ -477,9 +519,16 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
477
519
  ...widgetConfig?.offlineFormSlug && { formSlug: widgetConfig.offlineFormSlug }
478
520
  })
479
521
  });
480
- if (response.ok) setOfflineSubmitted(true);
522
+ if (response.ok) {
523
+ setOfflineSubmitted(true);
524
+ } else {
525
+ const errorBody = await response.text().catch(() => "");
526
+ console.error(`[ChatWidget] Offline form returned ${response.status}:`, errorBody);
527
+ setOfflineError("Something went wrong. Please try again.");
528
+ }
481
529
  } catch (error) {
482
530
  console.error("[ChatWidget] Offline form submission failed:", error);
531
+ setOfflineError("Unable to send message. Please check your connection and try again.");
483
532
  } finally {
484
533
  setIsLoading(false);
485
534
  }
@@ -503,8 +552,9 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
503
552
  }, []);
504
553
  const statusLabel = (() => {
505
554
  if (showOfflineForm) return null;
506
- if (availability?.mode === "live" && availability.agentsOnline > 0) return { dot: "#22c55e", text: "Online" };
507
- if (availability?.mode === "ai") return { dot: "#a78bfa", text: "AI Assistant" };
555
+ if (checkingAvailability) return { dot: "#f59e0b", text: "Checking for a team member..." };
556
+ if (widgetConfig?.signal_enabled) return { dot: "#a78bfa", text: "AI Assistant" };
557
+ if (availability && availability.agentsOnline > 0) return { dot: "#22c55e", text: "Online" };
508
558
  return { dot: "#9ca3af", text: "We'll respond soon" };
509
559
  })();
510
560
  const ChatButton = /* @__PURE__ */ jsx(
@@ -678,6 +728,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
678
728
  onBlur: (e) => e.currentTarget.style.borderColor = "#e5e7eb"
679
729
  }
680
730
  ) }),
731
+ offlineError && /* @__PURE__ */ jsx("div", { style: { padding: "8px 12px", borderRadius: 8, backgroundColor: "#fef2f2", border: "1px solid #fecaca", color: "#dc2626", fontSize: 13, marginBottom: 12 }, children: offlineError }),
681
732
  /* @__PURE__ */ jsx(
682
733
  "button",
683
734
  {
@@ -699,6 +750,75 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
699
750
  }
700
751
  )
701
752
  ] }) });
753
+ const CheckingScreen = /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 32, gap: 20, textAlign: "center" }, children: [
754
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: 64, height: 64 }, children: [
755
+ /* @__PURE__ */ jsx(
756
+ "div",
757
+ {
758
+ style: {
759
+ position: "absolute",
760
+ inset: 0,
761
+ borderRadius: "50%",
762
+ backgroundColor: `${primaryColor}15`,
763
+ animation: "checkPulse 2s infinite ease-out"
764
+ }
765
+ }
766
+ ),
767
+ /* @__PURE__ */ jsx(
768
+ "div",
769
+ {
770
+ style: {
771
+ position: "absolute",
772
+ inset: 8,
773
+ borderRadius: "50%",
774
+ backgroundColor: `${primaryColor}25`,
775
+ animation: "checkPulse 2s infinite ease-out 0.4s"
776
+ }
777
+ }
778
+ ),
779
+ /* @__PURE__ */ jsx(
780
+ "div",
781
+ {
782
+ style: {
783
+ position: "absolute",
784
+ inset: 16,
785
+ borderRadius: "50%",
786
+ backgroundColor: primaryColor,
787
+ display: "flex",
788
+ alignItems: "center",
789
+ justifyContent: "center"
790
+ },
791
+ children: /* @__PURE__ */ 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: [
792
+ /* @__PURE__ */ jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
793
+ /* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "7", r: "4" }),
794
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: "8", x2: "20", y2: "14" }),
795
+ /* @__PURE__ */ jsx("line", { x1: "23", y1: "11", x2: "17", y2: "11" })
796
+ ] })
797
+ }
798
+ )
799
+ ] }),
800
+ /* @__PURE__ */ jsxs("div", { children: [
801
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 16, fontWeight: 600, color: "#111827", marginBottom: 6 }, children: "Checking for a team member" }),
802
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 14, color: "#6b7280", lineHeight: 1.5 }, children: [
803
+ "One moment please",
804
+ /* @__PURE__ */ jsx("span", { style: { display: "inline-flex", width: 20 }, children: /* @__PURE__ */ jsx("span", { style: { animation: "checkDots 1.5s infinite steps(4, end)" }, children: "..." }) })
805
+ ] })
806
+ ] }),
807
+ /* @__PURE__ */ jsx("div", { style: { width: "80%", height: 3, backgroundColor: "#e5e7eb", borderRadius: 2, overflow: "hidden" }, children: /* @__PURE__ */ jsx(
808
+ "div",
809
+ {
810
+ style: {
811
+ width: "100%",
812
+ height: "100%",
813
+ backgroundColor: primaryColor,
814
+ borderRadius: 2,
815
+ animation: "checkProgress 5s linear forwards",
816
+ transformOrigin: "left"
817
+ }
818
+ }
819
+ ) }),
820
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#9ca3af" }, children: "This usually takes just a few seconds" })
821
+ ] });
702
822
  const MessagesView = /* @__PURE__ */ jsxs(Fragment, { children: [
703
823
  /* @__PURE__ */ jsxs(
704
824
  "div",
@@ -760,7 +880,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
760
880
  children: "Retry send"
761
881
  }
762
882
  ) }),
763
- message.role === "assistant" && widgetConfig?.handoff_enabled !== false && messages.filter((m) => m.role === "user").length >= 2 && message.id === messages.filter((m) => m.role === "assistant").slice(-1)[0]?.id && /* @__PURE__ */ jsx(
883
+ widgetConfig?.signal_enabled && message.role === "assistant" && !message.suggestions?.length && widgetConfig?.handoff_enabled !== false && messages.filter((m) => m.role === "user").length >= 2 && message.id === messages.filter((m) => m.role === "assistant").slice(-1)[0]?.id && /* @__PURE__ */ jsx(
764
884
  "button",
765
885
  {
766
886
  onClick: requestHandoff,
@@ -881,7 +1001,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
881
1001
  },
882
1002
  children: [
883
1003
  Header,
884
- showOfflineForm ? OfflineFormView : showWelcome && welcomeEnabled && messages.length === 0 ? WelcomeScreen : MessagesView,
1004
+ checkingAvailability ? CheckingScreen : showOfflineForm ? OfflineFormView : showWelcome && welcomeEnabled && messages.length === 0 ? WelcomeScreen : MessagesView,
885
1005
  showPoweredBy && /* @__PURE__ */ jsxs("div", { style: { padding: "6px 0", textAlign: "center", fontSize: 11, color: "#9ca3af", backgroundColor: "#ffffff", borderTop: "1px solid #f3f4f6" }, children: [
886
1006
  "Powered by",
887
1007
  " ",
@@ -896,10 +1016,25 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
896
1016
  0%, 80%, 100% { opacity: 0.3; }
897
1017
  40% { opacity: 1; }
898
1018
  }
1019
+ @keyframes checkPulse {
1020
+ 0% { transform: scale(1); opacity: 1; }
1021
+ 100% { transform: scale(1.8); opacity: 0; }
1022
+ }
1023
+ @keyframes checkDots {
1024
+ 0% { content: ''; }
1025
+ 25% { content: '.'; }
1026
+ 50% { content: '..'; }
1027
+ 75% { content: '...'; }
1028
+ }
1029
+ @keyframes checkProgress {
1030
+ from { transform: scaleX(0); }
1031
+ to { transform: scaleX(1); }
1032
+ }
899
1033
  ` })
900
1034
  ]
901
1035
  }
902
1036
  );
1037
+ if (!projectId) return null;
903
1038
  return /* @__PURE__ */ jsxs(Fragment, { children: [
904
1039
  ChatPopup,
905
1040
  ChatButton
@@ -1520,5 +1655,5 @@ function getDeviceType() {
1520
1655
  }
1521
1656
 
1522
1657
  export { ChatWidget, DesignRenderer, EngageWidget };
1523
- //# sourceMappingURL=chunk-XIF2CBLV.mjs.map
1524
- //# sourceMappingURL=chunk-XIF2CBLV.mjs.map
1658
+ //# sourceMappingURL=chunk-Y2FMP4QM.mjs.map
1659
+ //# sourceMappingURL=chunk-Y2FMP4QM.mjs.map