@uptrademedia/site-kit 1.0.20 → 1.0.24
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/analytics/index.js +6 -6
- package/dist/analytics/index.mjs +2 -2
- package/dist/{chunk-BZBJVG5Y.js → chunk-4KKQQRZV.js} +4 -4
- package/dist/{chunk-BZBJVG5Y.js.map → chunk-4KKQQRZV.js.map} +1 -1
- package/dist/{chunk-D5VBZVOE.js → chunk-6J26EHDM.js} +79 -30
- package/dist/chunk-6J26EHDM.js.map +1 -0
- package/dist/{chunk-VDMZZL2O.mjs → chunk-ASVFZY6X.mjs} +4 -4
- package/dist/{chunk-VDMZZL2O.mjs.map → chunk-ASVFZY6X.mjs.map} +1 -1
- package/dist/{chunk-KBS3KW2U.js → chunk-GKABCBZE.js} +2 -2
- package/dist/{chunk-KBS3KW2U.js.map → chunk-GKABCBZE.js.map} +1 -1
- package/dist/{chunk-SQHDILBN.js → chunk-HGTTGJVZ.js} +4 -2
- package/dist/chunk-HGTTGJVZ.js.map +1 -0
- package/dist/{chunk-DOHML47I.mjs → chunk-HHAJAANV.mjs} +46 -4
- package/dist/chunk-HHAJAANV.mjs.map +1 -0
- package/dist/{chunk-IJVPYQAB.mjs → chunk-JTLOJLWQ.mjs} +3 -50
- package/dist/chunk-JTLOJLWQ.mjs.map +1 -0
- package/dist/{chunk-BV4YYSAZ.js → chunk-KUGMH4ZF.js} +2 -50
- package/dist/chunk-KUGMH4ZF.js.map +1 -0
- package/dist/chunk-M5VNAX5I.mjs +54 -0
- package/dist/chunk-M5VNAX5I.mjs.map +1 -0
- package/dist/{chunk-UWUYO5DJ.mjs → chunk-MDOHOEME.mjs} +80 -31
- package/dist/chunk-MDOHOEME.mjs.map +1 -0
- package/dist/chunk-MXBDMOVK.js +56 -0
- package/dist/chunk-MXBDMOVK.js.map +1 -0
- package/dist/{chunk-YHQHSM76.mjs → chunk-OW2C3ATV.mjs} +4 -2
- package/dist/chunk-OW2C3ATV.mjs.map +1 -0
- package/dist/{chunk-K2HWVOEO.js → chunk-RM4XFDE6.js} +46 -3
- package/dist/chunk-RM4XFDE6.js.map +1 -0
- package/dist/{chunk-IT6R5VAZ.mjs → chunk-VZHEJXDY.mjs} +2 -2
- package/dist/{chunk-IT6R5VAZ.mjs.map → chunk-VZHEJXDY.mjs.map} +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/commerce/index.d.mts +1 -1
- package/dist/commerce/index.d.ts +1 -1
- package/dist/commerce/index.js +42 -38
- package/dist/commerce/index.mjs +1 -1
- package/dist/engage/index.d.mts +3 -2
- package/dist/engage/index.d.ts +3 -2
- package/dist/engage/index.js +4 -4
- package/dist/engage/index.mjs +1 -1
- package/dist/forms/index.js +5 -7
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +5 -7
- package/dist/forms/index.mjs.map +1 -1
- package/dist/images/index.d.mts +2 -54
- package/dist/images/index.d.ts +2 -54
- package/dist/images/index.js +13 -12
- package/dist/images/index.mjs +2 -1
- package/dist/images/server.d.mts +54 -0
- package/dist/images/server.d.ts +54 -0
- package/dist/images/server.js +13 -0
- package/dist/images/server.js.map +1 -0
- package/dist/images/server.mjs +4 -0
- package/dist/images/server.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +43 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -5
- package/dist/index.mjs.map +1 -1
- package/dist/redirects/index.js +5 -5
- package/dist/redirects/index.mjs +1 -1
- package/dist/setup/index.js +2 -2
- package/dist/setup/index.mjs +1 -1
- package/dist/setup/server.js +2 -2
- package/dist/setup/server.mjs +1 -1
- package/dist/socket-loader-3FWQWPDQ.js +16 -0
- package/dist/socket-loader-3FWQWPDQ.js.map +1 -0
- package/dist/socket-loader-N5ETWMXW.mjs +14 -0
- package/dist/socket-loader-N5ETWMXW.mjs.map +1 -0
- package/dist/{useEventModal-CaePVcfW.d.ts → useEventModal-DHO4-xhg.d.ts} +6 -1
- package/dist/{useEventModal-Dt6y1L0o.d.mts → useEventModal-Dbg2fYYk.d.mts} +6 -1
- package/package.json +6 -1
- package/dist/chunk-BV4YYSAZ.js.map +0 -1
- package/dist/chunk-D5VBZVOE.js.map +0 -1
- package/dist/chunk-DOHML47I.mjs.map +0 -1
- package/dist/chunk-IJVPYQAB.mjs.map +0 -1
- package/dist/chunk-K2HWVOEO.js.map +0 -1
- package/dist/chunk-SQHDILBN.js.map +0 -1
- package/dist/chunk-UWUYO5DJ.mjs.map +0 -1
- package/dist/chunk-YHQHSM76.mjs.map +0 -1
package/dist/analytics/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkHGTTGJVZ_js = require('../chunk-HGTTGJVZ.js');
|
|
5
5
|
require('../chunk-ZSMWDLMK.js');
|
|
6
6
|
var react = require('react');
|
|
7
7
|
|
|
8
8
|
function useContactTracking(options = {}) {
|
|
9
9
|
const { autoTrack = true, debug = false } = options;
|
|
10
|
-
const { trackConversion } =
|
|
10
|
+
const { trackConversion } = chunkHGTTGJVZ_js.useAnalytics();
|
|
11
11
|
const trackPhoneClick = react.useCallback((phoneNumber, metadata) => {
|
|
12
12
|
if (debug) console.log("[Analytics] Phone click:", phoneNumber);
|
|
13
13
|
trackConversion({
|
|
@@ -69,19 +69,19 @@ function ContactTracking({ debug = false }) {
|
|
|
69
69
|
|
|
70
70
|
Object.defineProperty(exports, "AnalyticsProvider", {
|
|
71
71
|
enumerable: true,
|
|
72
|
-
get: function () { return
|
|
72
|
+
get: function () { return chunkHGTTGJVZ_js.AnalyticsProvider; }
|
|
73
73
|
});
|
|
74
74
|
Object.defineProperty(exports, "WebVitals", {
|
|
75
75
|
enumerable: true,
|
|
76
|
-
get: function () { return
|
|
76
|
+
get: function () { return chunkHGTTGJVZ_js.WebVitals; }
|
|
77
77
|
});
|
|
78
78
|
Object.defineProperty(exports, "useAnalytics", {
|
|
79
79
|
enumerable: true,
|
|
80
|
-
get: function () { return
|
|
80
|
+
get: function () { return chunkHGTTGJVZ_js.useAnalytics; }
|
|
81
81
|
});
|
|
82
82
|
Object.defineProperty(exports, "useTrackEvent", {
|
|
83
83
|
enumerable: true,
|
|
84
|
-
get: function () { return
|
|
84
|
+
get: function () { return chunkHGTTGJVZ_js.useTrackEvent; }
|
|
85
85
|
});
|
|
86
86
|
exports.ContactTracking = ContactTracking;
|
|
87
87
|
exports.useContactTracking = useContactTracking;
|
package/dist/analytics/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useAnalytics } from '../chunk-
|
|
3
|
-
export { AnalyticsProvider, WebVitals, useAnalytics, useTrackEvent } from '../chunk-
|
|
2
|
+
import { useAnalytics } from '../chunk-OW2C3ATV.mjs';
|
|
3
|
+
export { AnalyticsProvider, WebVitals, useAnalytics, useTrackEvent } from '../chunk-OW2C3ATV.mjs';
|
|
4
4
|
import '../chunk-4XPGGLVP.mjs';
|
|
5
5
|
import { useCallback, useEffect } from 'react';
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ async function fetchRedirectRules(config) {
|
|
|
14
14
|
try {
|
|
15
15
|
const baseUrl = config.portalApiUrl || "https://api.uptrademedia.com";
|
|
16
16
|
const domain = config.domain || "";
|
|
17
|
-
const url = `${baseUrl}/public/seo/redirects?domain=${encodeURIComponent(domain)}`;
|
|
17
|
+
const url = `${baseUrl}/api/public/seo/redirects?domain=${encodeURIComponent(domain)}`;
|
|
18
18
|
const res = await fetch(url, {
|
|
19
19
|
headers: { "Content-Type": "application/json" },
|
|
20
20
|
next: { revalidate: cacheSeconds }
|
|
@@ -59,7 +59,7 @@ async function handleManagedRedirects(request, config) {
|
|
|
59
59
|
async function trackRedirectHit(config, fromPath) {
|
|
60
60
|
try {
|
|
61
61
|
const baseUrl = config.portalApiUrl || "https://api.uptrademedia.com";
|
|
62
|
-
await fetch(`${baseUrl}/public/seo/redirects/hit`, {
|
|
62
|
+
await fetch(`${baseUrl}/api/public/seo/redirects/hit`, {
|
|
63
63
|
method: "POST",
|
|
64
64
|
headers: { "Content-Type": "application/json" },
|
|
65
65
|
body: JSON.stringify({ domain: config.domain, from_path: fromPath })
|
|
@@ -84,5 +84,5 @@ exports.clearRedirectCache = clearRedirectCache;
|
|
|
84
84
|
exports.fetchRedirectRules = fetchRedirectRules;
|
|
85
85
|
exports.generateNextRedirects = generateNextRedirects;
|
|
86
86
|
exports.handleManagedRedirects = handleManagedRedirects;
|
|
87
|
-
//# sourceMappingURL=chunk-
|
|
88
|
-
//# sourceMappingURL=chunk-
|
|
87
|
+
//# sourceMappingURL=chunk-4KKQQRZV.js.map
|
|
88
|
+
//# sourceMappingURL=chunk-4KKQQRZV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/redirects/index.ts"],"names":["NextResponse"],"mappings":";;;;;AAsCA,IAAI,cAA8B,EAAC;AACnC,IAAI,WAAA,GAAc,CAAA;AAKlB,eAAsB,mBAAmB,MAAA,EAAiD;AACxF,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,MAAM,YAAA,GAAe,OAAO,YAAA,IAAgB,GAAA;AAG5C,EAAA,IAAI,WAAA,CAAY,MAAA,GAAS,CAAA,IAAK,GAAA,GAAM,WAAA,EAAa;AAC/C,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,OAAO,YAAA,IAAgB,8BAAA;AAEvC,IAAA,MAAM,MAAA,GAAS,OAAO,MAAA,IAAU,EAAA;AAChC,IAAA,MAAM,MAAM,CAAA,EAAG,OAAO,CAAA,
|
|
1
|
+
{"version":3,"sources":["../src/redirects/index.ts"],"names":["NextResponse"],"mappings":"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","file":"chunk-4KKQQRZV.js","sourcesContent":["/**\n * Managed Redirects - Next.js Middleware Helper\n * \n * Fetches redirect rules from Uptrade Portal and applies them.\n * Can be used in middleware.ts for server-side redirects.\n * \n * Usage in middleware.ts:\n * \n * import { handleManagedRedirects } from '@uptrade/site-kit/redirects'\n * \n * export async function middleware(request: NextRequest) {\n * const redirect = await handleManagedRedirects(request, {\n * domain: 'example.com', // Your site's domain (without https://)\n * portalApiUrl: process.env.PORTAL_API_URL || 'https://api.uptrademedia.com',\n * })\n * \n * if (redirect) return redirect\n * \n * return NextResponse.next()\n * }\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\n\nexport interface RedirectRule {\n from_path: string\n to_path: string\n redirect_type: '301' | '302' | '307' | '308'\n is_enabled: boolean\n}\n\nexport interface RedirectConfig {\n domain: string // Required: the domain to fetch redirects for\n portalApiUrl?: string\n cacheSeconds?: number\n}\n\n// Cache for redirect rules\nlet cachedRules: RedirectRule[] = []\nlet cacheExpiry = 0\n\n/**\n * Fetch redirect rules from Portal API\n */\nexport async function fetchRedirectRules(config: RedirectConfig): Promise<RedirectRule[]> {\n const now = Date.now()\n const cacheSeconds = config.cacheSeconds ?? 300 // 5 min default\n\n // Return cached if still valid\n if (cachedRules.length > 0 && now < cacheExpiry) {\n return cachedRules\n }\n\n try {\n const baseUrl = config.portalApiUrl || 'https://api.uptrademedia.com'\n // Use domain-based lookup from public endpoint (no auth required)\n const domain = config.domain || ''\n const url = `${baseUrl}/api/public/seo/redirects?domain=${encodeURIComponent(domain)}`\n\n const res = await fetch(url, {\n headers: { 'Content-Type': 'application/json' },\n next: { revalidate: cacheSeconds },\n })\n\n if (!res.ok) {\n console.error(`[site-kit] Failed to fetch redirects: ${res.status}`)\n return cachedRules\n }\n\n const data = await res.json()\n cachedRules = (data.redirects || []).filter((r: RedirectRule) => r.is_enabled)\n cacheExpiry = now + (cacheSeconds * 1000)\n \n return cachedRules\n } catch (error) {\n console.error('[site-kit] Error fetching redirects:', error)\n return cachedRules\n }\n}\n\n/**\n * Handle managed redirects in middleware\n * Returns a NextResponse.redirect if a match is found, otherwise undefined\n */\nexport async function handleManagedRedirects(\n request: NextRequest,\n config: RedirectConfig,\n): Promise<NextResponse | undefined> {\n const pathname = request.nextUrl.pathname\n \n // Skip for static assets and API routes\n if (\n pathname.startsWith('/_next') ||\n pathname.startsWith('/api') ||\n pathname.includes('.') // Has file extension\n ) {\n return undefined\n }\n\n const rules = await fetchRedirectRules(config)\n \n // Find matching redirect\n const match = rules.find(r => {\n // Exact match\n if (r.from_path === pathname) return true\n \n // Match with trailing slash variance\n const normalizedFrom = r.from_path.endsWith('/') \n ? r.from_path.slice(0, -1) \n : r.from_path\n const normalizedPath = pathname.endsWith('/') \n ? pathname.slice(0, -1) \n : pathname\n \n return normalizedFrom === normalizedPath\n })\n\n if (!match) {\n return undefined\n }\n\n // Build redirect URL\n const redirectUrl = new URL(match.to_path, request.url)\n \n // Preserve query params\n request.nextUrl.searchParams.forEach((value, key) => {\n redirectUrl.searchParams.set(key, value)\n })\n\n // Track hit (fire and forget)\n trackRedirectHit(config, match.from_path).catch(() => {})\n\n // Return redirect response\n const statusCode = parseInt(match.redirect_type) as 301 | 302 | 307 | 308\n return NextResponse.redirect(redirectUrl, statusCode)\n}\n\n/**\n * Track redirect hit for analytics\n */\nasync function trackRedirectHit(config: RedirectConfig, fromPath: string): Promise<void> {\n try {\n const baseUrl = config.portalApiUrl || 'https://api.uptrademedia.com'\n await fetch(`${baseUrl}/api/public/seo/redirects/hit`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ domain: config.domain, from_path: fromPath }),\n })\n } catch {\n // Ignore tracking errors\n }\n}\n\n/**\n * Generate Next.js redirects config from Portal\n * Use this in next.config.js for build-time redirects\n * \n * Usage in next.config.js:\n * \n * const { generateNextRedirects } = require('@uptrade/site-kit/redirects')\n * \n * module.exports = {\n * async redirects() {\n * return generateNextRedirects({\n * domain: 'example.com',\n * portalApiUrl: process.env.PORTAL_API_URL,\n * })\n * }\n * }\n */\nexport async function generateNextRedirects(config: RedirectConfig): Promise<Array<{\n source: string\n destination: string\n permanent: boolean\n}>> {\n const rules = await fetchRedirectRules({ ...config, cacheSeconds: 0 })\n \n return rules.map(r => ({\n source: r.from_path,\n destination: r.to_path,\n permanent: r.redirect_type === '301' || r.redirect_type === '308',\n }))\n}\n\n/**\n * Clear redirect cache (useful for development)\n */\nexport function clearRedirectCache(): void {\n cachedRules = []\n cacheExpiry = 0\n}\n"]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var React2 = require('react');
|
|
4
|
-
var socket_ioClient = require('socket.io-client');
|
|
5
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
5
|
var navigation = require('next/navigation');
|
|
7
6
|
|
|
@@ -36,7 +35,9 @@ function isLightColor(hex) {
|
|
|
36
35
|
const b = num & 255;
|
|
37
36
|
return (r * 299 + g * 587 + b * 114) / 1e3 > 160;
|
|
38
37
|
}
|
|
39
|
-
function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
38
|
+
function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl }) {
|
|
39
|
+
const [resolvedProjectId, setResolvedProjectId] = React2.useState(propProjectId || null);
|
|
40
|
+
const projectId = propProjectId || resolvedProjectId || "";
|
|
40
41
|
const [isOpen, setIsOpen] = React2.useState(false);
|
|
41
42
|
const [messages, setMessages] = React2.useState([]);
|
|
42
43
|
const [inputValue, setInputValue] = React2.useState("");
|
|
@@ -56,6 +57,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
56
57
|
const [showWelcome, setShowWelcome] = React2.useState(true);
|
|
57
58
|
const [checkingAvailability, setCheckingAvailability] = React2.useState(false);
|
|
58
59
|
React2.useRef(null);
|
|
60
|
+
const pendingInitialMessageRef = React2.useRef(null);
|
|
59
61
|
const messagesEndRef = React2.useRef(null);
|
|
60
62
|
const inputRef = React2.useRef(null);
|
|
61
63
|
const socketRef = React2.useRef(null);
|
|
@@ -72,7 +74,24 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
72
74
|
const offlineHeading = widgetConfig?.offline_heading ?? "No agents available right now";
|
|
73
75
|
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!";
|
|
74
76
|
const baseUrl = propApiUrl || getApiConfig().apiUrl;
|
|
77
|
+
React2.useEffect(() => {
|
|
78
|
+
if (propProjectId || resolvedProjectId) return;
|
|
79
|
+
const { apiKey } = getApiConfig();
|
|
80
|
+
if (!apiKey) return;
|
|
81
|
+
let cancelled = false;
|
|
82
|
+
fetch(`${baseUrl}/api/public/seo/project-info`, {
|
|
83
|
+
headers: { "x-api-key": apiKey }
|
|
84
|
+
}).then((res) => res.ok ? res.json() : null).then((data) => {
|
|
85
|
+
if (cancelled || !data?.valid || !data?.project_id) return;
|
|
86
|
+
setResolvedProjectId(data.project_id);
|
|
87
|
+
}).catch(() => {
|
|
88
|
+
});
|
|
89
|
+
return () => {
|
|
90
|
+
cancelled = true;
|
|
91
|
+
};
|
|
92
|
+
}, [propProjectId, resolvedProjectId, baseUrl]);
|
|
75
93
|
const fetchWidgetConfig = React2.useCallback(async () => {
|
|
94
|
+
if (!projectId) return;
|
|
76
95
|
try {
|
|
77
96
|
const { apiKey } = getApiConfig();
|
|
78
97
|
const response = await fetch(`${baseUrl}/engage/widget/config?projectId=${projectId}`, {
|
|
@@ -83,10 +102,13 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
83
102
|
setWidgetConfig(data ?? null);
|
|
84
103
|
}
|
|
85
104
|
} catch (error) {
|
|
86
|
-
|
|
105
|
+
if (process.env.NODE_ENV === "development") {
|
|
106
|
+
console.warn("[ChatWidget] Config fetch failed:", error instanceof Error ? error.message : error);
|
|
107
|
+
}
|
|
87
108
|
}
|
|
88
109
|
}, [projectId, baseUrl]);
|
|
89
110
|
const checkAvailability = React2.useCallback(async () => {
|
|
111
|
+
if (!projectId) return null;
|
|
90
112
|
try {
|
|
91
113
|
const { apiKey } = getApiConfig();
|
|
92
114
|
const response = await fetch(`${baseUrl}/engage/widget/availability?projectId=${projectId}`, {
|
|
@@ -98,7 +120,9 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
98
120
|
return data;
|
|
99
121
|
}
|
|
100
122
|
} catch (error) {
|
|
101
|
-
|
|
123
|
+
if (process.env.NODE_ENV === "development") {
|
|
124
|
+
console.warn("[ChatWidget] Availability check failed:", error instanceof Error ? error.message : error);
|
|
125
|
+
}
|
|
102
126
|
}
|
|
103
127
|
return null;
|
|
104
128
|
}, [projectId, baseUrl]);
|
|
@@ -186,14 +210,15 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
186
210
|
}
|
|
187
211
|
}, []);
|
|
188
212
|
const connectSocket = React2.useCallback(
|
|
189
|
-
(currentSessionId) => {
|
|
213
|
+
async (currentSessionId) => {
|
|
190
214
|
if (socketRef.current?.connected) return;
|
|
191
215
|
if (socketRef.current) {
|
|
192
216
|
socketRef.current.disconnect();
|
|
193
217
|
socketRef.current = null;
|
|
194
218
|
}
|
|
219
|
+
const { createSocket } = await import('./socket-loader-3FWQWPDQ.js');
|
|
195
220
|
const namespaceUrl = `${baseUrl.replace(/\/$/, "")}/engage/chat`;
|
|
196
|
-
const socket =
|
|
221
|
+
const socket = await createSocket(namespaceUrl, {
|
|
197
222
|
query: { projectId, visitorId, sessionId: currentSessionId },
|
|
198
223
|
transports: ["websocket", "polling"],
|
|
199
224
|
// Auto-reconnect config
|
|
@@ -320,18 +345,35 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
320
345
|
};
|
|
321
346
|
}, [fetchWidgetConfig, checkAvailability]);
|
|
322
347
|
React2.useEffect(() => {
|
|
323
|
-
if (isOpen && !showWelcome && !checkingAvailability && !showOfflineForm && !sessionId
|
|
324
|
-
initSession().then((id) => {
|
|
325
|
-
if (id
|
|
326
|
-
|
|
327
|
-
|
|
348
|
+
if (isOpen && !showWelcome && !checkingAvailability && !showOfflineForm && !sessionId) {
|
|
349
|
+
initSession().then(async (id) => {
|
|
350
|
+
if (!id) return;
|
|
351
|
+
setConnectionStatus("connecting");
|
|
352
|
+
await connectSocket(id);
|
|
353
|
+
const pending = pendingInitialMessageRef.current;
|
|
354
|
+
if (pending) {
|
|
355
|
+
pendingInitialMessageRef.current = null;
|
|
356
|
+
const waitForSocket = () => new Promise((resolve) => {
|
|
357
|
+
const check = (attempts = 0) => {
|
|
358
|
+
if (socketRef.current?.connected || attempts > 20) {
|
|
359
|
+
resolve();
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
setTimeout(() => check(attempts + 1), 150);
|
|
363
|
+
};
|
|
364
|
+
check();
|
|
365
|
+
});
|
|
366
|
+
await waitForSocket();
|
|
367
|
+
if (socketRef.current?.connected) {
|
|
368
|
+
socketRef.current.emit("visitor:message", { content: pending });
|
|
369
|
+
}
|
|
328
370
|
}
|
|
329
371
|
});
|
|
330
372
|
}
|
|
331
373
|
return () => {
|
|
332
374
|
if (pollingIntervalRef.current) clearInterval(pollingIntervalRef.current);
|
|
333
375
|
};
|
|
334
|
-
}, [isOpen, showWelcome, checkingAvailability, showOfflineForm, sessionId,
|
|
376
|
+
}, [isOpen, showWelcome, checkingAvailability, showOfflineForm, sessionId, initSession, connectSocket]);
|
|
335
377
|
const handleToggle = React2.useCallback(() => {
|
|
336
378
|
setIsOpen((prev) => !prev);
|
|
337
379
|
}, []);
|
|
@@ -341,17 +383,13 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
341
383
|
const beginChatSession = () => {
|
|
342
384
|
setMessages([{ id: "welcome", role: "assistant", content: welcomeMessage, timestamp: /* @__PURE__ */ new Date() }]);
|
|
343
385
|
if (initialMessage) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
setMessages((prev) => [...prev, userMsg]);
|
|
349
|
-
setIsLoading(true);
|
|
350
|
-
setLastFailedSend({ content: initialMessage, attachments: [] });
|
|
351
|
-
}, 100);
|
|
386
|
+
pendingInitialMessageRef.current = initialMessage;
|
|
387
|
+
const userMsg = { id: `user-${Date.now()}`, role: "user", content: initialMessage, timestamp: /* @__PURE__ */ new Date() };
|
|
388
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
389
|
+
setIsLoading(true);
|
|
352
390
|
}
|
|
353
391
|
};
|
|
354
|
-
if (
|
|
392
|
+
if (widgetConfig?.signal_enabled) {
|
|
355
393
|
beginChatSession();
|
|
356
394
|
return;
|
|
357
395
|
}
|
|
@@ -371,7 +409,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
371
409
|
setShowOfflineForm(true);
|
|
372
410
|
}
|
|
373
411
|
},
|
|
374
|
-
[
|
|
412
|
+
[widgetConfig?.signal_enabled, welcomeMessage, checkAvailability]
|
|
375
413
|
);
|
|
376
414
|
const uploadWidgetFile = React2.useCallback(
|
|
377
415
|
async (file) => {
|
|
@@ -485,11 +523,13 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
485
523
|
console.error("[ChatWidget] Handoff request failed:", error);
|
|
486
524
|
}
|
|
487
525
|
}, [sessionId, baseUrl, projectId, widgetConfig, offlineHeading]);
|
|
526
|
+
const [offlineError, setOfflineError] = React2.useState(null);
|
|
488
527
|
const handleOfflineSubmit = React2.useCallback(
|
|
489
528
|
async (e) => {
|
|
490
529
|
e.preventDefault();
|
|
491
530
|
if (!offlineForm.name || !offlineForm.email || !offlineForm.message) return;
|
|
492
531
|
setIsLoading(true);
|
|
532
|
+
setOfflineError(null);
|
|
493
533
|
try {
|
|
494
534
|
const { apiKey } = getApiConfig();
|
|
495
535
|
const response = await fetch(`${baseUrl}/engage/widget/offline-form`, {
|
|
@@ -503,9 +543,16 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
503
543
|
...widgetConfig?.offlineFormSlug && { formSlug: widgetConfig.offlineFormSlug }
|
|
504
544
|
})
|
|
505
545
|
});
|
|
506
|
-
if (response.ok)
|
|
546
|
+
if (response.ok) {
|
|
547
|
+
setOfflineSubmitted(true);
|
|
548
|
+
} else {
|
|
549
|
+
const errorBody = await response.text().catch(() => "");
|
|
550
|
+
console.error(`[ChatWidget] Offline form returned ${response.status}:`, errorBody);
|
|
551
|
+
setOfflineError("Something went wrong. Please try again.");
|
|
552
|
+
}
|
|
507
553
|
} catch (error) {
|
|
508
554
|
console.error("[ChatWidget] Offline form submission failed:", error);
|
|
555
|
+
setOfflineError("Unable to send message. Please check your connection and try again.");
|
|
509
556
|
} finally {
|
|
510
557
|
setIsLoading(false);
|
|
511
558
|
}
|
|
@@ -529,9 +576,9 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
529
576
|
}, []);
|
|
530
577
|
const statusLabel = (() => {
|
|
531
578
|
if (showOfflineForm) return null;
|
|
532
|
-
if (checkingAvailability) return { dot: "#f59e0b", text: "Checking
|
|
533
|
-
if (
|
|
534
|
-
if (availability
|
|
579
|
+
if (checkingAvailability) return { dot: "#f59e0b", text: "Checking for a team member..." };
|
|
580
|
+
if (widgetConfig?.signal_enabled) return { dot: "#a78bfa", text: "AI Assistant" };
|
|
581
|
+
if (availability && availability.agentsOnline > 0) return { dot: "#22c55e", text: "Online" };
|
|
535
582
|
return { dot: "#9ca3af", text: "We'll respond soon" };
|
|
536
583
|
})();
|
|
537
584
|
const ChatButton = /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -705,6 +752,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
705
752
|
onBlur: (e) => e.currentTarget.style.borderColor = "#e5e7eb"
|
|
706
753
|
}
|
|
707
754
|
) }),
|
|
755
|
+
offlineError && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "8px 12px", borderRadius: 8, backgroundColor: "#fef2f2", border: "1px solid #fecaca", color: "#dc2626", fontSize: 13, marginBottom: 12 }, children: offlineError }),
|
|
708
756
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
709
757
|
"button",
|
|
710
758
|
{
|
|
@@ -774,7 +822,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
774
822
|
)
|
|
775
823
|
] }),
|
|
776
824
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
777
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 16, fontWeight: 600, color: "#111827", marginBottom: 6 }, children: "Checking
|
|
825
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 16, fontWeight: 600, color: "#111827", marginBottom: 6 }, children: "Checking for a team member" }),
|
|
778
826
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 14, color: "#6b7280", lineHeight: 1.5 }, children: [
|
|
779
827
|
"One moment please",
|
|
780
828
|
/* @__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: "..." }) })
|
|
@@ -856,7 +904,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
856
904
|
children: "Retry send"
|
|
857
905
|
}
|
|
858
906
|
) }),
|
|
859
|
-
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__ */ jsxRuntime.jsx(
|
|
907
|
+
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__ */ jsxRuntime.jsx(
|
|
860
908
|
"button",
|
|
861
909
|
{
|
|
862
910
|
onClick: requestHandoff,
|
|
@@ -1010,6 +1058,7 @@ function ChatWidget({ projectId, config, apiUrl: propApiUrl }) {
|
|
|
1010
1058
|
]
|
|
1011
1059
|
}
|
|
1012
1060
|
);
|
|
1061
|
+
if (!projectId) return null;
|
|
1013
1062
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1014
1063
|
ChatPopup,
|
|
1015
1064
|
ChatButton
|
|
@@ -1632,5 +1681,5 @@ function getDeviceType() {
|
|
|
1632
1681
|
exports.ChatWidget = ChatWidget;
|
|
1633
1682
|
exports.DesignRenderer = DesignRenderer;
|
|
1634
1683
|
exports.EngageWidget = EngageWidget;
|
|
1635
|
-
//# sourceMappingURL=chunk-
|
|
1636
|
-
//# sourceMappingURL=chunk-
|
|
1684
|
+
//# sourceMappingURL=chunk-6J26EHDM.js.map
|
|
1685
|
+
//# sourceMappingURL=chunk-6J26EHDM.js.map
|