From 6cbb497a016d11660b7640d6dea0cbfb9c25a8c0 Mon Sep 17 00:00:00 2001
From: Kristina <kristin.fefelova@gmail.com>
Date: Thu, 29 Feb 2024 18:38:22 +0400
Subject: [PATCH] UBERF-5712: fix jumping when scroll in bottom and add auto
 scroll to new content (#4830)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
---
 .../reactions/ReactionsPresenter.svelte       |  8 +--
 .../src/components/Channel.svelte             |  2 +
 .../src/components/ChannelScrollView.svelte   | 51 ++++++++++++++++++-
 .../src/components/ChannelView.svelte         |  2 +-
 4 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/plugins/activity-resources/src/components/reactions/ReactionsPresenter.svelte b/plugins/activity-resources/src/components/reactions/ReactionsPresenter.svelte
index 4614fbc6da..1a9925fdce 100644
--- a/plugins/activity-resources/src/components/reactions/ReactionsPresenter.svelte
+++ b/plugins/activity-resources/src/components/reactions/ReactionsPresenter.svelte
@@ -30,14 +30,16 @@
   $: hasReactions = object?.reactions && object.reactions > 0
 
   $: if (object && hasReactions) {
-    reactionsQuery.query(activity.class.Reaction, { attachedTo: object._id }, (res?: Reaction[]) => {
-      reactions = res || []
+    reactionsQuery.query(activity.class.Reaction, { attachedTo: object._id }, (res: Reaction[]) => {
+      reactions = res
     })
+  } else {
+    reactionsQuery.unsubscribe()
   }
 
   const handleClick = (ev: CustomEvent) => {
     if (readonly) return
-    updateDocReactions(client, reactions, object, ev.detail)
+    void updateDocReactions(client, reactions, object, ev.detail)
   }
 </script>
 
diff --git a/plugins/chunter-resources/src/components/Channel.svelte b/plugins/chunter-resources/src/components/Channel.svelte
index 505567cea3..15c7374bd7 100644
--- a/plugins/chunter-resources/src/components/Channel.svelte
+++ b/plugins/chunter-resources/src/components/Channel.svelte
@@ -27,6 +27,7 @@
   export let context: DocNotifyContext
   export let object: Doc | undefined
   export let filters: Ref<ActivityMessagesFilter>[] = []
+  export let isAsideOpened = false
 
   const client = getClient()
   const hierarchy = client.getHierarchy()
@@ -70,6 +71,7 @@
     {selectedMessageId}
     {collection}
     provider={dataProvider}
+    {isAsideOpened}
     loadMoreAllowed={!isDocChannel}
   />
 {/if}
diff --git a/plugins/chunter-resources/src/components/ChannelScrollView.svelte b/plugins/chunter-resources/src/components/ChannelScrollView.svelte
index d3ac2ab699..2bcb5e074c 100644
--- a/plugins/chunter-resources/src/components/ChannelScrollView.svelte
+++ b/plugins/chunter-resources/src/components/ChannelScrollView.svelte
@@ -28,7 +28,7 @@
   } from '@hcengineering/activity-resources'
   import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
   import { get } from 'svelte/store'
-  import { tick } from 'svelte'
+  import { tick, beforeUpdate, afterUpdate } from 'svelte'
 
   import ActivityMessagesSeparator from './ChannelMessagesSeparator.svelte'
   import { filterChatMessages, getClosestDate, readChannelMessages } from '../utils'
@@ -49,6 +49,7 @@
   export let showEmbedded = false
   export let skipLabels = false
   export let loadMoreAllowed = true
+  export let isAsideOpened = false
 
   const dateSelectorHeight = 30
   const headerHeight = 50
@@ -83,6 +84,8 @@
 
   let messagesCount = 0
 
+  let wasAsideOpened = isAsideOpened
+
   $: messages = $messagesStore
   $: isLoading = $isLoadingStore
 
@@ -90,7 +93,7 @@
 
   $: notifyContext = $contextByDocStore.get(objectId)
 
-  $: filterChatMessages(messages, filters, objectClass, selectedFilters).then((filteredMessages) => {
+  $: void filterChatMessages(messages, filters, objectClass, selectedFilters).then((filteredMessages) => {
     displayMessages = filteredMessages
   })
 
@@ -224,10 +227,12 @@
     } else if (shouldLoadMoreDown() && provider.canLoadMore('forward', messages[messages.length - 1]?.createdOn)) {
       shouldScrollToNew = false
       void provider.loadMore('forward', messages[messages.length - 1]?.createdOn, limit)
+      isScrollAtBottom = false
     }
   }
 
   function handleScroll ({ autoScrolling }: ScrollParams) {
+    saveScrollPosition()
     if (autoScrolling) {
       return
     }
@@ -458,6 +463,48 @@
       loadMore()
     }
   }
+
+  let prevScrollHeight = 0
+  let isScrollAtBottom = false
+
+  function saveScrollPosition (): void {
+    if (!scrollElement) {
+      return
+    }
+
+    const { offsetHeight, scrollHeight, scrollTop } = scrollElement
+
+    prevScrollHeight = scrollHeight
+    isScrollAtBottom = scrollHeight === scrollTop + offsetHeight
+  }
+
+  beforeUpdate(() => {
+    if (!scrollElement) return
+
+    if (scrollElement.scrollHeight === scrollElement.clientHeight) {
+      isScrollAtBottom = true
+    }
+  })
+
+  afterUpdate(() => {
+    if (!scrollElement) return
+    const { scrollHeight } = scrollElement
+
+    if (!isInitialScrolling && prevScrollHeight < scrollHeight && isScrollAtBottom) {
+      scrollToBottom()
+    }
+  })
+
+  async function compensateAside (isOpened: boolean) {
+    if (!isInitialScrolling && isScrollAtBottom && !wasAsideOpened && isOpened) {
+      await wait()
+      scrollToBottom()
+    }
+
+    wasAsideOpened = isOpened
+  }
+
+  $: void compensateAside(isAsideOpened)
 </script>
 
 {#if isLoading}
diff --git a/plugins/chunter-resources/src/components/ChannelView.svelte b/plugins/chunter-resources/src/components/ChannelView.svelte
index 8083294e92..1f5b3dec96 100644
--- a/plugins/chunter-resources/src/components/ChannelView.svelte
+++ b/plugins/chunter-resources/src/components/ChannelView.svelte
@@ -77,7 +77,7 @@
   <div class="popupPanel-body" class:asideShown={withAside && isAsideShown}>
     <div class="popupPanel-body__main">
       {#key context._id}
-        <ChannelComponent {context} {object} {filters} />
+        <ChannelComponent {context} {object} {filters} isAsideOpened={(withAside && isAsideShown) || isThreadOpened} />
       {/key}
     </div>