@shaimaababiker/embed 0.1.3
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/index.d.ts +22 -0
- package/dist/index.js +862 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type AssistlyChatProps = {
|
|
4
|
+
chatbotId: number;
|
|
5
|
+
/** Origin of the Assistly deployment that hosts the chat API, e.g. https://chatbot-xi-rose-68.vercel.app */
|
|
6
|
+
origin: string;
|
|
7
|
+
/** Optional brand color for accents */
|
|
8
|
+
primaryColor?: string;
|
|
9
|
+
/** Fires when the chat panel has mounted and is ready to receive input */
|
|
10
|
+
onReady?: () => void;
|
|
11
|
+
/** Fires if the chat fails to mount */
|
|
12
|
+
onError?: (err: Error) => void;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Embeddable Assistly chat panel. Renders the full chat UI (intake form +
|
|
16
|
+
* active chat) inside whatever container the customer places it in. Talks
|
|
17
|
+
* directly to the Assistly API at `${origin}/api/...` — no iframe, no
|
|
18
|
+
* cross-origin cookie issues.
|
|
19
|
+
*/
|
|
20
|
+
declare function AssistlyChat({ chatbotId, origin, primaryColor, onReady, onError, }: AssistlyChatProps): react_jsx_runtime.JSX.Element | null;
|
|
21
|
+
|
|
22
|
+
export { AssistlyChat, type AssistlyChatProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __objRest = (source, exclude) => {
|
|
21
|
+
var target = {};
|
|
22
|
+
for (var prop in source)
|
|
23
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
+
target[prop] = source[prop];
|
|
25
|
+
if (source != null && __getOwnPropSymbols)
|
|
26
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/widget.tsx
|
|
34
|
+
import { useEffect as useEffect3, useMemo, useState as useState3 } from "react";
|
|
35
|
+
import { ApolloProvider } from "@apollo/client";
|
|
36
|
+
|
|
37
|
+
// src/ApolloProvider.tsx
|
|
38
|
+
import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
|
|
39
|
+
var defaultOptions = {
|
|
40
|
+
watchQuery: { fetchPolicy: "no-cache", errorPolicy: "all" },
|
|
41
|
+
query: { fetchPolicy: "no-cache", errorPolicy: "all" },
|
|
42
|
+
mutate: { fetchPolicy: "no-cache", errorPolicy: "all" }
|
|
43
|
+
};
|
|
44
|
+
function createApolloClient(origin) {
|
|
45
|
+
const baseUrl = origin.replace(/\/$/, "");
|
|
46
|
+
return new ApolloClient({
|
|
47
|
+
link: createHttpLink({ uri: `${baseUrl}/api/graphql` }),
|
|
48
|
+
cache: new InMemoryCache(),
|
|
49
|
+
defaultOptions
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/ChatbotClient.tsx
|
|
54
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
55
|
+
import { useQuery } from "@apollo/client";
|
|
56
|
+
import { z } from "zod";
|
|
57
|
+
import { useForm } from "react-hook-form";
|
|
58
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
59
|
+
|
|
60
|
+
// src/lib/startNewChat.ts
|
|
61
|
+
async function startNewChat(origin, guestName, guestEmail, chatbotId) {
|
|
62
|
+
var _a;
|
|
63
|
+
const baseUrl = origin.replace(/\/$/, "");
|
|
64
|
+
const response = await fetch(`${baseUrl}/api/start-chat`, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: { "Content-Type": "application/json" },
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
name: guestName,
|
|
69
|
+
email: guestEmail,
|
|
70
|
+
chatbot_id: chatbotId
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
const payload = await response.json().catch(() => null);
|
|
75
|
+
const message = (_a = payload == null ? void 0 : payload.error) != null ? _a : `Failed to start chat (${response.status})`;
|
|
76
|
+
throw new Error(message);
|
|
77
|
+
}
|
|
78
|
+
const data = await response.json();
|
|
79
|
+
if (typeof (data == null ? void 0 : data.chat_session_id) !== "number") {
|
|
80
|
+
throw new Error("Server returned an invalid response");
|
|
81
|
+
}
|
|
82
|
+
return data.chat_session_id;
|
|
83
|
+
}
|
|
84
|
+
var startNewChat_default = startNewChat;
|
|
85
|
+
|
|
86
|
+
// src/graphql/queries.ts
|
|
87
|
+
import { gql } from "@apollo/client";
|
|
88
|
+
var GET_MESSEGES_BY_CHAT_SESSION_ID = gql`
|
|
89
|
+
query GetMessagesByChatSessionId($chat_session_id: Int!) {
|
|
90
|
+
chat_sessions(id: $chat_session_id) {
|
|
91
|
+
created_at
|
|
92
|
+
id
|
|
93
|
+
messages {
|
|
94
|
+
id
|
|
95
|
+
sender
|
|
96
|
+
content
|
|
97
|
+
created_at
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
// src/ui/Avatar.tsx
|
|
104
|
+
import { rings } from "@dicebear/collection";
|
|
105
|
+
import { createAvatar } from "@dicebear/core";
|
|
106
|
+
import { jsx } from "react/jsx-runtime";
|
|
107
|
+
function utf8ToBase64(input) {
|
|
108
|
+
const bytes = new TextEncoder().encode(input);
|
|
109
|
+
let binary = "";
|
|
110
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
111
|
+
binary += String.fromCharCode(bytes[i]);
|
|
112
|
+
}
|
|
113
|
+
return btoa(binary);
|
|
114
|
+
}
|
|
115
|
+
function Avatar({ seed, className }) {
|
|
116
|
+
const avatar = createAvatar(rings, { seed });
|
|
117
|
+
const svg = avatar.toString();
|
|
118
|
+
const dataUrl = `data:image/svg+xml;base64,${utf8ToBase64(svg)}`;
|
|
119
|
+
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("img", { src: dataUrl, alt: "Avatar", width: 80, height: 80, className }) });
|
|
120
|
+
}
|
|
121
|
+
var Avatar_default = Avatar;
|
|
122
|
+
|
|
123
|
+
// src/ui/Messages.tsx
|
|
124
|
+
import ReactMarkdown from "react-markdown";
|
|
125
|
+
import remarkGfm from "remark-gfm";
|
|
126
|
+
import { UserCircle } from "lucide-react";
|
|
127
|
+
import { useEffect, useRef, useState } from "react";
|
|
128
|
+
|
|
129
|
+
// src/ui/ChatMotion.tsx
|
|
130
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
131
|
+
function FourDotWave({ className = "" }) {
|
|
132
|
+
const dots = [
|
|
133
|
+
{ color: "#8a2a2a", delay: "0s" },
|
|
134
|
+
// oxblood
|
|
135
|
+
{ color: "#c89a5b", delay: "0.12s" },
|
|
136
|
+
// brass
|
|
137
|
+
{ color: "#5a6b3b", delay: "0.24s" },
|
|
138
|
+
// moss
|
|
139
|
+
{ color: "#2c5b5e", delay: "0.36s" }
|
|
140
|
+
// teal
|
|
141
|
+
];
|
|
142
|
+
return /* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1.5 ${className}`, "aria-label": "Loading", children: [
|
|
143
|
+
dots.map((d, i) => /* @__PURE__ */ jsx2(
|
|
144
|
+
"span",
|
|
145
|
+
{
|
|
146
|
+
className: "dot-wave",
|
|
147
|
+
style: { backgroundColor: d.color, animationDelay: d.delay }
|
|
148
|
+
},
|
|
149
|
+
i
|
|
150
|
+
)),
|
|
151
|
+
/* @__PURE__ */ jsx2("style", { children: `
|
|
152
|
+
.dot-wave {
|
|
153
|
+
display: inline-block;
|
|
154
|
+
width: 7px;
|
|
155
|
+
height: 7px;
|
|
156
|
+
border-radius: 9999px;
|
|
157
|
+
will-change: transform;
|
|
158
|
+
animation: dotBounce 1.1s cubic-bezier(0.45, 0, 0.55, 1) infinite;
|
|
159
|
+
}
|
|
160
|
+
@keyframes dotBounce {
|
|
161
|
+
0%, 60%, 100% { transform: translate3d(0, 0, 0); }
|
|
162
|
+
30% { transform: translate3d(0, -6px, 0); }
|
|
163
|
+
}
|
|
164
|
+
` })
|
|
165
|
+
] });
|
|
166
|
+
}
|
|
167
|
+
function AiBubble({
|
|
168
|
+
children,
|
|
169
|
+
className = "",
|
|
170
|
+
springIn = true,
|
|
171
|
+
style,
|
|
172
|
+
typing = false
|
|
173
|
+
}) {
|
|
174
|
+
return /* @__PURE__ */ jsxs(
|
|
175
|
+
"div",
|
|
176
|
+
{
|
|
177
|
+
className: `ai-bubble ${springIn ? "ai-bubble-in" : ""} ${typing ? "ai-typing" : ""} ${className}`,
|
|
178
|
+
style,
|
|
179
|
+
children: [
|
|
180
|
+
children,
|
|
181
|
+
/* @__PURE__ */ jsx2("style", { children: `
|
|
182
|
+
.ai-bubble {
|
|
183
|
+
position: relative;
|
|
184
|
+
transform-origin: bottom left;
|
|
185
|
+
color: #1e1e1e;
|
|
186
|
+
background: linear-gradient(
|
|
187
|
+
135deg,
|
|
188
|
+
#eef2ff 0%,
|
|
189
|
+
#f5f3ff 35%,
|
|
190
|
+
#ecfeff 70%,
|
|
191
|
+
#eef2ff 100%
|
|
192
|
+
);
|
|
193
|
+
background-size: 250% 250%;
|
|
194
|
+
will-change: transform, background-position, box-shadow;
|
|
195
|
+
transition: box-shadow 220ms ease, background 220ms ease;
|
|
196
|
+
}
|
|
197
|
+
.ai-bubble-in {
|
|
198
|
+
animation: aiSpring 620ms cubic-bezier(0.175, 0.885, 0.32, 1.275) both;
|
|
199
|
+
}
|
|
200
|
+
/* Typing state: vibrant purple gradient with glow */
|
|
201
|
+
.ai-typing {
|
|
202
|
+
background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 35%, #8b5cf6 70%, #7c3aed 100%);
|
|
203
|
+
background-size: 200% 200%;
|
|
204
|
+
animation: aiTypingShift 4.5s ease-in-out infinite;
|
|
205
|
+
box-shadow: 0 12px 36px rgba(124,58,237,0.20), 0 1px 0 rgba(255,255,255,0.05) inset;
|
|
206
|
+
color: #fff;
|
|
207
|
+
border-color: rgba(255,255,255,0.08);
|
|
208
|
+
}
|
|
209
|
+
@keyframes aiSpring {
|
|
210
|
+
0% { transform: scale(0.4) translate3d(0, 12px, 0); opacity: 0; }
|
|
211
|
+
60% { transform: scale(1.04) translate3d(0, -2px, 0); opacity: 1; }
|
|
212
|
+
100% { transform: scale(1) translate3d(0, 0, 0); opacity: 1; }
|
|
213
|
+
}
|
|
214
|
+
@keyframes aiTypingShift {
|
|
215
|
+
0% { background-position: 0% 50%; filter: drop-shadow(0 0 0 rgba(124,58,237,0)); }
|
|
216
|
+
50% { background-position: 100% 50%; filter: drop-shadow(0 18px 48px rgba(124,58,237,0.18)); }
|
|
217
|
+
100% { background-position: 0% 50%; filter: drop-shadow(0 0 0 rgba(124,58,237,0)); }
|
|
218
|
+
}
|
|
219
|
+
` })
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
function UserBubble({
|
|
225
|
+
children,
|
|
226
|
+
className = "",
|
|
227
|
+
springIn = true,
|
|
228
|
+
style
|
|
229
|
+
}) {
|
|
230
|
+
return /* @__PURE__ */ jsxs(
|
|
231
|
+
"div",
|
|
232
|
+
{
|
|
233
|
+
className: `user-bubble ${springIn ? "user-bubble-in" : ""} ${className}`,
|
|
234
|
+
style,
|
|
235
|
+
children: [
|
|
236
|
+
children,
|
|
237
|
+
/* @__PURE__ */ jsx2("style", { children: `
|
|
238
|
+
.user-bubble {
|
|
239
|
+
position: relative;
|
|
240
|
+
transform-origin: bottom right;
|
|
241
|
+
background: #111113;
|
|
242
|
+
color: #ffffff;
|
|
243
|
+
will-change: transform;
|
|
244
|
+
}
|
|
245
|
+
.user-bubble-in {
|
|
246
|
+
animation: userSpring 520ms cubic-bezier(0.175, 0.885, 0.32, 1.275) both;
|
|
247
|
+
}
|
|
248
|
+
@keyframes userSpring {
|
|
249
|
+
0% { transform: scale(0.4) translate3d(0, 12px, 0); opacity: 0; }
|
|
250
|
+
60% { transform: scale(1.04) translate3d(0, -2px, 0); opacity: 1; }
|
|
251
|
+
100% { transform: scale(1) translate3d(0, 0, 0); opacity: 1; }
|
|
252
|
+
}
|
|
253
|
+
` })
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/ui/Messages.tsx
|
|
260
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
261
|
+
function formatTime(iso) {
|
|
262
|
+
try {
|
|
263
|
+
const d = new Date(iso);
|
|
264
|
+
return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
265
|
+
} catch (e) {
|
|
266
|
+
return "";
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function TypewriterMarkdown({ text, isFresh, components, onType }) {
|
|
270
|
+
const [displayedText, setDisplayedText] = useState("");
|
|
271
|
+
const [index, setIndex] = useState(0);
|
|
272
|
+
useEffect(() => {
|
|
273
|
+
setDisplayedText("");
|
|
274
|
+
setIndex(0);
|
|
275
|
+
}, [text]);
|
|
276
|
+
useEffect(() => {
|
|
277
|
+
if (isFresh && text && index < text.length) {
|
|
278
|
+
const timeout = setTimeout(() => {
|
|
279
|
+
setDisplayedText((prev) => prev + text[index]);
|
|
280
|
+
setIndex((prev) => prev + 1);
|
|
281
|
+
if (onType) onType();
|
|
282
|
+
}, 15);
|
|
283
|
+
return () => clearTimeout(timeout);
|
|
284
|
+
} else if (!isFresh) {
|
|
285
|
+
setDisplayedText(text || "");
|
|
286
|
+
}
|
|
287
|
+
}, [index, text, isFresh]);
|
|
288
|
+
return /* @__PURE__ */ jsx3(
|
|
289
|
+
ReactMarkdown,
|
|
290
|
+
{
|
|
291
|
+
remarkPlugins: [remarkGfm],
|
|
292
|
+
components,
|
|
293
|
+
children: isFresh ? displayedText : text
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
function Messages({ messages, chatbotName, logoUrl, isReviewPage = false }) {
|
|
298
|
+
const ref = useRef(null);
|
|
299
|
+
const [hoveredId, setHoveredId] = useState(null);
|
|
300
|
+
const scrollToBottom = (smooth = true) => {
|
|
301
|
+
if (ref.current) {
|
|
302
|
+
ref.current.scrollIntoView({ behavior: smooth ? "smooth" : "auto", block: "end" });
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
scrollToBottom();
|
|
307
|
+
}, [messages]);
|
|
308
|
+
const [isClient, setIsClient] = useState(false);
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
setIsClient(true);
|
|
311
|
+
}, []);
|
|
312
|
+
const markdownComponents = {
|
|
313
|
+
ul: (_a) => {
|
|
314
|
+
var _b = _a, { node } = _b, props = __objRest(_b, ["node"]);
|
|
315
|
+
return /* @__PURE__ */ jsx3("ul", __spreadValues({ className: "list-disc list-inside ml-5 mb-3" }, props));
|
|
316
|
+
},
|
|
317
|
+
ol: (_c) => {
|
|
318
|
+
var _d = _c, { node } = _d, props = __objRest(_d, ["node"]);
|
|
319
|
+
return /* @__PURE__ */ jsx3("ol", __spreadValues({ className: "list-decimal list-inside ml-5 mb-3" }, props));
|
|
320
|
+
},
|
|
321
|
+
h1: (_e) => {
|
|
322
|
+
var _f = _e, { node } = _f, props = __objRest(_f, ["node"]);
|
|
323
|
+
return /* @__PURE__ */ jsx3("h1", __spreadValues({ className: "text-2xl font-bold mb-3 font-display" }, props));
|
|
324
|
+
},
|
|
325
|
+
h2: (_g) => {
|
|
326
|
+
var _h = _g, { node } = _h, props = __objRest(_h, ["node"]);
|
|
327
|
+
return /* @__PURE__ */ jsx3("h2", __spreadValues({ className: "text-xl font-bold mb-3 font-display" }, props));
|
|
328
|
+
},
|
|
329
|
+
h3: (_i) => {
|
|
330
|
+
var _j = _i, { node } = _j, props = __objRest(_j, ["node"]);
|
|
331
|
+
return /* @__PURE__ */ jsx3("h3", __spreadValues({ className: "text-lg font-bold mb-3 font-display" }, props));
|
|
332
|
+
},
|
|
333
|
+
table: (_k) => {
|
|
334
|
+
var _l = _k, { node } = _l, props = __objRest(_l, ["node"]);
|
|
335
|
+
return /* @__PURE__ */ jsx3("table", __spreadValues({ className: "table-auto mb-3 w-full border-separate border-2 rounded-sm border-spacing-4", style: { borderColor: "rgba(26,20,15,0.18)" } }, props));
|
|
336
|
+
},
|
|
337
|
+
th: (_m) => {
|
|
338
|
+
var _n = _m, { node } = _n, props = __objRest(_n, ["node"]);
|
|
339
|
+
return /* @__PURE__ */ jsx3("th", __spreadValues({ className: "text-left underline" }, props));
|
|
340
|
+
},
|
|
341
|
+
p: (_o) => {
|
|
342
|
+
var _p = _o, { node } = _p, props = __objRest(_p, ["node"]);
|
|
343
|
+
return /* @__PURE__ */ jsx3("p", __spreadValues({ className: "whitespace-pre-wrap mb-3 last:mb-0 leading-relaxed" }, props));
|
|
344
|
+
},
|
|
345
|
+
a: (_q) => {
|
|
346
|
+
var _r = _q, { node } = _r, props = __objRest(_r, ["node"]);
|
|
347
|
+
return /* @__PURE__ */ jsx3("a", __spreadValues({ className: "hover:underline font-semibold", style: { color: "#c45d4f" }, rel: "noopener noreferrer", target: "_blank" }, props));
|
|
348
|
+
},
|
|
349
|
+
code: (_s) => {
|
|
350
|
+
var _t = _s, { node } = _t, props = __objRest(_t, ["node"]);
|
|
351
|
+
return /* @__PURE__ */ jsx3(
|
|
352
|
+
"code",
|
|
353
|
+
__spreadValues({
|
|
354
|
+
className: "px-1.5 py-0.5 rounded font-mono text-[13px]",
|
|
355
|
+
style: { background: "rgba(26,20,15,0.10)" }
|
|
356
|
+
}, props)
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col space-y-7 py-8 px-5 md:px-10 bg-transparent rounded-lg scroll-smooth ", children: [
|
|
361
|
+
messages.map((message, index) => {
|
|
362
|
+
const isSender = message.sender !== "user";
|
|
363
|
+
const isThinking = message.content === "" || message.content === "Thinking...";
|
|
364
|
+
const isFresh = index === messages.length - 1;
|
|
365
|
+
const showMeta = hoveredId === message.id || isReviewPage;
|
|
366
|
+
return /* @__PURE__ */ jsxs2(
|
|
367
|
+
"div",
|
|
368
|
+
{
|
|
369
|
+
onMouseEnter: () => setHoveredId(message.id),
|
|
370
|
+
onMouseLeave: () => setHoveredId(null),
|
|
371
|
+
className: `chat ${isSender ? "chat-start" : "chat-end"} relative group overflow-hidden`,
|
|
372
|
+
children: [
|
|
373
|
+
isReviewPage && /* @__PURE__ */ jsxs2("p", { className: "absolute -bottom-5 text-xs text-gray-300", children: [
|
|
374
|
+
"sent ",
|
|
375
|
+
new Date(message.created_at).toLocaleString()
|
|
376
|
+
] }),
|
|
377
|
+
isFresh && /* @__PURE__ */ jsx3(
|
|
378
|
+
"span",
|
|
379
|
+
{
|
|
380
|
+
"aria-hidden": true,
|
|
381
|
+
className: "ring-out pointer-events-none absolute -inset-2 rounded-[26px]"
|
|
382
|
+
}
|
|
383
|
+
),
|
|
384
|
+
/* @__PURE__ */ jsx3("div", { className: `chat-image avatar w-10 ${!isSender && "mr-4"}`, children: logoUrl ? /* @__PURE__ */ jsx3(
|
|
385
|
+
"img",
|
|
386
|
+
{
|
|
387
|
+
src: logoUrl,
|
|
388
|
+
alt: chatbotName || "Chatbot logo",
|
|
389
|
+
width: 48,
|
|
390
|
+
height: 48,
|
|
391
|
+
className: "h-12 w-12 rounded-full border object-cover",
|
|
392
|
+
style: { borderColor: "var(--hairline)" }
|
|
393
|
+
}
|
|
394
|
+
) : isSender ? /* @__PURE__ */ jsx3(
|
|
395
|
+
"div",
|
|
396
|
+
{
|
|
397
|
+
className: "border h-12 w-12 rounded-full bg-white overflow-hidden",
|
|
398
|
+
style: { borderColor: "var(--hairline)" },
|
|
399
|
+
children: /* @__PURE__ */ jsx3(Avatar_default, { seed: chatbotName, className: "h-12 w-12" })
|
|
400
|
+
}
|
|
401
|
+
) : /* @__PURE__ */ jsx3("div", { className: "h-12 w-12 rounded-full grid place-items-center", style: { background: "rgba(244,234,215,0.06)" }, children: /* @__PURE__ */ jsx3(UserCircle, { className: "text-[var(--brass-2)]" }) }) }),
|
|
402
|
+
isSender ? /* @__PURE__ */ jsx3(
|
|
403
|
+
AiBubble,
|
|
404
|
+
{
|
|
405
|
+
springIn: isFresh,
|
|
406
|
+
typing: isThinking,
|
|
407
|
+
className: "chat-bubble relative rounded-2xl px-4 py-3 max-w-[80%] font-body text-[15px] leading-relaxed",
|
|
408
|
+
style: isThinking ? {} : { border: "1px solid rgba(224,176,112,0.18)" },
|
|
409
|
+
children: isThinking ? /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 py-1", style: { color: "#1e1e1e" }, children: [
|
|
410
|
+
/* @__PURE__ */ jsx3(FourDotWave, {}),
|
|
411
|
+
/* @__PURE__ */ jsx3("span", { className: "font-mono text-[10px] uppercase tracking-[0.25em] opacity-70", children: "Thinking..." })
|
|
412
|
+
] }) : /* @__PURE__ */ jsx3(
|
|
413
|
+
TypewriterMarkdown,
|
|
414
|
+
{
|
|
415
|
+
text: message.content,
|
|
416
|
+
isFresh,
|
|
417
|
+
components: markdownComponents,
|
|
418
|
+
onType: () => scrollToBottom(false)
|
|
419
|
+
}
|
|
420
|
+
)
|
|
421
|
+
}
|
|
422
|
+
) : /* @__PURE__ */ jsx3(
|
|
423
|
+
UserBubble,
|
|
424
|
+
{
|
|
425
|
+
springIn: isFresh,
|
|
426
|
+
className: "chat-bubble relative rounded-2xl px-4 py-3 max-w-[80%] font-body text-[15px] leading-relaxed",
|
|
427
|
+
style: {
|
|
428
|
+
background: "#e9e3e3ff",
|
|
429
|
+
color: "#1e1e1e",
|
|
430
|
+
border: "1px solid rgba(231, 228, 224, 0.22)"
|
|
431
|
+
},
|
|
432
|
+
children: /* @__PURE__ */ jsx3(
|
|
433
|
+
ReactMarkdown,
|
|
434
|
+
{
|
|
435
|
+
remarkPlugins: [remarkGfm],
|
|
436
|
+
components: markdownComponents,
|
|
437
|
+
children: message.content
|
|
438
|
+
}
|
|
439
|
+
)
|
|
440
|
+
}
|
|
441
|
+
),
|
|
442
|
+
/* @__PURE__ */ jsxs2(
|
|
443
|
+
"div",
|
|
444
|
+
{
|
|
445
|
+
className: `mt-1.5 px-1 flex items-center gap-2 font-mono text-[10px] uppercase tracking-[0.2em] transition-opacity duration-200 ${showMeta ? "opacity-100" : "opacity-0"}`,
|
|
446
|
+
style: { color: "var(--muted-2)" },
|
|
447
|
+
children: [
|
|
448
|
+
/* @__PURE__ */ jsx3("span", { children: isSender ? chatbotName || "assistant" : "you" }),
|
|
449
|
+
/* @__PURE__ */ jsx3("span", { className: "w-1 h-1 rounded-full", style: { background: "var(--muted-2)" } }),
|
|
450
|
+
/* @__PURE__ */ jsx3("span", { children: formatTime(message.created_at) })
|
|
451
|
+
]
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
]
|
|
455
|
+
},
|
|
456
|
+
message.id || index
|
|
457
|
+
);
|
|
458
|
+
}),
|
|
459
|
+
/* @__PURE__ */ jsx3("div", { ref })
|
|
460
|
+
] });
|
|
461
|
+
}
|
|
462
|
+
var Messages_default = Messages;
|
|
463
|
+
|
|
464
|
+
// src/ui/form.tsx
|
|
465
|
+
import * as React2 from "react";
|
|
466
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
467
|
+
import {
|
|
468
|
+
Controller,
|
|
469
|
+
FormProvider,
|
|
470
|
+
useFormContext,
|
|
471
|
+
useFormState
|
|
472
|
+
} from "react-hook-form";
|
|
473
|
+
|
|
474
|
+
// src/lib/utils.ts
|
|
475
|
+
import { clsx } from "clsx";
|
|
476
|
+
import { twMerge } from "tailwind-merge";
|
|
477
|
+
function cn(...inputs) {
|
|
478
|
+
return twMerge(clsx(inputs));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/ui/label.tsx
|
|
482
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
483
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
484
|
+
|
|
485
|
+
// src/ui/form.tsx
|
|
486
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
487
|
+
var Form = FormProvider;
|
|
488
|
+
var FormFieldContext = React2.createContext(
|
|
489
|
+
{}
|
|
490
|
+
);
|
|
491
|
+
var FormField = (_a) => {
|
|
492
|
+
var props = __objRest(_a, []);
|
|
493
|
+
return /* @__PURE__ */ jsx5(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsx5(Controller, __spreadValues({}, props)) });
|
|
494
|
+
};
|
|
495
|
+
var useFormField = () => {
|
|
496
|
+
const fieldContext = React2.useContext(FormFieldContext);
|
|
497
|
+
const itemContext = React2.useContext(FormItemContext);
|
|
498
|
+
const { getFieldState } = useFormContext();
|
|
499
|
+
const formState = useFormState({ name: fieldContext.name });
|
|
500
|
+
const fieldState = getFieldState(fieldContext.name, formState);
|
|
501
|
+
if (!fieldContext) {
|
|
502
|
+
throw new Error("useFormField should be used within <FormField>");
|
|
503
|
+
}
|
|
504
|
+
const { id } = itemContext;
|
|
505
|
+
return __spreadValues({
|
|
506
|
+
id,
|
|
507
|
+
name: fieldContext.name,
|
|
508
|
+
formItemId: `${id}-form-item`,
|
|
509
|
+
formDescriptionId: `${id}-form-item-description`,
|
|
510
|
+
formMessageId: `${id}-form-item-message`
|
|
511
|
+
}, fieldState);
|
|
512
|
+
};
|
|
513
|
+
var FormItemContext = React2.createContext(
|
|
514
|
+
{}
|
|
515
|
+
);
|
|
516
|
+
function FormItem(_a) {
|
|
517
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
518
|
+
const id = React2.useId();
|
|
519
|
+
return /* @__PURE__ */ jsx5(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsx5(
|
|
520
|
+
"div",
|
|
521
|
+
__spreadValues({
|
|
522
|
+
"data-slot": "form-item",
|
|
523
|
+
className: cn("grid gap-2", className)
|
|
524
|
+
}, props)
|
|
525
|
+
) });
|
|
526
|
+
}
|
|
527
|
+
function FormControl(_a) {
|
|
528
|
+
var props = __objRest(_a, []);
|
|
529
|
+
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
|
530
|
+
return /* @__PURE__ */ jsx5(
|
|
531
|
+
Slot,
|
|
532
|
+
__spreadValues({
|
|
533
|
+
"data-slot": "form-control",
|
|
534
|
+
id: formItemId,
|
|
535
|
+
"aria-describedby": !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`,
|
|
536
|
+
"aria-invalid": !!error
|
|
537
|
+
}, props)
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/ui/input.tsx
|
|
542
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
543
|
+
function Input(_a) {
|
|
544
|
+
var _b = _a, { className, type } = _b, props = __objRest(_b, ["className", "type"]);
|
|
545
|
+
return /* @__PURE__ */ jsx6(
|
|
546
|
+
"input",
|
|
547
|
+
__spreadValues({
|
|
548
|
+
type,
|
|
549
|
+
"data-slot": "input",
|
|
550
|
+
className: cn(
|
|
551
|
+
"border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
552
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
553
|
+
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
554
|
+
className
|
|
555
|
+
)
|
|
556
|
+
}, props)
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/ui/button.tsx
|
|
561
|
+
import { Slot as Slot2 } from "@radix-ui/react-slot";
|
|
562
|
+
import { cva } from "class-variance-authority";
|
|
563
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
564
|
+
var buttonVariants = cva(
|
|
565
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
566
|
+
{
|
|
567
|
+
variants: {
|
|
568
|
+
variant: {
|
|
569
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
570
|
+
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
|
|
571
|
+
outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
572
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
573
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
574
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
575
|
+
},
|
|
576
|
+
size: {
|
|
577
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
578
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
579
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-3",
|
|
580
|
+
icon: "size-9"
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
defaultVariants: {
|
|
584
|
+
variant: "default",
|
|
585
|
+
size: "default"
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
function Button(_a) {
|
|
590
|
+
var _b = _a, {
|
|
591
|
+
className,
|
|
592
|
+
variant,
|
|
593
|
+
size,
|
|
594
|
+
asChild = false
|
|
595
|
+
} = _b, props = __objRest(_b, [
|
|
596
|
+
"className",
|
|
597
|
+
"variant",
|
|
598
|
+
"size",
|
|
599
|
+
"asChild"
|
|
600
|
+
]);
|
|
601
|
+
const Comp = asChild ? Slot2 : "button";
|
|
602
|
+
return /* @__PURE__ */ jsx7(
|
|
603
|
+
Comp,
|
|
604
|
+
__spreadValues({
|
|
605
|
+
"data-slot": "button",
|
|
606
|
+
className: cn(buttonVariants({ variant, size, className }))
|
|
607
|
+
}, props)
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// src/ChatbotClient.tsx
|
|
612
|
+
import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
613
|
+
var formSchema = z.object({
|
|
614
|
+
message: z.string().min(3, "Your Message is too short!")
|
|
615
|
+
});
|
|
616
|
+
function ChatbotClient({ id, chatbotName, origin }) {
|
|
617
|
+
const [name, setName] = useState2("");
|
|
618
|
+
const [email, setEmail] = useState2("");
|
|
619
|
+
const [onboardingStep, setOnboardingStep] = useState2(1);
|
|
620
|
+
const [chatId, setChatId] = useState2(0);
|
|
621
|
+
const [loading, setLoading] = useState2(false);
|
|
622
|
+
const [message, setMessage] = useState2([
|
|
623
|
+
{
|
|
624
|
+
id: -1,
|
|
625
|
+
content: `Hi there! I'm ${chatbotName}. I'd love to help you out, but first, could you tell me your name?`,
|
|
626
|
+
sender: "ai",
|
|
627
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
628
|
+
chat_session_id: 0
|
|
629
|
+
}
|
|
630
|
+
]);
|
|
631
|
+
const form = useForm({
|
|
632
|
+
resolver: zodResolver(formSchema),
|
|
633
|
+
defaultValues: {
|
|
634
|
+
message: ""
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
const { data } = useQuery(
|
|
638
|
+
GET_MESSEGES_BY_CHAT_SESSION_ID,
|
|
639
|
+
{
|
|
640
|
+
variables: { chat_session_id: chatId },
|
|
641
|
+
skip: !chatId
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
useEffect2(() => {
|
|
645
|
+
if (data && onboardingStep === 3) {
|
|
646
|
+
const chatSession = data.chat_sessions;
|
|
647
|
+
const dbMessages = chatSession.messages || [];
|
|
648
|
+
setMessage((prev) => {
|
|
649
|
+
const existingIds = new Set(prev.map((m) => m.id));
|
|
650
|
+
const newMessages = dbMessages.filter((m) => !existingIds.has(m.id));
|
|
651
|
+
return [...prev, ...newMessages];
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
}, [data, onboardingStep]);
|
|
655
|
+
async function onsubmit(values) {
|
|
656
|
+
const { message: formMessage } = values;
|
|
657
|
+
form.reset();
|
|
658
|
+
if (onboardingStep === 1) {
|
|
659
|
+
if (!formMessage.trim()) return;
|
|
660
|
+
const userMsg = {
|
|
661
|
+
id: Date.now(),
|
|
662
|
+
content: formMessage,
|
|
663
|
+
chat_session_id: 0,
|
|
664
|
+
sender: "user",
|
|
665
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
666
|
+
};
|
|
667
|
+
const aiMsg = {
|
|
668
|
+
id: Date.now() + 1,
|
|
669
|
+
content: `It's a pleasure to meet you, ${formMessage}! Just one more thing\u2014what's your email address so we can stay connected?`,
|
|
670
|
+
chat_session_id: 0,
|
|
671
|
+
sender: "ai",
|
|
672
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
673
|
+
};
|
|
674
|
+
setName(formMessage);
|
|
675
|
+
setOnboardingStep(2);
|
|
676
|
+
setMessage((prev) => [...prev, userMsg, aiMsg]);
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
if (onboardingStep === 2) {
|
|
680
|
+
if (!formMessage.trim()) return;
|
|
681
|
+
const isValidEmail = (email2) => {
|
|
682
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email2);
|
|
683
|
+
};
|
|
684
|
+
if (!isValidEmail(formMessage.trim())) {
|
|
685
|
+
setMessage((prev) => [
|
|
686
|
+
...prev,
|
|
687
|
+
{
|
|
688
|
+
id: Date.now() + 1,
|
|
689
|
+
content: "Please enter a valid email address so we can continue.",
|
|
690
|
+
chat_session_id: 0,
|
|
691
|
+
sender: "ai",
|
|
692
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
693
|
+
}
|
|
694
|
+
]);
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const userMsg = {
|
|
698
|
+
id: Date.now(),
|
|
699
|
+
content: formMessage,
|
|
700
|
+
chat_session_id: 0,
|
|
701
|
+
sender: "user",
|
|
702
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
703
|
+
};
|
|
704
|
+
setMessage((prev) => [...prev, userMsg]);
|
|
705
|
+
setLoading(true);
|
|
706
|
+
try {
|
|
707
|
+
const finalEmail = formMessage;
|
|
708
|
+
setEmail(finalEmail);
|
|
709
|
+
const newChatId = await startNewChat_default(origin, name, finalEmail, Number(id));
|
|
710
|
+
setChatId(newChatId);
|
|
711
|
+
setOnboardingStep(3);
|
|
712
|
+
} catch (error) {
|
|
713
|
+
console.error("Error starting chat:", error);
|
|
714
|
+
setMessage((prev) => [...prev, {
|
|
715
|
+
id: Date.now() + 1,
|
|
716
|
+
content: "Sorry, I had trouble setting up your session. Could you please try entering your email again?",
|
|
717
|
+
chat_session_id: 0,
|
|
718
|
+
sender: "ai",
|
|
719
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
720
|
+
}]);
|
|
721
|
+
} finally {
|
|
722
|
+
setLoading(false);
|
|
723
|
+
}
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
if (!chatId) return;
|
|
727
|
+
const userMessage = {
|
|
728
|
+
id: Date.now(),
|
|
729
|
+
content: formMessage,
|
|
730
|
+
chat_session_id: chatId,
|
|
731
|
+
sender: "user",
|
|
732
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
733
|
+
};
|
|
734
|
+
const loadingMessage = {
|
|
735
|
+
id: Date.now() + 1,
|
|
736
|
+
content: "Thinking...",
|
|
737
|
+
chat_session_id: chatId,
|
|
738
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
739
|
+
sender: "ai"
|
|
740
|
+
};
|
|
741
|
+
setMessage((prevMessages) => [...prevMessages, userMessage, loadingMessage]);
|
|
742
|
+
try {
|
|
743
|
+
const baseUrl = origin.replace(/\/$/, "");
|
|
744
|
+
const response = await fetch(`${baseUrl}/api/send-message`, {
|
|
745
|
+
method: "POST",
|
|
746
|
+
headers: { "Content-Type": "application/json" },
|
|
747
|
+
body: JSON.stringify({
|
|
748
|
+
name,
|
|
749
|
+
chat_session_id: chatId,
|
|
750
|
+
chabot_id: Number(id),
|
|
751
|
+
content: formMessage,
|
|
752
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
753
|
+
})
|
|
754
|
+
});
|
|
755
|
+
const result = await response.json();
|
|
756
|
+
setMessage(
|
|
757
|
+
(prevMessages) => prevMessages.map(
|
|
758
|
+
(msg) => msg.id === loadingMessage.id ? __spreadProps(__spreadValues({}, msg), { content: result.content, id: result.id }) : msg
|
|
759
|
+
)
|
|
760
|
+
);
|
|
761
|
+
} catch (error) {
|
|
762
|
+
console.error("Error Sending Message:", error);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return /* @__PURE__ */ jsx8("div", { className: "fixed inset-0 flex flex-col bg-gray-50 text-slate-900 md:p-6 md:pb-0", children: /* @__PURE__ */ jsxs3("div", { className: "flex flex-col w-full max-w-3xl mx-auto flex-1 overflow-hidden md:rounded-t-2xl border border-gray-200 bg-white relative", children: [
|
|
766
|
+
/* @__PURE__ */ jsxs3("div", { className: "border-b border-gray-100 bg-white py-3 px-4 md:py-6 md:px-8 flex items-center justify-between shrink-0", children: [
|
|
767
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center space-x-3 md:space-x-4 min-w-0", children: [
|
|
768
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative shrink-0", children: [
|
|
769
|
+
/* @__PURE__ */ jsx8(
|
|
770
|
+
Avatar_default,
|
|
771
|
+
{
|
|
772
|
+
seed: chatbotName != null ? chatbotName : "default-seed",
|
|
773
|
+
className: "w-9 h-9 md:w-10 md:h-10 bg-gray-100 rounded-full border border-gray-200"
|
|
774
|
+
}
|
|
775
|
+
),
|
|
776
|
+
/* @__PURE__ */ jsx8("div", { className: "absolute bottom-0 right-0 w-2.5 h-2.5 bg-emerald-500 border-2 border-white rounded-full" })
|
|
777
|
+
] }),
|
|
778
|
+
/* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
|
|
779
|
+
/* @__PURE__ */ jsx8("h1", { className: "truncate text-sm md:text-base font-semibold text-slate-900", children: chatbotName || "Assistant" }),
|
|
780
|
+
/* @__PURE__ */ jsxs3("p", { className: "text-xs text-slate-400 flex items-center gap-1.5", children: [
|
|
781
|
+
/* @__PURE__ */ jsx8("span", { className: "w-2 h-2 bg-emerald-500 rounded-full" }),
|
|
782
|
+
"Online"
|
|
783
|
+
] })
|
|
784
|
+
] })
|
|
785
|
+
] }),
|
|
786
|
+
/* @__PURE__ */ jsx8("div", { className: "hidden sm:block text-[11px] font-medium text-slate-400 bg-gray-50 px-2 py-1 rounded-md border border-gray-100", children: "Secure Session" })
|
|
787
|
+
] }),
|
|
788
|
+
/* @__PURE__ */ jsx8("div", { className: "flex-1 relative bg-white pb-32 md:pb-36 overflow-y-auto", children: /* @__PURE__ */ jsx8(Messages_default, { messages: message, chatbotName: chatbotName || "" }) }),
|
|
789
|
+
/* @__PURE__ */ jsx8("div", { className: "absolute bottom-0 w-full bg-white p-3 md:p-6 border-t border-gray-100", children: /* @__PURE__ */ jsx8(Form, __spreadProps(__spreadValues({}, form), { children: /* @__PURE__ */ jsxs3(
|
|
790
|
+
"form",
|
|
791
|
+
{
|
|
792
|
+
className: "relative flex items-center gap-2 md:gap-3 max-w-4xl mx-auto",
|
|
793
|
+
onSubmit: form.handleSubmit(onsubmit),
|
|
794
|
+
children: [
|
|
795
|
+
/* @__PURE__ */ jsx8("div", { className: "relative flex-1", children: /* @__PURE__ */ jsx8(
|
|
796
|
+
FormField,
|
|
797
|
+
{
|
|
798
|
+
control: form.control,
|
|
799
|
+
name: "message",
|
|
800
|
+
render: ({ field }) => /* @__PURE__ */ jsx8(FormItem, { className: "flex-1", children: /* @__PURE__ */ jsx8(FormControl, { children: /* @__PURE__ */ jsx8(
|
|
801
|
+
Input,
|
|
802
|
+
__spreadProps(__spreadValues({}, field), {
|
|
803
|
+
placeholder: onboardingStep === 1 ? "Your name..." : onboardingStep === 2 ? "Your email..." : "Type a message...",
|
|
804
|
+
className: "p-3 md:p-5 rounded-xl bg-gray-50 border-gray-200 text-slate-900 placeholder:text-slate-400 focus:ring-2 focus:ring-slate-200 focus:border-slate-300 transition-all"
|
|
805
|
+
})
|
|
806
|
+
) }) })
|
|
807
|
+
}
|
|
808
|
+
) }),
|
|
809
|
+
/* @__PURE__ */ jsx8(
|
|
810
|
+
Button,
|
|
811
|
+
{
|
|
812
|
+
type: "submit",
|
|
813
|
+
disabled: form.formState.isSubmitting || !form.formState.isValid || loading,
|
|
814
|
+
className: "h-12 w-12 md:h-16 md:w-16 rounded-xl bg-slate-900 text-white hover:bg-slate-800 transition-all shrink-0",
|
|
815
|
+
children: loading ? /* @__PURE__ */ jsx8("div", { className: "h-6 w-6 md:h-8 md:w-8 border-2 border-white border-t-transparent rounded-full animate-spin" }) : /* @__PURE__ */ jsx8("p", { className: "cursor-pointer text-sm md:text-base", children: "Send" })
|
|
816
|
+
}
|
|
817
|
+
)
|
|
818
|
+
]
|
|
819
|
+
}
|
|
820
|
+
) })) })
|
|
821
|
+
] }) });
|
|
822
|
+
}
|
|
823
|
+
var ChatbotClient_default = ChatbotClient;
|
|
824
|
+
|
|
825
|
+
// src/widget.tsx
|
|
826
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
827
|
+
function AssistlyChat({
|
|
828
|
+
chatbotId,
|
|
829
|
+
origin,
|
|
830
|
+
primaryColor,
|
|
831
|
+
onReady,
|
|
832
|
+
onError
|
|
833
|
+
}) {
|
|
834
|
+
const client = useMemo(() => createApolloClient(origin), [origin]);
|
|
835
|
+
const [mounted, setMounted] = useState3(false);
|
|
836
|
+
useEffect3(() => {
|
|
837
|
+
setMounted(true);
|
|
838
|
+
onReady == null ? void 0 : onReady();
|
|
839
|
+
try {
|
|
840
|
+
} catch (err) {
|
|
841
|
+
onError == null ? void 0 : onError(err);
|
|
842
|
+
}
|
|
843
|
+
}, [onReady, onError]);
|
|
844
|
+
if (!mounted) return null;
|
|
845
|
+
return /* @__PURE__ */ jsx9(ApolloProvider, { client, children: /* @__PURE__ */ jsx9(
|
|
846
|
+
"div",
|
|
847
|
+
{
|
|
848
|
+
style: __spreadValues({
|
|
849
|
+
width: "100%",
|
|
850
|
+
height: "100%",
|
|
851
|
+
minHeight: 400,
|
|
852
|
+
display: "flex",
|
|
853
|
+
flexDirection: "column"
|
|
854
|
+
}, primaryColor ? { "--assistly-primary": primaryColor } : null),
|
|
855
|
+
children: /* @__PURE__ */ jsx9(ChatbotClient_default, { id: String(chatbotId), chatbotName: "Assistant", origin })
|
|
856
|
+
}
|
|
857
|
+
) });
|
|
858
|
+
}
|
|
859
|
+
export {
|
|
860
|
+
AssistlyChat
|
|
861
|
+
};
|
|
862
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/widget.tsx","../src/ApolloProvider.tsx","../src/ChatbotClient.tsx","../src/lib/startNewChat.ts","../src/graphql/queries.ts","../src/ui/Avatar.tsx","../src/ui/Messages.tsx","../src/ui/ChatMotion.tsx","../src/ui/form.tsx","../src/lib/utils.ts","../src/ui/label.tsx","../src/ui/input.tsx","../src/ui/button.tsx"],"sourcesContent":["'use client';\n\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { ApolloProvider } from '@apollo/client';\nimport { createApolloClient } from './ApolloProvider';\nimport ChatbotClient from './ChatbotClient';\n\nexport type AssistlyChatProps = {\n chatbotId: number;\n /** Origin of the Assistly deployment that hosts the chat API, e.g. https://chatbot-xi-rose-68.vercel.app */\n origin: string;\n /** Optional brand color for accents */\n primaryColor?: string;\n /** Fires when the chat panel has mounted and is ready to receive input */\n onReady?: () => void;\n /** Fires if the chat fails to mount */\n onError?: (err: Error) => void;\n};\n\n/**\n * Embeddable Assistly chat panel. Renders the full chat UI (intake form +\n * active chat) inside whatever container the customer places it in. Talks\n * directly to the Assistly API at `${origin}/api/...` — no iframe, no\n * cross-origin cookie issues.\n */\nexport default function AssistlyChat({\n chatbotId,\n origin,\n primaryColor,\n onReady,\n onError,\n}: AssistlyChatProps) {\n const client = useMemo(() => createApolloClient(origin), [origin]);\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n onReady?.();\n try {\n // Reserved for future telemetry.\n } catch (err) {\n onError?.(err as Error);\n }\n }, [onReady, onError]);\n\n if (!mounted) return null;\n\n return (\n <ApolloProvider client={client}>\n <div\n style={{\n width: '100%',\n height: '100%',\n minHeight: 400,\n display: 'flex',\n flexDirection: 'column',\n // CSS custom property so consumers can theme accents without prop-drilling.\n ...(primaryColor ? ({ '--assistly-primary': primaryColor } as React.CSSProperties) : null),\n }}\n >\n <ChatbotClient id={String(chatbotId)} chatbotName=\"Assistant\" origin={origin} />\n </div>\n </ApolloProvider>\n );\n}\n","'use client';\n\nimport { ApolloClient, InMemoryCache, createHttpLink, type DefaultOptions } from '@apollo/client';\n\nconst defaultOptions: DefaultOptions = {\n watchQuery: { fetchPolicy: 'no-cache', errorPolicy: 'all' },\n query: { fetchPolicy: 'no-cache', errorPolicy: 'all' },\n mutate: { fetchPolicy: 'no-cache', errorPolicy: 'all' },\n};\n\nexport function createApolloClient(origin: string): ApolloClient<unknown> {\n const baseUrl = origin.replace(/\\/$/, '');\n return new ApolloClient({\n link: createHttpLink({ uri: `${baseUrl}/api/graphql` }),\n cache: new InMemoryCache(),\n defaultOptions,\n });\n}\n","'use client';\n\nimport { useEffect, useState } from \"react\";\nimport { useQuery } from \"@apollo/client\";\nimport { z } from \"zod\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from '@hookform/resolvers/zod';\n\nimport {\n Message,\n MessagesbyChatSessionIdResponse,\n MessagesbyChatSessionIdResponseVariables,\n} from \"./types\";\nimport startNewChat from \"./lib/startNewChat\";\nimport { GET_MESSEGES_BY_CHAT_SESSION_ID } from \"./graphql/queries\";\nimport Avatar from \"./ui/Avatar\";\nimport Messages from \"./ui/Messages\";\nimport { FormControl, FormField, FormItem, Form, } from \"./ui/form\";\nimport { Input } from \"./ui/input\";\nimport { Button } from \"./ui/button\";\n\ntype ChatbotClientProps = {\n id: string;\n chatbotName: string;\n origin: string;\n};\n\nconst formSchema = z.object({\n message: z.string().min(3, 'Your Message is too short!'),\n});\n\nfunction ChatbotClient({ id, chatbotName, origin }: ChatbotClientProps) {\n const [name, setName] = useState('');\n const [email, setEmail] = useState('');\n const [onboardingStep, setOnboardingStep] = useState(1);\n const [chatId, setChatId] = useState(0);\n const [loading, setLoading] = useState(false);\n const [message, setMessage] = useState<Message[]>([\n {\n id: -1,\n content: `Hi there! I'm ${chatbotName}. I'd love to help you out, but first, could you tell me your name?`,\n sender: 'ai',\n created_at: new Date().toISOString(),\n chat_session_id: 0,\n }\n ]);\n\n const form = useForm<z.infer<typeof formSchema>>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n message: ''\n }\n });\n\n const { data } = useQuery<MessagesbyChatSessionIdResponse, MessagesbyChatSessionIdResponseVariables>(\n GET_MESSEGES_BY_CHAT_SESSION_ID,\n {\n variables: { chat_session_id: chatId },\n skip: !chatId\n }\n );\n\n useEffect(() => {\n if (data && onboardingStep === 3) {\n const chatSession = data.chat_sessions as any;\n const dbMessages = chatSession.messages || [];\n setMessage((prev) => {\n const existingIds = new Set(prev.map((m) => m.id));\n const newMessages = dbMessages.filter((m: Message) => !existingIds.has(m.id));\n return [...prev, ...newMessages];\n });\n }\n }, [data, onboardingStep]);\n\n async function onsubmit(values: z.infer<typeof formSchema>) {\n const { message: formMessage } = values;\n form.reset();\n\n if (onboardingStep === 1) {\n if (!formMessage.trim()) return;\n\n const userMsg: Message = {\n id: Date.now(),\n content: formMessage,\n chat_session_id: 0,\n sender: 'user',\n created_at: new Date().toISOString(),\n };\n\n const aiMsg: Message = {\n id: Date.now() + 1,\n content: `It's a pleasure to meet you, ${formMessage}! Just one more thing—what's your email address so we can stay connected?`,\n chat_session_id: 0,\n sender: 'ai',\n created_at: new Date().toISOString(),\n };\n\n setName(formMessage);\n setOnboardingStep(2);\n setMessage((prev) => [...prev, userMsg, aiMsg]);\n return;\n }\n\n if (onboardingStep === 2) {\n if (!formMessage.trim()) return;\n\n const isValidEmail = (email: string) => {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n };\n\n if (!isValidEmail(formMessage.trim())) {\n setMessage((prev) => [\n ...prev,\n {\n id: Date.now() + 1,\n content: \"Please enter a valid email address so we can continue.\",\n chat_session_id: 0,\n sender: 'ai',\n created_at: new Date().toISOString(),\n },\n ]);\n return;\n }\n const userMsg: Message = {\n id: Date.now(),\n content: formMessage,\n chat_session_id: 0,\n sender: 'user',\n created_at: new Date().toISOString(),\n };\n\n setMessage((prev) => [...prev, userMsg]);\n setLoading(true);\n\n try {\n const finalEmail = formMessage;\n setEmail(finalEmail);\n const newChatId = await startNewChat(origin, name, finalEmail, Number(id));\n setChatId(newChatId);\n setOnboardingStep(3);\n\n } catch (error) {\n console.error('Error starting chat:', error);\n setMessage((prev) => [...prev, {\n id: Date.now() + 1,\n content: \"Sorry, I had trouble setting up your session. Could you please try entering your email again?\",\n chat_session_id: 0,\n sender: 'ai',\n created_at: new Date().toISOString(),\n }]);\n } finally {\n setLoading(false);\n }\n return;\n }\n\n if (!chatId) return;\n\n const userMessage: Message = {\n id: Date.now(),\n content: formMessage,\n chat_session_id: chatId,\n sender: 'user',\n created_at: new Date().toISOString(),\n };\n\n const loadingMessage: Message = {\n id: Date.now() + 1,\n content: 'Thinking...',\n chat_session_id: chatId,\n created_at: new Date().toISOString(),\n sender: 'ai',\n };\n setMessage((prevMessages) => [...prevMessages, userMessage, loadingMessage]);\n\n try {\n const baseUrl = origin.replace(/\\/$/, '');\n const response = await fetch(`${baseUrl}/api/send-message`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: name,\n chat_session_id: chatId,\n chabot_id: Number(id),\n content: formMessage,\n created_at: new Date().toISOString(),\n })\n });\n const result = await response.json();\n setMessage((prevMessages) =>\n prevMessages.map((msg) =>\n msg.id === loadingMessage.id ? { ...msg, content: result.content, id: result.id } : msg\n )\n );\n } catch (error) {\n console.error('Error Sending Message:', error);\n }\n }\n\n return (\n <div className=\"fixed inset-0 flex flex-col bg-gray-50 text-slate-900 md:p-6 md:pb-0\">\n <div className=\"flex flex-col w-full max-w-3xl mx-auto flex-1 overflow-hidden md:rounded-t-2xl border border-gray-200 bg-white relative\">\n <div className=\"border-b border-gray-100 bg-white py-3 px-4 md:py-6 md:px-8 flex items-center justify-between shrink-0\">\n <div className=\"flex items-center space-x-3 md:space-x-4 min-w-0\">\n <div className=\"relative shrink-0\">\n <Avatar\n seed={chatbotName ?? 'default-seed'}\n className=\"w-9 h-9 md:w-10 md:h-10 bg-gray-100 rounded-full border border-gray-200\"\n />\n <div className=\"absolute bottom-0 right-0 w-2.5 h-2.5 bg-emerald-500 border-2 border-white rounded-full\"></div>\n </div>\n <div className=\"min-w-0\">\n <h1 className=\"truncate text-sm md:text-base font-semibold text-slate-900\">\n {chatbotName || 'Assistant'}\n </h1>\n <p className=\"text-xs text-slate-400 flex items-center gap-1.5\">\n <span className=\"w-2 h-2 bg-emerald-500 rounded-full\"></span>\n Online\n </p>\n </div>\n </div>\n <div className=\"hidden sm:block text-[11px] font-medium text-slate-400 bg-gray-50 px-2 py-1 rounded-md border border-gray-100\">\n Secure Session\n </div>\n </div>\n\n <div className=\"flex-1 relative bg-white pb-32 md:pb-36 overflow-y-auto\">\n <Messages messages={message} chatbotName={chatbotName || ''} />\n </div>\n\n <div className=\"absolute bottom-0 w-full bg-white p-3 md:p-6 border-t border-gray-100\">\n <Form {...form}>\n <form\n className=\"relative flex items-center gap-2 md:gap-3 max-w-4xl mx-auto\"\n onSubmit={form.handleSubmit(onsubmit)}\n >\n <div className=\"relative flex-1\">\n <FormField\n control={form.control}\n name=\"message\"\n render={({ field }) => (\n <FormItem className=\"flex-1\">\n <FormControl>\n <Input\n {...field}\n placeholder={onboardingStep === 1 ? \"Your name...\" : onboardingStep === 2 ? \"Your email...\" : \"Type a message...\"}\n className=\"p-3 md:p-5 rounded-xl bg-gray-50 border-gray-200 text-slate-900 placeholder:text-slate-400 focus:ring-2 focus:ring-slate-200 focus:border-slate-300 transition-all\"\n />\n </FormControl>\n </FormItem>\n )}\n />\n </div>\n <Button\n type=\"submit\"\n disabled={form.formState.isSubmitting || !form.formState.isValid || loading}\n className=\"h-12 w-12 md:h-16 md:w-16 rounded-xl bg-slate-900 text-white hover:bg-slate-800 transition-all shrink-0\"\n >\n {loading ? (\n <div className=\"h-6 w-6 md:h-8 md:w-8 border-2 border-white border-t-transparent rounded-full animate-spin\" />\n ) : (\n <p className=\"cursor-pointer text-sm md:text-base\">Send</p>)}\n </Button>\n </form>\n </Form>\n </div>\n </div>\n </div>\n );\n}\n\nexport default ChatbotClient;\n","async function startNewChat(\n origin: string,\n guestName: string,\n guestEmail: string,\n chatbotId: number,\n): Promise<number> {\n const baseUrl = origin.replace(/\\/$/, '');\n const response = await fetch(`${baseUrl}/api/start-chat`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: guestName,\n email: guestEmail,\n chatbot_id: chatbotId,\n }),\n });\n\n if (!response.ok) {\n const payload = await response.json().catch(() => null);\n const message =\n payload?.error ?? `Failed to start chat (${response.status})`;\n throw new Error(message);\n }\n\n const data = await response.json();\n if (typeof data?.chat_session_id !== 'number') {\n throw new Error('Server returned an invalid response');\n }\n return data.chat_session_id;\n}\n\nexport default startNewChat;\n","import { gql } from \"@apollo/client\";\n\nexport const GET_MESSEGES_BY_CHAT_SESSION_ID = gql`\n query GetMessagesByChatSessionId($chat_session_id: Int!) {\n chat_sessions(id: $chat_session_id) {\n created_at\n id\n messages {\n id\n sender\n content\n created_at\n }\n }\n }\n`;\n","import React from 'react'\nimport { rings } from '@dicebear/collection'\nimport { createAvatar } from '@dicebear/core'\n\n/**\n * Browser-safe base64 encoder. Avoids `Buffer` because the embed is shipped\n * to non-Node consumers where `Buffer` is not defined.\n */\nfunction utf8ToBase64(input: string): string {\n const bytes = new TextEncoder().encode(input);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nfunction Avatar({ seed, className }: { seed: string; className?: string }) {\n const avatar = createAvatar(rings, { seed });\n const svg = avatar.toString();\n const dataUrl = `data:image/svg+xml;base64,${utf8ToBase64(svg)}`;\n\n return (\n <div>\n <img src={dataUrl} alt=\"Avatar\" width={80} height={80} className={className} />\n </div>\n );\n}\n\nexport default Avatar;\n","'use client'\n\nimport { Message } from \"../types\"\nimport ReactMarkdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport Avatar from \"./Avatar\";\nimport { UserCircle } from \"lucide-react\";\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { AiBubble, UserBubble, FourDotWave } from \"./ChatMotion\";\n\n/* -------------------------------------------------------------------------- */\n/* Small helpers */\n/* -------------------------------------------------------------------------- */\n\nfunction formatTime(iso: string) {\n try {\n const d = new Date(iso);\n return d.toLocaleTimeString([], { hour: \"2-digit\", minute: \"2-digit\" });\n } catch {\n return \"\";\n }\n}\n\nfunction TypewriterMarkdown({ text, isFresh, components, onType }: { text: string, isFresh: boolean, components: any, onType?: () => void }) {\n const [displayedText, setDisplayedText] = useState(\"\");\n const [index, setIndex] = useState(0);\n\n useEffect(() => {\n setDisplayedText(\"\");\n setIndex(0);\n }, [text]);\n\n useEffect(() => {\n if (isFresh && text && index < text.length) {\n const timeout = setTimeout(() => {\n setDisplayedText((prev) => prev + text[index]);\n setIndex((prev) => prev + 1);\n if (onType) onType();\n }, 15);\n return () => clearTimeout(timeout);\n } else if (!isFresh) {\n setDisplayedText(text || \"\");\n }\n }, [index, text, isFresh]);\n\n return (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={components}\n >\n {isFresh ? displayedText : text}\n </ReactMarkdown>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------------- */\n\nfunction Messages({ messages, chatbotName, logoUrl, isReviewPage = false }: { messages: Message[], chatbotName: string, logoUrl?: string, isReviewPage?: boolean }) {\n const ref = useRef<HTMLDivElement>(null);\n const [hoveredId, setHoveredId] = useState<number | string | null>(null);\n\n const scrollToBottom = (smooth = true) => {\n if (ref.current) {\n ref.current.scrollIntoView({ behavior: smooth ? \"smooth\" : \"auto\", block: \"end\" });\n }\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n const [isClient, setIsClient] = useState(false);\n\n useEffect(() => {\n setIsClient(true);\n }, []);\n\n const markdownComponents = {\n ul: ({ node, ...props }: any) => (<ul className=\"list-disc list-inside ml-5 mb-3\" {...props} />),\n ol: ({ node, ...props }: any) => (<ol className=\"list-decimal list-inside ml-5 mb-3\" {...props} />),\n h1: ({ node, ...props }: any) => (<h1 className=\"text-2xl font-bold mb-3 font-display\" {...props} />),\n h2: ({ node, ...props }: any) => (<h2 className=\"text-xl font-bold mb-3 font-display\" {...props} />),\n h3: ({ node, ...props }: any) => (<h3 className=\"text-lg font-bold mb-3 font-display\" {...props} />),\n table: ({ node, ...props }: any) => (<table className=\"table-auto mb-3 w-full border-separate border-2 rounded-sm border-spacing-4\" style={{ borderColor: \"rgba(26,20,15,0.18)\" }} {...props} />),\n th: ({ node, ...props }: any) => (<th className=\"text-left underline\" {...props} />),\n p: ({ node, ...props }: any) => (<p className=\"whitespace-pre-wrap mb-3 last:mb-0 leading-relaxed\" {...props} />),\n a: ({ node, ...props }: any) => (<a className=\"hover:underline font-semibold\" style={{ color: \"#c45d4f\" }} rel=\"noopener noreferrer\" target=\"_blank\" {...props} />),\n code: ({ node, ...props }: any) => (\n <code\n className=\"px-1.5 py-0.5 rounded font-mono text-[13px]\"\n style={{ background: \"rgba(26,20,15,0.10)\" }}\n {...props}\n />\n ),\n };\n\n return (\n <div className=\"flex flex-1 flex-col space-y-7 py-8 px-5 md:px-10 bg-transparent rounded-lg scroll-smooth \">\n {messages.map((message, index) => {\n const isSender = message.sender !== \"user\";\n const isThinking = message.content === \"\" || message.content === \"Thinking...\";\n const isFresh = index === messages.length - 1;\n const showMeta = hoveredId === message.id || isReviewPage;\n\n return (\n <div\n key={message.id || index}\n onMouseEnter={() => setHoveredId(message.id)}\n onMouseLeave={() => setHoveredId(null)}\n className={`chat ${isSender ? \"chat-start\" : \"chat-end\"} relative group overflow-hidden`}\n >\n {isReviewPage && (\n <p className=\"absolute -bottom-5 text-xs text-gray-300\">\n sent {new Date(message.created_at).toLocaleString()}\n </p>\n )}\n\n {isFresh && (\n <span\n aria-hidden\n className=\"ring-out pointer-events-none absolute -inset-2 rounded-[26px]\"\n />\n )}\n\n <div className={`chat-image avatar w-10 ${!isSender && \"mr-4\"}`}>\n {logoUrl ? (\n <img\n src={logoUrl}\n alt={chatbotName || \"Chatbot logo\"}\n width={48}\n height={48}\n className=\"h-12 w-12 rounded-full border object-cover\"\n style={{ borderColor: \"var(--hairline)\" }}\n />\n ) : isSender ? (\n <div\n className=\"border h-12 w-12 rounded-full bg-white overflow-hidden\"\n style={{ borderColor: \"var(--hairline)\" }}\n >\n <Avatar seed={chatbotName} className=\"h-12 w-12\" />\n </div>\n ) : (\n <div className=\"h-12 w-12 rounded-full grid place-items-center\" style={{ background: \"rgba(244,234,215,0.06)\" }}>\n <UserCircle className=\"text-[var(--brass-2)]\" />\n </div>\n )}\n </div>\n\n {isSender ? (\n <AiBubble\n springIn={isFresh}\n typing={isThinking}\n className=\"chat-bubble relative rounded-2xl px-4 py-3 max-w-[80%] font-body text-[15px] leading-relaxed\"\n style={isThinking ? {} : { border: \"1px solid rgba(224,176,112,0.18)\" }}\n >\n {isThinking ? (\n <div className=\"flex items-center gap-3 py-1\" style={{ color: \"#1e1e1e\" }}>\n <FourDotWave />\n <span className=\"font-mono text-[10px] uppercase tracking-[0.25em] opacity-70\">\n Thinking...\n </span>\n </div>\n ) : (\n <TypewriterMarkdown\n text={message.content}\n isFresh={isFresh}\n components={markdownComponents}\n onType={() => scrollToBottom(false)}\n />\n )}\n </AiBubble>\n ) : (\n <UserBubble\n springIn={isFresh}\n className=\"chat-bubble relative rounded-2xl px-4 py-3 max-w-[80%] font-body text-[15px] leading-relaxed\"\n style={{\n background: \"#e9e3e3ff\",\n color: \"#1e1e1e\",\n border: \"1px solid rgba(231, 228, 224, 0.22)\",\n }}\n >\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={markdownComponents}\n >\n {message.content}\n </ReactMarkdown>\n </UserBubble>\n )}\n\n <div\n className={`mt-1.5 px-1 flex items-center gap-2 font-mono text-[10px] uppercase tracking-[0.2em] transition-opacity duration-200 ${showMeta ? \"opacity-100\" : \"opacity-0\"\n }`}\n style={{ color: \"var(--muted-2)\" }}\n >\n <span>{isSender ? chatbotName || \"assistant\" : \"you\"}</span>\n <span className=\"w-1 h-1 rounded-full\" style={{ background: \"var(--muted-2)\" }} />\n <span>{formatTime(message.created_at)}</span>\n </div>\n </div>\n );\n })}\n <div ref={ref} />\n </div>\n );\n}\n\nexport default Messages;\n","'use client';\n\n/**\n * Re-usable Google-inspired motion primitives for the chat surface.\n *\n * 1. <FluidAura /> — full-bleed Gemini-style gradient mesh + SVG turbulence.\n * 2. <FourDotWave /> — 4 colored dots bouncing in a wave.\n * 3. <AiBubble /> — springy entrance + slow-shifting gradient background.\n *\n * All animations are pure CSS; no external libraries.\n */\n\nimport React from \"react\";\n\n/* -------------------------------------------------------------------------- */\n/* 1. Fluid Aura */\n/* -------------------------------------------------------------------------- */\n\nexport function FluidAura({ className = \"\" }: { className?: string }) {\n return (\n <div\n className={`pointer-events-none absolute inset-0 overflow-hidden ${className}`}\n aria-hidden\n >\n {/* The moving gradient mesh. Two layers offset for parallax effect. */}\n <div className=\"absolute inset-0 [filter:url(#auraDisplace)]\">\n <div className=\"aura-mesh aura-mesh-a\" />\n <div className=\"aura-mesh aura-mesh-b\" />\n </div>\n\n {/* SVG turbulence filter — gives the gradient the liquid ripple effect */}\n <svg className=\"absolute h-0 w-0\" aria-hidden focusable=\"false\">\n <defs>\n <filter id=\"auraDisplace\">\n <feTurbulence\n type=\"fractalNoise\"\n baseFrequency=\"0.012 0.018\"\n numOctaves=\"2\"\n seed=\"7\"\n >\n <animate\n attributeName=\"baseFrequency\"\n dur=\"22s\"\n values=\"0.012 0.018; 0.022 0.028; 0.012 0.018\"\n repeatCount=\"indefinite\"\n />\n </feTurbulence>\n <feDisplacementMap in=\"SourceGraphic\" scale=\"120\" />\n </filter>\n </defs>\n </svg>\n\n {/* Local styles — kept here so the component is self-contained. */}\n <style>{`\n .aura-mesh {\n position: absolute;\n inset: -25%;\n background: radial-gradient(\n circle at 20% 30%,\n rgba(66, 133, 244, 0.55) 0%,\n transparent 45%\n ),\n radial-gradient(\n circle at 80% 20%,\n rgba(155, 81, 224, 0.5) 0%,\n transparent 45%\n ),\n radial-gradient(\n circle at 70% 80%,\n rgba(234, 67, 53, 0.45) 0%,\n transparent 45%\n ),\n radial-gradient(\n circle at 25% 85%,\n rgba(251, 188, 5, 0.45) 0%,\n transparent 45%\n );\n will-change: transform;\n }\n .aura-mesh-a {\n animation: auraDrift1 18s ease-in-out infinite alternate;\n }\n .aura-mesh-b {\n animation: auraDrift2 24s ease-in-out infinite alternate;\n mix-blend-mode: screen;\n opacity: 0.7;\n }\n @keyframes auraDrift1 {\n from { transform: translate3d(-4%, -3%, 0) scale(1.05); }\n to { transform: translate3d(6%, 4%, 0) scale(1.15); }\n }\n @keyframes auraDrift2 {\n from { transform: translate3d(5%, 3%, 0) scale(1.10); }\n to { transform: translate3d(-5%, -4%, 0) scale(1.20); }\n }\n `}</style>\n </div>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* 2. Four-Dot Voice Wave */\n/* -------------------------------------------------------------------------- */\n\nexport function FourDotWave({ className = \"\" }: { className?: string }) {\n const dots = [\n { color: \"#8a2a2a\", delay: \"0s\" }, // oxblood\n { color: \"#c89a5b\", delay: \"0.12s\" }, // brass\n { color: \"#5a6b3b\", delay: \"0.24s\" }, // moss\n { color: \"#2c5b5e\", delay: \"0.36s\" }, // teal\n ];\n return (\n <span className={`inline-flex items-center gap-1.5 ${className}`} aria-label=\"Loading\">\n {dots.map((d, i) => (\n <span\n key={i}\n className=\"dot-wave\"\n style={{ backgroundColor: d.color, animationDelay: d.delay }}\n />\n ))}\n <style>{`\n .dot-wave {\n display: inline-block;\n width: 7px;\n height: 7px;\n border-radius: 9999px;\n will-change: transform;\n animation: dotBounce 1.1s cubic-bezier(0.45, 0, 0.55, 1) infinite;\n }\n @keyframes dotBounce {\n 0%, 60%, 100% { transform: translate3d(0, 0, 0); }\n 30% { transform: translate3d(0, -6px, 0); }\n }\n `}</style>\n </span>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* 3. Springy chat bubble with shifting gradient */\n/* -------------------------------------------------------------------------- */\n\nexport function AiBubble({\n children,\n className = \"\",\n springIn = true,\n style,\n typing = false,\n}: {\n children: React.ReactNode;\n className?: string;\n springIn?: boolean;\n style?: React.CSSProperties;\n typing?: boolean;\n}) {\n return (\n <div\n className={`ai-bubble ${springIn ? \"ai-bubble-in\" : \"\"} ${typing ? \"ai-typing\" : \"\"} ${className}`}\n style={style}\n >\n {children}\n <style>{`\n .ai-bubble {\n position: relative;\n transform-origin: bottom left;\n color: #1e1e1e;\n background: linear-gradient(\n 135deg,\n #eef2ff 0%,\n #f5f3ff 35%,\n #ecfeff 70%,\n #eef2ff 100%\n );\n background-size: 250% 250%;\n will-change: transform, background-position, box-shadow;\n transition: box-shadow 220ms ease, background 220ms ease;\n }\n .ai-bubble-in {\n animation: aiSpring 620ms cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n }\n /* Typing state: vibrant purple gradient with glow */\n .ai-typing {\n background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 35%, #8b5cf6 70%, #7c3aed 100%);\n background-size: 200% 200%;\n animation: aiTypingShift 4.5s ease-in-out infinite;\n box-shadow: 0 12px 36px rgba(124,58,237,0.20), 0 1px 0 rgba(255,255,255,0.05) inset;\n color: #fff;\n border-color: rgba(255,255,255,0.08);\n }\n @keyframes aiSpring {\n 0% { transform: scale(0.4) translate3d(0, 12px, 0); opacity: 0; }\n 60% { transform: scale(1.04) translate3d(0, -2px, 0); opacity: 1; }\n 100% { transform: scale(1) translate3d(0, 0, 0); opacity: 1; }\n }\n @keyframes aiTypingShift {\n 0% { background-position: 0% 50%; filter: drop-shadow(0 0 0 rgba(124,58,237,0)); }\n 50% { background-position: 100% 50%; filter: drop-shadow(0 18px 48px rgba(124,58,237,0.18)); }\n 100% { background-position: 0% 50%; filter: drop-shadow(0 0 0 rgba(124,58,237,0)); }\n }\n `}</style>\n </div>\n );\n}\n\nexport function UserBubble({\n children,\n className = \"\",\n springIn = true,\n style,\n}: {\n children: React.ReactNode;\n className?: string;\n springIn?: boolean;\n style?: React.CSSProperties;\n}) {\n return (\n <div\n className={`user-bubble ${springIn ? \"user-bubble-in\" : \"\"} ${className}`}\n style={style}\n >\n {children}\n <style>{`\n .user-bubble {\n position: relative;\n transform-origin: bottom right;\n background: #111113;\n color: #ffffff;\n will-change: transform;\n }\n .user-bubble-in {\n animation: userSpring 520ms cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n }\n @keyframes userSpring {\n 0% { transform: scale(0.4) translate3d(0, 12px, 0); opacity: 0; }\n 60% { transform: scale(1.04) translate3d(0, -2px, 0); opacity: 1; }\n 100% { transform: scale(1) translate3d(0, 0, 0); opacity: 1; }\n }\n `}</style>\n </div>\n );\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n useFormState,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"../lib/utils\"\nimport { Label } from \"./label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>(\n {} as FormFieldContextValue\n)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState } = useFormContext()\n const formState = useFormState({ name: fieldContext.name })\n const fieldState = getFieldState(fieldContext.name, formState)\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue>(\n {} as FormItemContextValue\n)\n\nfunction FormItem({ className, ...props }: React.ComponentProps<\"div\">) {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div\n data-slot=\"form-item\"\n className={cn(\"grid gap-2\", className)}\n {...props}\n />\n </FormItemContext.Provider>\n )\n}\n\nfunction FormLabel({\n className,\n ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n data-slot=\"form-label\"\n data-error={!!error}\n className={cn(\"data-[error=true]:text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n}\n\nfunction FormControl({ ...props }: React.ComponentProps<typeof Slot>) {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n data-slot=\"form-control\"\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n}\n\nfunction FormDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n data-slot=\"form-description\"\n id={formDescriptionId}\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nfunction FormMessage({ className, ...props }: React.ComponentProps<\"p\">) {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : props.children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n data-slot=\"form-message\"\n id={formMessageId}\n className={cn(\"text-destructive text-sm\", className)}\n {...props}\n >\n {body}\n </p>\n )\n}\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\n\nimport { cn } from \"../lib/utils\"\n\nfunction Label({\n className,\n ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Label }\n","import * as React from \"react\"\n\nimport { cn } from \"../lib/utils\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n return (\n <input\n type={type}\n data-slot=\"input\"\n className={cn(\n \"border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n \"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n \"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Input }\n","import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40\",\n outline:\n \"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-3\",\n icon: \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot : \"button\"\n\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n"],"mappings":"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","names":["useEffect","useState","useEffect","useState","jsx","jsx","jsx","jsxs","React","jsx","jsx","jsx","jsx","Slot","jsx","Slot","jsx","jsxs","useState","useEffect","email","jsx","useState","useEffect"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shaimaababiker/embed",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Embeddable Assistly chatbot as a React component. Drop-in replacement for the iframe-based embed.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"dev": "tsup --watch"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
24
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
25
|
+
"react-markdown": "^10.1.0",
|
|
26
|
+
"remark-gfm": "^4.0.1",
|
|
27
|
+
"lucide-react": "^0.570.0",
|
|
28
|
+
"@dicebear/collection": "^9.3.1",
|
|
29
|
+
"@dicebear/core": "^9.3.1",
|
|
30
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
31
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
32
|
+
"class-variance-authority": "^0.7.1",
|
|
33
|
+
"clsx": "^2.1.1",
|
|
34
|
+
"tailwind-merge": "^3.4.1",
|
|
35
|
+
"react-hook-form": "^7.71.1",
|
|
36
|
+
"@hookform/resolvers": "^5.2.2",
|
|
37
|
+
"zod": "^4.3.6"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@apollo/client": "^3.8.10"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/react": "^19.2.14",
|
|
44
|
+
"@types/react-dom": "^19.2.3",
|
|
45
|
+
"react": "^19.2.4",
|
|
46
|
+
"react-dom": "^19.2.4",
|
|
47
|
+
"tsup": "^8.3.5",
|
|
48
|
+
"typescript": "^5.9.3"
|
|
49
|
+
}
|
|
50
|
+
}
|