@droppii-org/chat-sdk 0.8.0 → 0.8.2

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.
Files changed (170) hide show
  1. package/dist/components/canned-response/cannedTrigger.d.ts +2 -0
  2. package/dist/components/canned-response/cannedTrigger.d.ts.map +1 -0
  3. package/dist/components/canned-response/cannedTrigger.js +3 -0
  4. package/dist/components/canned-response/insertCannedContent.js +2 -2
  5. package/dist/components/conversation/ConversationByGroupItem.js +1 -1
  6. package/dist/components/conversation/ConversationBySessionItem.js +4 -4
  7. package/dist/components/conversation/internalNotePreview.d.ts +1 -1
  8. package/dist/components/conversation/internalNotePreview.d.ts.map +1 -1
  9. package/dist/components/conversation/internalNotePreview.js +22 -3
  10. package/dist/components/conversation/rowTime.d.ts +2 -2
  11. package/dist/components/conversation/rowTime.d.ts.map +1 -1
  12. package/dist/components/conversation/rowTime.js +2 -4
  13. package/dist/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
  14. package/dist/components/conversation-detail/ConversationDetailInput.js +8 -3
  15. package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
  16. package/dist/components/conversation-detail/ConversationMessageList.js +7 -4
  17. package/dist/components/conversation-detail/bot/BotMenuSheet.d.ts.map +1 -1
  18. package/dist/components/conversation-detail/bot/BotMenuSheet.js +1 -1
  19. package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
  20. package/dist/components/conversation-inbox/ConversationInboxList.js +4 -0
  21. package/dist/components/conversation-inbox/InboxBootStatus.d.ts.map +1 -1
  22. package/dist/components/conversation-inbox/InboxBootStatus.js +10 -2
  23. package/dist/components/group/CreateGroupForm.d.ts.map +1 -1
  24. package/dist/components/group/CreateGroupForm.js +2 -1
  25. package/dist/components/group/CreateGroupFormCrmView.d.ts.map +1 -1
  26. package/dist/components/group/CreateGroupFormCrmView.js +1 -1
  27. package/dist/components/group/GroupMemberPickerCrm.d.ts.map +1 -1
  28. package/dist/components/group/GroupMemberPickerCrm.js +1 -1
  29. package/dist/components/media-collection/FileCollection.d.ts.map +1 -1
  30. package/dist/components/media-collection/FileCollection.js +2 -1
  31. package/dist/components/media-collection/ImageCollection.d.ts.map +1 -1
  32. package/dist/components/media-collection/ImageCollection.js +2 -1
  33. package/dist/components/media-collection/LinkCollection.d.ts.map +1 -1
  34. package/dist/components/media-collection/LinkCollection.js +14 -26
  35. package/dist/components/media-collection/VideoCollection.d.ts.map +1 -1
  36. package/dist/components/media-collection/VideoCollection.js +2 -1
  37. package/dist/components/media-resources/ResourceScrollContainer.d.ts.map +1 -1
  38. package/dist/components/media-resources/ResourceScrollContainer.js +34 -2
  39. package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
  40. package/dist/components/message/GroupMembersDrawer.js +2 -3
  41. package/dist/components/message/MessageList.d.ts.map +1 -1
  42. package/dist/components/message/MessageList.js +16 -5
  43. package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
  44. package/dist/components/message/footer/ActionBar.js +10 -44
  45. package/dist/components/message/footer/CannedResponsePlugin.d.ts.map +1 -1
  46. package/dist/components/message/footer/CannedResponsePlugin.js +3 -2
  47. package/dist/components/message/footer/EnterHandler.d.ts.map +1 -1
  48. package/dist/components/message/footer/EnterHandler.js +10 -47
  49. package/dist/components/message/footer/FilePreview.d.ts.map +1 -1
  50. package/dist/components/message/footer/FilePreview.js +2 -1
  51. package/dist/components/message/footer/LinkInputPreview.d.ts +1 -1
  52. package/dist/components/message/footer/LinkInputPreview.d.ts.map +1 -1
  53. package/dist/components/message/footer/LinkInputPreview.js +8 -1
  54. package/dist/components/message/footer/MediaUploadButtons.d.ts.map +1 -1
  55. package/dist/components/message/footer/MediaUploadButtons.js +4 -7
  56. package/dist/components/message/footer/index.d.ts.map +1 -1
  57. package/dist/components/message/footer/index.js +57 -16
  58. package/dist/components/message/footer/mention/useMentionOptions.d.ts.map +1 -1
  59. package/dist/components/message/footer/mention/useMentionOptions.js +2 -6
  60. package/dist/components/message/footer/resetEditorAfterSend.d.ts +7 -0
  61. package/dist/components/message/footer/resetEditorAfterSend.d.ts.map +1 -0
  62. package/dist/components/message/footer/resetEditorAfterSend.js +62 -0
  63. package/dist/components/message/groupMemberMenuCrm.d.ts +4 -4
  64. package/dist/components/message/groupMemberMenuCrm.d.ts.map +1 -1
  65. package/dist/components/message/groupMemberMenuCrm.js +73 -60
  66. package/dist/components/message/item/SystemLogMessage.d.ts.map +1 -1
  67. package/dist/components/message/item/SystemLogMessage.js +5 -2
  68. package/dist/components/message/item/index.d.ts.map +1 -1
  69. package/dist/components/message/item/index.js +1 -0
  70. package/dist/components/search-conversation/SearchConversationAsGroups.js +1 -1
  71. package/dist/components/search-conversation/SearchConversationAsMessages.js +1 -1
  72. package/dist/components/search-conversation/SearchConversationMyInbox.js +1 -1
  73. package/dist/components/thread/GroupInfoBodyCrm.d.ts.map +1 -1
  74. package/dist/components/thread/GroupInfoBodyCrm.js +2 -2
  75. package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
  76. package/dist/components/thread/GroupThreadInfo.js +2 -6
  77. package/dist/components/thread/ManualAssignPopover.d.ts.map +1 -1
  78. package/dist/components/thread/ManualAssignPopover.js +6 -8
  79. package/dist/components/thread/SessionDetailCard.d.ts.map +1 -1
  80. package/dist/components/thread/SessionDetailCard.js +3 -3
  81. package/dist/components/thread/SessionSection.d.ts.map +1 -1
  82. package/dist/components/thread/SessionSection.js +3 -9
  83. package/dist/components/thread/SessionTagPicker.d.ts +3 -1
  84. package/dist/components/thread/SessionTagPicker.d.ts.map +1 -1
  85. package/dist/components/thread/SessionTagPicker.js +2 -2
  86. package/dist/components/thread/sessionDateFormat.d.ts +2 -0
  87. package/dist/components/thread/sessionDateFormat.d.ts.map +1 -1
  88. package/dist/components/thread/sessionDateFormat.js +6 -0
  89. package/dist/constants/dateFormat.d.ts +2 -0
  90. package/dist/constants/dateFormat.d.ts.map +1 -0
  91. package/dist/constants/dateFormat.js +2 -0
  92. package/dist/hooks/common/useFetchUrlMetadata.d.ts +1 -0
  93. package/dist/hooks/common/useFetchUrlMetadata.d.ts.map +1 -1
  94. package/dist/hooks/conversation/useBotFlow.d.ts.map +1 -1
  95. package/dist/hooks/conversation/useBotFlow.js +64 -12
  96. package/dist/hooks/conversation/useCloseBotSession.d.ts +2 -0
  97. package/dist/hooks/conversation/useCloseBotSession.d.ts.map +1 -1
  98. package/dist/hooks/conversation/useCloseBotSession.js +17 -1
  99. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  100. package/dist/hooks/global/useGlobalEvent.js +148 -16
  101. package/dist/hooks/global/useLoginHealth.d.ts +3 -0
  102. package/dist/hooks/global/useLoginHealth.d.ts.map +1 -0
  103. package/dist/hooks/global/useLoginHealth.js +55 -0
  104. package/dist/hooks/group/useCreateGroup.d.ts.map +1 -1
  105. package/dist/hooks/group/useCreateGroup.js +75 -6
  106. package/dist/hooks/init/useChatBootPhase.d.ts +2 -0
  107. package/dist/hooks/init/useChatBootPhase.d.ts.map +1 -1
  108. package/dist/hooks/init/useChatBootPhase.js +11 -6
  109. package/dist/hooks/message/useMessage.d.ts.map +1 -1
  110. package/dist/hooks/message/useMessage.js +97 -28
  111. package/dist/hooks/message/usePinMessage.d.ts +2 -1
  112. package/dist/hooks/message/usePinMessage.d.ts.map +1 -1
  113. package/dist/hooks/message/usePinMessage.js +4 -1
  114. package/dist/hooks/message/usePinnedMessages.d.ts.map +1 -1
  115. package/dist/hooks/message/usePinnedMessages.js +13 -2
  116. package/dist/hooks/message/useRevokeMessage.d.ts.map +1 -1
  117. package/dist/hooks/message/useRevokeMessage.js +25 -0
  118. package/dist/hooks/message/useSendMessage.d.ts +15 -12
  119. package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
  120. package/dist/hooks/message/useSendMessage.js +199 -133
  121. package/dist/hooks/search/useSearchMessage.d.ts.map +1 -1
  122. package/dist/hooks/search/useSearchMessage.js +57 -3
  123. package/dist/hooks/session/useConversationSessionState.d.ts.map +1 -1
  124. package/dist/hooks/session/useConversationSessionState.js +4 -1
  125. package/dist/hooks/session/useSessionLatestPreview.d.ts.map +1 -1
  126. package/dist/hooks/session/useSessionLatestPreview.js +34 -4
  127. package/dist/hooks/user/useAuth.d.ts +1 -1
  128. package/dist/hooks/user/useAuth.d.ts.map +1 -1
  129. package/dist/hooks/user/useAuth.js +31 -15
  130. package/dist/index.d.ts +1 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +1 -0
  133. package/dist/locales/vi/boot.json +5 -1
  134. package/dist/locales/vi/common.json +34 -15
  135. package/dist/locales/vi/conversation-inbox.json +2 -1
  136. package/dist/screens/conversation-detail/index.d.ts.map +1 -1
  137. package/dist/screens/conversation-detail/index.js +6 -0
  138. package/dist/screens/desk-message/DeskBootCard.d.ts.map +1 -1
  139. package/dist/screens/desk-message/DeskBootCard.js +6 -4
  140. package/dist/store/boot.d.ts +5 -0
  141. package/dist/store/boot.d.ts.map +1 -1
  142. package/dist/store/boot.js +11 -1
  143. package/dist/store/conversation.d.ts.map +1 -1
  144. package/dist/store/conversation.js +5 -1
  145. package/dist/store/type.d.ts +3 -1
  146. package/dist/store/type.d.ts.map +1 -1
  147. package/dist/styles/global.css +1 -1
  148. package/dist/types/chat.d.ts +1 -1
  149. package/dist/types/chat.d.ts.map +1 -1
  150. package/dist/utils/common.d.ts.map +1 -1
  151. package/dist/utils/common.js +4 -1
  152. package/dist/utils/fileValidation.d.ts +7 -0
  153. package/dist/utils/fileValidation.d.ts.map +1 -1
  154. package/dist/utils/fileValidation.js +37 -13
  155. package/dist/utils/latestMessagePreviewable.d.ts +2 -0
  156. package/dist/utils/latestMessagePreviewable.d.ts.map +1 -0
  157. package/dist/utils/latestMessagePreviewable.js +18 -0
  158. package/dist/utils/mentionMembers.d.ts +3 -0
  159. package/dist/utils/mentionMembers.d.ts.map +1 -0
  160. package/dist/utils/mentionMembers.js +29 -0
  161. package/dist/utils/messageLog.d.ts +2 -2
  162. package/dist/utils/messageLog.d.ts.map +1 -1
  163. package/dist/utils/messageLog.js +129 -40
  164. package/dist/utils/notifiableMessage.d.ts +7 -0
  165. package/dist/utils/notifiableMessage.d.ts.map +1 -0
  166. package/dist/utils/notifiableMessage.js +26 -0
  167. package/dist/utils/withSdkTimeout.d.ts +11 -0
  168. package/dist/utils/withSdkTimeout.d.ts.map +1 -0
  169. package/dist/utils/withSdkTimeout.js +30 -0
  170. package/package.json +1 -1
@@ -12,7 +12,7 @@ import { LAYOUT_MEDIA } from "../../constants/layout";
12
12
  const OPTION_HEIGHT = 36;
13
13
  const MAX_VISIBLE_OPTIONS = 8;
14
14
  // The "Thêm thẻ" row of the tag box. Its list opens inline, so it pushes the card instead of floating over it.
15
- const SessionTagPicker = ({ labelId, available, selectedIds, onChange, }) => {
15
+ const SessionTagPicker = ({ labelId, available, selectedIds, selectedNames = [], onChange, }) => {
16
16
  const { t } = useTranslation("common");
17
17
  const isTouch = useMediaQuery(LAYOUT_MEDIA.touch);
18
18
  const [open, setOpen] = useState(false);
@@ -50,7 +50,7 @@ const SessionTagPicker = ({ labelId, available, selectedIds, onChange, }) => {
50
50
  event.stopPropagation();
51
51
  close();
52
52
  }
53
- }, children: [_jsxs("button", { ref: toggleRef, id: labelId, type: "button", "aria-label": t("session_add_tag"), "aria-expanded": open, "aria-controls": listId, className: "flex h-9 touch:min-h-10 w-full items-center gap-1 px-3 text-[13px] text-gray-600 hover:text-gray-900", onClick: () => (open ? close() : setOpen(true)), children: [_jsx(StrokeIcon, { name: "plus", size: 14 }), t("session_add_tag")] }), open && (_jsxs("div", { ref: panelRef, className: "mx-2 mb-2 flex flex-col gap-1 rounded-lg border border-gray-50 p-1", children: [_jsx(Input, { autoFocus: !isTouch, "aria-label": t("session_search_tag_placeholder"), "aria-controls": listId, placeholder: t("session_search_tag_placeholder"), value: keyword, onChange: (event) => setKeyword(event.target.value), prefix: _jsx(StrokeIcon, { name: "search", size: 16, className: "text-gray-400" }), className: "rounded-lg border-gray-300 text-[13px] focus-within:border-chat-focus focus-within:shadow-chat-focus-ring", allowClear: true }), _jsxs("ul", { id: listId, role: "listbox", "aria-multiselectable": true, "aria-labelledby": labelId, className: "overflow-y-auto", style: { height: listHeight }, children: [isLoading && (_jsx("li", { className: "flex justify-center py-2", children: _jsx(Spin, { size: "small" }) })), !isLoading && options.length === 0 && (_jsx("li", { className: "px-2 py-1.5 text-[13px] text-gray-600", children: t("session_no_tags") })), options.map((label) => {
53
+ }, children: [_jsxs("button", { ref: toggleRef, id: labelId, type: "button", "aria-label": t("session_add_tag"), "aria-expanded": open, "aria-controls": listId, className: "group flex min-h-9 touch:min-h-10 w-full items-center gap-1 px-3 py-1 text-left text-[13px] text-gray-600 hover:text-gray-900", onClick: () => (open ? close() : setOpen(true)), children: [selectedNames.length === 0 ? (_jsx("span", { className: "min-w-0 flex-1 truncate", children: t("session_add_tag_placeholder") })) : (_jsx("span", { className: "flex min-w-0 flex-1 flex-wrap gap-1", children: selectedNames.map((name, index) => (_jsx("span", { className: "inline-flex h-5 max-w-full items-center truncate rounded-md bg-[var(--dc-color-neutral-surface)] px-2 text-xs font-medium text-gray-900", children: name }, `${name}-${index}`))) })), _jsx(StrokeIcon, { name: "plus", size: 14, className: "shrink-0 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100 touch:opacity-100" })] }), open && (_jsxs("div", { ref: panelRef, className: "mx-2 mb-2 flex flex-col gap-1 rounded-lg border border-gray-50 p-1", children: [_jsx(Input, { autoFocus: !isTouch, "aria-label": t("session_search_tag_placeholder"), "aria-controls": listId, placeholder: t("session_search_tag_placeholder"), value: keyword, onChange: (event) => setKeyword(event.target.value), prefix: _jsx(StrokeIcon, { name: "search", size: 16, className: "text-gray-400" }), className: "rounded-lg border-gray-300 text-[13px] focus-within:border-chat-focus focus-within:shadow-chat-focus-ring", allowClear: true }), _jsxs("ul", { id: listId, role: "listbox", "aria-multiselectable": true, "aria-labelledby": labelId, className: "overflow-y-auto", style: { height: listHeight }, children: [isLoading && (_jsx("li", { className: "flex justify-center py-2", children: _jsx(Spin, { size: "small" }) })), !isLoading && options.length === 0 && (_jsx("li", { className: "px-2 py-1.5 text-[13px] text-gray-600", children: t("session_no_tags") })), options.map((label) => {
54
54
  const isSelected = selectedIds.includes(label.id);
55
55
  return (_jsx("li", { role: "option", "aria-selected": isSelected, children: _jsxs("button", { type: "button", className: `flex h-9 w-full items-center justify-between rounded px-2 text-left text-[13px] text-gray-900 hover:bg-gray-5 ${isSelected ? "bg-primary-25" : ""}`, onClick: () => toggle(label.id), children: [label.name, isSelected && _jsx(StrokeIcon, { name: "check", size: 14 })] }) }, label.id));
56
56
  })] })] }))] }));
@@ -1,3 +1,5 @@
1
1
  export declare const formatSessionTime: (dateString?: string | null) => string;
2
2
  export declare const formatSessionDate: (dateString?: string | null) => string;
3
+ /** "HH:mm dd/MM - HH:mm dd/MM" (start - end); an open session has no end, so only the start. */
4
+ export declare const formatSessionRange: (startDate?: string | null, endDate?: string | null) => string;
3
5
  //# sourceMappingURL=sessionDateFormat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sessionDateFormat.d.ts","sourceRoot":"","sources":["../../../src/components/thread/sessionDateFormat.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,GAAG,IAAI,WAI3D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,GAAG,IAAI,WAI3D,CAAC"}
1
+ {"version":3,"file":"sessionDateFormat.d.ts","sourceRoot":"","sources":["../../../src/components/thread/sessionDateFormat.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,GAAG,IAAI,WAI3D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,GAAG,IAAI,WAI3D,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,GAAG,IAAI,EACzB,UAAU,MAAM,GAAG,IAAI,WAKxB,CAAC"}
@@ -11,3 +11,9 @@ export const formatSessionDate = (dateString) => {
11
11
  const date = new Date(dateString);
12
12
  return `${formatSessionTime(dateString)} ${pad(date.getDate())}/${pad(date.getMonth() + 1)}`;
13
13
  };
14
+ /** "HH:mm dd/MM - HH:mm dd/MM" (start - end); an open session has no end, so only the start. */
15
+ export const formatSessionRange = (startDate, endDate) => {
16
+ const start = formatSessionDate(startDate);
17
+ const end = formatSessionDate(endDate);
18
+ return end ? `${start} - ${end}` : start;
19
+ };
@@ -0,0 +1,2 @@
1
+ export declare const LIBRARY_DATE_HEADER_FORMAT = "DD/MM/YYYY";
2
+ //# sourceMappingURL=dateFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dateFormat.d.ts","sourceRoot":"","sources":["../../src/constants/dateFormat.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,0BAA0B,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ // Day group headers in the media library follow the product spec (DD/MM/YYYY).
2
+ export const LIBRARY_DATE_HEADER_FORMAT = "DD/MM/YYYY";
@@ -2,6 +2,7 @@ export interface UrlMetadata {
2
2
  title?: string;
3
3
  description?: string;
4
4
  image?: string;
5
+ isEmpty?: boolean;
5
6
  url: string;
6
7
  }
7
8
  export declare const fetchUrlMetadata: (url: string) => Promise<UrlMetadata | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"useFetchUrlMetadata.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useFetchUrlMetadata.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,gBAAgB,GAAU,KAAK,MAAM,KAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAY9E,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,KAAK,MAAM,EAAE,iBAAc,8EAO3D,CAAC"}
1
+ {"version":3,"file":"useFetchUrlMetadata.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useFetchUrlMetadata.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,gBAAgB,GAAU,KAAK,MAAM,KAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAY9E,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,KAAK,MAAM,EAAE,iBAAc,8EAO3D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBotFlow.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotFlow.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAgB9B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;AAMtD,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAsBD,eAAO,MAAM,UAAU,GAAI,kCAGxB,gBAAgB;;;;;;;;;;;;6BAoKqB,MAAM;;6BA+DN,eAAe;;;CAmDtD,CAAC"}
1
+ {"version":3,"file":"useBotFlow.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotFlow.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAgB9B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;AAMtD,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAoCD,eAAO,MAAM,UAAU,GAAI,kCAGxB,gBAAgB;;;;;;;;;;;;6BA8KqB,MAAM;;6BAwFN,eAAe;;;CA+DtD,CAAC"}
@@ -21,6 +21,17 @@ const INITIAL_BOT_FLOW_STATE = {
21
21
  flowCurrentStep: null,
22
22
  flowIsEnd: false,
23
23
  };
24
+ // Safety net: a group whose message never arrives must not hide buttons forever.
25
+ const PENDING_GROUP_TIMEOUT_MS = 8000;
26
+ // Only these blocks make the server push a chat message carrying the group id.
27
+ const MESSAGE_BLOCK_TYPES = [
28
+ BotBlockType.BubbleText,
29
+ BotBlockType.BubbleImage,
30
+ ];
31
+ const hasMessageBlock = (step) => {
32
+ var _a, _b;
33
+ return !!((_b = (_a = step === null || step === void 0 ? void 0 : step.data) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.some((child) => MESSAGE_BLOCK_TYPES.includes(child.type)));
34
+ };
24
35
  const parseMessageFlowGroupId = (ex) => {
25
36
  var _a;
26
37
  try {
@@ -97,6 +108,12 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
97
108
  emitter.off("PUSH_NEW_MSG", handleNewMessage);
98
109
  };
99
110
  }, [authUserID]);
111
+ useEffect(() => {
112
+ if (!pendingGroupId)
113
+ return;
114
+ const timer = setTimeout(() => setPendingGroupId(null), PENDING_GROUP_TIMEOUT_MS);
115
+ return () => clearTimeout(timer);
116
+ }, [pendingGroupId]);
100
117
  const activeStep = isActiveConversation ? flowCurrentStep : null;
101
118
  const inputButtonsBlocks = (_d = activeStep === null || activeStep === void 0 ? void 0 : activeStep.data.children.filter((child) => child.type === BotBlockType.InputButtons)) !== null && _d !== void 0 ? _d : [];
102
119
  const currentButtonsBlock = inputButtonsBlocks.length > 0
@@ -138,6 +155,7 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
138
155
  });
139
156
  const nextGroupId = (_a = result.flowNextStep) === null || _a === void 0 ? void 0 : _a.id;
140
157
  setPendingGroupId(result.havingBotMessage &&
158
+ hasMessageBlock(result.flowNextStep) &&
141
159
  nextGroupId &&
142
160
  latestBotFlowGroupIdRef.current !== nextGroupId
143
161
  ? nextGroupId
@@ -187,24 +205,46 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
187
205
  await runStep(resetDetail.flowCurrentStep);
188
206
  });
189
207
  };
208
+ // The CS may have closed the session on the desk while this thread stayed
209
+ // open, so confirm against the server before showing the "end session" modal.
210
+ const checkCsSession = async () => {
211
+ var _a, _b;
212
+ if (!isInActiveCsSession)
213
+ return { active: false, step: activeStep };
214
+ const fresh = await detailQuery.refetch();
215
+ // A missing step means the session is gone; the stale CS step must not win.
216
+ const step = (_b = (_a = fresh.data) === null || _a === void 0 ? void 0 : _a.flowCurrentStep) !== null && _b !== void 0 ? _b : null;
217
+ return { active: isInCsSession({ flowCurrentStep: step }), step };
218
+ };
219
+ // The session refetch is async; a second tap meanwhile would run the same
220
+ // check-then-act again, so claim the slot before awaiting anything.
221
+ const checkingRef = useRef(false);
190
222
  const restart = async () => {
191
- if (isInActiveCsSession) {
192
- setPendingCsAction({ type: "restart" });
223
+ if (checkingRef.current)
193
224
  return;
225
+ checkingRef.current = true;
226
+ try {
227
+ if ((await checkCsSession()).active) {
228
+ setPendingCsAction({ type: "restart" });
229
+ return;
230
+ }
231
+ await performRestart();
232
+ }
233
+ finally {
234
+ checkingRef.current = false;
194
235
  }
195
- await performRestart();
196
236
  };
197
- const runMenuOption = async (item) => {
198
- if (!activeStep)
237
+ const runMenuOption = async (item, step = activeStep) => {
238
+ if (!step)
199
239
  return;
200
240
  await whileChoosing(async () => {
201
241
  await sendMergeMessage({
202
242
  plainText: item.label,
203
243
  richText: "",
204
244
  isInternal: false,
205
- flow: { groupId: activeStep.id, childId: null, actionId: item.id },
245
+ flow: { groupId: step.id, childId: null, actionId: item.id },
206
246
  });
207
- await runStep(activeStep, item.id);
247
+ await runStep(step, item.id);
208
248
  });
209
249
  };
210
250
  const selectMenuOption = async (item) => {
@@ -212,13 +252,23 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
212
252
  await restart();
213
253
  return;
214
254
  }
215
- if (isInActiveCsSession) {
216
- setPendingCsAction({ type: "menu", item });
255
+ if (checkingRef.current)
217
256
  return;
257
+ checkingRef.current = true;
258
+ try {
259
+ const { active, step } = await checkCsSession();
260
+ if (active) {
261
+ setPendingCsAction({ type: "menu", item });
262
+ return;
263
+ }
264
+ await runMenuOption(item, step);
265
+ }
266
+ finally {
267
+ checkingRef.current = false;
218
268
  }
219
- await runMenuOption(item);
220
269
  };
221
270
  const confirmEndCsSession = async () => {
271
+ var _a, _b;
222
272
  if (!pendingCsAction)
223
273
  return;
224
274
  const action = pendingCsAction;
@@ -229,10 +279,12 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
229
279
  await performRestart();
230
280
  }
231
281
  else {
232
- await runMenuOption(action.item);
282
+ // The server resets the flow step on close; run the menu item on it.
283
+ const fresh = await detailQuery.refetch();
284
+ await runMenuOption(action.item, (_b = (_a = fresh.data) === null || _a === void 0 ? void 0 : _a.flowCurrentStep) !== null && _b !== void 0 ? _b : activeStep);
233
285
  }
234
286
  }
235
- catch (_a) {
287
+ catch (_c) {
236
288
  toastMessage.error(t("thread_detail.bot.cs_confirm.close_failed"));
237
289
  setPendingCsAction(null);
238
290
  }
@@ -1,2 +1,4 @@
1
+ export declare const SESSION_ALREADY_CLOSED_CODE = 2005;
2
+ export declare const isSessionAlreadyClosedError: (error: unknown) => boolean;
1
3
  export declare const useCloseBotSession: () => import("@tanstack/react-query").UseMutationResult<void, Error, string, unknown>;
2
4
  //# sourceMappingURL=useCloseBotSession.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCloseBotSession.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useCloseBotSession.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,kBAAkB,uFAS9B,CAAC"}
1
+ {"version":3,"file":"useCloseBotSession.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useCloseBotSession.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAEhD,eAAO,MAAM,2BAA2B,GAAI,OAAO,OAAO,KAAG,OAQ5D,CAAC;AAEF,eAAO,MAAM,kBAAkB,uFAc9B,CAAC"}
@@ -3,11 +3,27 @@ import { useMutation } from "@tanstack/react-query";
3
3
  import { apiInstance } from "../../services/api";
4
4
  import { ENDPOINTS } from "../../services/routes";
5
5
  import { QUERY_KEYS } from "../../services/query";
6
+ // Backend code for "session already closed" (e.g. CS ended it on the desk).
7
+ export const SESSION_ALREADY_CLOSED_CODE = 2005;
8
+ export const isSessionAlreadyClosedError = (error) => {
9
+ var _a;
10
+ const data = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data;
11
+ if (!data)
12
+ return false;
13
+ return [data.code, data.errorCode, data.errCode, data.statusCode].some((value) => Number(value) === SESSION_ALREADY_CLOSED_CODE);
14
+ };
6
15
  export const useCloseBotSession = () => {
7
16
  return useMutation({
8
17
  mutationKey: [QUERY_KEYS.CLOSE_BOT_SESSION],
9
18
  mutationFn: async (conversationId) => {
10
- await apiInstance.post(ENDPOINTS.chatService.closeBotSession(conversationId));
19
+ try {
20
+ await apiInstance.post(ENDPOINTS.chatService.closeBotSession(conversationId));
21
+ }
22
+ catch (error) {
23
+ // Already closed elsewhere is the outcome we wanted; let the caller go on.
24
+ if (!isSessionAlreadyClosedError(error))
25
+ throw error;
26
+ }
11
27
  },
12
28
  });
13
29
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AAkDA,eAAO,MAAM,cAAc,YA8nB1B,CAAC"}
1
+ {"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AA6DA,eAAO,MAAM,cAAc,YA0wB1B,CAAC"}
@@ -1,8 +1,8 @@
1
- import { useEffect } from "react";
1
+ import { useEffect, useRef } from "react";
2
2
  import { useLatest } from "ahooks";
3
3
  import { DChatSDK } from "../../constants/sdk";
4
4
  import { CbEvents, GroupVisibility, MessageType, SessionType, } from "@droppii-org/wasm-client-sdk";
5
- import { BusinessNotificationType, ConnectStatus, CustomType, SyncStatus, } from "../../types/chat";
5
+ import { BusinessNotificationType, ConnectStatus, CustomType, SessionStatus, SyncStatus, } from "../../types/chat";
6
6
  import { pushNewMessage, updateOneMessage } from "../../hooks/message/useMessage";
7
7
  import { fetchPinnedMessages } from "../../hooks/message/usePinnedMessages";
8
8
  import { applyRevokedMessage } from "../../hooks/message/useRevokeMessage";
@@ -22,11 +22,17 @@ import { ignoreInternalLatestMessage } from "../../utils/common";
22
22
  import { invalidateSessionQueries } from "../../utils/queryHelpers";
23
23
  import { refreshPublicGroupLists } from "../../hooks/group/useJoinPublicGroup";
24
24
  import emitter from "../../utils/events";
25
+ import { withSdkTimeout } from "../../utils/withSdkTimeout";
26
+ import { isCoreLoggedIn, useLoginHealthProbe } from "./useLoginHealth";
25
27
  const notPushType = [MessageType.TypingMessage, MessageType.RevokeMessage];
28
+ const LOGIN_TIMEOUT_MS = 30000;
26
29
  export const useGlobalEvent = () => {
27
30
  const { user } = useChatContext();
28
31
  const onNavigate = useChatNavigate();
29
32
  const userRef = useLatest(user);
33
+ // One login at a time: boot, token refresh, the health probe and relogin all share it.
34
+ // Keyed by credential: the same user and token share a flight, a new one chains after it.
35
+ const loginInFlight = useRef(null);
30
36
  const queryClient = useQueryClient();
31
37
  const { updateConnectStatus, updateSyncStatus, getSelfUserInfo } = useChatContext();
32
38
  const updateConversationList = useConversationStore((state) => state.updateConversationList);
@@ -164,7 +170,20 @@ export const useGlobalEvent = () => {
164
170
  const inputStatusChangedHandler = ({ data, }) => {
165
171
  handleInputStatusChanged(data);
166
172
  };
173
+ // Token rotation (refresh timer, storage sync) must not lift a kick: re-logging in would
174
+ // kick the other session back. Only a different user, a logout or a reload starts over.
175
+ const isKickedForCurrentCredentials = () => {
176
+ const { isKicked, kickedUserID } = useBootStore.getState();
177
+ if (!isKicked)
178
+ return false;
179
+ if (!kickedUserID)
180
+ return true;
181
+ return kickedUserID === useAuthStore.getState().userID;
182
+ };
167
183
  const userTokenHandler = () => {
184
+ // A kicked account's token is dead; refreshing it would re-login and restart the kick loop.
185
+ if (isKickedForCurrentCredentials())
186
+ return;
168
187
  refetchChatToken(undefined, {
169
188
  onSettled(data) {
170
189
  var _a;
@@ -183,42 +202,129 @@ export const useGlobalEvent = () => {
183
202
  const initStore = () => {
184
203
  loadConversationList();
185
204
  };
186
- const tryLogin = async () => {
205
+ // Resolves true when this run ended with a usable core session.
206
+ const runLoginOnce = (run) => {
207
+ const { userID, chatToken } = useAuthStore.getState();
208
+ const key = `${userID}:${chatToken}`;
209
+ const running = loginInFlight.current;
210
+ if ((running === null || running === void 0 ? void 0 : running.key) === key)
211
+ return running.promise;
212
+ const start = running
213
+ ? // A different credential must not be dropped, but the running flight may already
214
+ // have logged core in: logging in again would only hit "repeated login".
215
+ running.promise
216
+ .catch(() => false)
217
+ .then((prevOk) => runChained(run, running.userID, prevOk))
218
+ : run();
219
+ const flight = { key, userID, promise: start };
220
+ flight.promise = start.finally(() => {
221
+ if (loginInFlight.current === flight)
222
+ loginInFlight.current = null;
223
+ });
224
+ loginInFlight.current = flight;
225
+ return flight.promise;
226
+ };
227
+ const runChained = async (run, prevUserID, prevOk) => {
228
+ if (isKickedForCurrentCredentials())
229
+ return false;
230
+ const { userID } = useAuthStore.getState();
231
+ if (!(await isCoreLoggedIn()))
232
+ return run();
233
+ // Same user already logged in by the previous flight: nothing to redo.
234
+ if (prevUserID === userID && prevOk)
235
+ return true;
236
+ // Another user, or the previous login failed with the old token: start over with the new one.
237
+ return reloginUnguarded();
238
+ };
239
+ const getCoreUserID = async () => {
240
+ try {
241
+ return (await withSdkTimeout(DChatSDK.getLoginUserID(), "getLoginUserID")).data;
242
+ }
243
+ catch (_a) {
244
+ return undefined;
245
+ }
246
+ };
247
+ const tryLogin = async (isRetry = false) => {
248
+ var _a;
249
+ if (isKickedForCurrentCredentials())
250
+ return false;
187
251
  const { userID, chatToken, platformID, wsAddress } = useAuthStore.getState();
188
252
  try {
189
- await DChatSDK.login({
253
+ await withSdkTimeout(DChatSDK.login({
190
254
  userID,
191
255
  token: chatToken,
192
256
  platformID,
193
257
  apiAddr: `${apiAddress}/chat-service`,
194
258
  wsAddr: `${wsAddress}/chat-service/ws`,
195
- });
259
+ }), "login", LOGIN_TIMEOUT_MS);
196
260
  initStore();
261
+ return true;
197
262
  }
198
263
  catch (error) {
199
- if (error.errCode === 10102) {
200
- updateConnectStatus(ConnectStatus.Connected);
201
- updateSyncStatus(SyncStatus.Success);
202
- // Already logged in (e.g. ChatProvider remounted): sync events may have fired while
203
- // nobody listened, so stop waiting for them rather than risk a boot screen that never ends.
204
- useBootStore.getState().markConnected();
205
- useBootStore.getState().markFirstSyncDone();
264
+ const errCode = (_a = error.errCode) !== null && _a !== void 0 ? _a : error.code;
265
+ if (errCode === 10102) {
266
+ // "Already logged in" is only true if core agrees; a stale tab can hold a dead session.
267
+ if (!isRetry && !(await isCoreLoggedIn())) {
268
+ return reloginUnguarded();
269
+ }
270
+ // Core may hold another user's session (shared storage); only trust it for this user.
271
+ if (!isRetry && (await getCoreUserID()) !== userID) {
272
+ return reloginUnguarded();
273
+ }
274
+ // Sync events may have fired while nobody listened (e.g. ChatProvider remounted); trust
275
+ // only what the boot store itself saw: connect, and the first sync finishing.
276
+ const boot = useBootStore.getState();
277
+ if (boot.hasConnected) {
278
+ updateConnectStatus(ConnectStatus.Connected);
279
+ if (boot.isFirstSyncDone)
280
+ updateSyncStatus(SyncStatus.Success);
281
+ }
206
282
  getSelfUserInfo();
207
283
  initStore();
208
- return;
284
+ return true;
209
285
  }
210
286
  useBootStore.getState().markFailed("engine");
211
287
  console.error(error);
288
+ return false;
289
+ }
290
+ };
291
+ // Drops a dead core session and logs in again with the current chat token; an
292
+ // expired token comes back through OnUserTokenExpired and is refreshed there.
293
+ const reloginUnguarded = async () => {
294
+ if (isKickedForCurrentCredentials())
295
+ return false;
296
+ try {
297
+ await withSdkTimeout(DChatSDK.logout(), "logout");
212
298
  }
299
+ catch (error) {
300
+ console.warn("logout before relogin", error);
301
+ }
302
+ return tryLogin(true);
303
+ };
304
+ const relogin = async () => {
305
+ await runLoginOnce(reloginUnguarded);
306
+ };
307
+ // The account signed in elsewhere and the token is now dead. Core logs itself
308
+ // out on a kick, so do not log out here or log back in: that would kick the
309
+ // other session in turn and loop. A reload starts a fresh sign-in.
310
+ const kickedOfflineHandler = () => {
311
+ updateConnectStatus(ConnectStatus.Disconnected);
312
+ useBootStore.getState().markKicked(useAuthStore.getState().userID);
213
313
  };
314
+ useLoginHealthProbe(relogin);
214
315
  const loginCheck = async () => {
215
316
  const chatToken = useAuthStore.getState().chatToken;
216
317
  const userID = useAuthStore.getState().userID;
217
318
  if (!chatToken || !userID) {
218
319
  return;
219
320
  }
321
+ // A kicked user stays blocked; only a different user starts a fresh boot.
322
+ if (isKickedForCurrentCredentials())
323
+ return;
324
+ if (useBootStore.getState().isKicked)
325
+ useBootStore.getState().reset();
220
326
  useBootStore.getState().startBoot(userID);
221
- tryLogin();
327
+ void runLoginOnce(() => tryLogin());
222
328
  };
223
329
  const connectingHandler = () => {
224
330
  useBootStore.getState().markConnecting();
@@ -282,12 +388,36 @@ export const useGlobalEvent = () => {
282
388
  queryKey: [QUERY_KEYS.GET_BOT_DETAIL, botId],
283
389
  });
284
390
  };
391
+ // A closed session resets the bot flow server-side, so the open thread's
392
+ // cached step and menu are stale until refetched.
393
+ const handleSessionClosed = (conversationId) => {
394
+ const conversation = useConversationStore.getState().conversationData;
395
+ if (!conversation)
396
+ return;
397
+ const openId = conversation.conversationID;
398
+ if (conversationId && conversationId !== openId)
399
+ return;
400
+ // Keep the in-flight refetch an action started; cancelling it would
401
+ // leave that action waiting on a result that never comes.
402
+ void queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.GET_CONVERSATION_DETAIL, openId] }, { cancelRefetch: false });
403
+ void queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.GET_BOT_MAIN_MENU, openId] }, { cancelRefetch: false });
404
+ };
285
405
  const businessNotificationHandler = ({ data, }) => {
286
406
  console.log(data.key, "business notification");
287
407
  switch (data.key) {
288
- case BusinessNotificationType.SESSION_STATE_UPDATED:
289
- updateSession(JSON.parse(data.data || "{}"));
408
+ case BusinessNotificationType.SESSION_STATE_UPDATED: {
409
+ const session = JSON.parse(data.data || "{}");
410
+ updateSession(session);
411
+ if (session.status === SessionStatus.COMPLETED) {
412
+ handleSessionClosed(session.conversationId);
413
+ }
414
+ break;
415
+ }
416
+ case BusinessNotificationType.SESSION_CLOSED: {
417
+ const closed = JSON.parse(data.data || "{}");
418
+ handleSessionClosed(closed.conversationId);
290
419
  break;
420
+ }
291
421
  case BusinessNotificationType.SESSION_CREATED:
292
422
  updateSession(JSON.parse(data.data || "{}"));
293
423
  queryClient.invalidateQueries({
@@ -446,6 +576,7 @@ export const useGlobalEvent = () => {
446
576
  //account
447
577
  DChatSDK.on(CbEvents.OnUserTokenExpired, userTokenHandler);
448
578
  DChatSDK.on(CbEvents.OnUserTokenInvalid, userTokenHandler);
579
+ DChatSDK.on(CbEvents.OnKickedOffline, kickedOfflineHandler);
449
580
  DChatSDK.on(CbEvents.OnConnecting, connectingHandler);
450
581
  DChatSDK.on(CbEvents.OnConnectSuccess, connectSuccessHandler);
451
582
  DChatSDK.on(CbEvents.OnConnectFailed, connectFailedHandler);
@@ -481,6 +612,7 @@ export const useGlobalEvent = () => {
481
612
  //account
482
613
  DChatSDK.off(CbEvents.OnUserTokenExpired, userTokenHandler);
483
614
  DChatSDK.off(CbEvents.OnUserTokenInvalid, userTokenHandler);
615
+ DChatSDK.off(CbEvents.OnKickedOffline, kickedOfflineHandler);
484
616
  DChatSDK.off(CbEvents.OnConnecting, connectingHandler);
485
617
  DChatSDK.off(CbEvents.OnConnectSuccess, connectSuccessHandler);
486
618
  DChatSDK.off(CbEvents.OnConnectFailed, connectFailedHandler);
@@ -0,0 +1,3 @@
1
+ export declare const isCoreLoggedIn: () => Promise<boolean>;
2
+ export declare const useLoginHealthProbe: (relogin: () => Promise<void>) => void;
3
+ //# sourceMappingURL=useLoginHealth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLoginHealth.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useLoginHealth.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,cAAc,QAAa,OAAO,CAAC,OAAO,CAQtD,CAAC;AAKF,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,OAAO,CAAC,IAAI,CAAC,SA6B/D,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { useEffect } from "react";
2
+ import { useLatest } from "ahooks";
3
+ import { LoginStatus } from "@droppii-org/wasm-client-sdk";
4
+ import { DChatSDK } from "../../constants/sdk";
5
+ import useAuthStore from "../../store/auth";
6
+ import useBootStore from "../../store/boot";
7
+ import { withSdkTimeout } from "../../utils/withSdkTimeout";
8
+ // A failed or hung status read counts as not logged in: either way the tab cannot talk to core.
9
+ export const isCoreLoggedIn = async () => {
10
+ try {
11
+ const { data } = await withSdkTimeout(DChatSDK.getLoginStatus(), "getLoginStatus");
12
+ return data === LoginStatus.Logged || data === LoginStatus.Logging;
13
+ }
14
+ catch (error) {
15
+ console.warn("getLoginStatus", error);
16
+ return false;
17
+ }
18
+ };
19
+ // A desk tab left open for hours can come back with core logged out while the UI still
20
+ // shows "connected". Checking when the tab is shown again or the network returns repairs
21
+ // it without a reload.
22
+ export const useLoginHealthProbe = (relogin) => {
23
+ const reloginRef = useLatest(relogin);
24
+ useEffect(() => {
25
+ let probing = false;
26
+ const probe = async () => {
27
+ var _a;
28
+ if (probing || document.visibilityState === "hidden")
29
+ return;
30
+ const { userID, apiAddress, chatToken } = useAuthStore.getState();
31
+ if (!userID || !apiAddress || !chatToken || !DChatSDK)
32
+ return;
33
+ // Boot owns the first login; after a kick the token is dead and a relogin
34
+ // would only kick the other session again.
35
+ const boot = useBootStore.getState();
36
+ const isBooting = !boot.isFirstSyncDone && !boot.failedStep;
37
+ if (boot.isKicked || isBooting)
38
+ return;
39
+ probing = true;
40
+ try {
41
+ if (!(await isCoreLoggedIn()))
42
+ await ((_a = reloginRef.current) === null || _a === void 0 ? void 0 : _a.call(reloginRef));
43
+ }
44
+ finally {
45
+ probing = false;
46
+ }
47
+ };
48
+ document.addEventListener("visibilitychange", probe);
49
+ window.addEventListener("online", probe);
50
+ return () => {
51
+ document.removeEventListener("visibilitychange", probe);
52
+ window.removeEventListener("online", probe);
53
+ };
54
+ }, [reloginRef]);
55
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"useCreateGroup.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useCreateGroup.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAqCD,eAAO,MAAM,cAAc;6DAQ2B,iBAAiB;CA2DtE,CAAC"}
1
+ {"version":3,"file":"useCreateGroup.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useCreateGroup.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAyGD,eAAO,MAAM,cAAc;6DAS2B,iBAAiB;CAkFtE,CAAC"}