@diffsome/react 1.2.8 → 1.2.10

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/chat.css CHANGED
@@ -246,6 +246,23 @@
246
246
  color: #10b981;
247
247
  }
248
248
 
249
+ .diffsome-chat-message-pending {
250
+ opacity: 0.7;
251
+ }
252
+
253
+ .diffsome-chat-message-failed {
254
+ opacity: 0.7;
255
+ border: 1px solid #ef4444;
256
+ }
257
+
258
+ .diffsome-chat-message-status {
259
+ font-style: italic;
260
+ }
261
+
262
+ .diffsome-chat-message-error {
263
+ color: #ef4444;
264
+ }
265
+
249
266
  /* System Message */
250
267
  .diffsome-chat-message-system {
251
268
  align-self: center;
package/dist/index.d.mts CHANGED
@@ -876,6 +876,8 @@ interface Message {
876
876
  sender_name?: string;
877
877
  created_at?: string;
878
878
  is_read?: boolean;
879
+ is_pending?: boolean;
880
+ is_failed?: boolean;
879
881
  }
880
882
  interface ChatWidgetProps {
881
883
  messages: Message[];
@@ -897,6 +899,8 @@ interface ChatMessageProps {
897
899
  senderName?: string;
898
900
  timestamp?: string;
899
901
  isRead?: boolean;
902
+ isPending?: boolean;
903
+ isFailed?: boolean;
900
904
  className?: string;
901
905
  }
902
906
  declare const ChatMessage: React__default.FC<ChatMessageProps>;
package/dist/index.d.ts CHANGED
@@ -876,6 +876,8 @@ interface Message {
876
876
  sender_name?: string;
877
877
  created_at?: string;
878
878
  is_read?: boolean;
879
+ is_pending?: boolean;
880
+ is_failed?: boolean;
879
881
  }
880
882
  interface ChatWidgetProps {
881
883
  messages: Message[];
@@ -897,6 +899,8 @@ interface ChatMessageProps {
897
899
  senderName?: string;
898
900
  timestamp?: string;
899
901
  isRead?: boolean;
902
+ isPending?: boolean;
903
+ isFailed?: boolean;
900
904
  className?: string;
901
905
  }
902
906
  declare const ChatMessage: React__default.FC<ChatMessageProps>;
package/dist/index.js CHANGED
@@ -2595,6 +2595,8 @@ var ChatMessage = ({
2595
2595
  senderName,
2596
2596
  timestamp,
2597
2597
  isRead,
2598
+ isPending,
2599
+ isFailed,
2598
2600
  className = ""
2599
2601
  }) => {
2600
2602
  const isVisitor = senderType === "visitor";
@@ -2608,12 +2610,12 @@ var ChatMessage = ({
2608
2610
  className: `diffsome-chat-message ${isVisitor ? "diffsome-chat-message-visitor" : "diffsome-chat-message-agent"} ${className}`,
2609
2611
  children: [
2610
2612
  !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: [
2613
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `diffsome-chat-message-bubble ${isPending ? "diffsome-chat-message-pending" : ""} ${isFailed ? "diffsome-chat-message-failed" : ""}`, children: [
2612
2614
  /* @__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: [
2615
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "diffsome-chat-message-time", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "diffsome-chat-message-status", children: "Sending..." }) : isFailed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "diffsome-chat-message-status diffsome-chat-message-error", children: "Failed" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2614
2616
  timestamp,
2615
2617
  isVisitor && isRead && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "diffsome-chat-message-read", children: " \u2713" })
2616
- ] })
2618
+ ] }) })
2617
2619
  ] })
2618
2620
  ]
2619
2621
  }
@@ -2773,7 +2775,9 @@ var ChatWidget = ({
2773
2775
  senderType: msg.sender_type,
2774
2776
  senderName: msg.sender_name,
2775
2777
  timestamp: formatTime(msg.created_at),
2776
- isRead: msg.is_read
2778
+ isRead: msg.is_read,
2779
+ isPending: msg.is_pending,
2780
+ isFailed: msg.is_failed
2777
2781
  },
2778
2782
  msg.id
2779
2783
  )),
@@ -2824,6 +2828,7 @@ var ChatBubble = ({
2824
2828
  const [loading, setLoading] = (0, import_react24.useState)(false);
2825
2829
  const [typing, setTyping] = (0, import_react24.useState)(false);
2826
2830
  const [unreadCount, setUnreadCount] = (0, import_react24.useState)(0);
2831
+ const seenMessageIds = (0, import_react24.useRef)(/* @__PURE__ */ new Set());
2827
2832
  const initChat = (0, import_react24.useCallback)(async () => {
2828
2833
  if (conversationId) return;
2829
2834
  setLoading(true);
@@ -2837,14 +2842,14 @@ var ChatBubble = ({
2837
2842
  const conn = client.chat.connect(result.conversation_id);
2838
2843
  setConnection(conn);
2839
2844
  const existingMessages = await conn.getMessages();
2845
+ existingMessages.forEach((m) => seenMessageIds.current.add(m.id));
2840
2846
  setMessages(existingMessages);
2841
2847
  conn.onMessage((msg) => {
2842
- setMessages((prev) => {
2843
- if (prev.some((m) => m.id === msg.id)) {
2844
- return prev;
2845
- }
2846
- return [...prev, msg];
2847
- });
2848
+ if (seenMessageIds.current.has(msg.id)) {
2849
+ return;
2850
+ }
2851
+ seenMessageIds.current.add(msg.id);
2852
+ setMessages((prev) => [...prev, msg]);
2848
2853
  if (!isOpen && msg.sender_type !== "visitor") {
2849
2854
  setUnreadCount((c) => c + 1);
2850
2855
  }
@@ -2875,10 +2880,28 @@ var ChatBubble = ({
2875
2880
  };
2876
2881
  const handleSend = async (content) => {
2877
2882
  if (!connection) return;
2878
- try {
2879
- await connection.send(content);
2883
+ const tempId = -Date.now();
2884
+ const pendingMessage = {
2885
+ id: tempId,
2886
+ content,
2887
+ sender_type: "visitor",
2888
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
2889
+ is_pending: true
2890
+ };
2891
+ setMessages((prev) => [...prev, pendingMessage]);
2892
+ try {
2893
+ const sentMessage = await connection.send(content);
2894
+ if (sentMessage) {
2895
+ seenMessageIds.current.add(sentMessage.id);
2896
+ setMessages(
2897
+ (prev) => prev.map((m) => m.id === tempId ? { ...sentMessage, is_pending: false } : m)
2898
+ );
2899
+ }
2880
2900
  } catch (error) {
2881
2901
  console.error("Failed to send message:", error);
2902
+ setMessages(
2903
+ (prev) => prev.map((m) => m.id === tempId ? { ...m, is_pending: false, is_failed: true } : m)
2904
+ );
2882
2905
  }
2883
2906
  };
2884
2907
  const handleTyping = () => {
package/dist/index.mjs CHANGED
@@ -2490,19 +2490,21 @@ function RichContent({
2490
2490
  }
2491
2491
 
2492
2492
  // src/components/chat/ChatBubble.tsx
2493
- import { useState as useState22, useEffect as useEffect21, useCallback as useCallback22 } from "react";
2493
+ import { useState as useState22, useEffect as useEffect21, useCallback as useCallback22, useRef as useRef3 } from "react";
2494
2494
 
2495
2495
  // src/components/chat/ChatWidget.tsx
2496
2496
  import { useRef as useRef2, useEffect as useEffect20 } from "react";
2497
2497
 
2498
2498
  // src/components/chat/ChatMessage.tsx
2499
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
2499
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
2500
2500
  var ChatMessage = ({
2501
2501
  content,
2502
2502
  senderType,
2503
2503
  senderName,
2504
2504
  timestamp,
2505
2505
  isRead,
2506
+ isPending,
2507
+ isFailed,
2506
2508
  className = ""
2507
2509
  }) => {
2508
2510
  const isVisitor = senderType === "visitor";
@@ -2516,12 +2518,12 @@ var ChatMessage = ({
2516
2518
  className: `diffsome-chat-message ${isVisitor ? "diffsome-chat-message-visitor" : "diffsome-chat-message-agent"} ${className}`,
2517
2519
  children: [
2518
2520
  !isVisitor && senderName && /* @__PURE__ */ jsx3("div", { className: "diffsome-chat-message-sender", children: senderName }),
2519
- /* @__PURE__ */ jsxs2("div", { className: "diffsome-chat-message-bubble", children: [
2521
+ /* @__PURE__ */ jsxs2("div", { className: `diffsome-chat-message-bubble ${isPending ? "diffsome-chat-message-pending" : ""} ${isFailed ? "diffsome-chat-message-failed" : ""}`, children: [
2520
2522
  /* @__PURE__ */ jsx3("div", { className: "diffsome-chat-message-content", children: content }),
2521
- timestamp && /* @__PURE__ */ jsxs2("div", { className: "diffsome-chat-message-time", children: [
2523
+ /* @__PURE__ */ jsx3("div", { className: "diffsome-chat-message-time", children: isPending ? /* @__PURE__ */ jsx3("span", { className: "diffsome-chat-message-status", children: "Sending..." }) : isFailed ? /* @__PURE__ */ jsx3("span", { className: "diffsome-chat-message-status diffsome-chat-message-error", children: "Failed" }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
2522
2524
  timestamp,
2523
2525
  isVisitor && isRead && /* @__PURE__ */ jsx3("span", { className: "diffsome-chat-message-read", children: " \u2713" })
2524
- ] })
2526
+ ] }) })
2525
2527
  ] })
2526
2528
  ]
2527
2529
  }
@@ -2619,7 +2621,7 @@ var ChatInput = ({
2619
2621
  };
2620
2622
 
2621
2623
  // src/components/chat/ChatWidget.tsx
2622
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
2624
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
2623
2625
  var ChatWidget = ({
2624
2626
  messages,
2625
2627
  onSend,
@@ -2673,7 +2675,7 @@ var ChatWidget = ({
2673
2675
  /* @__PURE__ */ jsx5("div", { className: "diffsome-chat-messages", children: loading ? /* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-loading", children: [
2674
2676
  /* @__PURE__ */ jsx5("div", { className: "diffsome-chat-loading-spinner" }),
2675
2677
  /* @__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: [
2678
+ ] }) : messages.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "diffsome-chat-empty", children: /* @__PURE__ */ jsx5("span", { children: "No messages yet. Start the conversation!" }) }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
2677
2679
  messages.map((msg) => /* @__PURE__ */ jsx5(
2678
2680
  ChatMessage,
2679
2681
  {
@@ -2681,7 +2683,9 @@ var ChatWidget = ({
2681
2683
  senderType: msg.sender_type,
2682
2684
  senderName: msg.sender_name,
2683
2685
  timestamp: formatTime(msg.created_at),
2684
- isRead: msg.is_read
2686
+ isRead: msg.is_read,
2687
+ isPending: msg.is_pending,
2688
+ isFailed: msg.is_failed
2685
2689
  },
2686
2690
  msg.id
2687
2691
  )),
@@ -2732,6 +2736,7 @@ var ChatBubble = ({
2732
2736
  const [loading, setLoading] = useState22(false);
2733
2737
  const [typing, setTyping] = useState22(false);
2734
2738
  const [unreadCount, setUnreadCount] = useState22(0);
2739
+ const seenMessageIds = useRef3(/* @__PURE__ */ new Set());
2735
2740
  const initChat = useCallback22(async () => {
2736
2741
  if (conversationId) return;
2737
2742
  setLoading(true);
@@ -2745,14 +2750,14 @@ var ChatBubble = ({
2745
2750
  const conn = client.chat.connect(result.conversation_id);
2746
2751
  setConnection(conn);
2747
2752
  const existingMessages = await conn.getMessages();
2753
+ existingMessages.forEach((m) => seenMessageIds.current.add(m.id));
2748
2754
  setMessages(existingMessages);
2749
2755
  conn.onMessage((msg) => {
2750
- setMessages((prev) => {
2751
- if (prev.some((m) => m.id === msg.id)) {
2752
- return prev;
2753
- }
2754
- return [...prev, msg];
2755
- });
2756
+ if (seenMessageIds.current.has(msg.id)) {
2757
+ return;
2758
+ }
2759
+ seenMessageIds.current.add(msg.id);
2760
+ setMessages((prev) => [...prev, msg]);
2756
2761
  if (!isOpen && msg.sender_type !== "visitor") {
2757
2762
  setUnreadCount((c) => c + 1);
2758
2763
  }
@@ -2783,10 +2788,28 @@ var ChatBubble = ({
2783
2788
  };
2784
2789
  const handleSend = async (content) => {
2785
2790
  if (!connection) return;
2786
- try {
2787
- await connection.send(content);
2791
+ const tempId = -Date.now();
2792
+ const pendingMessage = {
2793
+ id: tempId,
2794
+ content,
2795
+ sender_type: "visitor",
2796
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
2797
+ is_pending: true
2798
+ };
2799
+ setMessages((prev) => [...prev, pendingMessage]);
2800
+ try {
2801
+ const sentMessage = await connection.send(content);
2802
+ if (sentMessage) {
2803
+ seenMessageIds.current.add(sentMessage.id);
2804
+ setMessages(
2805
+ (prev) => prev.map((m) => m.id === tempId ? { ...sentMessage, is_pending: false } : m)
2806
+ );
2807
+ }
2788
2808
  } catch (error) {
2789
2809
  console.error("Failed to send message:", error);
2810
+ setMessages(
2811
+ (prev) => prev.map((m) => m.id === tempId ? { ...m, is_pending: false, is_failed: true } : m)
2812
+ );
2790
2813
  }
2791
2814
  };
2792
2815
  const handleTyping = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diffsome/react",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
4
4
  "description": "React hooks and providers for Diffsome SDK - Headless e-commerce & CMS",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",