@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.js
CHANGED
|
@@ -20,8 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ChatBubble: () => ChatBubble,
|
|
24
|
+
ChatInput: () => ChatInput,
|
|
25
|
+
ChatMessage: () => ChatMessage,
|
|
26
|
+
ChatWidget: () => ChatWidget,
|
|
23
27
|
DiffsomeContext: () => DiffsomeContext,
|
|
24
28
|
DiffsomeProvider: () => DiffsomeProvider,
|
|
29
|
+
RichContent: () => RichContent,
|
|
25
30
|
useAuth: () => useAuth,
|
|
26
31
|
useAvailableSlots: () => useAvailableSlots,
|
|
27
32
|
useBlog: () => useBlog,
|
|
@@ -38,6 +43,7 @@ __export(index_exports, {
|
|
|
38
43
|
useCanReview: () => useCanReview,
|
|
39
44
|
useCart: () => useCart,
|
|
40
45
|
useCategories: () => useCategories,
|
|
46
|
+
useChat: () => useChat,
|
|
41
47
|
useClient: () => useClient,
|
|
42
48
|
useComments: () => useComments,
|
|
43
49
|
useCoupons: () => useCoupons,
|
|
@@ -2408,10 +2414,549 @@ function useTypedEntity(slug) {
|
|
|
2408
2414
|
delete: (id) => client.entities.deleteRecord(slug, id)
|
|
2409
2415
|
}), [client, slug]);
|
|
2410
2416
|
}
|
|
2417
|
+
|
|
2418
|
+
// src/hooks/useChat.ts
|
|
2419
|
+
var import_react21 = require("react");
|
|
2420
|
+
function useChat(options = {}) {
|
|
2421
|
+
const client = useClient();
|
|
2422
|
+
const [conversation, setConversation] = (0, import_react21.useState)(null);
|
|
2423
|
+
const [messages, setMessages] = (0, import_react21.useState)([]);
|
|
2424
|
+
const [loading, setLoading] = (0, import_react21.useState)(false);
|
|
2425
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
2426
|
+
const [connected, setConnected] = (0, import_react21.useState)(false);
|
|
2427
|
+
const [agentTyping, setAgentTyping] = (0, import_react21.useState)(false);
|
|
2428
|
+
const [connection, setConnection] = (0, import_react21.useState)(null);
|
|
2429
|
+
const start = (0, import_react21.useCallback)(async (startOptions) => {
|
|
2430
|
+
setLoading(true);
|
|
2431
|
+
setError(null);
|
|
2432
|
+
try {
|
|
2433
|
+
const result = await client.chat.start({
|
|
2434
|
+
visitor_name: startOptions?.visitorName || options.visitorName,
|
|
2435
|
+
visitor_email: startOptions?.visitorEmail || options.visitorEmail,
|
|
2436
|
+
initial_message: startOptions?.greeting || options.greeting
|
|
2437
|
+
});
|
|
2438
|
+
const conv = await client.chat.get(result.conversation_id);
|
|
2439
|
+
setConversation(conv);
|
|
2440
|
+
const conn = client.chat.connect(result.conversation_id);
|
|
2441
|
+
setConnection(conn);
|
|
2442
|
+
setConnected(true);
|
|
2443
|
+
const existingMessages = await conn.getMessages();
|
|
2444
|
+
setMessages(existingMessages);
|
|
2445
|
+
const unsubMessage = conn.onMessage((msg) => {
|
|
2446
|
+
setMessages((prev) => {
|
|
2447
|
+
if (prev.some((m) => m.id === msg.id)) return prev;
|
|
2448
|
+
return [...prev, msg];
|
|
2449
|
+
});
|
|
2450
|
+
});
|
|
2451
|
+
const unsubTyping = conn.onTyping((senderType) => {
|
|
2452
|
+
if (senderType === "agent") {
|
|
2453
|
+
setAgentTyping(true);
|
|
2454
|
+
setTimeout(() => setAgentTyping(false), 3e3);
|
|
2455
|
+
}
|
|
2456
|
+
});
|
|
2457
|
+
conn.onStatusChange((status) => {
|
|
2458
|
+
setConversation((prev) => prev ? { ...prev, status } : null);
|
|
2459
|
+
});
|
|
2460
|
+
} catch (err) {
|
|
2461
|
+
setError(err instanceof Error ? err : new Error("Failed to start chat"));
|
|
2462
|
+
} finally {
|
|
2463
|
+
setLoading(false);
|
|
2464
|
+
}
|
|
2465
|
+
}, [client.chat, options.visitorName, options.visitorEmail, options.greeting]);
|
|
2466
|
+
const send = (0, import_react21.useCallback)(async (content) => {
|
|
2467
|
+
if (!connection) {
|
|
2468
|
+
throw new Error("Not connected to chat");
|
|
2469
|
+
}
|
|
2470
|
+
try {
|
|
2471
|
+
const message = await connection.send(content);
|
|
2472
|
+
} catch (err) {
|
|
2473
|
+
setError(err instanceof Error ? err : new Error("Failed to send message"));
|
|
2474
|
+
throw err;
|
|
2475
|
+
}
|
|
2476
|
+
}, [connection]);
|
|
2477
|
+
const sendTyping = (0, import_react21.useCallback)(() => {
|
|
2478
|
+
connection?.sendTyping();
|
|
2479
|
+
}, [connection]);
|
|
2480
|
+
const close = (0, import_react21.useCallback)(async () => {
|
|
2481
|
+
if (!connection) return;
|
|
2482
|
+
try {
|
|
2483
|
+
await connection.close();
|
|
2484
|
+
setConversation((prev) => prev ? { ...prev, status: "closed" } : null);
|
|
2485
|
+
} catch (err) {
|
|
2486
|
+
setError(err instanceof Error ? err : new Error("Failed to close chat"));
|
|
2487
|
+
}
|
|
2488
|
+
}, [connection]);
|
|
2489
|
+
const disconnect = (0, import_react21.useCallback)(() => {
|
|
2490
|
+
connection?.disconnect();
|
|
2491
|
+
setConnected(false);
|
|
2492
|
+
setConnection(null);
|
|
2493
|
+
}, [connection]);
|
|
2494
|
+
(0, import_react21.useEffect)(() => {
|
|
2495
|
+
if (options.autoConnect) {
|
|
2496
|
+
start();
|
|
2497
|
+
}
|
|
2498
|
+
return () => {
|
|
2499
|
+
connection?.disconnect();
|
|
2500
|
+
};
|
|
2501
|
+
}, [options.autoConnect]);
|
|
2502
|
+
return {
|
|
2503
|
+
conversation,
|
|
2504
|
+
messages,
|
|
2505
|
+
loading,
|
|
2506
|
+
error,
|
|
2507
|
+
connected,
|
|
2508
|
+
agentTyping,
|
|
2509
|
+
start,
|
|
2510
|
+
send,
|
|
2511
|
+
sendTyping,
|
|
2512
|
+
close,
|
|
2513
|
+
disconnect
|
|
2514
|
+
};
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
// src/components/RichContent.tsx
|
|
2518
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2519
|
+
var quillStyles = `
|
|
2520
|
+
/* Quill Alignment */
|
|
2521
|
+
.ql-align-center { text-align: center; }
|
|
2522
|
+
.ql-align-right { text-align: right; }
|
|
2523
|
+
.ql-align-justify { text-align: justify; }
|
|
2524
|
+
|
|
2525
|
+
/* Quill Font Sizes */
|
|
2526
|
+
.ql-size-small { font-size: 0.75em; }
|
|
2527
|
+
.ql-size-large { font-size: 1.5em; }
|
|
2528
|
+
.ql-size-huge { font-size: 2.5em; }
|
|
2529
|
+
|
|
2530
|
+
/* Quill Fonts */
|
|
2531
|
+
.ql-font-serif { font-family: Georgia, Times New Roman, serif; }
|
|
2532
|
+
.ql-font-monospace { font-family: Monaco, Courier New, monospace; }
|
|
2533
|
+
|
|
2534
|
+
/* Quill Indent */
|
|
2535
|
+
.ql-indent-1 { padding-left: 3em; }
|
|
2536
|
+
.ql-indent-2 { padding-left: 6em; }
|
|
2537
|
+
.ql-indent-3 { padding-left: 9em; }
|
|
2538
|
+
.ql-indent-4 { padding-left: 12em; }
|
|
2539
|
+
.ql-indent-5 { padding-left: 15em; }
|
|
2540
|
+
|
|
2541
|
+
/* Quill Video */
|
|
2542
|
+
.ql-video {
|
|
2543
|
+
display: block;
|
|
2544
|
+
max-width: 100%;
|
|
2545
|
+
margin: 1em 0;
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
/* Quill Code Block */
|
|
2549
|
+
.ql-code-block-container {
|
|
2550
|
+
background-color: #23241f;
|
|
2551
|
+
color: #f8f8f2;
|
|
2552
|
+
border-radius: 0.375rem;
|
|
2553
|
+
padding: 1em;
|
|
2554
|
+
margin: 1em 0;
|
|
2555
|
+
overflow-x: auto;
|
|
2556
|
+
}
|
|
2557
|
+
`;
|
|
2558
|
+
function RichContent({
|
|
2559
|
+
html,
|
|
2560
|
+
className = "",
|
|
2561
|
+
prose = true,
|
|
2562
|
+
proseVariant = "default",
|
|
2563
|
+
proseSize = "base",
|
|
2564
|
+
maxWidth = "none"
|
|
2565
|
+
}) {
|
|
2566
|
+
const proseClasses = prose ? [
|
|
2567
|
+
"prose",
|
|
2568
|
+
proseVariant !== "default" && `prose-${proseVariant}`,
|
|
2569
|
+
proseSize !== "base" && `prose-${proseSize}`,
|
|
2570
|
+
maxWidth !== "none" && `max-w-${maxWidth}`
|
|
2571
|
+
].filter(Boolean).join(" ") : "";
|
|
2572
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2573
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { dangerouslySetInnerHTML: { __html: quillStyles } }),
|
|
2574
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2575
|
+
"div",
|
|
2576
|
+
{
|
|
2577
|
+
className: `rich-content ${proseClasses} ${className}`.trim(),
|
|
2578
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
2579
|
+
}
|
|
2580
|
+
)
|
|
2581
|
+
] });
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
// src/components/chat/ChatBubble.tsx
|
|
2585
|
+
var import_react24 = require("react");
|
|
2586
|
+
|
|
2587
|
+
// src/components/chat/ChatWidget.tsx
|
|
2588
|
+
var import_react23 = require("react");
|
|
2589
|
+
|
|
2590
|
+
// src/components/chat/ChatMessage.tsx
|
|
2591
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
2592
|
+
var ChatMessage = ({
|
|
2593
|
+
content,
|
|
2594
|
+
senderType,
|
|
2595
|
+
senderName,
|
|
2596
|
+
timestamp,
|
|
2597
|
+
isRead,
|
|
2598
|
+
className = ""
|
|
2599
|
+
}) => {
|
|
2600
|
+
const isVisitor = senderType === "visitor";
|
|
2601
|
+
const isSystem = senderType === "system";
|
|
2602
|
+
if (isSystem) {
|
|
2603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `diffsome-chat-message-system ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: content }) });
|
|
2604
|
+
}
|
|
2605
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2606
|
+
"div",
|
|
2607
|
+
{
|
|
2608
|
+
className: `diffsome-chat-message ${isVisitor ? "diffsome-chat-message-visitor" : "diffsome-chat-message-agent"} ${className}`,
|
|
2609
|
+
children: [
|
|
2610
|
+
!isVisitor && senderName && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "diffsome-chat-message-sender", children: senderName }),
|
|
2611
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "diffsome-chat-message-bubble", children: [
|
|
2612
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "diffsome-chat-message-content", children: content }),
|
|
2613
|
+
timestamp && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "diffsome-chat-message-time", children: [
|
|
2614
|
+
timestamp,
|
|
2615
|
+
isVisitor && isRead && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "diffsome-chat-message-read", children: " \u2713" })
|
|
2616
|
+
] })
|
|
2617
|
+
] })
|
|
2618
|
+
]
|
|
2619
|
+
}
|
|
2620
|
+
);
|
|
2621
|
+
};
|
|
2622
|
+
|
|
2623
|
+
// src/components/chat/ChatInput.tsx
|
|
2624
|
+
var import_react22 = require("react");
|
|
2625
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2626
|
+
var ChatInput = ({
|
|
2627
|
+
onSend,
|
|
2628
|
+
onTyping,
|
|
2629
|
+
placeholder = "Type a message...",
|
|
2630
|
+
disabled = false,
|
|
2631
|
+
className = ""
|
|
2632
|
+
}) => {
|
|
2633
|
+
const [message, setMessage] = (0, import_react22.useState)("");
|
|
2634
|
+
const inputRef = (0, import_react22.useRef)(null);
|
|
2635
|
+
const typingTimeoutRef = (0, import_react22.useRef)(null);
|
|
2636
|
+
const handleSubmit = (e) => {
|
|
2637
|
+
e.preventDefault();
|
|
2638
|
+
if (message.trim() && !disabled) {
|
|
2639
|
+
onSend(message.trim());
|
|
2640
|
+
setMessage("");
|
|
2641
|
+
inputRef.current?.focus();
|
|
2642
|
+
}
|
|
2643
|
+
};
|
|
2644
|
+
const handleKeyDown = (e) => {
|
|
2645
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
2646
|
+
e.preventDefault();
|
|
2647
|
+
handleSubmit(e);
|
|
2648
|
+
}
|
|
2649
|
+
};
|
|
2650
|
+
const handleChange = (e) => {
|
|
2651
|
+
setMessage(e.target.value);
|
|
2652
|
+
if (onTyping) {
|
|
2653
|
+
if (typingTimeoutRef.current) {
|
|
2654
|
+
clearTimeout(typingTimeoutRef.current);
|
|
2655
|
+
}
|
|
2656
|
+
onTyping();
|
|
2657
|
+
typingTimeoutRef.current = setTimeout(() => {
|
|
2658
|
+
typingTimeoutRef.current = null;
|
|
2659
|
+
}, 2e3);
|
|
2660
|
+
}
|
|
2661
|
+
};
|
|
2662
|
+
(0, import_react22.useEffect)(() => {
|
|
2663
|
+
return () => {
|
|
2664
|
+
if (typingTimeoutRef.current) {
|
|
2665
|
+
clearTimeout(typingTimeoutRef.current);
|
|
2666
|
+
}
|
|
2667
|
+
};
|
|
2668
|
+
}, []);
|
|
2669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2670
|
+
"form",
|
|
2671
|
+
{
|
|
2672
|
+
className: `diffsome-chat-input ${className}`,
|
|
2673
|
+
onSubmit: handleSubmit,
|
|
2674
|
+
children: [
|
|
2675
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2676
|
+
"textarea",
|
|
2677
|
+
{
|
|
2678
|
+
ref: inputRef,
|
|
2679
|
+
value: message,
|
|
2680
|
+
onChange: handleChange,
|
|
2681
|
+
onKeyDown: handleKeyDown,
|
|
2682
|
+
placeholder,
|
|
2683
|
+
disabled,
|
|
2684
|
+
rows: 1,
|
|
2685
|
+
className: "diffsome-chat-input-field"
|
|
2686
|
+
}
|
|
2687
|
+
),
|
|
2688
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2689
|
+
"button",
|
|
2690
|
+
{
|
|
2691
|
+
type: "submit",
|
|
2692
|
+
disabled: disabled || !message.trim(),
|
|
2693
|
+
className: "diffsome-chat-input-button",
|
|
2694
|
+
"aria-label": "Send message",
|
|
2695
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2696
|
+
"svg",
|
|
2697
|
+
{
|
|
2698
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2699
|
+
viewBox: "0 0 24 24",
|
|
2700
|
+
fill: "currentColor",
|
|
2701
|
+
width: "20",
|
|
2702
|
+
height: "20",
|
|
2703
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" })
|
|
2704
|
+
}
|
|
2705
|
+
)
|
|
2706
|
+
}
|
|
2707
|
+
)
|
|
2708
|
+
]
|
|
2709
|
+
}
|
|
2710
|
+
);
|
|
2711
|
+
};
|
|
2712
|
+
|
|
2713
|
+
// src/components/chat/ChatWidget.tsx
|
|
2714
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2715
|
+
var ChatWidget = ({
|
|
2716
|
+
messages,
|
|
2717
|
+
onSend,
|
|
2718
|
+
onTyping,
|
|
2719
|
+
onClose,
|
|
2720
|
+
title = "Chat Support",
|
|
2721
|
+
subtitle = "We typically reply within a few minutes",
|
|
2722
|
+
placeholder = "Type a message...",
|
|
2723
|
+
loading = false,
|
|
2724
|
+
typing = false,
|
|
2725
|
+
className = ""
|
|
2726
|
+
}) => {
|
|
2727
|
+
const messagesEndRef = (0, import_react23.useRef)(null);
|
|
2728
|
+
const scrollToBottom = () => {
|
|
2729
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2730
|
+
};
|
|
2731
|
+
(0, import_react23.useEffect)(() => {
|
|
2732
|
+
scrollToBottom();
|
|
2733
|
+
}, [messages, typing]);
|
|
2734
|
+
const formatTime = (timestamp) => {
|
|
2735
|
+
if (!timestamp) return void 0;
|
|
2736
|
+
const date = new Date(timestamp);
|
|
2737
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
2738
|
+
};
|
|
2739
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `diffsome-chat-widget ${className}`, children: [
|
|
2740
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-header", children: [
|
|
2741
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-header-info", children: [
|
|
2742
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-header-title", children: title }),
|
|
2743
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-header-subtitle", children: subtitle })
|
|
2744
|
+
] }),
|
|
2745
|
+
onClose && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2746
|
+
"button",
|
|
2747
|
+
{
|
|
2748
|
+
className: "diffsome-chat-header-close",
|
|
2749
|
+
onClick: onClose,
|
|
2750
|
+
"aria-label": "Close chat",
|
|
2751
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2752
|
+
"svg",
|
|
2753
|
+
{
|
|
2754
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2755
|
+
viewBox: "0 0 24 24",
|
|
2756
|
+
fill: "currentColor",
|
|
2757
|
+
width: "24",
|
|
2758
|
+
height: "24",
|
|
2759
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" })
|
|
2760
|
+
}
|
|
2761
|
+
)
|
|
2762
|
+
}
|
|
2763
|
+
)
|
|
2764
|
+
] }),
|
|
2765
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-messages", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-loading", children: [
|
|
2766
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-loading-spinner" }),
|
|
2767
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Loading messages..." })
|
|
2768
|
+
] }) : messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-empty", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "No messages yet. Start the conversation!" }) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
2769
|
+
messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2770
|
+
ChatMessage,
|
|
2771
|
+
{
|
|
2772
|
+
content: msg.content,
|
|
2773
|
+
senderType: msg.senderType,
|
|
2774
|
+
senderName: msg.senderName,
|
|
2775
|
+
timestamp: formatTime(msg.timestamp),
|
|
2776
|
+
isRead: msg.isRead
|
|
2777
|
+
},
|
|
2778
|
+
msg.id
|
|
2779
|
+
)),
|
|
2780
|
+
typing && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-typing", children: [
|
|
2781
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-typing-indicator", children: [
|
|
2782
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
|
|
2783
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
|
|
2784
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {})
|
|
2785
|
+
] }),
|
|
2786
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Agent is typing..." })
|
|
2787
|
+
] }),
|
|
2788
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: messagesEndRef })
|
|
2789
|
+
] }) }),
|
|
2790
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2791
|
+
ChatInput,
|
|
2792
|
+
{
|
|
2793
|
+
onSend,
|
|
2794
|
+
onTyping,
|
|
2795
|
+
placeholder,
|
|
2796
|
+
disabled: loading
|
|
2797
|
+
}
|
|
2798
|
+
)
|
|
2799
|
+
] });
|
|
2800
|
+
};
|
|
2801
|
+
|
|
2802
|
+
// src/components/chat/ChatBubble.tsx
|
|
2803
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2804
|
+
var ChatBubble = ({
|
|
2805
|
+
client,
|
|
2806
|
+
title = "Chat Support",
|
|
2807
|
+
subtitle = "We typically reply within a few minutes",
|
|
2808
|
+
placeholder = "Type a message...",
|
|
2809
|
+
visitorName,
|
|
2810
|
+
visitorEmail,
|
|
2811
|
+
greeting,
|
|
2812
|
+
primaryColor = "#6366f1",
|
|
2813
|
+
position = "bottom-right",
|
|
2814
|
+
zIndex = 9999,
|
|
2815
|
+
showUnreadBadge = true,
|
|
2816
|
+
className = "",
|
|
2817
|
+
onOpen,
|
|
2818
|
+
onClose
|
|
2819
|
+
}) => {
|
|
2820
|
+
const [isOpen, setIsOpen] = (0, import_react24.useState)(false);
|
|
2821
|
+
const [messages, setMessages] = (0, import_react24.useState)([]);
|
|
2822
|
+
const [conversationId, setConversationId] = (0, import_react24.useState)(null);
|
|
2823
|
+
const [connection, setConnection] = (0, import_react24.useState)(null);
|
|
2824
|
+
const [loading, setLoading] = (0, import_react24.useState)(false);
|
|
2825
|
+
const [typing, setTyping] = (0, import_react24.useState)(false);
|
|
2826
|
+
const [unreadCount, setUnreadCount] = (0, import_react24.useState)(0);
|
|
2827
|
+
const initChat = (0, import_react24.useCallback)(async () => {
|
|
2828
|
+
if (conversationId) return;
|
|
2829
|
+
setLoading(true);
|
|
2830
|
+
try {
|
|
2831
|
+
const result = await client.chat.start({
|
|
2832
|
+
visitor_name: visitorName,
|
|
2833
|
+
visitor_email: visitorEmail,
|
|
2834
|
+
initial_message: greeting
|
|
2835
|
+
});
|
|
2836
|
+
setConversationId(result.conversation_id);
|
|
2837
|
+
const conn = client.chat.connect(result.conversation_id);
|
|
2838
|
+
setConnection(conn);
|
|
2839
|
+
const existingMessages = await conn.getMessages();
|
|
2840
|
+
setMessages(existingMessages);
|
|
2841
|
+
conn.onMessage((msg) => {
|
|
2842
|
+
setMessages((prev) => [...prev, msg]);
|
|
2843
|
+
if (!isOpen && msg.senderType !== "visitor") {
|
|
2844
|
+
setUnreadCount((c) => c + 1);
|
|
2845
|
+
}
|
|
2846
|
+
});
|
|
2847
|
+
conn.onTyping((senderType) => {
|
|
2848
|
+
if (senderType === "agent") {
|
|
2849
|
+
setTyping(true);
|
|
2850
|
+
setTimeout(() => setTyping(false), 3e3);
|
|
2851
|
+
}
|
|
2852
|
+
});
|
|
2853
|
+
} catch (error) {
|
|
2854
|
+
console.error("Failed to initialize chat:", error);
|
|
2855
|
+
} finally {
|
|
2856
|
+
setLoading(false);
|
|
2857
|
+
}
|
|
2858
|
+
}, [client.chat, conversationId, visitorName, visitorEmail, greeting, isOpen]);
|
|
2859
|
+
const handleOpen = () => {
|
|
2860
|
+
setIsOpen(true);
|
|
2861
|
+
setUnreadCount(0);
|
|
2862
|
+
onOpen?.();
|
|
2863
|
+
if (!conversationId) {
|
|
2864
|
+
initChat();
|
|
2865
|
+
}
|
|
2866
|
+
};
|
|
2867
|
+
const handleClose = () => {
|
|
2868
|
+
setIsOpen(false);
|
|
2869
|
+
onClose?.();
|
|
2870
|
+
};
|
|
2871
|
+
const handleSend = async (content) => {
|
|
2872
|
+
if (!connection) return;
|
|
2873
|
+
const tempMessage = {
|
|
2874
|
+
id: Date.now(),
|
|
2875
|
+
content,
|
|
2876
|
+
senderType: "visitor",
|
|
2877
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2878
|
+
};
|
|
2879
|
+
setMessages((prev) => [...prev, tempMessage]);
|
|
2880
|
+
try {
|
|
2881
|
+
await connection.send(content);
|
|
2882
|
+
} catch (error) {
|
|
2883
|
+
console.error("Failed to send message:", error);
|
|
2884
|
+
}
|
|
2885
|
+
};
|
|
2886
|
+
const handleTyping = () => {
|
|
2887
|
+
connection?.sendTyping();
|
|
2888
|
+
};
|
|
2889
|
+
(0, import_react24.useEffect)(() => {
|
|
2890
|
+
return () => {
|
|
2891
|
+
connection?.disconnect();
|
|
2892
|
+
};
|
|
2893
|
+
}, [connection]);
|
|
2894
|
+
const positionClass = position === "bottom-left" ? "diffsome-chat-bubble-left" : "diffsome-chat-bubble-right";
|
|
2895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2896
|
+
"div",
|
|
2897
|
+
{
|
|
2898
|
+
className: `diffsome-chat-bubble-container ${positionClass} ${className}`,
|
|
2899
|
+
style: { "--diffsome-chat-primary": primaryColor, zIndex },
|
|
2900
|
+
children: [
|
|
2901
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2902
|
+
ChatWidget,
|
|
2903
|
+
{
|
|
2904
|
+
messages,
|
|
2905
|
+
onSend: handleSend,
|
|
2906
|
+
onTyping: handleTyping,
|
|
2907
|
+
onClose: handleClose,
|
|
2908
|
+
title,
|
|
2909
|
+
subtitle,
|
|
2910
|
+
placeholder,
|
|
2911
|
+
loading,
|
|
2912
|
+
typing
|
|
2913
|
+
}
|
|
2914
|
+
),
|
|
2915
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2916
|
+
"button",
|
|
2917
|
+
{
|
|
2918
|
+
className: `diffsome-chat-bubble-button ${isOpen ? "diffsome-chat-bubble-button-open" : ""}`,
|
|
2919
|
+
onClick: isOpen ? handleClose : handleOpen,
|
|
2920
|
+
"aria-label": isOpen ? "Close chat" : "Open chat",
|
|
2921
|
+
children: [
|
|
2922
|
+
isOpen ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2923
|
+
"svg",
|
|
2924
|
+
{
|
|
2925
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2926
|
+
viewBox: "0 0 24 24",
|
|
2927
|
+
fill: "currentColor",
|
|
2928
|
+
width: "28",
|
|
2929
|
+
height: "28",
|
|
2930
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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" })
|
|
2931
|
+
}
|
|
2932
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2933
|
+
"svg",
|
|
2934
|
+
{
|
|
2935
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2936
|
+
viewBox: "0 0 24 24",
|
|
2937
|
+
fill: "currentColor",
|
|
2938
|
+
width: "28",
|
|
2939
|
+
height: "28",
|
|
2940
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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" })
|
|
2941
|
+
}
|
|
2942
|
+
),
|
|
2943
|
+
showUnreadBadge && unreadCount > 0 && !isOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "diffsome-chat-bubble-badge", children: unreadCount > 9 ? "9+" : unreadCount })
|
|
2944
|
+
]
|
|
2945
|
+
}
|
|
2946
|
+
)
|
|
2947
|
+
]
|
|
2948
|
+
}
|
|
2949
|
+
);
|
|
2950
|
+
};
|
|
2411
2951
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2412
2952
|
0 && (module.exports = {
|
|
2953
|
+
ChatBubble,
|
|
2954
|
+
ChatInput,
|
|
2955
|
+
ChatMessage,
|
|
2956
|
+
ChatWidget,
|
|
2413
2957
|
DiffsomeContext,
|
|
2414
2958
|
DiffsomeProvider,
|
|
2959
|
+
RichContent,
|
|
2415
2960
|
useAuth,
|
|
2416
2961
|
useAvailableSlots,
|
|
2417
2962
|
useBlog,
|
|
@@ -2428,6 +2973,7 @@ function useTypedEntity(slug) {
|
|
|
2428
2973
|
useCanReview,
|
|
2429
2974
|
useCart,
|
|
2430
2975
|
useCategories,
|
|
2976
|
+
useChat,
|
|
2431
2977
|
useClient,
|
|
2432
2978
|
useComments,
|
|
2433
2979
|
useCoupons,
|