@microsoft/omnichannel-chat-widget 1.8.3-main.ec1328d → 1.8.4-main.7bdb634
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/lib/cjs/common/Constants.js +6 -0
- package/lib/cjs/common/facades/FacadeChatSDK.js +6 -0
- package/lib/cjs/common/telemetry/TelemetryConstants.js +34 -0
- package/lib/cjs/common/utils/SecureEventBus.js +307 -0
- package/lib/cjs/common/utils/dispatchCustomEvent.js +25 -0
- package/lib/cjs/components/citationpanestateful/CitationDim.js +29 -0
- package/lib/cjs/components/citationpanestateful/CitationPaneStateful.js +199 -0
- package/lib/cjs/components/citationpanestateful/common/defaultProps/defaultCitationPaneProps.js +70 -0
- package/lib/cjs/components/confirmationpanestateful/interfaces/IConfirmationPaneLocalizedTexts.js +1 -0
- package/lib/cjs/components/livechatwidget/LiveChatWidget.js +4 -4
- package/lib/cjs/components/livechatwidget/common/ActivitySubscriber/AddActivitySubscriber.js +127 -0
- package/lib/cjs/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js +4 -5
- package/lib/cjs/components/livechatwidget/common/ChatWidgetEvents.js +15 -0
- package/lib/cjs/components/livechatwidget/common/PersistentConversationHandler.js +284 -0
- package/lib/cjs/components/livechatwidget/common/createAdapter.js +2 -0
- package/lib/cjs/components/livechatwidget/common/defaultProps/defaultPersistentChatHistoryProps.js +18 -0
- package/lib/cjs/components/livechatwidget/common/endChat.js +28 -3
- package/lib/cjs/components/livechatwidget/common/getMockChatSDKIfApplicable.js +4 -3
- package/lib/cjs/components/livechatwidget/common/initWebChatComposer.js +8 -6
- package/lib/cjs/components/livechatwidget/common/overridePropsOnMockIfApplicable.js +2 -1
- package/lib/cjs/components/livechatwidget/common/startChat.js +5 -4
- package/lib/cjs/components/livechatwidget/interfaces/IMockProps.js +8 -2
- package/lib/cjs/components/livechatwidget/interfaces/IPersistentChatHistoryProps.js +1 -0
- package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +29 -5
- package/lib/cjs/components/webchatcontainerstateful/WebChatContainerStateful.js +122 -11
- package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatAdapter.js +43 -14
- package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatSDK.js +6 -1
- package/lib/cjs/components/webchatcontainerstateful/common/activities/botActivity.js +14 -0
- package/lib/cjs/components/webchatcontainerstateful/common/activities/conversationDividerActivity.js +17 -0
- package/lib/cjs/components/webchatcontainerstateful/common/activityConverters/convertPersistentChatHistoryMessageToActivity.js +97 -0
- package/lib/cjs/components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts.js +2 -1
- package/lib/cjs/components/webchatcontainerstateful/common/defaultProps/defaultWebChatStatefulProps.js +1 -1
- package/lib/cjs/components/webchatcontainerstateful/common/defaultStyles/defaultWebChatStyles.js +1 -1
- package/lib/cjs/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +36 -2
- package/lib/cjs/components/webchatcontainerstateful/common/utils/fontUtils.js +28 -0
- package/lib/cjs/components/webchatcontainerstateful/hooks/usePersistentChatHistory.js +59 -0
- package/lib/cjs/components/webchatcontainerstateful/interfaces/ICitation.js +1 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/WebChatEventSubscribers.js +122 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/Constants.js +10 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/ConversationDividerActivity.js +18 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LazyLoadActivity.js +1038 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LoadInlineBannerActivity.js +34 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.js +44 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityStatusMiddleware.js +16 -2
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultAvatarTextStyles.js +1 -1
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultInLineBannerStyle.js +20 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultSystemMessageStyles.js +1 -1
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/DeliveredTimestamp.js +2 -2
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/HistoryMessageTimestamp.js +59 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/NotDeliveredTimestamp.js +4 -3
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/SendingTimestamp.js +2 -2
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/citationsMiddleware.js +97 -30
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.js +2 -2
- package/lib/cjs/contexts/common/LiveChatWidgetActionType.js +46 -45
- package/lib/cjs/contexts/common/LiveChatWidgetContextInitialState.js +2 -0
- package/lib/cjs/contexts/createReducer.js +15 -0
- package/lib/cjs/index.js +9 -1
- package/lib/esm/common/Constants.js +6 -0
- package/lib/esm/common/facades/FacadeChatSDK.js +6 -0
- package/lib/esm/common/telemetry/TelemetryConstants.js +34 -0
- package/lib/esm/common/utils/SecureEventBus.js +328 -0
- package/lib/esm/common/utils/dispatchCustomEvent.js +18 -0
- package/lib/esm/components/citationpanestateful/CitationDim.js +20 -0
- package/lib/esm/components/citationpanestateful/CitationPaneStateful.js +188 -0
- package/lib/esm/components/citationpanestateful/common/defaultProps/defaultCitationPaneProps.js +61 -0
- package/lib/esm/components/confirmationpanestateful/interfaces/IConfirmationPaneLocalizedTexts.js +1 -0
- package/lib/esm/components/livechatwidget/LiveChatWidget.js +4 -4
- package/lib/esm/components/livechatwidget/common/ActivitySubscriber/AddActivitySubscriber.js +120 -0
- package/lib/esm/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js +4 -5
- package/lib/esm/components/livechatwidget/common/ChatWidgetEvents.js +8 -0
- package/lib/esm/components/livechatwidget/common/PersistentConversationHandler.js +277 -0
- package/lib/esm/components/livechatwidget/common/createAdapter.js +2 -0
- package/lib/esm/components/livechatwidget/common/defaultProps/defaultPersistentChatHistoryProps.js +11 -0
- package/lib/esm/components/livechatwidget/common/endChat.js +29 -4
- package/lib/esm/components/livechatwidget/common/getMockChatSDKIfApplicable.js +4 -3
- package/lib/esm/components/livechatwidget/common/initWebChatComposer.js +8 -6
- package/lib/esm/components/livechatwidget/common/overridePropsOnMockIfApplicable.js +2 -1
- package/lib/esm/components/livechatwidget/common/startChat.js +5 -4
- package/lib/esm/components/livechatwidget/interfaces/IMockProps.js +3 -3
- package/lib/esm/components/livechatwidget/interfaces/IPersistentChatHistoryProps.js +1 -0
- package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +29 -5
- package/lib/esm/components/webchatcontainerstateful/WebChatContainerStateful.js +125 -12
- package/lib/esm/components/webchatcontainerstateful/common/DesignerChatAdapter.js +43 -14
- package/lib/esm/components/webchatcontainerstateful/common/DesignerChatSDK.js +6 -1
- package/lib/esm/components/webchatcontainerstateful/common/activities/botActivity.js +7 -0
- package/lib/esm/components/webchatcontainerstateful/common/activities/conversationDividerActivity.js +9 -0
- package/lib/esm/components/webchatcontainerstateful/common/activityConverters/convertPersistentChatHistoryMessageToActivity.js +90 -0
- package/lib/esm/components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts.js +2 -1
- package/lib/esm/components/webchatcontainerstateful/common/defaultProps/defaultWebChatStatefulProps.js +2 -2
- package/lib/esm/components/webchatcontainerstateful/common/defaultStyles/defaultWebChatStyles.js +1 -1
- package/lib/esm/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +32 -0
- package/lib/esm/components/webchatcontainerstateful/common/utils/fontUtils.js +21 -0
- package/lib/esm/components/webchatcontainerstateful/hooks/usePersistentChatHistory.js +51 -0
- package/lib/esm/components/webchatcontainerstateful/interfaces/ICitation.js +1 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/WebChatEventSubscribers.js +115 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/Constants.js +3 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/ConversationDividerActivity.js +10 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LazyLoadActivity.js +1060 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LoadInlineBannerActivity.js +25 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.js +42 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityStatusMiddleware.js +13 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultAvatarTextStyles.js +1 -1
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultInLineBannerStyle.js +13 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultSystemMessageStyles.js +1 -1
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/DeliveredTimestamp.js +1 -1
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/HistoryMessageTimestamp.js +52 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/NotDeliveredTimestamp.js +2 -2
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/SendingTimestamp.js +1 -1
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/citationsMiddleware.js +98 -30
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.js +2 -2
- package/lib/esm/contexts/common/LiveChatWidgetActionType.js +46 -45
- package/lib/esm/contexts/common/LiveChatWidgetContextInitialState.js +2 -0
- package/lib/esm/contexts/createReducer.js +15 -0
- package/lib/esm/index.js +1 -0
- package/lib/types/common/Constants.d.ts +5 -0
- package/lib/types/common/facades/FacadeChatSDK.d.ts +3 -1
- package/lib/types/common/telemetry/TelemetryConstants.d.ts +33 -2
- package/lib/types/common/utils/SecureEventBus.d.ts +159 -0
- package/lib/types/common/utils/dispatchCustomEvent.d.ts +2 -0
- package/lib/types/components/citationpanestateful/CitationDim.d.ts +5 -0
- package/lib/types/components/citationpanestateful/CitationPaneStateful.d.ts +4 -0
- package/lib/types/components/citationpanestateful/common/defaultProps/defaultCitationPaneProps.d.ts +11 -0
- package/lib/types/components/citationpanestateful/interfaces/ICitationPaneStatefulProps.d.ts +19 -0
- package/lib/types/components/confirmationpanestateful/common/defaultProps/defaultConfirmationPaneLocalizedTexts.d.ts +1 -1
- package/lib/types/components/confirmationpanestateful/interfaces/IConfirmationPaneStatefulProps.d.ts +1 -1
- package/lib/types/components/livechatwidget/common/ActivitySubscriber/AddActivitySubscriber.d.ts +45 -0
- package/lib/types/components/livechatwidget/common/ChatWidgetEvents.d.ts +7 -0
- package/lib/types/components/livechatwidget/common/PersistentConversationHandler.d.ts +28 -0
- package/lib/types/components/livechatwidget/common/defaultProps/defaultPersistentChatHistoryProps.d.ts +2 -0
- package/lib/types/components/livechatwidget/common/getMockChatSDKIfApplicable.d.ts +2 -1
- package/lib/types/components/livechatwidget/interfaces/ILiveChatWidgetProps.d.ts +5 -1
- package/lib/types/components/livechatwidget/interfaces/IMockProps.d.ts +5 -3
- package/lib/types/components/livechatwidget/interfaces/IPersistentChatHistoryProps.d.ts +7 -0
- package/lib/types/components/webchatcontainerstateful/common/DesignerChatAdapter.d.ts +4 -2
- package/lib/types/components/webchatcontainerstateful/common/DesignerChatSDK.d.ts +5 -0
- package/lib/types/components/webchatcontainerstateful/common/activities/botActivity.d.ts +7 -0
- package/lib/types/components/webchatcontainerstateful/common/activities/conversationDividerActivity.d.ts +10 -0
- package/lib/types/components/webchatcontainerstateful/common/activityConverters/convertPersistentChatHistoryMessageToActivity.d.ts +2 -0
- package/lib/types/components/webchatcontainerstateful/common/utils/chatAdapterUtils.d.ts +6 -1
- package/lib/types/components/webchatcontainerstateful/common/utils/fontUtils.d.ts +10 -0
- package/lib/types/components/webchatcontainerstateful/hooks/usePersistentChatHistory.d.ts +4 -0
- package/lib/types/components/webchatcontainerstateful/interfaces/ICitation.d.ts +12 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/WebChatEventSubscribers.d.ts +7 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/Constants.d.ts +3 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/ConversationDividerActivity.d.ts +4 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LazyLoadActivity.d.ts +326 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LoadInlineBannerActivity.d.ts +8 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityStatusMiddleware.d.ts +1 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultInLineBannerStyle.d.ts +2 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/HistoryMessageTimestamp.d.ts +2 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/citationsMiddleware.d.ts +3 -4
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.d.ts +2 -2
- package/lib/types/contexts/common/ILiveChatWidgetContext.d.ts +1 -0
- package/lib/types/contexts/common/ILiveChatWidgetLocalizedTexts.d.ts +1 -0
- package/lib/types/contexts/common/LiveChatWidgetActionType.d.ts +46 -45
- package/lib/types/index.d.ts +1 -0
- package/package.json +3 -3
- /package/lib/cjs/components/{confirmationpanestateful/interfaces/IConfirmationPaneLocalizedText.js → citationpanestateful/interfaces/ICitationPaneStatefulProps.js} +0 -0
- /package/lib/esm/components/{confirmationpanestateful/interfaces/IConfirmationPaneLocalizedText.js → citationpanestateful/interfaces/ICitationPaneStatefulProps.js} +0 -0
- /package/lib/types/components/confirmationpanestateful/interfaces/{IConfirmationPaneLocalizedText.d.ts → IConfirmationPaneLocalizedTexts.d.ts} +0 -0
|
@@ -0,0 +1,1060 @@
|
|
|
1
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
3
|
+
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
|
4
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
5
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
7
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
8
|
+
/**
|
|
9
|
+
* LazyLoadActivity Component
|
|
10
|
+
*
|
|
11
|
+
* This component implements a sophisticated lazy loading system for chat history in the webchat widget.
|
|
12
|
+
* It uses an IntersectionObserver to detect when the user scrolls near the top of the chat container
|
|
13
|
+
* and then triggers the loading of previous chat messages.
|
|
14
|
+
*
|
|
15
|
+
* Key Features:
|
|
16
|
+
* - Intersection Observer based detection for optimal performance
|
|
17
|
+
* - Reliable scroll management with retry mechanisms
|
|
18
|
+
* - Immediate user feedback even during initialization delays
|
|
19
|
+
* - Handles edge cases like minimize/maximize widget scenarios
|
|
20
|
+
* - Memory leak prevention with proper cleanup
|
|
21
|
+
*
|
|
22
|
+
* Architecture:
|
|
23
|
+
* - LazyLoadHandler: Static class managing all lazy load logic
|
|
24
|
+
* - LazyLoadActivity: React component providing the UI and lifecycle integration for lazy loading
|
|
25
|
+
*
|
|
26
|
+
* Flow:
|
|
27
|
+
* 1. Component renders a trigger element at the top of chat history
|
|
28
|
+
* 2. IntersectionObserver watches when this element becomes visible
|
|
29
|
+
* 3. When visible, dispatches event to fetch more chat history
|
|
30
|
+
* 4. Performs controlled scroll to maintain user position
|
|
31
|
+
* 5. Resets observer for next lazy load cycle
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { LogLevel, TelemetryEvent } from "../../../../../../common/telemetry/TelemetryConstants";
|
|
35
|
+
import React, { useEffect, useState } from "react";
|
|
36
|
+
import { BroadcastEvent } from "../../../../../../common/telemetry/TelemetryConstants";
|
|
37
|
+
import { BroadcastService } from "@microsoft/omnichannel-chat-components";
|
|
38
|
+
import ChatWidgetEvents from "../../../../../livechatwidget/common/ChatWidgetEvents";
|
|
39
|
+
import { LazyLoadActivityConstants } from "./Constants";
|
|
40
|
+
import LoadInlineBannerActivity from "./LoadInlineBannerActivity";
|
|
41
|
+
import { TelemetryHelper } from "../../../../../../common/telemetry/TelemetryHelper";
|
|
42
|
+
import { createTimer } from "../../../../../../common/utils";
|
|
43
|
+
import dispatchCustomEvent from "../../../../../../common/utils/dispatchCustomEvent";
|
|
44
|
+
import SecureEventBus from "../../../../../../common/utils/SecureEventBus";
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* Interface defining the state of a scroll operation
|
|
48
|
+
* Used to track and verify scroll actions for reliability
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* LazyLoadHandler - Static class managing all lazy loading functionality
|
|
52
|
+
*
|
|
53
|
+
* This class uses a singleton pattern with static methods to ensure consistent
|
|
54
|
+
* state management across component re-renders and widget lifecycle events.
|
|
55
|
+
*
|
|
56
|
+
* State Management:
|
|
57
|
+
* - initialized: Tracks if the IntersectionObserver has been set up
|
|
58
|
+
* - paused: Temporarily disables lazy loading (during initialization/loading)
|
|
59
|
+
* - pendingScrollAction: Prevents overlapping scroll operations
|
|
60
|
+
* - isReady: Indicates when the system is fully ready for user interactions
|
|
61
|
+
* - initializationQueue: Stores user actions while system initializes
|
|
62
|
+
*
|
|
63
|
+
* Reliability Features:
|
|
64
|
+
* - Retry mechanisms with exponential backoff
|
|
65
|
+
* - Scroll verification with tolerance checking
|
|
66
|
+
* - Multiple container detection strategies
|
|
67
|
+
* - Immediate user feedback during delays
|
|
68
|
+
* - Proper memory management and cleanup
|
|
69
|
+
*/
|
|
70
|
+
let LazyLoadHandler = /*#__PURE__*/function () {
|
|
71
|
+
function LazyLoadHandler() {
|
|
72
|
+
_classCallCheck(this, LazyLoadHandler);
|
|
73
|
+
}
|
|
74
|
+
_createClass(LazyLoadHandler, null, [{
|
|
75
|
+
key: "logLifecycleEvent",
|
|
76
|
+
value:
|
|
77
|
+
// DOM element identifiers
|
|
78
|
+
// Main widget container
|
|
79
|
+
// Intersection trigger element
|
|
80
|
+
|
|
81
|
+
// Observer and initialization state
|
|
82
|
+
// Observer setup completion flag
|
|
83
|
+
// Temporary disable flag
|
|
84
|
+
// The intersection observer instance
|
|
85
|
+
|
|
86
|
+
// Scroll operation state
|
|
87
|
+
// Current scroll operation tracking
|
|
88
|
+
// Prevents concurrent scroll operations
|
|
89
|
+
|
|
90
|
+
// Timeout and queue management
|
|
91
|
+
// Tracks all setTimeout IDs for cleanup
|
|
92
|
+
|
|
93
|
+
// Flag to track if a reset is needed when component mounts
|
|
94
|
+
|
|
95
|
+
// Telemetry tracking - lifecycle events only
|
|
96
|
+
|
|
97
|
+
// Simple lifecycle logging without complex state tracking
|
|
98
|
+
function logLifecycleEvent(event, description, elapsedTime) {
|
|
99
|
+
try {
|
|
100
|
+
TelemetryHelper.logActionEvent(LogLevel.INFO, {
|
|
101
|
+
Event: event,
|
|
102
|
+
Description: description,
|
|
103
|
+
...(elapsedTime && {
|
|
104
|
+
ElapsedTimeInMilliseconds: elapsedTime
|
|
105
|
+
})
|
|
106
|
+
});
|
|
107
|
+
} catch (error) {
|
|
108
|
+
// Silent fail - don't break functionality for telemetry issues
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Broadcast event subscription for marking reset needed when chat is closed/reopened
|
|
113
|
+
}, {
|
|
114
|
+
key: "setHasMoreHistoryAvailable",
|
|
115
|
+
value:
|
|
116
|
+
// Tracks if more history can be loaded
|
|
117
|
+
|
|
118
|
+
// Debug method to track what's changing hasMoreHistoryAvailable
|
|
119
|
+
function setHasMoreHistoryAvailable(value) {
|
|
120
|
+
LazyLoadHandler.hasMoreHistoryAvailable = value;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Direct reset method that can be called externally
|
|
125
|
+
* This bypasses the broadcast system for more reliable resets
|
|
126
|
+
*/
|
|
127
|
+
}, {
|
|
128
|
+
key: "directReset",
|
|
129
|
+
value: function directReset() {
|
|
130
|
+
LazyLoadHandler.resetPending = true;
|
|
131
|
+
LazyLoadHandler.setHasMoreHistoryAvailable(true);
|
|
132
|
+
LazyLoadHandler.unmount();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Main initialization method for the lazy loading system
|
|
137
|
+
*
|
|
138
|
+
* This method sets up the IntersectionObserver that watches for when the trigger
|
|
139
|
+
* element becomes visible, indicating the user has scrolled near the top.
|
|
140
|
+
*
|
|
141
|
+
* Process:
|
|
142
|
+
* 1. Prevents duplicate initialization
|
|
143
|
+
* 2. Sets up intersection callback to handle visibility events
|
|
144
|
+
* 3. Finds appropriate scroll container with fallback strategies
|
|
145
|
+
* 4. Configures observer with optimal settings for chat history loading
|
|
146
|
+
* 5. Waits for target element availability with exponential backoff
|
|
147
|
+
*
|
|
148
|
+
* Observer Configuration:
|
|
149
|
+
* - root: The scrollable container (webchat or fallback)
|
|
150
|
+
* - rootMargin: 20px top margin to trigger slightly before element is visible
|
|
151
|
+
* - threshold: 0.05 (5%) visibility required to trigger
|
|
152
|
+
*/
|
|
153
|
+
}, {
|
|
154
|
+
key: "useLazyLoadObserver",
|
|
155
|
+
value: function useLazyLoadObserver() {
|
|
156
|
+
// Auto-correct stale state: if hasMoreHistoryAvailable is false but we're trying to initialize, reset it
|
|
157
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
158
|
+
LazyLoadHandler.setHasMoreHistoryAvailable(true);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Prevent duplicate initialization
|
|
162
|
+
if (LazyLoadHandler.initialized) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Start initialization timing
|
|
167
|
+
LazyLoadHandler.initTimer = createTimer();
|
|
168
|
+
LazyLoadHandler.logLifecycleEvent(TelemetryEvent.LCWLazyLoadInitializationStarted, "LazyLoad observer initialization started");
|
|
169
|
+
|
|
170
|
+
// Reset readiness during initialization to handle user interactions
|
|
171
|
+
LazyLoadHandler.isReady = false;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Intersection Observer Callback
|
|
175
|
+
*
|
|
176
|
+
* Triggered when the target element's visibility changes.
|
|
177
|
+
* Guards against triggering during paused states or pending operations.
|
|
178
|
+
*
|
|
179
|
+
* @param entries - Array of intersection observer entries
|
|
180
|
+
*/
|
|
181
|
+
const callback = entries => {
|
|
182
|
+
// Guard clauses: Don't trigger if paused, already processing, or no more history available
|
|
183
|
+
if (LazyLoadHandler.paused || LazyLoadHandler.pendingScrollAction || !LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
entries.forEach(entry => {
|
|
187
|
+
// Check if element is intersecting with any visibility
|
|
188
|
+
if (entry.isIntersecting && entry.intersectionRatio > 0) {
|
|
189
|
+
// Double-check history availability at trigger time
|
|
190
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
LazyLoadHandler.handleLazyLoadTrigger();
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Observer Setup Function
|
|
200
|
+
*
|
|
201
|
+
* Handles the complex process of finding the right container and
|
|
202
|
+
* setting up the intersection observer with proper configuration.
|
|
203
|
+
*/
|
|
204
|
+
const setupObserver = () => {
|
|
205
|
+
// Find the scroll container using multiple strategies
|
|
206
|
+
const {
|
|
207
|
+
container: scrollContainer
|
|
208
|
+
} = LazyLoadHandler.findScrollContainer();
|
|
209
|
+
if (!scrollContainer) {
|
|
210
|
+
// Schedule retry with faster timeout for better responsiveness
|
|
211
|
+
const timeoutId = window.setTimeout(() => {
|
|
212
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
213
|
+
setupObserver();
|
|
214
|
+
}, 100); // Reduced from 200ms to 100ms for faster container detection
|
|
215
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Configure intersection observer options
|
|
220
|
+
const options = {
|
|
221
|
+
root: scrollContainer,
|
|
222
|
+
// Container to observe within
|
|
223
|
+
rootMargin: "20px 0px 0px 0px",
|
|
224
|
+
// Trigger 20px before element is visible
|
|
225
|
+
threshold: 0.05 // Trigger when 5% of element is visible
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const observer = new IntersectionObserver(callback, options);
|
|
229
|
+
|
|
230
|
+
// Wait for target element and finalize setup
|
|
231
|
+
LazyLoadHandler.waitForTargetElement(() => {
|
|
232
|
+
const targetElement = document.getElementById(LazyLoadHandler.targetId);
|
|
233
|
+
if (targetElement) {
|
|
234
|
+
observer.observe(targetElement);
|
|
235
|
+
LazyLoadHandler.observer = observer;
|
|
236
|
+
LazyLoadHandler.initialized = true;
|
|
237
|
+
LazyLoadHandler.isReady = true; // Mark system as ready
|
|
238
|
+
|
|
239
|
+
// Log successful initialization
|
|
240
|
+
LazyLoadHandler.logLifecycleEvent(TelemetryEvent.LCWLazyLoadInitializationCompleted, "LazyLoad observer initialization completed", LazyLoadHandler.initTimer.milliSecondsElapsed);
|
|
241
|
+
|
|
242
|
+
// Process any actions that were queued during initialization
|
|
243
|
+
LazyLoadHandler.processInitializationQueue();
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
setupObserver();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Waits for the target element to be available in the DOM
|
|
252
|
+
*
|
|
253
|
+
* Uses exponential backoff to retry finding the target element.
|
|
254
|
+
* This is necessary because the target element may not be immediately
|
|
255
|
+
* available when the observer is being set up.
|
|
256
|
+
*
|
|
257
|
+
* @param callback - Function to call when target element is found
|
|
258
|
+
* @param maxAttempts - Maximum number of retry attempts (default: 10)
|
|
259
|
+
* @param attempt - Current attempt number (default: 1)
|
|
260
|
+
*/
|
|
261
|
+
}, {
|
|
262
|
+
key: "waitForTargetElement",
|
|
263
|
+
value: function waitForTargetElement(callback) {
|
|
264
|
+
let maxAttempts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10;
|
|
265
|
+
let attempt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
|
|
266
|
+
const targetElement = document.getElementById(LazyLoadHandler.targetId);
|
|
267
|
+
|
|
268
|
+
// Target found, execute callback
|
|
269
|
+
if (targetElement) {
|
|
270
|
+
callback();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Max attempts reached, log error
|
|
275
|
+
if (attempt >= maxAttempts) {
|
|
276
|
+
LazyLoadHandler.logLifecycleEvent(TelemetryEvent.LCWLazyLoadTargetElementNotFound, "Target element not found after max attempts");
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Schedule retry with exponential backoff (50ms * attempt number for faster initial attempts)
|
|
281
|
+
const timeoutId = window.setTimeout(() => {
|
|
282
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
283
|
+
LazyLoadHandler.waitForTargetElement(callback, maxAttempts, attempt + 1);
|
|
284
|
+
}, 50 * attempt); // Reduced from 100ms to 50ms for faster element detection
|
|
285
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Handles immediate scroll requests when system might not be ready
|
|
290
|
+
*
|
|
291
|
+
* This is crucial for handling minimize/maximize scenarios where users
|
|
292
|
+
* immediately scroll up before the observer is fully initialized.
|
|
293
|
+
*
|
|
294
|
+
* Two-Path Strategy:
|
|
295
|
+
* 1. If ready: Execute normal lazy load trigger
|
|
296
|
+
* 2. If not ready: Provide immediate feedback + queue action for later
|
|
297
|
+
*
|
|
298
|
+
* This ensures users always get visual feedback even during initialization delays.
|
|
299
|
+
*/
|
|
300
|
+
}, {
|
|
301
|
+
key: "handleImmediateScrollRequest",
|
|
302
|
+
value: function handleImmediateScrollRequest() {
|
|
303
|
+
if (LazyLoadHandler.isReady) {
|
|
304
|
+
// System is ready, handle normally
|
|
305
|
+
LazyLoadHandler.handleLazyLoadTrigger();
|
|
306
|
+
} else {
|
|
307
|
+
// System not ready, provide immediate feedback and queue action
|
|
308
|
+
LazyLoadHandler.executeImmediateScrollFeedback();
|
|
309
|
+
|
|
310
|
+
// Queue the full lazy load action to execute when system is ready
|
|
311
|
+
LazyLoadHandler.initializationQueue.push(() => {
|
|
312
|
+
LazyLoadHandler.handleLazyLoadTrigger();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Try to speed up initialization
|
|
316
|
+
LazyLoadHandler.expediteInitialization();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Provides immediate scroll feedback during initialization
|
|
322
|
+
*
|
|
323
|
+
* When the system isn't ready but user scrolls up, this provides
|
|
324
|
+
* immediate visual feedback (20px scroll) so the user knows their
|
|
325
|
+
* action was recognized.
|
|
326
|
+
*/
|
|
327
|
+
}, {
|
|
328
|
+
key: "executeImmediateScrollFeedback",
|
|
329
|
+
value: function executeImmediateScrollFeedback() {
|
|
330
|
+
// Find container and validate scrollability
|
|
331
|
+
const {
|
|
332
|
+
container,
|
|
333
|
+
isScrollable
|
|
334
|
+
} = LazyLoadHandler.findScrollContainer();
|
|
335
|
+
if (container && isScrollable) {
|
|
336
|
+
const currentScrollTop = container.scrollTop;
|
|
337
|
+
const immediateScrollTarget = currentScrollTop + 20; // Small immediate scroll for feedback
|
|
338
|
+
|
|
339
|
+
// Use requestAnimationFrame for smooth scroll execution
|
|
340
|
+
requestAnimationFrame(() => {
|
|
341
|
+
if (container) {
|
|
342
|
+
container.scrollTop = immediateScrollTarget;
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Forces faster initialization attempts
|
|
350
|
+
*
|
|
351
|
+
* When user interacts before system is ready, this tries to
|
|
352
|
+
* speed up the initialization process.
|
|
353
|
+
*/
|
|
354
|
+
}, {
|
|
355
|
+
key: "expediteInitialization",
|
|
356
|
+
value: function expediteInitialization() {
|
|
357
|
+
// Force faster initialization attempts if not already initialized
|
|
358
|
+
if (!LazyLoadHandler.initialized) {
|
|
359
|
+
LazyLoadHandler.useLazyLoadObserver();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Processes all queued actions once system is ready
|
|
365
|
+
*
|
|
366
|
+
* During initialization, user actions are queued. Once the system
|
|
367
|
+
* is ready, this processes all queued actions with small delays
|
|
368
|
+
* between them to prevent overwhelming the system.
|
|
369
|
+
*/
|
|
370
|
+
}, {
|
|
371
|
+
key: "processInitializationQueue",
|
|
372
|
+
value: function processInitializationQueue() {
|
|
373
|
+
// Process all queued actions sequentially
|
|
374
|
+
while (LazyLoadHandler.initializationQueue.length > 0) {
|
|
375
|
+
const action = LazyLoadHandler.initializationQueue.shift();
|
|
376
|
+
if (action) {
|
|
377
|
+
// Add small delay between queued actions to prevent conflicts
|
|
378
|
+
const timeoutId = window.setTimeout(() => {
|
|
379
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
380
|
+
action();
|
|
381
|
+
}, 25); // Reduced from 100ms to 25ms for faster processing
|
|
382
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Manually checks if target element is visible and triggers lazy load
|
|
389
|
+
*
|
|
390
|
+
* This is used when the intersection observer might not be ready yet
|
|
391
|
+
* but we need to check if the trigger element is already in view.
|
|
392
|
+
*
|
|
393
|
+
* Uses getBoundingClientRect() to calculate visibility manually.
|
|
394
|
+
*/
|
|
395
|
+
}, {
|
|
396
|
+
key: "checkVisibilityAndTrigger",
|
|
397
|
+
value: function checkVisibilityAndTrigger() {
|
|
398
|
+
// Don't trigger if no more history is available
|
|
399
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const targetElement = document.getElementById(LazyLoadHandler.targetId);
|
|
403
|
+
if (!targetElement) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const {
|
|
407
|
+
container
|
|
408
|
+
} = LazyLoadHandler.findScrollContainer();
|
|
409
|
+
if (!container) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Get bounding rectangles for visibility calculation
|
|
414
|
+
const targetRect = targetElement.getBoundingClientRect();
|
|
415
|
+
const containerRect = container.getBoundingClientRect();
|
|
416
|
+
|
|
417
|
+
// Check if target element intersects with container viewport
|
|
418
|
+
const isVisible = targetRect.top < containerRect.bottom &&
|
|
419
|
+
// Target top is above container bottom
|
|
420
|
+
targetRect.bottom > containerRect.top &&
|
|
421
|
+
// Target bottom is below container top
|
|
422
|
+
targetRect.left < containerRect.right &&
|
|
423
|
+
// Target left is before container right
|
|
424
|
+
targetRect.right > containerRect.left // Target right is after container left
|
|
425
|
+
;
|
|
426
|
+
|
|
427
|
+
if (isVisible) {
|
|
428
|
+
LazyLoadHandler.handleImmediateScrollRequest();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Main lazy load trigger handler
|
|
434
|
+
*
|
|
435
|
+
* This is the core method that executes when the trigger element becomes visible.
|
|
436
|
+
* It coordinates the entire lazy loading process:
|
|
437
|
+
*
|
|
438
|
+
* 1. Sets flags to prevent concurrent operations
|
|
439
|
+
* 2. Dispatches event to fetch more chat history
|
|
440
|
+
* 3. Waits for content to load
|
|
441
|
+
* 4. Executes scroll adjustment to maintain user position
|
|
442
|
+
*
|
|
443
|
+
* Timing: Uses 300ms delay to allow content loading before scroll adjustment
|
|
444
|
+
*/
|
|
445
|
+
}, {
|
|
446
|
+
key: "handleLazyLoadTrigger",
|
|
447
|
+
value: function handleLazyLoadTrigger() {
|
|
448
|
+
// Final guard: Don't proceed if no more history is available
|
|
449
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Set flags to prevent overlapping operations
|
|
454
|
+
LazyLoadHandler.pendingScrollAction = true; // Block new scroll actions
|
|
455
|
+
LazyLoadHandler.paused = true; // Pause intersection observer
|
|
456
|
+
|
|
457
|
+
// Dispatch custom event to trigger chat history fetching
|
|
458
|
+
// This event is handled by other parts of the chat system
|
|
459
|
+
dispatchCustomEvent(ChatWidgetEvents.FETCH_PERSISTENT_CHAT_HISTORY);
|
|
460
|
+
|
|
461
|
+
// Wait for content to load before performing scroll adjustment
|
|
462
|
+
// 200ms provides good balance between responsiveness and content loading
|
|
463
|
+
const timeoutId = window.setTimeout(() => {
|
|
464
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
465
|
+
LazyLoadHandler.executeReliableScroll();
|
|
466
|
+
}, 200); // Reduced from 300ms to 200ms for faster response
|
|
467
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Executes reliable scroll with validation and retry logic
|
|
472
|
+
*
|
|
473
|
+
* This method implements a robust scroll system that:
|
|
474
|
+
* 1. Finds and validates the scroll container
|
|
475
|
+
* 2. Calculates target scroll position (current + 35px)
|
|
476
|
+
* 3. Sets up scroll state for tracking and retries
|
|
477
|
+
* 4. Initiates the scroll attempt process
|
|
478
|
+
*
|
|
479
|
+
* If no suitable container is found, schedules a retry.
|
|
480
|
+
*/
|
|
481
|
+
}, {
|
|
482
|
+
key: "executeReliableScroll",
|
|
483
|
+
value: function executeReliableScroll() {
|
|
484
|
+
// Guard: Don't execute scroll if no more history is available
|
|
485
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
486
|
+
LazyLoadHandler.finishScrollAction();
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Find container using multiple fallback strategies
|
|
491
|
+
const {
|
|
492
|
+
container,
|
|
493
|
+
isScrollable
|
|
494
|
+
} = LazyLoadHandler.findScrollContainer();
|
|
495
|
+
if (!container || !isScrollable) {
|
|
496
|
+
LazyLoadHandler.scheduleScrollRetry();
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Calculate scroll positions
|
|
501
|
+
const initialScrollTop = container.scrollTop;
|
|
502
|
+
const targetScrollTop = initialScrollTop + 35; // 35px down to maintain position
|
|
503
|
+
|
|
504
|
+
// Set up scroll state for tracking and retries
|
|
505
|
+
LazyLoadHandler.scrollState = {
|
|
506
|
+
container,
|
|
507
|
+
initialScrollTop,
|
|
508
|
+
targetScrollTop,
|
|
509
|
+
attemptCount: 0,
|
|
510
|
+
maxAttempts: 5 // Allow up to 5 retry attempts
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
// Begin the scroll attempt process
|
|
514
|
+
LazyLoadHandler.attemptScroll();
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Attempts to perform scroll with verification and retry logic
|
|
519
|
+
*
|
|
520
|
+
* This method implements a sophisticated scroll system:
|
|
521
|
+
*
|
|
522
|
+
* 1. Uses requestAnimationFrame for smooth execution
|
|
523
|
+
* 2. Performs the scroll operation
|
|
524
|
+
* 3. Verifies scroll actually occurred (5px tolerance)
|
|
525
|
+
* 4. Retries with exponential backoff if failed
|
|
526
|
+
* 5. Continues operation after max attempts
|
|
527
|
+
*
|
|
528
|
+
* The two-frame approach ensures scroll is applied and then verified
|
|
529
|
+
* after the browser has had time to process the scroll change.
|
|
530
|
+
*/
|
|
531
|
+
}, {
|
|
532
|
+
key: "attemptScroll",
|
|
533
|
+
value: function attemptScroll() {
|
|
534
|
+
// Guard: Don't attempt scroll if no more history is available
|
|
535
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
536
|
+
LazyLoadHandler.finishScrollAction();
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
if (!LazyLoadHandler.scrollState) {
|
|
540
|
+
LazyLoadHandler.finishScrollAction();
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Extract current scroll state
|
|
545
|
+
const {
|
|
546
|
+
container,
|
|
547
|
+
targetScrollTop,
|
|
548
|
+
attemptCount,
|
|
549
|
+
maxAttempts
|
|
550
|
+
} = LazyLoadHandler.scrollState;
|
|
551
|
+
LazyLoadHandler.scrollState.attemptCount++;
|
|
552
|
+
|
|
553
|
+
// Perform scroll using requestAnimationFrame for smooth execution
|
|
554
|
+
// Frame 1: Apply the scroll
|
|
555
|
+
requestAnimationFrame(() => {
|
|
556
|
+
// Double-check history availability before applying scroll
|
|
557
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
558
|
+
LazyLoadHandler.finishScrollAction();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (container) {
|
|
562
|
+
container.scrollTop = targetScrollTop;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Frame 2: Verify scroll occurred after browser has processed the change
|
|
566
|
+
requestAnimationFrame(() => {
|
|
567
|
+
// Triple-check history availability before verification
|
|
568
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
569
|
+
LazyLoadHandler.finishScrollAction();
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const actualScrollTop = container ? container.scrollTop : 0;
|
|
573
|
+
const scrollSucceeded = Math.abs(actualScrollTop - targetScrollTop) < 5; // 5px tolerance for success
|
|
574
|
+
|
|
575
|
+
if (scrollSucceeded) {
|
|
576
|
+
LazyLoadHandler.finishScrollAction();
|
|
577
|
+
} else if (attemptCount < maxAttempts) {
|
|
578
|
+
// Retry with exponential backoff (100ms * attempt number)
|
|
579
|
+
const timeoutId = window.setTimeout(() => {
|
|
580
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
581
|
+
LazyLoadHandler.attemptScroll();
|
|
582
|
+
}, 100 * attemptCount); // Exponential backoff
|
|
583
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
584
|
+
} else {
|
|
585
|
+
LazyLoadHandler.finishScrollAction();
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Finishes scroll action and prepares for next cycle
|
|
593
|
+
*
|
|
594
|
+
* Cleans up scroll state and schedules the reset cycle.
|
|
595
|
+
* Uses delays to allow content stabilization before re-enabling
|
|
596
|
+
* the intersection observer for the next lazy load cycle.
|
|
597
|
+
*/
|
|
598
|
+
}, {
|
|
599
|
+
key: "finishScrollAction",
|
|
600
|
+
value: function finishScrollAction() {
|
|
601
|
+
// Clean up scroll tracking state
|
|
602
|
+
LazyLoadHandler.scrollState = null;
|
|
603
|
+
LazyLoadHandler.pendingScrollAction = false;
|
|
604
|
+
|
|
605
|
+
// Schedule unpause and reset with delay for content stabilization
|
|
606
|
+
const timeoutId = window.setTimeout(() => {
|
|
607
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
608
|
+
LazyLoadHandler.paused = false; // Re-enable intersection observer
|
|
609
|
+
LazyLoadHandler.scheduleReset(); // Schedule next cycle reset
|
|
610
|
+
}, 500);
|
|
611
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Schedules retry for failed scroll operations
|
|
616
|
+
*
|
|
617
|
+
* Used when scroll container is not available or scrollable.
|
|
618
|
+
* Provides a longer delay to allow container to become ready.
|
|
619
|
+
*/
|
|
620
|
+
}, {
|
|
621
|
+
key: "scheduleScrollRetry",
|
|
622
|
+
value: function scheduleScrollRetry() {
|
|
623
|
+
// Don't schedule retry if no more history is available
|
|
624
|
+
if (!LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
625
|
+
LazyLoadHandler.finishScrollAction();
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const timeoutId = window.setTimeout(() => {
|
|
629
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
630
|
+
// Only retry if we're still in a pending scroll action state and have more history
|
|
631
|
+
if (LazyLoadHandler.pendingScrollAction && LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
632
|
+
LazyLoadHandler.executeReliableScroll();
|
|
633
|
+
}
|
|
634
|
+
}, 1000); // 1 second delay for container readiness
|
|
635
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Schedules observer reset for next lazy load cycle
|
|
640
|
+
*
|
|
641
|
+
* After a lazy load operation completes, the observer needs to be reset
|
|
642
|
+
* to detect the next time the user scrolls to the top.
|
|
643
|
+
*/
|
|
644
|
+
}, {
|
|
645
|
+
key: "scheduleReset",
|
|
646
|
+
value: function scheduleReset() {
|
|
647
|
+
const timeoutId = window.setTimeout(() => {
|
|
648
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
649
|
+
LazyLoadHandler.reset();
|
|
650
|
+
}, 1000); // 1 second delay before resetting for next cycle
|
|
651
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Finds the appropriate scroll container using multiple strategies
|
|
656
|
+
*
|
|
657
|
+
* Container Detection Priority:
|
|
658
|
+
* 1. Primary: Specific webchat scroll container (.webchat__basic-transcript__scrollable)
|
|
659
|
+
* 2. Secondary: Widget root container (ms_lcw_webchat_root)
|
|
660
|
+
* 3. Tertiary: Any scrollable parent of the target element
|
|
661
|
+
* 4. Fallback: Best available container (even if not scrollable)
|
|
662
|
+
*
|
|
663
|
+
* Returns both the container and whether it's actually scrollable.
|
|
664
|
+
*
|
|
665
|
+
* @returns Object containing container element and scrollability status
|
|
666
|
+
*/
|
|
667
|
+
}, {
|
|
668
|
+
key: "findScrollContainer",
|
|
669
|
+
value: function findScrollContainer() {
|
|
670
|
+
// Primary: Look for the specific webchat scroll container
|
|
671
|
+
const webchatContainer = document.querySelector(LazyLoadActivityConstants.SCROLL_ID);
|
|
672
|
+
if (webchatContainer && LazyLoadHandler.isElementScrollable(webchatContainer)) {
|
|
673
|
+
return {
|
|
674
|
+
container: webchatContainer,
|
|
675
|
+
isScrollable: true
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Secondary: Try the root container
|
|
680
|
+
const rootContainer = document.getElementById(LazyLoadHandler.rootId);
|
|
681
|
+
if (rootContainer && LazyLoadHandler.isElementScrollable(rootContainer)) {
|
|
682
|
+
return {
|
|
683
|
+
container: rootContainer,
|
|
684
|
+
isScrollable: true
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Tertiary: Find any scrollable parent of the target element
|
|
689
|
+
const targetElement = document.getElementById(LazyLoadHandler.targetId);
|
|
690
|
+
if (targetElement) {
|
|
691
|
+
const scrollableParent = LazyLoadHandler.findScrollableParent(targetElement);
|
|
692
|
+
if (scrollableParent) {
|
|
693
|
+
return {
|
|
694
|
+
container: scrollableParent,
|
|
695
|
+
isScrollable: true
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Fallback: Return the best available container even if not scrollable
|
|
701
|
+
// This allows the system to continue functioning in edge cases
|
|
702
|
+
return {
|
|
703
|
+
container: webchatContainer || rootContainer || document.body,
|
|
704
|
+
isScrollable: false
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Determines if an element is scrollable
|
|
710
|
+
*
|
|
711
|
+
* Checks two conditions:
|
|
712
|
+
* 1. Content overflow: scrollHeight > clientHeight (content extends beyond visible area)
|
|
713
|
+
* 2. CSS overflow settings: overflow/overflowY set to 'auto' or 'scroll'
|
|
714
|
+
*
|
|
715
|
+
* @param element - The element to check for scrollability
|
|
716
|
+
* @returns true if element is scrollable, false otherwise
|
|
717
|
+
*/
|
|
718
|
+
}, {
|
|
719
|
+
key: "isElementScrollable",
|
|
720
|
+
value: function isElementScrollable(element) {
|
|
721
|
+
const style = window.getComputedStyle(element);
|
|
722
|
+
const hasScrollableContent = element.scrollHeight > element.clientHeight;
|
|
723
|
+
const hasScrollableOverflow = style.overflow === "auto" || style.overflow === "scroll" || style.overflowY === "auto" || style.overflowY === "scroll";
|
|
724
|
+
return hasScrollableContent && hasScrollableOverflow;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Traverses up the DOM tree to find a scrollable parent element
|
|
729
|
+
*
|
|
730
|
+
* Starting from the given element, walks up the parent chain
|
|
731
|
+
* until it finds a scrollable element or reaches document.body.
|
|
732
|
+
*
|
|
733
|
+
* @param element - Starting element to search from
|
|
734
|
+
* @returns Scrollable parent element or null if none found
|
|
735
|
+
*/
|
|
736
|
+
}, {
|
|
737
|
+
key: "findScrollableParent",
|
|
738
|
+
value: function findScrollableParent(element) {
|
|
739
|
+
let parent = element.parentElement;
|
|
740
|
+
while (parent && parent !== document.body) {
|
|
741
|
+
if (LazyLoadHandler.isElementScrollable(parent)) {
|
|
742
|
+
return parent;
|
|
743
|
+
}
|
|
744
|
+
parent = parent.parentElement;
|
|
745
|
+
}
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Legacy method - redirects to new reliable scroll system
|
|
751
|
+
*
|
|
752
|
+
* Maintained for backwards compatibility with existing code
|
|
753
|
+
* that might call this method directly.
|
|
754
|
+
*/
|
|
755
|
+
}, {
|
|
756
|
+
key: "moveScrollDown",
|
|
757
|
+
value: function moveScrollDown() {
|
|
758
|
+
LazyLoadHandler.executeReliableScroll();
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Legacy scroll adjustment method with enhancements
|
|
763
|
+
*
|
|
764
|
+
* Enhanced version of the original adjustScroll method:
|
|
765
|
+
* - Validates container scrollability before attempting scroll
|
|
766
|
+
* - Uses requestAnimationFrame for smooth execution
|
|
767
|
+
* - Provides logging for debugging
|
|
768
|
+
*
|
|
769
|
+
* @param scrollContainer - The container element to scroll
|
|
770
|
+
*/
|
|
771
|
+
}, {
|
|
772
|
+
key: "adjustScroll",
|
|
773
|
+
value: function adjustScroll(scrollContainer) {
|
|
774
|
+
// Validate container is scrollable before attempting scroll
|
|
775
|
+
if (!LazyLoadHandler.isElementScrollable(scrollContainer)) {
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
const currentScrollTop = scrollContainer.scrollTop;
|
|
779
|
+
const moveDownBy = 35; // Standard scroll adjustment amount
|
|
780
|
+
const targetScrollTop = currentScrollTop + moveDownBy;
|
|
781
|
+
|
|
782
|
+
// Use requestAnimationFrame for smooth scroll execution
|
|
783
|
+
requestAnimationFrame(() => {
|
|
784
|
+
scrollContainer.scrollTop = targetScrollTop;
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Handles the NO_MORE_HISTORY_AVAILABLE event
|
|
790
|
+
*
|
|
791
|
+
* Called when there's no more chat history to load.
|
|
792
|
+
* Disables further lazy loading attempts and cleans up the observer.
|
|
793
|
+
* Also removes the trigger element from the DOM to prevent further triggering.
|
|
794
|
+
*/
|
|
795
|
+
}, {
|
|
796
|
+
key: "handleNoMoreHistoryAvailable",
|
|
797
|
+
value: function handleNoMoreHistoryAvailable() {
|
|
798
|
+
LazyLoadHandler.setHasMoreHistoryAvailable(false);
|
|
799
|
+
LazyLoadHandler.paused = true;
|
|
800
|
+
LazyLoadHandler.pendingScrollAction = false; // Reset this to prevent stuck states
|
|
801
|
+
|
|
802
|
+
LazyLoadHandler.logLifecycleEvent(TelemetryEvent.LCWLazyLoadNoMoreHistory, "No more history available");
|
|
803
|
+
|
|
804
|
+
// Clear all pending timeouts to stop any scheduled operations
|
|
805
|
+
LazyLoadHandler.retryTimeouts.forEach(timeoutId => {
|
|
806
|
+
clearTimeout(timeoutId);
|
|
807
|
+
});
|
|
808
|
+
LazyLoadHandler.retryTimeouts.clear();
|
|
809
|
+
|
|
810
|
+
// Disconnect observer to prevent further triggering
|
|
811
|
+
if (LazyLoadHandler.observer) {
|
|
812
|
+
LazyLoadHandler.observer.disconnect();
|
|
813
|
+
LazyLoadHandler.observer = null;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// Clear scroll state
|
|
817
|
+
LazyLoadHandler.scrollState = null;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Resets the lazy load system for the next cycle
|
|
822
|
+
*
|
|
823
|
+
* This method prepares the system for the next lazy load operation:
|
|
824
|
+
* 1. Cleans up current state
|
|
825
|
+
* 2. Resets all flags and queues
|
|
826
|
+
* 3. Reinitializes the observer with faster timing
|
|
827
|
+
*
|
|
828
|
+
* Called after each lazy load cycle completes.
|
|
829
|
+
*/
|
|
830
|
+
}, {
|
|
831
|
+
key: "reset",
|
|
832
|
+
value: function reset() {
|
|
833
|
+
LazyLoadHandler.unmount(); // Clean up current state
|
|
834
|
+
LazyLoadHandler.initialized = false; // Reset initialization flag
|
|
835
|
+
LazyLoadHandler.isReady = false; // Reset readiness flag
|
|
836
|
+
LazyLoadHandler.setHasMoreHistoryAvailable(true); // Reset history availability flag
|
|
837
|
+
LazyLoadHandler.initializationQueue = []; // Clear action queue
|
|
838
|
+
LazyLoadHandler.resetPending = false; // Clear pending reset flag
|
|
839
|
+
|
|
840
|
+
// Reinitialize with faster timing for better responsiveness
|
|
841
|
+
const timeoutId = window.setTimeout(() => {
|
|
842
|
+
LazyLoadHandler.retryTimeouts.delete(timeoutId);
|
|
843
|
+
LazyLoadHandler.useLazyLoadObserver();
|
|
844
|
+
}, 25); // Reduced from 50ms to 25ms for faster reset
|
|
845
|
+
LazyLoadHandler.retryTimeouts.add(timeoutId);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Comprehensive cleanup method
|
|
850
|
+
*
|
|
851
|
+
* Performs complete cleanup of all lazy load resources:
|
|
852
|
+
* - Clears all pending timeouts to prevent memory leaks
|
|
853
|
+
* - Removes intersection observer and event listeners
|
|
854
|
+
* - Resets all state variables to initial values
|
|
855
|
+
* - Clears action queue
|
|
856
|
+
*
|
|
857
|
+
* Critical for preventing memory leaks and ensuring clean component unmounting.
|
|
858
|
+
*/
|
|
859
|
+
}, {
|
|
860
|
+
key: "unmount",
|
|
861
|
+
value: function unmount() {
|
|
862
|
+
LazyLoadHandler.retryTimeouts.forEach(timeoutId => {
|
|
863
|
+
clearTimeout(timeoutId);
|
|
864
|
+
});
|
|
865
|
+
LazyLoadHandler.retryTimeouts.clear();
|
|
866
|
+
|
|
867
|
+
// Clean up intersection observer
|
|
868
|
+
const targetElement = document.getElementById(LazyLoadHandler.targetId);
|
|
869
|
+
if (targetElement && LazyLoadHandler.observer) {
|
|
870
|
+
LazyLoadHandler.observer.unobserve(targetElement);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Reset all state variables to initial values
|
|
874
|
+
LazyLoadHandler.observer = null;
|
|
875
|
+
LazyLoadHandler.initialized = false;
|
|
876
|
+
LazyLoadHandler.paused = false;
|
|
877
|
+
LazyLoadHandler.pendingScrollAction = false;
|
|
878
|
+
LazyLoadHandler.scrollState = null;
|
|
879
|
+
LazyLoadHandler.isReady = false;
|
|
880
|
+
LazyLoadHandler.initializationQueue = [];
|
|
881
|
+
// Note: Don't reset resetPending here as it needs to persist across unmount/mount cycles
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Complete cleanup including broadcast event listener
|
|
886
|
+
*
|
|
887
|
+
* This method is used for final cleanup when the LazyLoadActivity component is being destroyed completely.
|
|
888
|
+
* It includes unsubscribing from broadcast events and performing complete cleanup.
|
|
889
|
+
* This is different from reset() which prepares the system for a new chat session.
|
|
890
|
+
*/
|
|
891
|
+
}, {
|
|
892
|
+
key: "destroy",
|
|
893
|
+
value: function destroy() {
|
|
894
|
+
LazyLoadHandler.logLifecycleEvent(TelemetryEvent.LCWLazyLoadDestroyed, "LazyLoad component destroyed");
|
|
895
|
+
LazyLoadHandler.unmount();
|
|
896
|
+
|
|
897
|
+
// Clean up broadcast event subscription
|
|
898
|
+
if (LazyLoadHandler.resetEventListener) {
|
|
899
|
+
LazyLoadHandler.resetEventListener.unsubscribe();
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}]);
|
|
903
|
+
return LazyLoadHandler;
|
|
904
|
+
}();
|
|
905
|
+
/**
|
|
906
|
+
* LazyLoadActivity React Component
|
|
907
|
+
*
|
|
908
|
+
* This component serves as the React wrapper for the LazyLoadHandler system.
|
|
909
|
+
* It renders the trigger element and manages the component lifecycle.
|
|
910
|
+
*
|
|
911
|
+
* Component Lifecycle:
|
|
912
|
+
* 1. Mount: Initializes lazy load observer and sets up scroll listener
|
|
913
|
+
* 2. Active: Monitors user scroll behavior and responds to interactions
|
|
914
|
+
* 3. Unmount: Cleans up all resources and prevents memory leaks
|
|
915
|
+
*
|
|
916
|
+
* Key Features:
|
|
917
|
+
* - Automatic initialization on mount
|
|
918
|
+
* - Scroll event monitoring for immediate responsiveness
|
|
919
|
+
* - Proper cleanup on unmount
|
|
920
|
+
* - Handles minimize/maximize scenarios
|
|
921
|
+
* - Reactive rendering based on history availability
|
|
922
|
+
*/
|
|
923
|
+
_defineProperty(LazyLoadHandler, "rootId", "ms_lcw_webchat_root");
|
|
924
|
+
_defineProperty(LazyLoadHandler, "targetId", "lazy-load-trigger-element");
|
|
925
|
+
_defineProperty(LazyLoadHandler, "initialized", false);
|
|
926
|
+
_defineProperty(LazyLoadHandler, "paused", false);
|
|
927
|
+
_defineProperty(LazyLoadHandler, "observer", null);
|
|
928
|
+
_defineProperty(LazyLoadHandler, "scrollState", null);
|
|
929
|
+
_defineProperty(LazyLoadHandler, "pendingScrollAction", false);
|
|
930
|
+
_defineProperty(LazyLoadHandler, "retryTimeouts", new Set());
|
|
931
|
+
_defineProperty(LazyLoadHandler, "resetPending", false);
|
|
932
|
+
_defineProperty(LazyLoadHandler, "initTimer", createTimer());
|
|
933
|
+
_defineProperty(LazyLoadHandler, "resetEventListener", BroadcastService.getMessageByEventName(BroadcastEvent.PersistentConversationReset).subscribe(() => {
|
|
934
|
+
LazyLoadHandler.logLifecycleEvent(TelemetryEvent.LCWLazyLoadReset, "LazyLoad reset triggered");
|
|
935
|
+
LazyLoadHandler.resetPending = true;
|
|
936
|
+
LazyLoadHandler.setHasMoreHistoryAvailable(true); // Reset this immediately so activityMiddleware doesn't block rendering
|
|
937
|
+
LazyLoadHandler.unmount(); // Clean up current state immediately
|
|
938
|
+
}));
|
|
939
|
+
// Readiness and queue system (handles minimize/maximize scenarios)
|
|
940
|
+
_defineProperty(LazyLoadHandler, "isReady", false);
|
|
941
|
+
// System readiness flag
|
|
942
|
+
_defineProperty(LazyLoadHandler, "initializationQueue", []);
|
|
943
|
+
// Queue for actions during initialization
|
|
944
|
+
// History availability state
|
|
945
|
+
_defineProperty(LazyLoadHandler, "hasMoreHistoryAvailable", true);
|
|
946
|
+
const LazyLoadActivity = props => {
|
|
947
|
+
const [hasMoreHistory, setHasMoreHistory] = useState(LazyLoadHandler.hasMoreHistoryAvailable);
|
|
948
|
+
useEffect(() => {
|
|
949
|
+
LazyLoadHandler.logLifecycleEvent(TelemetryEvent.LCWLazyLoadActivityMounted, "LazyLoadActivity component mounted");
|
|
950
|
+
|
|
951
|
+
// Set up event listeners FIRST - before any early returns
|
|
952
|
+
// Event listener for NO_MORE_HISTORY_AVAILABLE
|
|
953
|
+
const handleNoMoreHistory = () => {
|
|
954
|
+
LazyLoadHandler.handleNoMoreHistoryAvailable();
|
|
955
|
+
// Update React state to trigger re-render and hide component
|
|
956
|
+
setHasMoreHistory(false);
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
// Event listener for PersistentConversationReset to sync React state
|
|
960
|
+
// This fixes the issue where banner doesn't appear in start chat + close chat + start chat sequence
|
|
961
|
+
// by ensuring React state (hasMoreHistory) is synchronized with handler state when reset occurs
|
|
962
|
+
const handlePersistentConversationReset = () => {
|
|
963
|
+
// Update React state to trigger re-render and show component for new chat session
|
|
964
|
+
setHasMoreHistory(true);
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
// Add secure event listener for no more history signal
|
|
968
|
+
const eventBus = SecureEventBus.getInstance();
|
|
969
|
+
const unsubscribeNoMoreHistory = eventBus.subscribe(ChatWidgetEvents.NO_MORE_HISTORY_AVAILABLE, handleNoMoreHistory);
|
|
970
|
+
|
|
971
|
+
// Add event listener for persistent conversation reset
|
|
972
|
+
const resetSubscription = BroadcastService.getMessageByEventName(BroadcastEvent.PersistentConversationReset).subscribe(handlePersistentConversationReset);
|
|
973
|
+
|
|
974
|
+
// Sync React state with handler state on mount in case they're out of sync
|
|
975
|
+
if (hasMoreHistory !== LazyLoadHandler.hasMoreHistoryAvailable) {
|
|
976
|
+
setHasMoreHistory(LazyLoadHandler.hasMoreHistoryAvailable);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// Check if a reset was pending from a previous chat session
|
|
980
|
+
if (LazyLoadHandler.resetPending) {
|
|
981
|
+
LazyLoadHandler.resetPending = false;
|
|
982
|
+
LazyLoadHandler.reset();
|
|
983
|
+
|
|
984
|
+
// Still need to return cleanup function even after reset
|
|
985
|
+
return () => {
|
|
986
|
+
unsubscribeNoMoreHistory();
|
|
987
|
+
resetSubscription.unsubscribe();
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// Initialize the lazy load observer system
|
|
992
|
+
LazyLoadHandler.useLazyLoadObserver();
|
|
993
|
+
|
|
994
|
+
// Pause initially to prevent unexpected triggers during initialization
|
|
995
|
+
LazyLoadHandler.paused = true;
|
|
996
|
+
|
|
997
|
+
// Set up initialization completion with visibility check
|
|
998
|
+
const initTimeoutId = window.setTimeout(() => {
|
|
999
|
+
LazyLoadHandler.paused = false; // Enable lazy loading
|
|
1000
|
+
|
|
1001
|
+
// Check if target is already visible after initialization
|
|
1002
|
+
// This handles cases where user scrolled during initialization
|
|
1003
|
+
LazyLoadHandler.checkVisibilityAndTrigger();
|
|
1004
|
+
}, 200); // Reduced from 500ms to 200ms for faster initial load
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Scroll Event Handler for Immediate Responsiveness
|
|
1008
|
+
*
|
|
1009
|
+
* This listener provides immediate feedback when users scroll
|
|
1010
|
+
* before the system is fully ready (e.g., after minimize/maximize).
|
|
1011
|
+
*
|
|
1012
|
+
* Uses passive event listener for better performance.
|
|
1013
|
+
*/
|
|
1014
|
+
const handleScroll = () => {
|
|
1015
|
+
if (!LazyLoadHandler.isReady) {
|
|
1016
|
+
// System not ready, but user is scrolling - check if we should trigger
|
|
1017
|
+
window.setTimeout(() => {
|
|
1018
|
+
LazyLoadHandler.checkVisibilityAndTrigger();
|
|
1019
|
+
}, 50); // Reduced from 100ms to 50ms for faster response
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
|
|
1023
|
+
// Find container and attach scroll listener
|
|
1024
|
+
const {
|
|
1025
|
+
container
|
|
1026
|
+
} = LazyLoadHandler.findScrollContainer();
|
|
1027
|
+
if (container) {
|
|
1028
|
+
container.addEventListener("scroll", handleScroll, {
|
|
1029
|
+
passive: true
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// Cleanup function - critical for preventing memory leaks
|
|
1034
|
+
return () => {
|
|
1035
|
+
clearTimeout(initTimeoutId);
|
|
1036
|
+
|
|
1037
|
+
// Remove event listeners
|
|
1038
|
+
unsubscribeNoMoreHistory();
|
|
1039
|
+
resetSubscription.unsubscribe();
|
|
1040
|
+
if (container) {
|
|
1041
|
+
container.removeEventListener("scroll", handleScroll);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// Perform complete system cleanup including broadcast event listener
|
|
1045
|
+
LazyLoadHandler.destroy();
|
|
1046
|
+
};
|
|
1047
|
+
}, []); // Empty dependency array - only run on mount/unmount
|
|
1048
|
+
|
|
1049
|
+
// Don't render if no more history is available
|
|
1050
|
+
if (!hasMoreHistory) {
|
|
1051
|
+
return null;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// Render the trigger element that the intersection observer watches
|
|
1055
|
+
return /*#__PURE__*/React.createElement(LoadInlineBannerActivity, _extends({}, props || {}, {
|
|
1056
|
+
id: LazyLoadHandler.targetId
|
|
1057
|
+
}));
|
|
1058
|
+
};
|
|
1059
|
+
export default LazyLoadActivity;
|
|
1060
|
+
export { LazyLoadHandler };
|