@droppii-org/chat-sdk 0.6.24 → 0.6.26
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/context/ChatContext.d.ts.map +1 -1
- package/dist/context/ChatContext.js +13 -2
- package/dist/hooks/conversation/useResolveConversation.d.ts.map +1 -1
- package/dist/hooks/conversation/useResolveConversation.js +22 -6
- package/dist/screens/conversation-inbox/index.d.ts.map +1 -1
- package/dist/screens/conversation-inbox/index.js +12 -8
- package/dist/store/conversation.d.ts +1 -0
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +38 -9
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,iBAAiB,EAGlB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,iBAAiB,EAGlB,MAAM,cAAc,CAAC;AAWtB,eAAO,MAAM,WAAW,0CAQtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAU5D,eAAO,MAAM,YAAY,GAAI,oGAQ1B,iBAAiB,4CAgJnB,CAAC"}
|
|
@@ -6,9 +6,10 @@ import { ConnectStatus, SyncStatus, } from "../types/chat";
|
|
|
6
6
|
import { DChatSDK } from "../constants/sdk";
|
|
7
7
|
import MainLayout from "../layout";
|
|
8
8
|
import useAuthStore from "../store/auth";
|
|
9
|
-
import { setUrlStateEnabled } from "../store/conversation";
|
|
9
|
+
import { setUrlNavigate, setUrlStateEnabled } from "../store/conversation";
|
|
10
10
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
11
11
|
import { ConfigProvider } from "antd";
|
|
12
|
+
import { StyleProvider } from "@ant-design/cssinjs";
|
|
12
13
|
const queryClient = new QueryClient();
|
|
13
14
|
export const ChatContext = createContext({
|
|
14
15
|
user: null,
|
|
@@ -35,6 +36,16 @@ export const ChatProvider = ({ children, config, renderCustomMessage, onNavigate
|
|
|
35
36
|
useEffect(() => {
|
|
36
37
|
setUrlStateEnabled(useUrlState);
|
|
37
38
|
}, [useUrlState]);
|
|
39
|
+
// Lets clearSelectedConversation route URL cleanup through the host's
|
|
40
|
+
// router instead of a raw history.replaceState.
|
|
41
|
+
// Gated on useUrlState like useChatNavigate, even though the sole current
|
|
42
|
+
// consumer (clearSelectedConversation) already checks urlStateEnabled
|
|
43
|
+
// itself — keeps this registration from becoming a footgun if a future
|
|
44
|
+
// bubble-mode-unaware consumer is added.
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
setUrlNavigate(useUrlState ? (onNavigate !== null && onNavigate !== void 0 ? onNavigate : null) : null);
|
|
47
|
+
return () => setUrlNavigate(null);
|
|
48
|
+
}, [onNavigate, useUrlState]);
|
|
38
49
|
const themeStyle = {
|
|
39
50
|
"--dc-color-primary": (_a = theme === null || theme === void 0 ? void 0 : theme.primary) !== null && _a !== void 0 ? _a : DEFAULT_THEME["--dc-color-primary"],
|
|
40
51
|
"--dc-color-primary-hover": (_b = theme === null || theme === void 0 ? void 0 : theme.primaryHover) !== null && _b !== void 0 ? _b : DEFAULT_THEME["--dc-color-primary-hover"],
|
|
@@ -121,5 +132,5 @@ export const ChatProvider = ({ children, config, renderCustomMessage, onNavigate
|
|
|
121
132
|
onNavigate,
|
|
122
133
|
useUrlState,
|
|
123
134
|
renderGroupAccessModal,
|
|
124
|
-
}, children: _jsx(ConfigProvider, { getPopupContainer: () => { var _a; return (_a = rootRef.current) !== null && _a !== void 0 ? _a : document.body; }, children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx("div", { ref: rootRef, style: themeStyle, className: "contents", children: _jsx(MainLayout, { children: children }) }) }) }) }));
|
|
135
|
+
}, children: _jsx(StyleProvider, { hashPriority: "high", children: _jsx(ConfigProvider, { getPopupContainer: () => { var _a; return (_a = rootRef.current) !== null && _a !== void 0 ? _a : document.body; }, children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx("div", { ref: rootRef, style: themeStyle, className: "contents", children: _jsx(MainLayout, { children: children }) }) }) }) }) }));
|
|
125
136
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useResolveConversation.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useResolveConversation.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAe,MAAM,8BAA8B,CAAC;AAU7E,MAAM,WAAW,4BAA4B;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2BD,eAAO,MAAM,wBAAwB,GACnC,OAAO,MAAM,KACZ,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAWjC,CAAC;
|
|
1
|
+
{"version":3,"file":"useResolveConversation.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useResolveConversation.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAe,MAAM,8BAA8B,CAAC;AAU7E,MAAM,WAAW,4BAA4B;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2BD,eAAO,MAAM,wBAAwB,GACnC,OAAO,MAAM,KACZ,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAWjC,CAAC;AAkDF,eAAO,MAAM,sBAAsB,GAAI,wDAMpC,4BAA4B;;;CA4H9B,CAAC"}
|
|
@@ -32,21 +32,37 @@ export const fetchConversationByBotId = async (botId) => {
|
|
|
32
32
|
const fetchConversationByTarget = ({ conversationId, userId, groupId, botId, }) => {
|
|
33
33
|
if (conversationId)
|
|
34
34
|
return fetchByConversationId(conversationId);
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
// groupId before userId: a group-message notification link carries both
|
|
36
|
+
// (the group, plus the sender's userId as secondary info) — resolving
|
|
37
|
+
// userId first would wrongly open a 1:1 thread with the sender instead
|
|
38
|
+
// of the group.
|
|
37
39
|
if (groupId)
|
|
38
40
|
return fetchBySource(groupId, SessionType.Group);
|
|
39
41
|
if (botId)
|
|
40
42
|
return fetchConversationByBotId(botId);
|
|
43
|
+
if (userId)
|
|
44
|
+
return fetchBySource(userId, SessionType.Single);
|
|
41
45
|
return Promise.resolve(null);
|
|
42
46
|
};
|
|
47
|
+
// Mirrors fetchConversationByTarget's conversationId → groupId → botId →
|
|
48
|
+
// userId precedence exactly — matching on any present field independently
|
|
49
|
+
// (the old OR-chain) let a stale field win over the one that's actually
|
|
50
|
+
// authoritative. Concretely: viewing a 1:1 with sender X, then a group
|
|
51
|
+
// notification for the same sender arrives ({groupId, userId: X}) — matching
|
|
52
|
+
// on userId alone would treat the already-open 1:1 as satisfying the group
|
|
53
|
+
// target and skip resolving the group entirely.
|
|
43
54
|
const matchesTarget = (conversation, { conversationId, userId, groupId, botId }) => {
|
|
44
55
|
if (!conversation)
|
|
45
56
|
return false;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
if (conversationId)
|
|
58
|
+
return conversation.conversationID === conversationId;
|
|
59
|
+
if (groupId)
|
|
60
|
+
return conversation.groupID === groupId;
|
|
61
|
+
if (botId)
|
|
62
|
+
return resolveConversationBotId(conversation) === botId;
|
|
63
|
+
if (userId)
|
|
64
|
+
return conversation.userID === userId;
|
|
65
|
+
return false;
|
|
50
66
|
};
|
|
51
67
|
const targetKey = ({ conversationId, userId, groupId, botId, messageId, }) => `${conversationId !== null && conversationId !== void 0 ? conversationId : ""}|${userId !== null && userId !== void 0 ? userId : ""}|${groupId !== null && groupId !== void 0 ? groupId : ""}|${botId !== null && botId !== void 0 ? botId : ""}|${messageId !== null && messageId !== void 0 ? messageId : ""}`;
|
|
52
68
|
export const useResolveConversation = ({ conversationId, userId, groupId, botId, messageId, }) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-inbox/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAM/D,MAAM,WAAW,2BAA2B;IAC1C,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,6FAA6F;IAC7F,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3E;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-inbox/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAM/D,MAAM,WAAW,2BAA2B;IAC1C,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,6FAA6F;IAC7F,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3E;AAkOD,QAAA,MAAM,sBAAsB,GAAI,OAAO,2BAA2B,4CAQjE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -80,20 +80,24 @@ const useInboxConversationList = (chatCategory) => {
|
|
|
80
80
|
const DChatConversationInboxBody = ({ onSelectThread, className, moreOptions, showSearch = true, headerTitle, headerRightSlot, onCopyMessageLink, target, conversationList, }) => {
|
|
81
81
|
const { t } = useTranslation("conversation-inbox");
|
|
82
82
|
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
83
|
+
const removedFromGroupModalOpen = useConversationStore((state) => state.removedFromGroupModalOpen);
|
|
83
84
|
const [isSearchOpen, { setTrue: openSearch, setFalse: closeSearch }] = useBoolean(false);
|
|
84
85
|
const { threadId, userId, groupId, botId, messageId } = target;
|
|
85
86
|
// Any of the four targets opens the detail screen — useResolveConversation
|
|
86
87
|
// turns userId/groupId/botId into a thread (creating the bot one when
|
|
87
88
|
// missing), so entry points that only know the peer still work.
|
|
88
89
|
// threadId alone must also match selectedConversationId: clearSelectedConversation
|
|
89
|
-
// strips threadId from the URL
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
// strips threadId (and groupId/userId/botId) from the URL through the
|
|
91
|
+
// host's router (setUrlNavigate) when one is registered, so useSearchParams
|
|
92
|
+
// picks up the change on its own — but the
|
|
93
|
+
// modal-open check still covers the brief render between the reject firing
|
|
94
|
+
// and that router navigation completing, so the list shows immediately
|
|
95
|
+
// instead of flashing empty behind the modal.
|
|
96
|
+
const hasConversationTarget = !removedFromGroupModalOpen &&
|
|
97
|
+
!!((threadId && threadId === selectedConversationId) ||
|
|
98
|
+
userId ||
|
|
99
|
+
groupId ||
|
|
100
|
+
botId);
|
|
97
101
|
if (hasConversationTarget) {
|
|
98
102
|
return (_jsx(DChatConversationDetail, { className: className, moreOptions: moreOptions, conversationId: threadId !== null && threadId !== void 0 ? threadId : undefined, userId: userId, groupId: groupId, botId: botId, onCopyMessageLink: onCopyMessageLink, messageId: messageId }));
|
|
99
103
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ConversationStore } from "./type";
|
|
2
2
|
export declare const setUrlStateEnabled: (enabled: boolean) => void;
|
|
3
|
+
export declare const setUrlNavigate: (fn: ((url: string) => void) | null) => void;
|
|
3
4
|
declare const useConversationStore: import("zustand").UseBoundStore<import("zustand").StoreApi<ConversationStore>>;
|
|
4
5
|
export default useConversationStore;
|
|
5
6
|
//# sourceMappingURL=conversation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/store/conversation.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAY3C,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,SAElD,CAAC;AAEF,QAAA,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/store/conversation.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAY3C,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,SAElD,CAAC;AAUF,eAAO,MAAM,cAAc,GAAI,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,SAEhE,CAAC;AAEF,QAAA,MAAM,oBAAoB,gFAsZvB,CAAC;AAEJ,eAAe,oBAAoB,CAAC"}
|
|
@@ -13,6 +13,17 @@ let urlStateEnabled = true;
|
|
|
13
13
|
export const setUrlStateEnabled = (enabled) => {
|
|
14
14
|
urlStateEnabled = enabled;
|
|
15
15
|
};
|
|
16
|
+
// Module-level (not store state): ChatProvider syncs this from its onNavigate
|
|
17
|
+
// prop, same reason as urlStateEnabled above. clearSelectedConversation uses
|
|
18
|
+
// this instead of window.history.replaceState directly — Next's Pages Router
|
|
19
|
+
// compat shim for useSearchParams only re-reads the URL after a router
|
|
20
|
+
// navigation, never after a raw history.replaceState, so a caller reading
|
|
21
|
+
// groupId/userId/botId via useSearchParams would keep seeing the stale,
|
|
22
|
+
// just-cleared value forever.
|
|
23
|
+
let navigate = null;
|
|
24
|
+
export const setUrlNavigate = (fn) => {
|
|
25
|
+
navigate = fn;
|
|
26
|
+
};
|
|
16
27
|
const useConversationStore = create((set, get) => ({
|
|
17
28
|
conversationData: null,
|
|
18
29
|
setConversationData: (data, dataSearchClientMsgID, options) => {
|
|
@@ -258,19 +269,37 @@ const useConversationStore = create((set, get) => ({
|
|
|
258
269
|
clearSelectedConversation: () => {
|
|
259
270
|
// DeskConversationList's threadId-driven effect re-selects the same
|
|
260
271
|
// conversation on its next run otherwise (conversationList changes
|
|
261
|
-
// trigger it) — clobbering this reset right back.
|
|
262
|
-
// dependency by design: this store has no access to one.
|
|
272
|
+
// trigger it) — clobbering this reset right back.
|
|
263
273
|
if (urlStateEnabled && typeof window !== "undefined") {
|
|
264
274
|
const params = new URLSearchParams(window.location.search);
|
|
265
|
-
// `conversationId` is an accepted alias for `threadId
|
|
266
|
-
//
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
275
|
+
// `conversationId` is an accepted alias for `threadId`; groupId/botId/
|
|
276
|
+
// userId are the BIZ inbox's notification/deep-link entry params —
|
|
277
|
+
// leaving any of these behind would let the next effect run (or a
|
|
278
|
+
// URL-reading hasConversationTarget check) re-select the target we
|
|
279
|
+
// just rejected. Listed in the same conversationId -> groupId -> userId
|
|
280
|
+
// -> botId precedence useResolveConversation resolves them by.
|
|
281
|
+
const staleParams = [
|
|
282
|
+
"threadId",
|
|
283
|
+
"conversationId",
|
|
284
|
+
"groupId",
|
|
285
|
+
"botId",
|
|
286
|
+
"userId",
|
|
287
|
+
];
|
|
288
|
+
const hadStaleParam = staleParams.some((key) => params.has(key));
|
|
289
|
+
if (hadStaleParam) {
|
|
290
|
+
staleParams.forEach((key) => params.delete(key));
|
|
271
291
|
const query = params.toString();
|
|
272
292
|
const url = `${window.location.pathname}${query ? `?${query}` : ""}`;
|
|
273
|
-
|
|
293
|
+
// Prefer the host's router (set via setUrlNavigate) so Next's
|
|
294
|
+
// useSearchParams actually re-reads the cleared params on the next
|
|
295
|
+
// render — a raw history.replaceState leaves useSearchParams stale
|
|
296
|
+
// until an unrelated router navigation happens to occur. Falls back
|
|
297
|
+
// to history.replaceState when no navigate fn is registered (e.g.
|
|
298
|
+
// CRM never set one — matches this function's prior behavior there).
|
|
299
|
+
if (navigate)
|
|
300
|
+
navigate(url);
|
|
301
|
+
else
|
|
302
|
+
window.history.replaceState(null, "", url);
|
|
274
303
|
}
|
|
275
304
|
}
|
|
276
305
|
// Deselecting is normal navigation, not a reason to drop the groupID
|