@droppii-org/chat-sdk 0.6.23 → 0.6.25
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/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationDetailInput.js +5 -1
- package/dist/components/message/footer/mention/MentionMenu.d.ts.map +1 -1
- package/dist/components/message/footer/mention/MentionMenu.js +5 -2
- package/dist/components/message/footer/mention/useMentionOptions.d.ts +1 -1
- package/dist/components/message/footer/mention/useMentionOptions.d.ts.map +1 -1
- package/dist/components/message/footer/mention/useMentionOptions.js +7 -42
- package/dist/context/ChatContext.d.ts.map +1 -1
- package/dist/context/ChatContext.js +11 -1
- 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":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAmB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,QAAA,MAAM,uBAAuB,GAAI,4EAM9B,4BAA4B,
|
|
1
|
+
{"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAmB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,QAAA,MAAM,uBAAuB,GAAI,4EAM9B,4BAA4B,4CAurB9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -97,11 +97,15 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
|
|
|
97
97
|
const [dismissedTriggerStart, setDismissedTriggerStart] = useState(null);
|
|
98
98
|
// 1v1 threads have no groupID — mentions are a group-only concept
|
|
99
99
|
// (matches CRM's MentionMenu, which already guards on the same field).
|
|
100
|
+
// Bot threads don't support tagging at all — not just CS staff filtering
|
|
101
|
+
// (DROPPII-30799 follow-up): the whole trigger is suppressed, same as
|
|
102
|
+
// groupless 1v1 threads.
|
|
100
103
|
const mentionTrigger = !(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID) ||
|
|
104
|
+
isBotPeer(conversationData) ||
|
|
101
105
|
(rawMentionTrigger === null || rawMentionTrigger === void 0 ? void 0 : rawMentionTrigger.triggerStart) === dismissedTriggerStart
|
|
102
106
|
? null
|
|
103
107
|
: rawMentionTrigger;
|
|
104
|
-
const rawMentionOptions = useMentionOptions(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID, (_a = mentionTrigger === null || mentionTrigger === void 0 ? void 0 : mentionTrigger.query) !== null && _a !== void 0 ? _a : ""
|
|
108
|
+
const rawMentionOptions = useMentionOptions(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID, (_a = mentionTrigger === null || mentionTrigger === void 0 ? void 0 : mentionTrigger.query) !== null && _a !== void 0 ? _a : "");
|
|
105
109
|
const isMentionMenuOpen = mentionTrigger !== null;
|
|
106
110
|
const [selectedMentionIndex, setSelectedMentionIndex] = useState(0);
|
|
107
111
|
const { tokens: mentionTokens, addToken, onValueChange, resetTokens } = useMentionTokens();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MentionMenu.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/MentionMenu.tsx"],"names":[],"mappings":"AA8BA,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAWjE,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"MentionMenu.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/MentionMenu.tsx"],"names":[],"mappings":"AA8BA,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAWjE,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,WAAW,GAAI,0BAA0B,gBAAgB,mDA4I9D,CAAC;AA+CF,eAAe,WAAW,CAAC"}
|
|
@@ -41,7 +41,7 @@ const MentionMenu = ({ groupID, isBotThread }) => {
|
|
|
41
41
|
const checkForMentionMatch = useBasicTypeaheadTriggerMatch("@", {
|
|
42
42
|
minLength: 0,
|
|
43
43
|
});
|
|
44
|
-
const options = useMentionOptions(groupID, query !== null && query !== void 0 ? query : ""
|
|
44
|
+
const options = useMentionOptions(groupID, query !== null && query !== void 0 ? query : "");
|
|
45
45
|
// Re-evaluated per query change (menu re-opens/re-queries on every "@"),
|
|
46
46
|
// so this stays in sync with mentions added/removed since the last count.
|
|
47
47
|
const mentionedUserIDs = useMemo(() => editor.getEditorState().read(() => $getMentionedUserIDs($getRoot())), [editor, query]);
|
|
@@ -71,7 +71,10 @@ const MentionMenu = ({ groupID, isBotThread }) => {
|
|
|
71
71
|
});
|
|
72
72
|
closeMenu();
|
|
73
73
|
}, [editor]);
|
|
74
|
-
|
|
74
|
+
// Bot threads don't support tagging at all, not just CS-staff filtering
|
|
75
|
+
// (DROPPII-30799 follow-up) — the whole trigger is suppressed, same as
|
|
76
|
+
// groupless 1v1 threads.
|
|
77
|
+
if (!groupID || isBotThread)
|
|
75
78
|
return null;
|
|
76
79
|
return (_jsx(LexicalTypeaheadMenuPlugin, { onQueryChange: setQuery, onSelectOption: onSelectOption, onOpen: () => setIsMentionMenuOpen(true), onClose: () => setIsMentionMenuOpen(false), triggerFn: checkForMentionMatch, options: typeaheadOptions, menuRenderFn: (anchorElementRef, { selectedIndex, setHighlightedIndex, selectOptionAndCleanUp }) => {
|
|
77
80
|
if (!anchorElementRef.current)
|
|
@@ -5,5 +5,5 @@ export interface MentionOption {
|
|
|
5
5
|
isAtAll: boolean;
|
|
6
6
|
}
|
|
7
7
|
export declare const ALL_MEMBERS_USER_ID = "__all__";
|
|
8
|
-
export declare const useMentionOptions: (groupID: string | undefined, query: string
|
|
8
|
+
export declare const useMentionOptions: (groupID: string | undefined, query: string) => MentionOption[];
|
|
9
9
|
//# sourceMappingURL=useMentionOptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMentionOptions.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/useMentionOptions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useMentionOptions.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/useMentionOptions.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAe7C,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,GAAG,SAAS,EAC3B,OAAO,MAAM,KACZ,aAAa,EAyCf,CAAC"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo } from "react";
|
|
2
2
|
import { useTranslation } from "react-i18next";
|
|
3
3
|
import { useGroupMembers } from "../../../../hooks/group/useGroupMembers";
|
|
4
4
|
import useAuthStore from "../../../../store/auth";
|
|
5
|
-
import useUsersInfoStore from "../../../../store/usersInfo";
|
|
6
|
-
import { DChatSDK } from "../../../../constants/sdk";
|
|
7
|
-
import { AccountType } from "../../../../types/chat";
|
|
8
5
|
export const ALL_MEMBERS_USER_ID = "__all__";
|
|
9
6
|
// Prefix matches rank above mid-string matches, then alphabetical — matches
|
|
10
7
|
// the "closest match first" ranking spec'd for this feature (not just a
|
|
@@ -15,52 +12,20 @@ const matchRank = (displayName, keyword) => {
|
|
|
15
12
|
return 0;
|
|
16
13
|
return 1;
|
|
17
14
|
};
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
const
|
|
23
|
-
var _a, _b, _c;
|
|
24
|
-
try {
|
|
25
|
-
return (((_c = (_b = (_a = JSON.parse(ex || "{}")) === null || _a === void 0 ? void 0 : _a.userInfo) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.accountType) === AccountType.Staff);
|
|
26
|
-
}
|
|
27
|
-
catch (_d) {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
export const useMentionOptions = (groupID, query,
|
|
32
|
-
// Bot threads shouldn't surface CS/staff accounts as tag targets — they
|
|
33
|
-
// aren't part of the customer-facing conversation. Real member-managed
|
|
34
|
-
// groups have no such restriction (DROPPII-30799).
|
|
35
|
-
excludeStaff = false) => {
|
|
15
|
+
// Bot threads don't reach this hook at all — both mention triggers
|
|
16
|
+
// (ConversationDetailInput, MentionMenu) suppress the trigger entirely for
|
|
17
|
+
// bot peers (DROPPII-30799 follow-up), so there's no staff-filtering concern
|
|
18
|
+
// left to handle here.
|
|
19
|
+
export const useMentionOptions = (groupID, query) => {
|
|
36
20
|
const { t } = useTranslation();
|
|
37
21
|
const { members } = useGroupMembers(groupID);
|
|
38
22
|
const currentUserID = useAuthStore((state) => state.userID);
|
|
39
|
-
const usersInfo = useUsersInfoStore((state) => state.usersInfo);
|
|
40
|
-
// Only fetch when actually needed: bot threads (excludeStaff) require the
|
|
41
|
-
// account-level accountType, which GroupMemberItem.ex doesn't carry.
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
if (!excludeStaff || members.length === 0)
|
|
44
|
-
return;
|
|
45
|
-
const { usersInfo: cache, upsertUsers } = useUsersInfoStore.getState();
|
|
46
|
-
const missingIds = members
|
|
47
|
-
.map((member) => member.userID)
|
|
48
|
-
.filter((userID) => !cache[userID]);
|
|
49
|
-
if (missingIds.length === 0)
|
|
50
|
-
return;
|
|
51
|
-
DChatSDK.getUsersInfo(missingIds)
|
|
52
|
-
.then(({ data }) => upsertUsers(data))
|
|
53
|
-
.catch((error) => {
|
|
54
|
-
console.error("Error fetching mention candidates' user info:", error);
|
|
55
|
-
});
|
|
56
|
-
}, [excludeStaff, members]);
|
|
57
23
|
return useMemo(() => {
|
|
58
24
|
const keyword = query.trim().toLowerCase();
|
|
59
25
|
// Self-tagging isn't a useful mention target — the sender already
|
|
60
26
|
// knows who they are — so the current user is filtered out entirely.
|
|
61
27
|
const memberOptions = members
|
|
62
28
|
.filter((member) => member.userID !== currentUserID)
|
|
63
|
-
.filter((member) => { var _a; return !excludeStaff || !isStaffMember((_a = usersInfo[member.userID]) === null || _a === void 0 ? void 0 : _a.ex); })
|
|
64
29
|
.map((member) => ({
|
|
65
30
|
userID: member.userID,
|
|
66
31
|
displayName: member.nickname || member.userID,
|
|
@@ -83,5 +48,5 @@ excludeStaff = false) => {
|
|
|
83
48
|
};
|
|
84
49
|
const matchesAll = !keyword || allOption.displayName.toLowerCase().includes(keyword);
|
|
85
50
|
return matchesAll ? [allOption, ...memberOptions] : memberOptions;
|
|
86
|
-
}, [members, query, t, currentUserID
|
|
51
|
+
}, [members, query, t, currentUserID]);
|
|
87
52
|
};
|
|
@@ -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;AAUtB,eAAO,MAAM,WAAW,0CAQtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAU5D,eAAO,MAAM,YAAY,GAAI,oGAQ1B,iBAAiB,
|
|
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;AAUtB,eAAO,MAAM,WAAW,0CAQtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAU5D,eAAO,MAAM,YAAY,GAAI,oGAQ1B,iBAAiB,4CA8InB,CAAC"}
|
|
@@ -6,7 +6,7 @@ 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
12
|
const queryClient = new QueryClient();
|
|
@@ -35,6 +35,16 @@ export const ChatProvider = ({ children, config, renderCustomMessage, onNavigate
|
|
|
35
35
|
useEffect(() => {
|
|
36
36
|
setUrlStateEnabled(useUrlState);
|
|
37
37
|
}, [useUrlState]);
|
|
38
|
+
// Lets clearSelectedConversation route URL cleanup through the host's
|
|
39
|
+
// router instead of a raw history.replaceState.
|
|
40
|
+
// Gated on useUrlState like useChatNavigate, even though the sole current
|
|
41
|
+
// consumer (clearSelectedConversation) already checks urlStateEnabled
|
|
42
|
+
// itself — keeps this registration from becoming a footgun if a future
|
|
43
|
+
// bubble-mode-unaware consumer is added.
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
setUrlNavigate(useUrlState ? (onNavigate !== null && onNavigate !== void 0 ? onNavigate : null) : null);
|
|
46
|
+
return () => setUrlNavigate(null);
|
|
47
|
+
}, [onNavigate, useUrlState]);
|
|
38
48
|
const themeStyle = {
|
|
39
49
|
"--dc-color-primary": (_a = theme === null || theme === void 0 ? void 0 : theme.primary) !== null && _a !== void 0 ? _a : DEFAULT_THEME["--dc-color-primary"],
|
|
40
50
|
"--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"],
|
|
@@ -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
|