@sonordev/site-kit 2.9.0 → 3.0.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/dist/EngageWidget-LRE4VD7O.js +14 -0
- package/dist/{EngageWidget-JIXUBG47.js.map → EngageWidget-LRE4VD7O.js.map} +1 -1
- package/dist/EngageWidget-OAOLB6ED.mjs +5 -0
- package/dist/{EngageWidget-4W5EM4UO.mjs.map → EngageWidget-OAOLB6ED.mjs.map} +1 -1
- package/dist/chunk-2FEQ6TYD.mjs +37 -0
- package/dist/chunk-2FEQ6TYD.mjs.map +1 -0
- package/dist/{chunk-5QLM6LZ2.mjs → chunk-APRAGA5G.mjs} +3 -3
- package/dist/{chunk-5QLM6LZ2.mjs.map → chunk-APRAGA5G.mjs.map} +1 -1
- package/dist/{chunk-HANRPNKG.js → chunk-FMI65E5Y.js} +3 -3
- package/dist/{chunk-HANRPNKG.js.map → chunk-FMI65E5Y.js.map} +1 -1
- package/dist/{chunk-SLJJJWMV.js → chunk-FPU2QPO4.js} +338 -33
- package/dist/chunk-FPU2QPO4.js.map +1 -0
- package/dist/chunk-MLJXELPA.js +693 -0
- package/dist/chunk-MLJXELPA.js.map +1 -0
- package/dist/{chunk-IAV32YHL.mjs → chunk-RV45YMBJ.mjs} +338 -33
- package/dist/chunk-RV45YMBJ.mjs.map +1 -0
- package/dist/chunk-TCVHI3JP.mjs +686 -0
- package/dist/chunk-TCVHI3JP.mjs.map +1 -0
- package/dist/chunk-YBKALLBH.js +46 -0
- package/dist/chunk-YBKALLBH.js.map +1 -0
- package/dist/engage/index.d.mts +2 -2
- package/dist/engage/index.d.ts +2 -2
- package/dist/engage/index.js +5 -4
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +2 -1
- package/dist/engage/index.mjs.map +1 -1
- package/dist/forms/index.js +19 -683
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +4 -676
- package/dist/forms/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/layout/client.js +2 -2
- package/dist/layout/client.mjs +1 -1
- package/dist/layout/index.js +2 -2
- package/dist/layout/index.mjs +1 -1
- package/dist/middleware/index.d.mts +62 -1
- package/dist/middleware/index.d.ts +62 -1
- package/dist/middleware/index.js +105 -0
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +103 -1
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/slots/contract.d.mts +83 -0
- package/dist/slots/contract.d.ts +83 -0
- package/dist/slots/contract.js +41 -0
- package/dist/slots/contract.js.map +1 -0
- package/dist/slots/contract.mjs +4 -0
- package/dist/slots/contract.mjs.map +1 -0
- package/dist/slots/index.d.mts +104 -0
- package/dist/slots/index.d.ts +104 -0
- package/dist/slots/index.js +186 -0
- package/dist/slots/index.js.map +1 -0
- package/dist/slots/index.mjs +146 -0
- package/dist/slots/index.mjs.map +1 -0
- package/dist/{types-BnCwwUX3.d.ts → types-D_1iUxOQ.d.mts} +18 -1
- package/dist/{types-BnCwwUX3.d.mts → types-D_1iUxOQ.d.ts} +18 -1
- package/package.json +11 -1
- package/dist/EngageWidget-4W5EM4UO.mjs +0 -4
- package/dist/EngageWidget-JIXUBG47.js +0 -13
- package/dist/chunk-IAV32YHL.mjs.map +0 -1
- package/dist/chunk-SLJJJWMV.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var chunkMLJXELPA_js = require('./chunk-MLJXELPA.js');
|
|
4
5
|
var React2 = require('react');
|
|
5
6
|
var ReactDOM = require('react-dom');
|
|
6
7
|
var navigation = require('next/navigation');
|
|
@@ -13,7 +14,260 @@ var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
|
13
14
|
var ReactDOM__default = /*#__PURE__*/_interopDefault(ReactDOM);
|
|
14
15
|
var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
function alpha(rgb, a) {
|
|
18
|
+
return `rgba(var(--sk-primary-rgb, ${rgb}), ${a})`;
|
|
19
|
+
}
|
|
20
|
+
function asString(v) {
|
|
21
|
+
return typeof v === "string" && v.trim() ? v : void 0;
|
|
22
|
+
}
|
|
23
|
+
function asRecord(v) {
|
|
24
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
25
|
+
}
|
|
26
|
+
function isNavigable(action) {
|
|
27
|
+
return /^(https?:\/\/|\/|#|tel:|mailto:)/i.test(action.trim());
|
|
28
|
+
}
|
|
29
|
+
var DISPLAY_ONLY = ["heading", "section_header", "paragraph"];
|
|
30
|
+
function InlineManagedForm({ slug, prefill, primaryColor, primaryRgb }) {
|
|
31
|
+
const {
|
|
32
|
+
form,
|
|
33
|
+
isLoading,
|
|
34
|
+
fetchError,
|
|
35
|
+
submitError,
|
|
36
|
+
visibleFields,
|
|
37
|
+
values,
|
|
38
|
+
errors,
|
|
39
|
+
setFieldValue,
|
|
40
|
+
submit,
|
|
41
|
+
isSubmitting,
|
|
42
|
+
isComplete
|
|
43
|
+
} = chunkMLJXELPA_js.useForm(slug, { initialValues: prefill || {} });
|
|
44
|
+
const cardStyle = {
|
|
45
|
+
marginTop: 8,
|
|
46
|
+
padding: 12,
|
|
47
|
+
borderRadius: 12,
|
|
48
|
+
border: `1px solid ${alpha(primaryRgb, 0.25)}`,
|
|
49
|
+
backgroundColor: alpha(primaryRgb, 0.04)
|
|
50
|
+
};
|
|
51
|
+
if (isLoading) {
|
|
52
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, fontSize: 13, color: "var(--sk-text-tertiary, #9ca3af)" }, children: "Loading form\u2026" }) });
|
|
53
|
+
}
|
|
54
|
+
if (fetchError || !form) {
|
|
55
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, fontSize: 13, color: "var(--sk-text-tertiary, #9ca3af)" }, children: "This form is unavailable right now." }) });
|
|
56
|
+
}
|
|
57
|
+
if (isComplete) {
|
|
58
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, fontSize: 13.5, color: "var(--sk-text-primary, #111827)", lineHeight: 1.5 }, children: form.success_message }) });
|
|
59
|
+
}
|
|
60
|
+
const inputBase = {
|
|
61
|
+
width: "100%",
|
|
62
|
+
padding: "8px 10px",
|
|
63
|
+
borderRadius: 8,
|
|
64
|
+
// Longhand (not the `border` shorthand) so the error-state `borderColor`
|
|
65
|
+
// override doesn't mix shorthand+longhand and trigger React's style warning.
|
|
66
|
+
borderWidth: 1,
|
|
67
|
+
borderStyle: "solid",
|
|
68
|
+
borderColor: "var(--sk-border, #e5e7eb)",
|
|
69
|
+
backgroundColor: "var(--sk-bg, #ffffff)",
|
|
70
|
+
color: "var(--sk-text-primary, #111827)",
|
|
71
|
+
fontSize: 13.5,
|
|
72
|
+
boxSizing: "border-box",
|
|
73
|
+
outline: "none"
|
|
74
|
+
};
|
|
75
|
+
const renderField = (field) => {
|
|
76
|
+
const value = values[field.slug];
|
|
77
|
+
const strValue = value == null ? "" : String(value);
|
|
78
|
+
const err = errors[field.slug];
|
|
79
|
+
const labelEl = !field.hide_label && field.label ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
80
|
+
"label",
|
|
81
|
+
{
|
|
82
|
+
htmlFor: `echo-form-${form.id}-${field.slug}`,
|
|
83
|
+
style: { display: "block", fontSize: 12.5, fontWeight: 600, marginBottom: 4, color: "var(--sk-text-secondary, #4b5563)" },
|
|
84
|
+
children: [
|
|
85
|
+
field.label,
|
|
86
|
+
field.is_required ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sk-error, #ef4444)" }, children: " *" }) : null
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
) : null;
|
|
90
|
+
const id = `echo-form-${form.id}-${field.slug}`;
|
|
91
|
+
const common = {
|
|
92
|
+
id,
|
|
93
|
+
placeholder: field.placeholder || (field.hide_label ? field.label : void 0),
|
|
94
|
+
"aria-invalid": !!err,
|
|
95
|
+
style: { ...inputBase, ...err ? { borderColor: "var(--sk-error, #ef4444)" } : {} }
|
|
96
|
+
};
|
|
97
|
+
let control;
|
|
98
|
+
switch (field.field_type) {
|
|
99
|
+
case "textarea":
|
|
100
|
+
control = /* @__PURE__ */ jsxRuntime.jsx(
|
|
101
|
+
"textarea",
|
|
102
|
+
{
|
|
103
|
+
...common,
|
|
104
|
+
rows: 3,
|
|
105
|
+
value: strValue,
|
|
106
|
+
onChange: (e) => setFieldValue(field.slug, e.target.value),
|
|
107
|
+
style: { ...common.style, resize: "vertical" }
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
break;
|
|
111
|
+
case "select":
|
|
112
|
+
control = /* @__PURE__ */ jsxRuntime.jsxs("select", { ...common, value: strValue, onChange: (e) => setFieldValue(field.slug, e.target.value), children: [
|
|
113
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: field.placeholder || "Select\u2026" }),
|
|
114
|
+
(field.options || []).map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
115
|
+
] });
|
|
116
|
+
break;
|
|
117
|
+
case "radio":
|
|
118
|
+
control = /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", style: { display: "flex", flexDirection: "column", gap: 4 }, children: (field.options || []).map((opt) => /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: 13, cursor: "pointer" }, children: [
|
|
119
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
120
|
+
"input",
|
|
121
|
+
{
|
|
122
|
+
type: "radio",
|
|
123
|
+
name: id,
|
|
124
|
+
checked: strValue === opt.value,
|
|
125
|
+
onChange: () => setFieldValue(field.slug, opt.value)
|
|
126
|
+
}
|
|
127
|
+
),
|
|
128
|
+
opt.label
|
|
129
|
+
] }, opt.value)) });
|
|
130
|
+
break;
|
|
131
|
+
case "checkbox":
|
|
132
|
+
control = /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: 13, cursor: "pointer" }, children: [
|
|
133
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
134
|
+
"input",
|
|
135
|
+
{
|
|
136
|
+
type: "checkbox",
|
|
137
|
+
checked: value === true || value === "true",
|
|
138
|
+
onChange: (e) => setFieldValue(field.slug, e.target.checked)
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
field.placeholder || field.label
|
|
142
|
+
] });
|
|
143
|
+
break;
|
|
144
|
+
default: {
|
|
145
|
+
const typeMap = {
|
|
146
|
+
email: "email",
|
|
147
|
+
phone: "tel",
|
|
148
|
+
tel: "tel",
|
|
149
|
+
number: "number",
|
|
150
|
+
date: "date",
|
|
151
|
+
time: "time",
|
|
152
|
+
datetime: "datetime-local"
|
|
153
|
+
};
|
|
154
|
+
control = /* @__PURE__ */ jsxRuntime.jsx(
|
|
155
|
+
"input",
|
|
156
|
+
{
|
|
157
|
+
...common,
|
|
158
|
+
type: typeMap[field.field_type] || "text",
|
|
159
|
+
value: strValue,
|
|
160
|
+
onChange: (e) => setFieldValue(field.slug, e.target.value)
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 8 }, children: [
|
|
166
|
+
field.field_type === "checkbox" ? null : labelEl,
|
|
167
|
+
control,
|
|
168
|
+
err ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "4px 0 0", fontSize: 11.5, color: "var(--sk-error, #ef4444)" }, children: err }) : null
|
|
169
|
+
] }, field.id || field.slug);
|
|
170
|
+
};
|
|
171
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
172
|
+
"form",
|
|
173
|
+
{
|
|
174
|
+
style: cardStyle,
|
|
175
|
+
onSubmit: (e) => {
|
|
176
|
+
e.preventDefault();
|
|
177
|
+
void submit();
|
|
178
|
+
},
|
|
179
|
+
children: [
|
|
180
|
+
form.name ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13.5, fontWeight: 600, marginBottom: 8, color: "var(--sk-text-primary, #111827)" }, children: form.name }) : null,
|
|
181
|
+
visibleFields.map((field) => {
|
|
182
|
+
if (field.field_type === "hidden") return null;
|
|
183
|
+
if (DISPLAY_ONLY.includes(field.field_type)) {
|
|
184
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0 0 8px", fontSize: 12.5, color: "var(--sk-text-secondary, #4b5563)" }, children: field.label }, field.id || field.slug);
|
|
185
|
+
}
|
|
186
|
+
return renderField(field);
|
|
187
|
+
}),
|
|
188
|
+
submitError ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", style: { margin: "0 0 8px", fontSize: 12, color: "var(--sk-error, #ef4444)" }, children: submitError }) : null,
|
|
189
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
190
|
+
"button",
|
|
191
|
+
{
|
|
192
|
+
type: "submit",
|
|
193
|
+
disabled: isSubmitting,
|
|
194
|
+
style: {
|
|
195
|
+
width: "100%",
|
|
196
|
+
padding: "9px 14px",
|
|
197
|
+
borderRadius: 8,
|
|
198
|
+
border: "none",
|
|
199
|
+
backgroundColor: primaryColor,
|
|
200
|
+
color: "#fff",
|
|
201
|
+
fontSize: 13.5,
|
|
202
|
+
fontWeight: 600,
|
|
203
|
+
cursor: isSubmitting ? "default" : "pointer",
|
|
204
|
+
opacity: isSubmitting ? 0.7 : 1
|
|
205
|
+
},
|
|
206
|
+
children: isSubmitting ? "Sending\u2026" : form.submit_button_text || "Submit"
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
function SuggestActionChip({ action, message, primaryColor, primaryRgb, onSuggest }) {
|
|
214
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
215
|
+
"button",
|
|
216
|
+
{
|
|
217
|
+
type: "button",
|
|
218
|
+
onClick: () => onSuggest(action, message),
|
|
219
|
+
style: {
|
|
220
|
+
padding: "6px 12px",
|
|
221
|
+
borderRadius: 16,
|
|
222
|
+
border: `1px solid ${primaryColor}`,
|
|
223
|
+
backgroundColor: alpha(primaryRgb, 0.063),
|
|
224
|
+
color: primaryColor,
|
|
225
|
+
fontSize: 13,
|
|
226
|
+
cursor: "pointer"
|
|
227
|
+
},
|
|
228
|
+
children: message
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
function EchoUiActions({ actions, primaryColor, primaryRgb, onSuggest }) {
|
|
233
|
+
if (!actions?.length) return null;
|
|
234
|
+
const chips = actions.filter((a) => a?.type === "suggest_action");
|
|
235
|
+
const forms = actions.filter((a) => a?.type === "show_form");
|
|
236
|
+
if (!chips.length && !forms.length) return null;
|
|
237
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 8, display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
238
|
+
forms.map((a, i) => {
|
|
239
|
+
const slug = asString(a.data?.formSlug);
|
|
240
|
+
if (!slug) return null;
|
|
241
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
242
|
+
InlineManagedForm,
|
|
243
|
+
{
|
|
244
|
+
slug,
|
|
245
|
+
prefill: asRecord(a.data?.prefill),
|
|
246
|
+
primaryColor,
|
|
247
|
+
primaryRgb
|
|
248
|
+
},
|
|
249
|
+
`form-${slug}-${i}`
|
|
250
|
+
);
|
|
251
|
+
}),
|
|
252
|
+
chips.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: chips.map((a, i) => {
|
|
253
|
+
const message = asString(a.data?.message);
|
|
254
|
+
const action = asString(a.data?.action);
|
|
255
|
+
const label = message || action;
|
|
256
|
+
if (!label) return null;
|
|
257
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
258
|
+
SuggestActionChip,
|
|
259
|
+
{
|
|
260
|
+
action,
|
|
261
|
+
message: label,
|
|
262
|
+
primaryColor,
|
|
263
|
+
primaryRgb,
|
|
264
|
+
onSuggest
|
|
265
|
+
},
|
|
266
|
+
`chip-${i}`
|
|
267
|
+
);
|
|
268
|
+
}) }) : null
|
|
269
|
+
] });
|
|
270
|
+
}
|
|
17
271
|
function getApiConfig() {
|
|
18
272
|
const isDev = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
|
|
19
273
|
const defaultApiUrl = isDev && process.env?.SONOR_API_URL ? process.env.SONOR_API_URL : "https://api.sonor.io";
|
|
@@ -71,8 +325,8 @@ function hexToRgbString(hex, fallback = "59, 130, 246") {
|
|
|
71
325
|
if (!match) return fallback;
|
|
72
326
|
return `${parseInt(match[1], 16)}, ${parseInt(match[2], 16)}, ${parseInt(match[3], 16)}`;
|
|
73
327
|
}
|
|
74
|
-
function hexAlpha(rgbVar,
|
|
75
|
-
return `rgba(var(${rgbVar}, ${fallbackRgb}), ${
|
|
328
|
+
function hexAlpha(rgbVar, alpha2, fallbackRgb = "59, 130, 246") {
|
|
329
|
+
return `rgba(var(${rgbVar}, ${fallbackRgb}), ${alpha2})`;
|
|
76
330
|
}
|
|
77
331
|
function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, signalUrl: propSignalUrl, suggested_questions: propSuggestedQuestions, assistant_name: propAssistantName, welcome_message: propWelcomeMessage, assistant_avatar: propAssistantAvatar }) {
|
|
78
332
|
const [resolvedProjectId, setResolvedProjectId] = React2.useState(propProjectId || null);
|
|
@@ -268,11 +522,29 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
268
522
|
const aiContent = data?.content ?? data?.response ?? data?.message ?? "I'm sorry, I couldn't process that.";
|
|
269
523
|
const suggestions = data?.suggestions;
|
|
270
524
|
const offerHandoff = data?.offerHandoff === true || data?.offer_handoff === true;
|
|
525
|
+
const uiActions = Array.isArray(data?.uiActions) ? data.uiActions.filter((a) => a && typeof a === "object" && typeof a.type === "string" && a.data && typeof a.data === "object") : void 0;
|
|
271
526
|
const newConversationId = data?.conversationId ?? conversationId;
|
|
272
|
-
return { content: aiContent, suggestions, offerHandoff, conversationId: newConversationId };
|
|
527
|
+
return { content: aiContent, suggestions, offerHandoff, uiActions, conversationId: newConversationId };
|
|
273
528
|
},
|
|
274
529
|
[signalUrl, visitorId, fetchSiteContext]
|
|
275
530
|
);
|
|
531
|
+
const pushEchoReply = React2.useCallback(
|
|
532
|
+
(reply, probeContent) => {
|
|
533
|
+
setMessages((prev) => [
|
|
534
|
+
...prev,
|
|
535
|
+
{
|
|
536
|
+
id: `ai-${Date.now()}`,
|
|
537
|
+
role: "assistant",
|
|
538
|
+
content: reply.content,
|
|
539
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
540
|
+
...reply.suggestions?.length ? { suggestions: reply.suggestions } : {},
|
|
541
|
+
...reply.uiActions?.length ? { uiActions: reply.uiActions } : {},
|
|
542
|
+
...reply.offerHandoff || userRequestedHandoff(probeContent) ? { offerHandoff: true } : {}
|
|
543
|
+
}
|
|
544
|
+
]);
|
|
545
|
+
},
|
|
546
|
+
[]
|
|
547
|
+
);
|
|
276
548
|
const handleSocketMessage = React2.useCallback((data) => {
|
|
277
549
|
switch (data.type || data.event) {
|
|
278
550
|
case "message": {
|
|
@@ -475,19 +747,8 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
475
747
|
{ id: `u-${Date.now()}`, role: "user", content: pending, timestamp: /* @__PURE__ */ new Date() }
|
|
476
748
|
]);
|
|
477
749
|
try {
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
setMessages((prev) => [
|
|
481
|
-
...prev,
|
|
482
|
-
{
|
|
483
|
-
id: `ai-${Date.now()}`,
|
|
484
|
-
role: "assistant",
|
|
485
|
-
content: aiContent,
|
|
486
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
487
|
-
...suggestions?.length ? { suggestions } : {},
|
|
488
|
-
...offerHandoff || userWantsHandoff ? { offerHandoff: true } : {}
|
|
489
|
-
}
|
|
490
|
-
]);
|
|
750
|
+
const reply = await sendToSignalApi(pending, id);
|
|
751
|
+
pushEchoReply(reply, pending);
|
|
491
752
|
} catch (err) {
|
|
492
753
|
console.error("[ChatWidget] Signal API error:", err);
|
|
493
754
|
setMessages((prev) => [
|
|
@@ -530,7 +791,7 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
530
791
|
return () => {
|
|
531
792
|
if (pollingIntervalRef.current) clearInterval(pollingIntervalRef.current);
|
|
532
793
|
};
|
|
533
|
-
}, [isOpen, showWelcome, checkingAvailability, showOfflineForm, sessionId, initSession, connectSocket, sendToSignalApi]);
|
|
794
|
+
}, [isOpen, showWelcome, checkingAvailability, showOfflineForm, sessionId, initSession, connectSocket, sendToSignalApi, pushEchoReply]);
|
|
534
795
|
const handleToggle = React2.useCallback(() => {
|
|
535
796
|
setIsOpen((prev) => !prev);
|
|
536
797
|
}, []);
|
|
@@ -622,19 +883,9 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
622
883
|
setIsLoading(true);
|
|
623
884
|
if (widgetConfig?.signal_enabled && !isHandedOff && hasText) {
|
|
624
885
|
try {
|
|
625
|
-
const
|
|
886
|
+
const reply = await sendToSignalApi(content, sessionId);
|
|
626
887
|
const lastUserContent = messages.filter((m) => m.role === "user").slice(-1)[0]?.content ?? "";
|
|
627
|
-
|
|
628
|
-
...prev,
|
|
629
|
-
{
|
|
630
|
-
id: `ai-${Date.now()}`,
|
|
631
|
-
role: "assistant",
|
|
632
|
-
content: aiContent,
|
|
633
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
634
|
-
...suggestions?.length ? { suggestions } : {},
|
|
635
|
-
...offerHandoff || userRequestedHandoff(lastUserContent) ? { offerHandoff: true } : {}
|
|
636
|
-
}
|
|
637
|
-
]);
|
|
888
|
+
pushEchoReply(reply, lastUserContent);
|
|
638
889
|
} catch (err) {
|
|
639
890
|
console.error("[ChatWidget] Signal API error:", err);
|
|
640
891
|
setMessages((prev) => [
|
|
@@ -670,7 +921,52 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
670
921
|
}
|
|
671
922
|
}, 3e3);
|
|
672
923
|
},
|
|
673
|
-
[inputValue, isLoading, pendingFiles, uploadWidgetFile, widgetConfig?.signal_enabled, isHandedOff, sendToSignalApi, sessionId]
|
|
924
|
+
[inputValue, isLoading, pendingFiles, uploadWidgetFile, widgetConfig?.signal_enabled, isHandedOff, sendToSignalApi, sessionId, pushEchoReply]
|
|
925
|
+
);
|
|
926
|
+
const sendEchoText = React2.useCallback(
|
|
927
|
+
async (text) => {
|
|
928
|
+
const content = text.trim();
|
|
929
|
+
if (!content || isLoading) return;
|
|
930
|
+
setMessages((prev) => [
|
|
931
|
+
...prev,
|
|
932
|
+
{ id: `user-${Date.now()}`, role: "user", content, timestamp: /* @__PURE__ */ new Date() }
|
|
933
|
+
]);
|
|
934
|
+
setIsLoading(true);
|
|
935
|
+
try {
|
|
936
|
+
const reply = await sendToSignalApi(content, sessionId);
|
|
937
|
+
pushEchoReply(reply, content);
|
|
938
|
+
} catch (err) {
|
|
939
|
+
console.error("[ChatWidget] Signal API error:", err);
|
|
940
|
+
setMessages((prev) => [
|
|
941
|
+
...prev,
|
|
942
|
+
{
|
|
943
|
+
id: `err-${Date.now()}`,
|
|
944
|
+
role: "assistant",
|
|
945
|
+
content: "I apologize, but I encountered an error. Would you like to speak with a team member?",
|
|
946
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
947
|
+
suggestions: ["Talk to a person", "Try again"],
|
|
948
|
+
offerHandoff: true
|
|
949
|
+
}
|
|
950
|
+
]);
|
|
951
|
+
} finally {
|
|
952
|
+
setIsLoading(false);
|
|
953
|
+
}
|
|
954
|
+
},
|
|
955
|
+
[isLoading, sessionId, sendToSignalApi, pushEchoReply]
|
|
956
|
+
);
|
|
957
|
+
const handleSuggestAction = React2.useCallback(
|
|
958
|
+
(action, message) => {
|
|
959
|
+
const a = (action || "").trim();
|
|
960
|
+
if (a && isNavigable(a)) {
|
|
961
|
+
if (typeof window !== "undefined") {
|
|
962
|
+
if (/^https?:\/\//i.test(a)) window.open(a, "_blank", "noopener,noreferrer");
|
|
963
|
+
else window.location.href = a;
|
|
964
|
+
}
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
if (message?.trim()) void sendEchoText(message);
|
|
968
|
+
},
|
|
969
|
+
[sendEchoText]
|
|
674
970
|
);
|
|
675
971
|
const retryFailedSend = React2.useCallback(() => {
|
|
676
972
|
if (!lastFailedSend || !sessionId) return;
|
|
@@ -1148,6 +1444,15 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
1148
1444
|
},
|
|
1149
1445
|
i
|
|
1150
1446
|
)) }) : null,
|
|
1447
|
+
message.uiActions?.length ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1448
|
+
EchoUiActions,
|
|
1449
|
+
{
|
|
1450
|
+
actions: message.uiActions,
|
|
1451
|
+
primaryColor,
|
|
1452
|
+
primaryRgb,
|
|
1453
|
+
onSuggest: handleSuggestAction
|
|
1454
|
+
}
|
|
1455
|
+
) : null,
|
|
1151
1456
|
message.sendFailed && lastFailedSend && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1152
1457
|
"button",
|
|
1153
1458
|
{
|
|
@@ -2022,5 +2327,5 @@ function getDeviceType() {
|
|
|
2022
2327
|
exports.ChatWidget = ChatWidget;
|
|
2023
2328
|
exports.DesignRenderer = DesignRenderer;
|
|
2024
2329
|
exports.EngageWidget = EngageWidget;
|
|
2025
|
-
//# sourceMappingURL=chunk-
|
|
2026
|
-
//# sourceMappingURL=chunk-
|
|
2330
|
+
//# sourceMappingURL=chunk-FPU2QPO4.js.map
|
|
2331
|
+
//# sourceMappingURL=chunk-FPU2QPO4.js.map
|