@diffsome/react 1.2.1 → 1.2.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.mts +181 -5
- package/dist/index.d.ts +181 -5
- package/dist/index.js +546 -0
- package/dist/index.mjs +540 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2322,9 +2322,548 @@ function useTypedEntity(slug) {
|
|
|
2322
2322
|
delete: (id) => client.entities.deleteRecord(slug, id)
|
|
2323
2323
|
}), [client, slug]);
|
|
2324
2324
|
}
|
|
2325
|
+
|
|
2326
|
+
// src/hooks/useChat.ts
|
|
2327
|
+
import { useState as useState20, useEffect as useEffect18, useCallback as useCallback21 } from "react";
|
|
2328
|
+
function useChat(options = {}) {
|
|
2329
|
+
const client = useClient();
|
|
2330
|
+
const [conversation, setConversation] = useState20(null);
|
|
2331
|
+
const [messages, setMessages] = useState20([]);
|
|
2332
|
+
const [loading, setLoading] = useState20(false);
|
|
2333
|
+
const [error, setError] = useState20(null);
|
|
2334
|
+
const [connected, setConnected] = useState20(false);
|
|
2335
|
+
const [agentTyping, setAgentTyping] = useState20(false);
|
|
2336
|
+
const [connection, setConnection] = useState20(null);
|
|
2337
|
+
const start = useCallback21(async (startOptions) => {
|
|
2338
|
+
setLoading(true);
|
|
2339
|
+
setError(null);
|
|
2340
|
+
try {
|
|
2341
|
+
const result = await client.chat.start({
|
|
2342
|
+
visitor_name: startOptions?.visitorName || options.visitorName,
|
|
2343
|
+
visitor_email: startOptions?.visitorEmail || options.visitorEmail,
|
|
2344
|
+
initial_message: startOptions?.greeting || options.greeting
|
|
2345
|
+
});
|
|
2346
|
+
const conv = await client.chat.get(result.conversation_id);
|
|
2347
|
+
setConversation(conv);
|
|
2348
|
+
const conn = client.chat.connect(result.conversation_id);
|
|
2349
|
+
setConnection(conn);
|
|
2350
|
+
setConnected(true);
|
|
2351
|
+
const existingMessages = await conn.getMessages();
|
|
2352
|
+
setMessages(existingMessages);
|
|
2353
|
+
const unsubMessage = conn.onMessage((msg) => {
|
|
2354
|
+
setMessages((prev) => {
|
|
2355
|
+
if (prev.some((m) => m.id === msg.id)) return prev;
|
|
2356
|
+
return [...prev, msg];
|
|
2357
|
+
});
|
|
2358
|
+
});
|
|
2359
|
+
const unsubTyping = conn.onTyping((senderType) => {
|
|
2360
|
+
if (senderType === "agent") {
|
|
2361
|
+
setAgentTyping(true);
|
|
2362
|
+
setTimeout(() => setAgentTyping(false), 3e3);
|
|
2363
|
+
}
|
|
2364
|
+
});
|
|
2365
|
+
conn.onStatusChange((status) => {
|
|
2366
|
+
setConversation((prev) => prev ? { ...prev, status } : null);
|
|
2367
|
+
});
|
|
2368
|
+
} catch (err) {
|
|
2369
|
+
setError(err instanceof Error ? err : new Error("Failed to start chat"));
|
|
2370
|
+
} finally {
|
|
2371
|
+
setLoading(false);
|
|
2372
|
+
}
|
|
2373
|
+
}, [client.chat, options.visitorName, options.visitorEmail, options.greeting]);
|
|
2374
|
+
const send = useCallback21(async (content) => {
|
|
2375
|
+
if (!connection) {
|
|
2376
|
+
throw new Error("Not connected to chat");
|
|
2377
|
+
}
|
|
2378
|
+
try {
|
|
2379
|
+
const message = await connection.send(content);
|
|
2380
|
+
} catch (err) {
|
|
2381
|
+
setError(err instanceof Error ? err : new Error("Failed to send message"));
|
|
2382
|
+
throw err;
|
|
2383
|
+
}
|
|
2384
|
+
}, [connection]);
|
|
2385
|
+
const sendTyping = useCallback21(() => {
|
|
2386
|
+
connection?.sendTyping();
|
|
2387
|
+
}, [connection]);
|
|
2388
|
+
const close = useCallback21(async () => {
|
|
2389
|
+
if (!connection) return;
|
|
2390
|
+
try {
|
|
2391
|
+
await connection.close();
|
|
2392
|
+
setConversation((prev) => prev ? { ...prev, status: "closed" } : null);
|
|
2393
|
+
} catch (err) {
|
|
2394
|
+
setError(err instanceof Error ? err : new Error("Failed to close chat"));
|
|
2395
|
+
}
|
|
2396
|
+
}, [connection]);
|
|
2397
|
+
const disconnect = useCallback21(() => {
|
|
2398
|
+
connection?.disconnect();
|
|
2399
|
+
setConnected(false);
|
|
2400
|
+
setConnection(null);
|
|
2401
|
+
}, [connection]);
|
|
2402
|
+
useEffect18(() => {
|
|
2403
|
+
if (options.autoConnect) {
|
|
2404
|
+
start();
|
|
2405
|
+
}
|
|
2406
|
+
return () => {
|
|
2407
|
+
connection?.disconnect();
|
|
2408
|
+
};
|
|
2409
|
+
}, [options.autoConnect]);
|
|
2410
|
+
return {
|
|
2411
|
+
conversation,
|
|
2412
|
+
messages,
|
|
2413
|
+
loading,
|
|
2414
|
+
error,
|
|
2415
|
+
connected,
|
|
2416
|
+
agentTyping,
|
|
2417
|
+
start,
|
|
2418
|
+
send,
|
|
2419
|
+
sendTyping,
|
|
2420
|
+
close,
|
|
2421
|
+
disconnect
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
// src/components/RichContent.tsx
|
|
2426
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
2427
|
+
var quillStyles = `
|
|
2428
|
+
/* Quill Alignment */
|
|
2429
|
+
.ql-align-center { text-align: center; }
|
|
2430
|
+
.ql-align-right { text-align: right; }
|
|
2431
|
+
.ql-align-justify { text-align: justify; }
|
|
2432
|
+
|
|
2433
|
+
/* Quill Font Sizes */
|
|
2434
|
+
.ql-size-small { font-size: 0.75em; }
|
|
2435
|
+
.ql-size-large { font-size: 1.5em; }
|
|
2436
|
+
.ql-size-huge { font-size: 2.5em; }
|
|
2437
|
+
|
|
2438
|
+
/* Quill Fonts */
|
|
2439
|
+
.ql-font-serif { font-family: Georgia, Times New Roman, serif; }
|
|
2440
|
+
.ql-font-monospace { font-family: Monaco, Courier New, monospace; }
|
|
2441
|
+
|
|
2442
|
+
/* Quill Indent */
|
|
2443
|
+
.ql-indent-1 { padding-left: 3em; }
|
|
2444
|
+
.ql-indent-2 { padding-left: 6em; }
|
|
2445
|
+
.ql-indent-3 { padding-left: 9em; }
|
|
2446
|
+
.ql-indent-4 { padding-left: 12em; }
|
|
2447
|
+
.ql-indent-5 { padding-left: 15em; }
|
|
2448
|
+
|
|
2449
|
+
/* Quill Video */
|
|
2450
|
+
.ql-video {
|
|
2451
|
+
display: block;
|
|
2452
|
+
max-width: 100%;
|
|
2453
|
+
margin: 1em 0;
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
/* Quill Code Block */
|
|
2457
|
+
.ql-code-block-container {
|
|
2458
|
+
background-color: #23241f;
|
|
2459
|
+
color: #f8f8f2;
|
|
2460
|
+
border-radius: 0.375rem;
|
|
2461
|
+
padding: 1em;
|
|
2462
|
+
margin: 1em 0;
|
|
2463
|
+
overflow-x: auto;
|
|
2464
|
+
}
|
|
2465
|
+
`;
|
|
2466
|
+
function RichContent({
|
|
2467
|
+
html,
|
|
2468
|
+
className = "",
|
|
2469
|
+
prose = true,
|
|
2470
|
+
proseVariant = "default",
|
|
2471
|
+
proseSize = "base",
|
|
2472
|
+
maxWidth = "none"
|
|
2473
|
+
}) {
|
|
2474
|
+
const proseClasses = prose ? [
|
|
2475
|
+
"prose",
|
|
2476
|
+
proseVariant !== "default" && `prose-${proseVariant}`,
|
|
2477
|
+
proseSize !== "base" && `prose-${proseSize}`,
|
|
2478
|
+
maxWidth !== "none" && `max-w-${maxWidth}`
|
|
2479
|
+
].filter(Boolean).join(" ") : "";
|
|
2480
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2481
|
+
/* @__PURE__ */ jsx2("style", { dangerouslySetInnerHTML: { __html: quillStyles } }),
|
|
2482
|
+
/* @__PURE__ */ jsx2(
|
|
2483
|
+
"div",
|
|
2484
|
+
{
|
|
2485
|
+
className: `rich-content ${proseClasses} ${className}`.trim(),
|
|
2486
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
2487
|
+
}
|
|
2488
|
+
)
|
|
2489
|
+
] });
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
// src/components/chat/ChatBubble.tsx
|
|
2493
|
+
import { useState as useState22, useEffect as useEffect21, useCallback as useCallback22 } from "react";
|
|
2494
|
+
|
|
2495
|
+
// src/components/chat/ChatWidget.tsx
|
|
2496
|
+
import { useRef as useRef2, useEffect as useEffect20 } from "react";
|
|
2497
|
+
|
|
2498
|
+
// src/components/chat/ChatMessage.tsx
|
|
2499
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2500
|
+
var ChatMessage = ({
|
|
2501
|
+
content,
|
|
2502
|
+
senderType,
|
|
2503
|
+
senderName,
|
|
2504
|
+
timestamp,
|
|
2505
|
+
isRead,
|
|
2506
|
+
className = ""
|
|
2507
|
+
}) => {
|
|
2508
|
+
const isVisitor = senderType === "visitor";
|
|
2509
|
+
const isSystem = senderType === "system";
|
|
2510
|
+
if (isSystem) {
|
|
2511
|
+
return /* @__PURE__ */ jsx3("div", { className: `diffsome-chat-message-system ${className}`, children: /* @__PURE__ */ jsx3("span", { children: content }) });
|
|
2512
|
+
}
|
|
2513
|
+
return /* @__PURE__ */ jsxs2(
|
|
2514
|
+
"div",
|
|
2515
|
+
{
|
|
2516
|
+
className: `diffsome-chat-message ${isVisitor ? "diffsome-chat-message-visitor" : "diffsome-chat-message-agent"} ${className}`,
|
|
2517
|
+
children: [
|
|
2518
|
+
!isVisitor && senderName && /* @__PURE__ */ jsx3("div", { className: "diffsome-chat-message-sender", children: senderName }),
|
|
2519
|
+
/* @__PURE__ */ jsxs2("div", { className: "diffsome-chat-message-bubble", children: [
|
|
2520
|
+
/* @__PURE__ */ jsx3("div", { className: "diffsome-chat-message-content", children: content }),
|
|
2521
|
+
timestamp && /* @__PURE__ */ jsxs2("div", { className: "diffsome-chat-message-time", children: [
|
|
2522
|
+
timestamp,
|
|
2523
|
+
isVisitor && isRead && /* @__PURE__ */ jsx3("span", { className: "diffsome-chat-message-read", children: " \u2713" })
|
|
2524
|
+
] })
|
|
2525
|
+
] })
|
|
2526
|
+
]
|
|
2527
|
+
}
|
|
2528
|
+
);
|
|
2529
|
+
};
|
|
2530
|
+
|
|
2531
|
+
// src/components/chat/ChatInput.tsx
|
|
2532
|
+
import { useState as useState21, useRef, useEffect as useEffect19 } from "react";
|
|
2533
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2534
|
+
var ChatInput = ({
|
|
2535
|
+
onSend,
|
|
2536
|
+
onTyping,
|
|
2537
|
+
placeholder = "Type a message...",
|
|
2538
|
+
disabled = false,
|
|
2539
|
+
className = ""
|
|
2540
|
+
}) => {
|
|
2541
|
+
const [message, setMessage] = useState21("");
|
|
2542
|
+
const inputRef = useRef(null);
|
|
2543
|
+
const typingTimeoutRef = useRef(null);
|
|
2544
|
+
const handleSubmit = (e) => {
|
|
2545
|
+
e.preventDefault();
|
|
2546
|
+
if (message.trim() && !disabled) {
|
|
2547
|
+
onSend(message.trim());
|
|
2548
|
+
setMessage("");
|
|
2549
|
+
inputRef.current?.focus();
|
|
2550
|
+
}
|
|
2551
|
+
};
|
|
2552
|
+
const handleKeyDown = (e) => {
|
|
2553
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
2554
|
+
e.preventDefault();
|
|
2555
|
+
handleSubmit(e);
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
const handleChange = (e) => {
|
|
2559
|
+
setMessage(e.target.value);
|
|
2560
|
+
if (onTyping) {
|
|
2561
|
+
if (typingTimeoutRef.current) {
|
|
2562
|
+
clearTimeout(typingTimeoutRef.current);
|
|
2563
|
+
}
|
|
2564
|
+
onTyping();
|
|
2565
|
+
typingTimeoutRef.current = setTimeout(() => {
|
|
2566
|
+
typingTimeoutRef.current = null;
|
|
2567
|
+
}, 2e3);
|
|
2568
|
+
}
|
|
2569
|
+
};
|
|
2570
|
+
useEffect19(() => {
|
|
2571
|
+
return () => {
|
|
2572
|
+
if (typingTimeoutRef.current) {
|
|
2573
|
+
clearTimeout(typingTimeoutRef.current);
|
|
2574
|
+
}
|
|
2575
|
+
};
|
|
2576
|
+
}, []);
|
|
2577
|
+
return /* @__PURE__ */ jsxs3(
|
|
2578
|
+
"form",
|
|
2579
|
+
{
|
|
2580
|
+
className: `diffsome-chat-input ${className}`,
|
|
2581
|
+
onSubmit: handleSubmit,
|
|
2582
|
+
children: [
|
|
2583
|
+
/* @__PURE__ */ jsx4(
|
|
2584
|
+
"textarea",
|
|
2585
|
+
{
|
|
2586
|
+
ref: inputRef,
|
|
2587
|
+
value: message,
|
|
2588
|
+
onChange: handleChange,
|
|
2589
|
+
onKeyDown: handleKeyDown,
|
|
2590
|
+
placeholder,
|
|
2591
|
+
disabled,
|
|
2592
|
+
rows: 1,
|
|
2593
|
+
className: "diffsome-chat-input-field"
|
|
2594
|
+
}
|
|
2595
|
+
),
|
|
2596
|
+
/* @__PURE__ */ jsx4(
|
|
2597
|
+
"button",
|
|
2598
|
+
{
|
|
2599
|
+
type: "submit",
|
|
2600
|
+
disabled: disabled || !message.trim(),
|
|
2601
|
+
className: "diffsome-chat-input-button",
|
|
2602
|
+
"aria-label": "Send message",
|
|
2603
|
+
children: /* @__PURE__ */ jsx4(
|
|
2604
|
+
"svg",
|
|
2605
|
+
{
|
|
2606
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2607
|
+
viewBox: "0 0 24 24",
|
|
2608
|
+
fill: "currentColor",
|
|
2609
|
+
width: "20",
|
|
2610
|
+
height: "20",
|
|
2611
|
+
children: /* @__PURE__ */ jsx4("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" })
|
|
2612
|
+
}
|
|
2613
|
+
)
|
|
2614
|
+
}
|
|
2615
|
+
)
|
|
2616
|
+
]
|
|
2617
|
+
}
|
|
2618
|
+
);
|
|
2619
|
+
};
|
|
2620
|
+
|
|
2621
|
+
// src/components/chat/ChatWidget.tsx
|
|
2622
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2623
|
+
var ChatWidget = ({
|
|
2624
|
+
messages,
|
|
2625
|
+
onSend,
|
|
2626
|
+
onTyping,
|
|
2627
|
+
onClose,
|
|
2628
|
+
title = "Chat Support",
|
|
2629
|
+
subtitle = "We typically reply within a few minutes",
|
|
2630
|
+
placeholder = "Type a message...",
|
|
2631
|
+
loading = false,
|
|
2632
|
+
typing = false,
|
|
2633
|
+
className = ""
|
|
2634
|
+
}) => {
|
|
2635
|
+
const messagesEndRef = useRef2(null);
|
|
2636
|
+
const scrollToBottom = () => {
|
|
2637
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2638
|
+
};
|
|
2639
|
+
useEffect20(() => {
|
|
2640
|
+
scrollToBottom();
|
|
2641
|
+
}, [messages, typing]);
|
|
2642
|
+
const formatTime = (timestamp) => {
|
|
2643
|
+
if (!timestamp) return void 0;
|
|
2644
|
+
const date = new Date(timestamp);
|
|
2645
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
2646
|
+
};
|
|
2647
|
+
return /* @__PURE__ */ jsxs4("div", { className: `diffsome-chat-widget ${className}`, children: [
|
|
2648
|
+
/* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-header", children: [
|
|
2649
|
+
/* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-header-info", children: [
|
|
2650
|
+
/* @__PURE__ */ jsx5("div", { className: "diffsome-chat-header-title", children: title }),
|
|
2651
|
+
/* @__PURE__ */ jsx5("div", { className: "diffsome-chat-header-subtitle", children: subtitle })
|
|
2652
|
+
] }),
|
|
2653
|
+
onClose && /* @__PURE__ */ jsx5(
|
|
2654
|
+
"button",
|
|
2655
|
+
{
|
|
2656
|
+
className: "diffsome-chat-header-close",
|
|
2657
|
+
onClick: onClose,
|
|
2658
|
+
"aria-label": "Close chat",
|
|
2659
|
+
children: /* @__PURE__ */ jsx5(
|
|
2660
|
+
"svg",
|
|
2661
|
+
{
|
|
2662
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2663
|
+
viewBox: "0 0 24 24",
|
|
2664
|
+
fill: "currentColor",
|
|
2665
|
+
width: "24",
|
|
2666
|
+
height: "24",
|
|
2667
|
+
children: /* @__PURE__ */ jsx5("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
|
|
2668
|
+
}
|
|
2669
|
+
)
|
|
2670
|
+
}
|
|
2671
|
+
)
|
|
2672
|
+
] }),
|
|
2673
|
+
/* @__PURE__ */ jsx5("div", { className: "diffsome-chat-messages", children: loading ? /* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-loading", children: [
|
|
2674
|
+
/* @__PURE__ */ jsx5("div", { className: "diffsome-chat-loading-spinner" }),
|
|
2675
|
+
/* @__PURE__ */ jsx5("span", { children: "Loading messages..." })
|
|
2676
|
+
] }) : messages.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "diffsome-chat-empty", children: /* @__PURE__ */ jsx5("span", { children: "No messages yet. Start the conversation!" }) }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
2677
|
+
messages.map((msg) => /* @__PURE__ */ jsx5(
|
|
2678
|
+
ChatMessage,
|
|
2679
|
+
{
|
|
2680
|
+
content: msg.content,
|
|
2681
|
+
senderType: msg.senderType,
|
|
2682
|
+
senderName: msg.senderName,
|
|
2683
|
+
timestamp: formatTime(msg.timestamp),
|
|
2684
|
+
isRead: msg.isRead
|
|
2685
|
+
},
|
|
2686
|
+
msg.id
|
|
2687
|
+
)),
|
|
2688
|
+
typing && /* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-typing", children: [
|
|
2689
|
+
/* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-typing-indicator", children: [
|
|
2690
|
+
/* @__PURE__ */ jsx5("span", {}),
|
|
2691
|
+
/* @__PURE__ */ jsx5("span", {}),
|
|
2692
|
+
/* @__PURE__ */ jsx5("span", {})
|
|
2693
|
+
] }),
|
|
2694
|
+
/* @__PURE__ */ jsx5("span", { children: "Agent is typing..." })
|
|
2695
|
+
] }),
|
|
2696
|
+
/* @__PURE__ */ jsx5("div", { ref: messagesEndRef })
|
|
2697
|
+
] }) }),
|
|
2698
|
+
/* @__PURE__ */ jsx5(
|
|
2699
|
+
ChatInput,
|
|
2700
|
+
{
|
|
2701
|
+
onSend,
|
|
2702
|
+
onTyping,
|
|
2703
|
+
placeholder,
|
|
2704
|
+
disabled: loading
|
|
2705
|
+
}
|
|
2706
|
+
)
|
|
2707
|
+
] });
|
|
2708
|
+
};
|
|
2709
|
+
|
|
2710
|
+
// src/components/chat/ChatBubble.tsx
|
|
2711
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2712
|
+
var ChatBubble = ({
|
|
2713
|
+
client,
|
|
2714
|
+
title = "Chat Support",
|
|
2715
|
+
subtitle = "We typically reply within a few minutes",
|
|
2716
|
+
placeholder = "Type a message...",
|
|
2717
|
+
visitorName,
|
|
2718
|
+
visitorEmail,
|
|
2719
|
+
greeting,
|
|
2720
|
+
primaryColor = "#6366f1",
|
|
2721
|
+
position = "bottom-right",
|
|
2722
|
+
zIndex = 9999,
|
|
2723
|
+
showUnreadBadge = true,
|
|
2724
|
+
className = "",
|
|
2725
|
+
onOpen,
|
|
2726
|
+
onClose
|
|
2727
|
+
}) => {
|
|
2728
|
+
const [isOpen, setIsOpen] = useState22(false);
|
|
2729
|
+
const [messages, setMessages] = useState22([]);
|
|
2730
|
+
const [conversationId, setConversationId] = useState22(null);
|
|
2731
|
+
const [connection, setConnection] = useState22(null);
|
|
2732
|
+
const [loading, setLoading] = useState22(false);
|
|
2733
|
+
const [typing, setTyping] = useState22(false);
|
|
2734
|
+
const [unreadCount, setUnreadCount] = useState22(0);
|
|
2735
|
+
const initChat = useCallback22(async () => {
|
|
2736
|
+
if (conversationId) return;
|
|
2737
|
+
setLoading(true);
|
|
2738
|
+
try {
|
|
2739
|
+
const result = await client.chat.start({
|
|
2740
|
+
visitor_name: visitorName,
|
|
2741
|
+
visitor_email: visitorEmail,
|
|
2742
|
+
initial_message: greeting
|
|
2743
|
+
});
|
|
2744
|
+
setConversationId(result.conversation_id);
|
|
2745
|
+
const conn = client.chat.connect(result.conversation_id);
|
|
2746
|
+
setConnection(conn);
|
|
2747
|
+
const existingMessages = await conn.getMessages();
|
|
2748
|
+
setMessages(existingMessages);
|
|
2749
|
+
conn.onMessage((msg) => {
|
|
2750
|
+
setMessages((prev) => [...prev, msg]);
|
|
2751
|
+
if (!isOpen && msg.senderType !== "visitor") {
|
|
2752
|
+
setUnreadCount((c) => c + 1);
|
|
2753
|
+
}
|
|
2754
|
+
});
|
|
2755
|
+
conn.onTyping((senderType) => {
|
|
2756
|
+
if (senderType === "agent") {
|
|
2757
|
+
setTyping(true);
|
|
2758
|
+
setTimeout(() => setTyping(false), 3e3);
|
|
2759
|
+
}
|
|
2760
|
+
});
|
|
2761
|
+
} catch (error) {
|
|
2762
|
+
console.error("Failed to initialize chat:", error);
|
|
2763
|
+
} finally {
|
|
2764
|
+
setLoading(false);
|
|
2765
|
+
}
|
|
2766
|
+
}, [client.chat, conversationId, visitorName, visitorEmail, greeting, isOpen]);
|
|
2767
|
+
const handleOpen = () => {
|
|
2768
|
+
setIsOpen(true);
|
|
2769
|
+
setUnreadCount(0);
|
|
2770
|
+
onOpen?.();
|
|
2771
|
+
if (!conversationId) {
|
|
2772
|
+
initChat();
|
|
2773
|
+
}
|
|
2774
|
+
};
|
|
2775
|
+
const handleClose = () => {
|
|
2776
|
+
setIsOpen(false);
|
|
2777
|
+
onClose?.();
|
|
2778
|
+
};
|
|
2779
|
+
const handleSend = async (content) => {
|
|
2780
|
+
if (!connection) return;
|
|
2781
|
+
const tempMessage = {
|
|
2782
|
+
id: Date.now(),
|
|
2783
|
+
content,
|
|
2784
|
+
senderType: "visitor",
|
|
2785
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2786
|
+
};
|
|
2787
|
+
setMessages((prev) => [...prev, tempMessage]);
|
|
2788
|
+
try {
|
|
2789
|
+
await connection.send(content);
|
|
2790
|
+
} catch (error) {
|
|
2791
|
+
console.error("Failed to send message:", error);
|
|
2792
|
+
}
|
|
2793
|
+
};
|
|
2794
|
+
const handleTyping = () => {
|
|
2795
|
+
connection?.sendTyping();
|
|
2796
|
+
};
|
|
2797
|
+
useEffect21(() => {
|
|
2798
|
+
return () => {
|
|
2799
|
+
connection?.disconnect();
|
|
2800
|
+
};
|
|
2801
|
+
}, [connection]);
|
|
2802
|
+
const positionClass = position === "bottom-left" ? "diffsome-chat-bubble-left" : "diffsome-chat-bubble-right";
|
|
2803
|
+
return /* @__PURE__ */ jsxs5(
|
|
2804
|
+
"div",
|
|
2805
|
+
{
|
|
2806
|
+
className: `diffsome-chat-bubble-container ${positionClass} ${className}`,
|
|
2807
|
+
style: { "--diffsome-chat-primary": primaryColor, zIndex },
|
|
2808
|
+
children: [
|
|
2809
|
+
isOpen && /* @__PURE__ */ jsx6(
|
|
2810
|
+
ChatWidget,
|
|
2811
|
+
{
|
|
2812
|
+
messages,
|
|
2813
|
+
onSend: handleSend,
|
|
2814
|
+
onTyping: handleTyping,
|
|
2815
|
+
onClose: handleClose,
|
|
2816
|
+
title,
|
|
2817
|
+
subtitle,
|
|
2818
|
+
placeholder,
|
|
2819
|
+
loading,
|
|
2820
|
+
typing
|
|
2821
|
+
}
|
|
2822
|
+
),
|
|
2823
|
+
/* @__PURE__ */ jsxs5(
|
|
2824
|
+
"button",
|
|
2825
|
+
{
|
|
2826
|
+
className: `diffsome-chat-bubble-button ${isOpen ? "diffsome-chat-bubble-button-open" : ""}`,
|
|
2827
|
+
onClick: isOpen ? handleClose : handleOpen,
|
|
2828
|
+
"aria-label": isOpen ? "Close chat" : "Open chat",
|
|
2829
|
+
children: [
|
|
2830
|
+
isOpen ? /* @__PURE__ */ jsx6(
|
|
2831
|
+
"svg",
|
|
2832
|
+
{
|
|
2833
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2834
|
+
viewBox: "0 0 24 24",
|
|
2835
|
+
fill: "currentColor",
|
|
2836
|
+
width: "28",
|
|
2837
|
+
height: "28",
|
|
2838
|
+
children: /* @__PURE__ */ jsx6("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
|
|
2839
|
+
}
|
|
2840
|
+
) : /* @__PURE__ */ jsx6(
|
|
2841
|
+
"svg",
|
|
2842
|
+
{
|
|
2843
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2844
|
+
viewBox: "0 0 24 24",
|
|
2845
|
+
fill: "currentColor",
|
|
2846
|
+
width: "28",
|
|
2847
|
+
height: "28",
|
|
2848
|
+
children: /* @__PURE__ */ jsx6("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" })
|
|
2849
|
+
}
|
|
2850
|
+
),
|
|
2851
|
+
showUnreadBadge && unreadCount > 0 && !isOpen && /* @__PURE__ */ jsx6("span", { className: "diffsome-chat-bubble-badge", children: unreadCount > 9 ? "9+" : unreadCount })
|
|
2852
|
+
]
|
|
2853
|
+
}
|
|
2854
|
+
)
|
|
2855
|
+
]
|
|
2856
|
+
}
|
|
2857
|
+
);
|
|
2858
|
+
};
|
|
2325
2859
|
export {
|
|
2860
|
+
ChatBubble,
|
|
2861
|
+
ChatInput,
|
|
2862
|
+
ChatMessage,
|
|
2863
|
+
ChatWidget,
|
|
2326
2864
|
DiffsomeContext,
|
|
2327
2865
|
DiffsomeProvider,
|
|
2866
|
+
RichContent,
|
|
2328
2867
|
useAuth,
|
|
2329
2868
|
useAvailableSlots,
|
|
2330
2869
|
useBlog,
|
|
@@ -2341,6 +2880,7 @@ export {
|
|
|
2341
2880
|
useCanReview,
|
|
2342
2881
|
useCart,
|
|
2343
2882
|
useCategories,
|
|
2883
|
+
useChat,
|
|
2344
2884
|
useClient,
|
|
2345
2885
|
useComments,
|
|
2346
2886
|
useCoupons,
|