@aigentyc/chat-sdk 0.1.0
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/LICENSE +21 -0
- package/README.md +156 -0
- package/dist/JsonRenderResult-Ftw4AKwb.d.cts +18 -0
- package/dist/JsonRenderResult-Ftw4AKwb.d.ts +18 -0
- package/dist/JsonRenderResult-GQOYPLVH.cjs +15 -0
- package/dist/JsonRenderResult-GQOYPLVH.cjs.map +1 -0
- package/dist/JsonRenderResult-ZFJ6VWMS.js +6 -0
- package/dist/JsonRenderResult-ZFJ6VWMS.js.map +1 -0
- package/dist/SlotsContext-CBtt36al.d.ts +148 -0
- package/dist/SlotsContext-CHvISDJT.d.cts +148 -0
- package/dist/VisualizationRenderer-FNFYNN66.js +5 -0
- package/dist/VisualizationRenderer-FNFYNN66.js.map +1 -0
- package/dist/VisualizationRenderer-VKMZXRUX.cjs +20 -0
- package/dist/VisualizationRenderer-VKMZXRUX.cjs.map +1 -0
- package/dist/ai-elements.cjs +4608 -0
- package/dist/ai-elements.cjs.map +1 -0
- package/dist/ai-elements.d.cts +897 -0
- package/dist/ai-elements.d.ts +897 -0
- package/dist/ai-elements.js +4363 -0
- package/dist/ai-elements.js.map +1 -0
- package/dist/chunk-3MP2EGEJ.cjs +270 -0
- package/dist/chunk-3MP2EGEJ.cjs.map +1 -0
- package/dist/chunk-3RW7O444.js +26 -0
- package/dist/chunk-3RW7O444.js.map +1 -0
- package/dist/chunk-42ARGQXE.js +51 -0
- package/dist/chunk-42ARGQXE.js.map +1 -0
- package/dist/chunk-4FBVV64J.js +257 -0
- package/dist/chunk-4FBVV64J.js.map +1 -0
- package/dist/chunk-4QT25AXI.js +21 -0
- package/dist/chunk-4QT25AXI.js.map +1 -0
- package/dist/chunk-525KS5HM.cjs +30 -0
- package/dist/chunk-525KS5HM.cjs.map +1 -0
- package/dist/chunk-5F3O3ZJH.js +299 -0
- package/dist/chunk-5F3O3ZJH.js.map +1 -0
- package/dist/chunk-5QSXB6UL.cjs +259 -0
- package/dist/chunk-5QSXB6UL.cjs.map +1 -0
- package/dist/chunk-5T4FJ2SR.js +664 -0
- package/dist/chunk-5T4FJ2SR.js.map +1 -0
- package/dist/chunk-7BNYTOTE.cjs +67 -0
- package/dist/chunk-7BNYTOTE.cjs.map +1 -0
- package/dist/chunk-AWAJOSFP.cjs +96 -0
- package/dist/chunk-AWAJOSFP.cjs.map +1 -0
- package/dist/chunk-BKDV2H6Z.js +224 -0
- package/dist/chunk-BKDV2H6Z.js.map +1 -0
- package/dist/chunk-FQN6OBGN.cjs +171 -0
- package/dist/chunk-FQN6OBGN.cjs.map +1 -0
- package/dist/chunk-FYPJSHCL.js +190 -0
- package/dist/chunk-FYPJSHCL.js.map +1 -0
- package/dist/chunk-J2H6MLQF.cjs +680 -0
- package/dist/chunk-J2H6MLQF.cjs.map +1 -0
- package/dist/chunk-J2K7EJYP.cjs +198 -0
- package/dist/chunk-J2K7EJYP.cjs.map +1 -0
- package/dist/chunk-JI5KCSOI.cjs +23 -0
- package/dist/chunk-JI5KCSOI.cjs.map +1 -0
- package/dist/chunk-JOO6C3XT.cjs +44 -0
- package/dist/chunk-JOO6C3XT.cjs.map +1 -0
- package/dist/chunk-KBGPBUTI.cjs +78 -0
- package/dist/chunk-KBGPBUTI.cjs.map +1 -0
- package/dist/chunk-MT2AMINB.js +75 -0
- package/dist/chunk-MT2AMINB.js.map +1 -0
- package/dist/chunk-MZQKGNWF.js +4 -0
- package/dist/chunk-MZQKGNWF.js.map +1 -0
- package/dist/chunk-NG7OTWXQ.cjs +226 -0
- package/dist/chunk-NG7OTWXQ.cjs.map +1 -0
- package/dist/chunk-NPJKLYLV.js +68 -0
- package/dist/chunk-NPJKLYLV.js.map +1 -0
- package/dist/chunk-NW2ESHRV.js +685 -0
- package/dist/chunk-NW2ESHRV.js.map +1 -0
- package/dist/chunk-NWF735F5.js +1631 -0
- package/dist/chunk-NWF735F5.js.map +1 -0
- package/dist/chunk-NYQSM3EB.cjs +305 -0
- package/dist/chunk-NYQSM3EB.cjs.map +1 -0
- package/dist/chunk-OU7OROOE.cjs +1643 -0
- package/dist/chunk-OU7OROOE.cjs.map +1 -0
- package/dist/chunk-PS3U7T37.js +42 -0
- package/dist/chunk-PS3U7T37.js.map +1 -0
- package/dist/chunk-Q7T3VAJV.cjs +687 -0
- package/dist/chunk-Q7T3VAJV.cjs.map +1 -0
- package/dist/chunk-QYCEHFAB.js +265 -0
- package/dist/chunk-QYCEHFAB.js.map +1 -0
- package/dist/chunk-RPDJXB3U.js +676 -0
- package/dist/chunk-RPDJXB3U.js.map +1 -0
- package/dist/chunk-UKEL7FWS.js +64 -0
- package/dist/chunk-UKEL7FWS.js.map +1 -0
- package/dist/chunk-VS3NZ7FX.js +164 -0
- package/dist/chunk-VS3NZ7FX.js.map +1 -0
- package/dist/chunk-WZLWAVSS.cjs +73 -0
- package/dist/chunk-WZLWAVSS.cjs.map +1 -0
- package/dist/chunk-X5YEOOPK.cjs +758 -0
- package/dist/chunk-X5YEOOPK.cjs.map +1 -0
- package/dist/chunk-X7R334SB.cjs +5 -0
- package/dist/chunk-X7R334SB.cjs.map +1 -0
- package/dist/chunk-XXNDL5SJ.cjs +432 -0
- package/dist/chunk-XXNDL5SJ.cjs.map +1 -0
- package/dist/chunk-YQELMJW5.js +429 -0
- package/dist/chunk-YQELMJW5.js.map +1 -0
- package/dist/components.cjs +551 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.cts +181 -0
- package/dist/components.d.ts +181 -0
- package/dist/components.js +483 -0
- package/dist/components.js.map +1 -0
- package/dist/core.cjs +283 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +455 -0
- package/dist/core.d.ts +455 -0
- package/dist/core.js +241 -0
- package/dist/core.js.map +1 -0
- package/dist/hooks.cjs +324 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.cts +163 -0
- package/dist/hooks.d.ts +163 -0
- package/dist/hooks.js +277 -0
- package/dist/hooks.js.map +1 -0
- package/dist/i18n.cjs +26 -0
- package/dist/i18n.cjs.map +1 -0
- package/dist/i18n.d.cts +50 -0
- package/dist/i18n.d.ts +50 -0
- package/dist/i18n.js +5 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.cjs +466 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +80 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +438 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction-tracker-D9P1Oq4j.d.cts +83 -0
- package/dist/interaction-tracker-D9P1Oq4j.d.ts +83 -0
- package/dist/json-render.cjs +23 -0
- package/dist/json-render.cjs.map +1 -0
- package/dist/json-render.d.cts +857 -0
- package/dist/json-render.d.ts +857 -0
- package/dist/json-render.js +6 -0
- package/dist/json-render.js.map +1 -0
- package/dist/live-chat-transport-4XLOIPOE.js +4 -0
- package/dist/live-chat-transport-4XLOIPOE.js.map +1 -0
- package/dist/live-chat-transport-ALVRGWX7.cjs +13 -0
- package/dist/live-chat-transport-ALVRGWX7.cjs.map +1 -0
- package/dist/select-B4l9yoyn.d.cts +99 -0
- package/dist/select-B4l9yoyn.d.ts +99 -0
- package/dist/styles.css +2 -0
- package/dist/theme.cjs +18 -0
- package/dist/theme.cjs.map +1 -0
- package/dist/theme.d.cts +55 -0
- package/dist/theme.d.ts +55 -0
- package/dist/theme.js +5 -0
- package/dist/theme.js.map +1 -0
- package/dist/tools.cjs +32 -0
- package/dist/tools.cjs.map +1 -0
- package/dist/tools.d.cts +117 -0
- package/dist/tools.d.ts +117 -0
- package/dist/tools.js +11 -0
- package/dist/tools.js.map +1 -0
- package/dist/types-DKJ_-nbG.d.cts +349 -0
- package/dist/types-DKJ_-nbG.d.ts +349 -0
- package/dist/ui.cjs +667 -0
- package/dist/ui.cjs.map +1 -0
- package/dist/ui.d.cts +95 -0
- package/dist/ui.d.ts +95 -0
- package/dist/ui.js +414 -0
- package/dist/ui.js.map +1 -0
- package/package.json +255 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
// src/providers/LiveChatProvider.tsx
|
|
8
|
+
var LiveChatContext = react.createContext(null);
|
|
9
|
+
function LiveChatProvider({
|
|
10
|
+
children,
|
|
11
|
+
chatServiceUrl,
|
|
12
|
+
apiKey,
|
|
13
|
+
projectId,
|
|
14
|
+
sessionId,
|
|
15
|
+
userInfo
|
|
16
|
+
}) {
|
|
17
|
+
const [state, setState] = react.useState("ai");
|
|
18
|
+
const [messages, setMessages] = react.useState([]);
|
|
19
|
+
const [operatorName, setOperatorName] = react.useState("");
|
|
20
|
+
const [queuePosition, setQueuePosition] = react.useState(0);
|
|
21
|
+
const [showIdentityForm, setShowIdentityForm] = react.useState(false);
|
|
22
|
+
const transportRef = react.useRef(null);
|
|
23
|
+
const aiHistoryGetterRef = react.useRef(null);
|
|
24
|
+
const STORAGE_KEY = `livechat-session-${projectId}`;
|
|
25
|
+
const registerAiHistoryGetter = react.useCallback(
|
|
26
|
+
(getter) => {
|
|
27
|
+
aiHistoryGetterRef.current = getter;
|
|
28
|
+
},
|
|
29
|
+
[]
|
|
30
|
+
);
|
|
31
|
+
const resetState = react.useCallback(() => {
|
|
32
|
+
transportRef.current?.disconnect?.();
|
|
33
|
+
transportRef.current = null;
|
|
34
|
+
setState("ai");
|
|
35
|
+
setMessages([]);
|
|
36
|
+
setOperatorName("");
|
|
37
|
+
setQueuePosition(0);
|
|
38
|
+
setShowIdentityForm(false);
|
|
39
|
+
if (typeof window !== "undefined") {
|
|
40
|
+
try {
|
|
41
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}, [STORAGE_KEY]);
|
|
46
|
+
const persistSession = react.useCallback(
|
|
47
|
+
(liveChatSessionId) => {
|
|
48
|
+
if (typeof window === "undefined") return;
|
|
49
|
+
try {
|
|
50
|
+
sessionStorage.setItem(STORAGE_KEY, liveChatSessionId);
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
[STORAGE_KEY]
|
|
55
|
+
);
|
|
56
|
+
const attachListeners = react.useCallback(
|
|
57
|
+
(transport) => {
|
|
58
|
+
transport.on("state-change", setState);
|
|
59
|
+
transport.on("queued", (data) => {
|
|
60
|
+
setQueuePosition(data.position);
|
|
61
|
+
if (data.liveChatSessionId) persistSession(data.liveChatSessionId);
|
|
62
|
+
});
|
|
63
|
+
transport.on(
|
|
64
|
+
"queue-update",
|
|
65
|
+
(data) => setQueuePosition(data.position)
|
|
66
|
+
);
|
|
67
|
+
transport.on(
|
|
68
|
+
"accepted",
|
|
69
|
+
(data) => setOperatorName(data.operatorName)
|
|
70
|
+
);
|
|
71
|
+
transport.on(
|
|
72
|
+
"message",
|
|
73
|
+
(data) => setMessages((prev) => [...prev, data])
|
|
74
|
+
);
|
|
75
|
+
transport.on("system", (data) => {
|
|
76
|
+
setMessages((prev) => [
|
|
77
|
+
...prev,
|
|
78
|
+
{
|
|
79
|
+
id: Date.now(),
|
|
80
|
+
content: data.message,
|
|
81
|
+
senderType: "system",
|
|
82
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
83
|
+
systemMessageType: data.type
|
|
84
|
+
}
|
|
85
|
+
]);
|
|
86
|
+
});
|
|
87
|
+
transport.on("ended", () => setState("ended"));
|
|
88
|
+
transport.on("handback-ai", () => resetState());
|
|
89
|
+
},
|
|
90
|
+
[persistSession, resetState]
|
|
91
|
+
);
|
|
92
|
+
react.useEffect(() => {
|
|
93
|
+
if (typeof window === "undefined") return;
|
|
94
|
+
let cancelled = false;
|
|
95
|
+
const storedSessionId = (() => {
|
|
96
|
+
try {
|
|
97
|
+
return sessionStorage.getItem(STORAGE_KEY);
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
})();
|
|
102
|
+
if (!storedSessionId || transportRef.current) return;
|
|
103
|
+
async function rejoin() {
|
|
104
|
+
const { LiveChatTransport } = await import('./live-chat-transport-ALVRGWX7.cjs');
|
|
105
|
+
if (cancelled || !LiveChatTransport) return;
|
|
106
|
+
const transportConfig = {
|
|
107
|
+
chatServiceUrl,
|
|
108
|
+
apiKey,
|
|
109
|
+
projectId,
|
|
110
|
+
visitorSessionId: sessionId
|
|
111
|
+
};
|
|
112
|
+
const transport = new LiveChatTransport(transportConfig);
|
|
113
|
+
attachListeners(transport);
|
|
114
|
+
transport.on("rejoin-success", (data) => {
|
|
115
|
+
if (cancelled) return;
|
|
116
|
+
if (data.state === "live") {
|
|
117
|
+
setState("live");
|
|
118
|
+
setOperatorName(data.operatorName || "Operator");
|
|
119
|
+
} else if (data.state === "queued") {
|
|
120
|
+
setState("queued");
|
|
121
|
+
setQueuePosition(data.position || 1);
|
|
122
|
+
}
|
|
123
|
+
if (data.messages?.length) {
|
|
124
|
+
setMessages(data.messages);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
transport.on("rejoin-failed", () => {
|
|
128
|
+
if (cancelled) return;
|
|
129
|
+
if (typeof window !== "undefined") {
|
|
130
|
+
try {
|
|
131
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
132
|
+
} catch {
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
transport.disconnect?.();
|
|
136
|
+
transportRef.current = null;
|
|
137
|
+
});
|
|
138
|
+
transportRef.current = transport;
|
|
139
|
+
await transport.connect();
|
|
140
|
+
transport.rejoinSession(storedSessionId);
|
|
141
|
+
}
|
|
142
|
+
rejoin().catch(() => {
|
|
143
|
+
if (typeof window !== "undefined") {
|
|
144
|
+
try {
|
|
145
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return () => {
|
|
151
|
+
cancelled = true;
|
|
152
|
+
};
|
|
153
|
+
}, []);
|
|
154
|
+
const initiate = react.useCallback(
|
|
155
|
+
async (visitorName, visitorEmail) => {
|
|
156
|
+
if (transportRef.current) return;
|
|
157
|
+
try {
|
|
158
|
+
const { LiveChatTransport } = await import('./live-chat-transport-ALVRGWX7.cjs');
|
|
159
|
+
if (!LiveChatTransport) {
|
|
160
|
+
console.error("[LiveChat] LiveChatTransport not available");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const transportConfig = {
|
|
164
|
+
chatServiceUrl,
|
|
165
|
+
apiKey,
|
|
166
|
+
projectId,
|
|
167
|
+
visitorSessionId: sessionId
|
|
168
|
+
};
|
|
169
|
+
const transport = new LiveChatTransport(transportConfig);
|
|
170
|
+
attachListeners(transport);
|
|
171
|
+
transportRef.current = transport;
|
|
172
|
+
await transport.connect();
|
|
173
|
+
transport.requestHandoff({
|
|
174
|
+
visitorName,
|
|
175
|
+
visitorEmail,
|
|
176
|
+
aiChatHistory: aiHistoryGetterRef.current?.() || []
|
|
177
|
+
});
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error("[LiveChat] Failed to initiate:", error);
|
|
180
|
+
setState("ai");
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
[chatServiceUrl, apiKey, projectId, sessionId, attachListeners]
|
|
184
|
+
);
|
|
185
|
+
const cancel = react.useCallback(() => {
|
|
186
|
+
const sid = transportRef.current?.getSessionId?.();
|
|
187
|
+
if (sid) transportRef.current?.cancelRequest?.(sid);
|
|
188
|
+
resetState();
|
|
189
|
+
}, [resetState]);
|
|
190
|
+
const end = react.useCallback(() => {
|
|
191
|
+
transportRef.current?.endChat?.();
|
|
192
|
+
}, []);
|
|
193
|
+
const send = react.useCallback((content) => {
|
|
194
|
+
if (!content.trim()) return;
|
|
195
|
+
transportRef.current?.sendMessage?.(content);
|
|
196
|
+
setMessages((prev) => [
|
|
197
|
+
...prev,
|
|
198
|
+
{
|
|
199
|
+
id: Date.now(),
|
|
200
|
+
content,
|
|
201
|
+
senderType: "visitor",
|
|
202
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
203
|
+
}
|
|
204
|
+
]);
|
|
205
|
+
}, []);
|
|
206
|
+
const submitRating = react.useCallback(
|
|
207
|
+
(rating, comment) => {
|
|
208
|
+
transportRef.current?.submitRating?.(rating, comment);
|
|
209
|
+
},
|
|
210
|
+
[]
|
|
211
|
+
);
|
|
212
|
+
const returnToAI = react.useCallback(() => {
|
|
213
|
+
resetState();
|
|
214
|
+
}, [resetState]);
|
|
215
|
+
const requestManualHandoff = react.useCallback(() => {
|
|
216
|
+
setShowIdentityForm(true);
|
|
217
|
+
}, []);
|
|
218
|
+
const value = react.useMemo(
|
|
219
|
+
() => ({
|
|
220
|
+
state,
|
|
221
|
+
messages,
|
|
222
|
+
operatorName,
|
|
223
|
+
queuePosition,
|
|
224
|
+
showIdentityForm,
|
|
225
|
+
initiate,
|
|
226
|
+
send,
|
|
227
|
+
end,
|
|
228
|
+
cancel,
|
|
229
|
+
submitRating,
|
|
230
|
+
returnToAI,
|
|
231
|
+
requestManualHandoff,
|
|
232
|
+
setShowIdentityForm,
|
|
233
|
+
registerAiHistoryGetter,
|
|
234
|
+
userInfo
|
|
235
|
+
}),
|
|
236
|
+
[
|
|
237
|
+
state,
|
|
238
|
+
messages,
|
|
239
|
+
operatorName,
|
|
240
|
+
queuePosition,
|
|
241
|
+
showIdentityForm,
|
|
242
|
+
initiate,
|
|
243
|
+
send,
|
|
244
|
+
end,
|
|
245
|
+
cancel,
|
|
246
|
+
submitRating,
|
|
247
|
+
returnToAI,
|
|
248
|
+
requestManualHandoff,
|
|
249
|
+
registerAiHistoryGetter,
|
|
250
|
+
userInfo
|
|
251
|
+
]
|
|
252
|
+
);
|
|
253
|
+
return /* @__PURE__ */ jsxRuntime.jsx(LiveChatContext.Provider, { value, children });
|
|
254
|
+
}
|
|
255
|
+
function useLiveChat() {
|
|
256
|
+
return react.useContext(LiveChatContext);
|
|
257
|
+
}
|
|
258
|
+
var PreviewEmbedContext = react.createContext(null);
|
|
259
|
+
function PreviewEmbedProvider({ children }) {
|
|
260
|
+
const [preview, setPreview] = react.useState(null);
|
|
261
|
+
const openPreview = react.useCallback(
|
|
262
|
+
(info) => setPreview(info),
|
|
263
|
+
[]
|
|
264
|
+
);
|
|
265
|
+
const closePreview = react.useCallback(() => setPreview(null), []);
|
|
266
|
+
const value = react.useMemo(
|
|
267
|
+
() => ({ preview, openPreview, closePreview }),
|
|
268
|
+
[preview, openPreview, closePreview]
|
|
269
|
+
);
|
|
270
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PreviewEmbedContext.Provider, { value, children });
|
|
271
|
+
}
|
|
272
|
+
function usePreviewEmbed() {
|
|
273
|
+
return react.useContext(PreviewEmbedContext);
|
|
274
|
+
}
|
|
275
|
+
var MOBILE_BREAKPOINT = 768;
|
|
276
|
+
var getIsMobile = () => typeof window !== "undefined" && window.innerWidth < MOBILE_BREAKPOINT;
|
|
277
|
+
function useIsMobile() {
|
|
278
|
+
const [isMobile, setIsMobile] = react.useState(getIsMobile);
|
|
279
|
+
const initialWidthRef = react.useRef(null);
|
|
280
|
+
react.useEffect(() => {
|
|
281
|
+
if (typeof window === "undefined") return;
|
|
282
|
+
if (initialWidthRef.current === null) {
|
|
283
|
+
initialWidthRef.current = window.innerWidth;
|
|
284
|
+
}
|
|
285
|
+
const checkMobile = () => {
|
|
286
|
+
const currentWidth = window.innerWidth;
|
|
287
|
+
const widthCrossedBreakpoint = currentWidth < MOBILE_BREAKPOINT !== initialWidthRef.current < MOBILE_BREAKPOINT || Math.abs(currentWidth - initialWidthRef.current) > 100;
|
|
288
|
+
if (widthCrossedBreakpoint) {
|
|
289
|
+
initialWidthRef.current = currentWidth;
|
|
290
|
+
setIsMobile(currentWidth < MOBILE_BREAKPOINT);
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
window.addEventListener("resize", checkMobile);
|
|
294
|
+
return () => window.removeEventListener("resize", checkMobile);
|
|
295
|
+
}, []);
|
|
296
|
+
return isMobile;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
exports.LiveChatProvider = LiveChatProvider;
|
|
300
|
+
exports.PreviewEmbedProvider = PreviewEmbedProvider;
|
|
301
|
+
exports.useIsMobile = useIsMobile;
|
|
302
|
+
exports.useLiveChat = useLiveChat;
|
|
303
|
+
exports.usePreviewEmbed = usePreviewEmbed;
|
|
304
|
+
//# sourceMappingURL=chunk-NYQSM3EB.cjs.map
|
|
305
|
+
//# sourceMappingURL=chunk-NYQSM3EB.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/LiveChatProvider.tsx","../src/providers/PreviewEmbedProvider.tsx","../src/hooks/use-mobile.ts"],"names":["createContext","useState","useRef","useCallback","useEffect","useMemo","jsx","useContext"],"mappings":"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","file":"chunk-NYQSM3EB.cjs","sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useState,\n useCallback,\n useRef,\n useEffect,\n useMemo,\n type ReactNode,\n} from \"react\";\nimport type {\n LiveChatState,\n LiveChatMessage,\n} from \"../core/types\";\nimport { LiveChatTransport } from \"../core/live-chat-transport\";\nimport type { LiveChatConfig as LiveChatTransportConfig } from \"../core/live-chat-transport\";\n\ninterface LiveChatContextValue {\n /** Current live chat state machine state. */\n state: LiveChatState;\n /** Live chat messages. */\n messages: LiveChatMessage[];\n /** Name of the connected operator. */\n operatorName: string;\n /** Current position in queue. */\n queuePosition: number;\n /** Whether to show the visitor identity form. */\n showIdentityForm: boolean;\n /** Initiate a live chat session. */\n initiate: (visitorName?: string, visitorEmail?: string) => Promise<void>;\n /** Send a message in live chat. */\n send: (content: string) => void;\n /** End the live chat session. */\n end: () => void;\n /** Cancel a pending live chat request. */\n cancel: () => void;\n /** Submit a satisfaction rating. */\n submitRating: (rating: \"positive\" | \"negative\", comment?: string) => void;\n /** Return to AI chat mode. */\n returnToAI: () => void;\n /** Request manual handoff (shows identity form). */\n requestManualHandoff: () => void;\n /** Control identity form visibility. */\n setShowIdentityForm: (show: boolean) => void;\n /** Register a getter for AI chat history (used for context handoff). */\n registerAiHistoryGetter: (\n getter: () => Array<{ role: string; content: string }>\n ) => void;\n /** Pre-filled user info. */\n userInfo?: { name?: string; email?: string } | null;\n}\n\nconst LiveChatContext = createContext<LiveChatContextValue | null>(null);\n\n/** Props for the LiveChatProvider. */\nexport interface LiveChatProviderProps {\n children: ReactNode;\n /** Chat service WebSocket URL. */\n chatServiceUrl: string;\n /** API key for authentication. */\n apiKey: string;\n /** Project identifier. */\n projectId: string;\n /** Visitor session ID (typically the AI chat session). */\n sessionId: string;\n /** Pre-filled user info. */\n userInfo?: { name?: string; email?: string } | null;\n}\n\n/**\n * Provides live chat functionality with operators.\n * Manages a state machine: \"ai\" -> \"requesting\" -> \"queued\" -> \"live\" -> \"ended\".\n * Uses a Socket.IO transport that is lazily loaded.\n */\nexport function LiveChatProvider({\n children,\n chatServiceUrl,\n apiKey,\n projectId,\n sessionId,\n userInfo,\n}: LiveChatProviderProps) {\n const [state, setState] = useState<LiveChatState>(\"ai\");\n const [messages, setMessages] = useState<LiveChatMessage[]>([]);\n const [operatorName, setOperatorName] = useState(\"\");\n const [queuePosition, setQueuePosition] = useState(0);\n const [showIdentityForm, setShowIdentityForm] = useState(false);\n const transportRef = useRef<any>(null);\n const aiHistoryGetterRef = useRef<\n (() => Array<{ role: string; content: string }>) | null\n >(null);\n\n const STORAGE_KEY = `livechat-session-${projectId}`;\n\n const registerAiHistoryGetter = useCallback(\n (getter: () => Array<{ role: string; content: string }>) => {\n aiHistoryGetterRef.current = getter;\n },\n []\n );\n\n const resetState = useCallback(() => {\n transportRef.current?.disconnect?.();\n transportRef.current = null;\n setState(\"ai\");\n setMessages([]);\n setOperatorName(\"\");\n setQueuePosition(0);\n setShowIdentityForm(false);\n if (typeof window !== \"undefined\") {\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // Ignore.\n }\n }\n }, [STORAGE_KEY]);\n\n const persistSession = useCallback(\n (liveChatSessionId: string) => {\n if (typeof window === \"undefined\") return;\n try {\n sessionStorage.setItem(STORAGE_KEY, liveChatSessionId);\n } catch {\n // Ignore.\n }\n },\n [STORAGE_KEY]\n );\n\n /** Attach standard event listeners to a transport instance. */\n const attachListeners = useCallback(\n (transport: any) => {\n transport.on(\"state-change\", setState);\n transport.on(\"queued\", (data: any) => {\n setQueuePosition(data.position);\n if (data.liveChatSessionId) persistSession(data.liveChatSessionId);\n });\n transport.on(\"queue-update\", (data: any) =>\n setQueuePosition(data.position)\n );\n transport.on(\"accepted\", (data: any) =>\n setOperatorName(data.operatorName)\n );\n transport.on(\"message\", (data: LiveChatMessage) =>\n setMessages((prev) => [...prev, data])\n );\n transport.on(\"system\", (data: any) => {\n setMessages((prev) => [\n ...prev,\n {\n id: Date.now(),\n content: data.message,\n senderType: \"system\" as const,\n timestamp: new Date().toISOString(),\n systemMessageType: data.type,\n },\n ]);\n });\n transport.on(\"ended\", () => setState(\"ended\"));\n transport.on(\"handback-ai\", () => resetState());\n },\n [persistSession, resetState]\n );\n\n // Attempt to rejoin on mount if there's a stored session\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n let cancelled = false;\n\n const storedSessionId = (() => {\n try {\n return sessionStorage.getItem(STORAGE_KEY);\n } catch {\n return null;\n }\n })();\n\n if (!storedSessionId || transportRef.current) return;\n\n async function rejoin() {\n // Dynamically import the transport to avoid bundling Socket.IO unconditionally\n const { LiveChatTransport } = await import(\"../core/live-chat-transport\");\n if (cancelled || !LiveChatTransport) return;\n\n const transportConfig: LiveChatTransportConfig = {\n chatServiceUrl,\n apiKey,\n projectId,\n visitorSessionId: sessionId,\n };\n\n const transport = new (LiveChatTransport as any)(transportConfig);\n attachListeners(transport);\n\n transport.on(\"rejoin-success\", (data: any) => {\n if (cancelled) return;\n if (data.state === \"live\") {\n setState(\"live\");\n setOperatorName(data.operatorName || \"Operator\");\n } else if (data.state === \"queued\") {\n setState(\"queued\");\n setQueuePosition(data.position || 1);\n }\n if (data.messages?.length) {\n setMessages(data.messages);\n }\n });\n\n transport.on(\"rejoin-failed\", () => {\n if (cancelled) return;\n if (typeof window !== \"undefined\") {\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // Ignore.\n }\n }\n transport.disconnect?.();\n transportRef.current = null;\n });\n\n transportRef.current = transport;\n await transport.connect();\n transport.rejoinSession(storedSessionId!);\n }\n\n rejoin().catch(() => {\n if (typeof window !== \"undefined\") {\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // Ignore.\n }\n }\n });\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const initiate = useCallback(\n async (visitorName?: string, visitorEmail?: string) => {\n if (transportRef.current) return;\n\n try {\n const { LiveChatTransport } = await import(\"../core/live-chat-transport\");\n if (!LiveChatTransport) {\n console.error(\"[LiveChat] LiveChatTransport not available\");\n return;\n }\n\n const transportConfig: LiveChatTransportConfig = {\n chatServiceUrl,\n apiKey,\n projectId,\n visitorSessionId: sessionId,\n };\n\n const transport = new (LiveChatTransport as any)(transportConfig);\n attachListeners(transport);\n\n transportRef.current = transport;\n await transport.connect();\n\n transport.requestHandoff({\n visitorName,\n visitorEmail,\n aiChatHistory: aiHistoryGetterRef.current?.() || [],\n });\n } catch (error) {\n console.error(\"[LiveChat] Failed to initiate:\", error);\n setState(\"ai\");\n }\n },\n [chatServiceUrl, apiKey, projectId, sessionId, attachListeners]\n );\n\n const cancel = useCallback(() => {\n const sid = transportRef.current?.getSessionId?.();\n if (sid) transportRef.current?.cancelRequest?.(sid);\n resetState();\n }, [resetState]);\n\n const end = useCallback(() => {\n transportRef.current?.endChat?.();\n }, []);\n\n const send = useCallback((content: string) => {\n if (!content.trim()) return;\n transportRef.current?.sendMessage?.(content);\n setMessages((prev) => [\n ...prev,\n {\n id: Date.now(),\n content,\n senderType: \"visitor\" as const,\n timestamp: new Date().toISOString(),\n },\n ]);\n }, []);\n\n const submitRating = useCallback(\n (rating: \"positive\" | \"negative\", comment?: string) => {\n transportRef.current?.submitRating?.(rating, comment);\n },\n []\n );\n\n const returnToAI = useCallback(() => {\n resetState();\n }, [resetState]);\n\n const requestManualHandoff = useCallback(() => {\n setShowIdentityForm(true);\n }, []);\n\n const value = useMemo<LiveChatContextValue>(\n () => ({\n state,\n messages,\n operatorName,\n queuePosition,\n showIdentityForm,\n initiate,\n send,\n end,\n cancel,\n submitRating,\n returnToAI,\n requestManualHandoff,\n setShowIdentityForm,\n registerAiHistoryGetter,\n userInfo,\n }),\n [\n state,\n messages,\n operatorName,\n queuePosition,\n showIdentityForm,\n initiate,\n send,\n end,\n cancel,\n submitRating,\n returnToAI,\n requestManualHandoff,\n registerAiHistoryGetter,\n userInfo,\n ]\n );\n\n return (\n <LiveChatContext.Provider value={value}>{children}</LiveChatContext.Provider>\n );\n}\n\n/**\n * Returns the live chat context, or `null` if not within a LiveChatProvider.\n *\n * Live chat is opt-in (`enableLiveChat` on `ChatProvider`), so components that\n * optionally show live-chat UI should handle the null case gracefully.\n */\nexport function useLiveChat(): LiveChatContextValue | null {\n return useContext(LiveChatContext);\n}\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useState,\n useCallback,\n useMemo,\n type ReactNode,\n} from \"react\";\n\n/** Information about a preview to display in an embedded panel. */\nexport interface PreviewInfo {\n /** URL to preview. */\n url: string;\n /** Optional title for the preview. */\n title?: string;\n /** Optional description for the preview. */\n description?: string;\n}\n\ninterface PreviewEmbedContextValue {\n /** Current preview info, or null if no preview is active. */\n preview: PreviewInfo | null;\n /** Open a preview panel with the given info. */\n openPreview: (info: PreviewInfo) => void;\n /** Close the active preview panel. */\n closePreview: () => void;\n}\n\nconst PreviewEmbedContext = createContext<PreviewEmbedContextValue | null>(null);\n\n/** Props for the PreviewEmbedProvider. */\nexport interface PreviewEmbedProviderProps {\n children: ReactNode;\n}\n\n/**\n * Provides state for an embedded preview panel (e.g. in-chat link previews).\n */\nexport function PreviewEmbedProvider({ children }: PreviewEmbedProviderProps) {\n const [preview, setPreview] = useState<PreviewInfo | null>(null);\n\n const openPreview = useCallback(\n (info: PreviewInfo) => setPreview(info),\n []\n );\n\n const closePreview = useCallback(() => setPreview(null), []);\n\n const value = useMemo<PreviewEmbedContextValue>(\n () => ({ preview, openPreview, closePreview }),\n [preview, openPreview, closePreview]\n );\n\n return (\n <PreviewEmbedContext.Provider value={value}>\n {children}\n </PreviewEmbedContext.Provider>\n );\n}\n\n/**\n * Returns the preview embed context.\n * Returns null if used outside a PreviewEmbedProvider (non-throwing for optional usage).\n */\nexport function usePreviewEmbed(): PreviewEmbedContextValue | null {\n return useContext(PreviewEmbedContext);\n}\n","\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\n\nconst MOBILE_BREAKPOINT = 768;\n\n/** Get initial mobile state with SSR guard. */\nconst getIsMobile = () =>\n typeof window !== \"undefined\" && window.innerWidth < MOBILE_BREAKPOINT;\n\n/**\n * Detects whether the viewport is mobile-sized.\n * Ignores height-only changes (e.g. virtual keyboard) and only reacts\n * when width actually crosses the breakpoint.\n *\n * SSR-safe: returns false during server rendering.\n */\nexport function useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState<boolean>(getIsMobile);\n const initialWidthRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n if (initialWidthRef.current === null) {\n initialWidthRef.current = window.innerWidth;\n }\n\n const checkMobile = () => {\n const currentWidth = window.innerWidth;\n const widthCrossedBreakpoint =\n currentWidth < MOBILE_BREAKPOINT !==\n initialWidthRef.current! < MOBILE_BREAKPOINT ||\n Math.abs(currentWidth - initialWidthRef.current!) > 100;\n\n if (widthCrossedBreakpoint) {\n initialWidthRef.current = currentWidth;\n setIsMobile(currentWidth < MOBILE_BREAKPOINT);\n }\n };\n\n window.addEventListener(\"resize\", checkMobile);\n return () => window.removeEventListener(\"resize\", checkMobile);\n }, []);\n\n return isMobile;\n}\n\nexport default useIsMobile;\n"]}
|