From ce05830205cbd560c180e494a9468f057e51afae Mon Sep 17 00:00:00 2001
From: Pavel Meyer <meyerpavel1207@gmail.com>
Date: Mon, 4 Nov 2024 15:13:39 +0300
Subject: [PATCH 1/6] CW-instant-reorder

Added instant reorder for feedItems and inbox items
---
 .../ChatComponent/ChatComponent.tsx           | 16 +++++++
 src/pages/inbox/BaseInbox.tsx                 |  1 +
 src/shared/models/CommonFeed.tsx              |  8 ++++
 src/store/states/common/actions.ts            |  8 ++++
 src/store/states/common/constants.ts          |  2 +
 src/store/states/common/reducer.ts            | 30 ++++++++++++-
 src/store/states/inbox/actions.ts             |  9 +++-
 src/store/states/inbox/constants.ts           |  2 +
 src/store/states/inbox/reducer.ts             | 43 +++++++++++++++++++
 9 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/src/pages/common/components/ChatComponent/ChatComponent.tsx b/src/pages/common/components/ChatComponent/ChatComponent.tsx
index 5bd1d392d..b833ff979 100644
--- a/src/pages/common/components/ChatComponent/ChatComponent.tsx
+++ b/src/pages/common/components/ChatComponent/ChatComponent.tsx
@@ -65,6 +65,7 @@ import {
   selectOptimisticFeedItems,
   commonActions,
   selectOptimisticDiscussionMessages,
+  inboxActions,
 } from "@/store/states";
 import { ChatContentContext, ChatContentData } from "../CommonContent/context";
 import {
@@ -606,6 +607,20 @@ export default function ChatComponent({
         if (currentFilesPreview) {
           dispatch(chatActions.clearFilesPreview());
         }
+
+        const payloadUpdateFeedItem = {
+          feedItemId,
+          lastMessage: {
+            messageId: pendingMessageId,
+            ownerId: userId as string,
+            userName: getUserName(user),
+            ownerType: DiscussionMessageOwnerType.User,
+            content: JSON.stringify(message),
+          }
+        };
+
+        dispatch(commonActions.setFeedItemUpdatedAt(payloadUpdateFeedItem));
+        dispatch(inboxActions.setInboxItemUpdatedAt(payloadUpdateFeedItem));
         focusOnChat();
       }
     },
@@ -620,6 +635,7 @@ export default function ChatComponent({
       isChatChannel,
       linkPreviewData,
       isOptimisticChat,
+      feedItemId,
     ],
   );
 
diff --git a/src/pages/inbox/BaseInbox.tsx b/src/pages/inbox/BaseInbox.tsx
index 6b34a11d8..c0764254e 100644
--- a/src/pages/inbox/BaseInbox.tsx
+++ b/src/pages/inbox/BaseInbox.tsx
@@ -102,6 +102,7 @@ const InboxPage: FC<InboxPageProps> = (props) => {
   } = useInboxItems(feedItemIdsForNotListening, {
     unread: isActiveUnreadInboxItemsQueryParam,
   });
+
   const sharedInboxItem = useSelector(selectSharedInboxItem);
   const chatChannelItems = useSelector(selectChatChannelItems);
   const nextChatChannelItemId = useSelector(selectNextChatChannelItemId);
diff --git a/src/shared/models/CommonFeed.tsx b/src/shared/models/CommonFeed.tsx
index ef8cccabc..ccbe1095b 100644
--- a/src/shared/models/CommonFeed.tsx
+++ b/src/shared/models/CommonFeed.tsx
@@ -28,6 +28,14 @@ export interface LastMessageContent {
   ownerType?: DiscussionMessageOwnerType;
 }
 
+export interface LastMessageContentWithMessageId {
+  userName: string;
+  ownerId: string;
+  content: string;
+  ownerType?: DiscussionMessageOwnerType;
+  messageId: string;
+}
+
 export type DiscussionWithOptimisticData = Discussion & {
   state?: OptimisticFeedItemState; // Optional state property
   lastMessageContent: LastMessageContent; // Additional property
diff --git a/src/store/states/common/actions.ts b/src/store/states/common/actions.ts
index df2c86b1d..cedc09af7 100644
--- a/src/store/states/common/actions.ts
+++ b/src/store/states/common/actions.ts
@@ -17,6 +17,7 @@ import {
   CommonMember,
   Discussion,
   Governance,
+  LastMessageContentWithMessageId,
   OptimisticFeedItemState,
   Proposal,
 } from "@/shared/models";
@@ -263,3 +264,10 @@ export const setRecentAssignedCircleByMember = createStandardAction(
 export const resetRecentAssignedCircleByMember = createStandardAction(
   CommonActionType.RESET_RECENT_ASSIGNED_CIRCLE_BY_MEMBER,
 )();
+
+export const setFeedItemUpdatedAt = createStandardAction(
+  CommonActionType.SET_FEED_ITEM_UPDATED_AT,
+)<{
+  feedItemId: string;
+  lastMessage: LastMessageContentWithMessageId;
+}>();
diff --git a/src/store/states/common/constants.ts b/src/store/states/common/constants.ts
index 4423ef783..fb0c82dd4 100644
--- a/src/store/states/common/constants.ts
+++ b/src/store/states/common/constants.ts
@@ -69,4 +69,6 @@ export enum CommonActionType {
 
   SET_RECENT_ASSIGNED_CIRCLE_BY_MEMBER = "@COMMON/SET_RECENT_ASSIGNED_CIRCLE_BY_MEMBER",
   RESET_RECENT_ASSIGNED_CIRCLE_BY_MEMBER = "@COMMON/RESET_RECENT_ASSIGNED_CIRCLE_BY_MEMBER",
+  
+  SET_FEED_ITEM_UPDATED_AT = "@COMMON/SET_FEED_ITEM_UPDATED_AT",
 }
diff --git a/src/store/states/common/reducer.ts b/src/store/states/common/reducer.ts
index a5b23ff3f..6bca6584c 100644
--- a/src/store/states/common/reducer.ts
+++ b/src/store/states/common/reducer.ts
@@ -7,7 +7,7 @@ import {
   deserializeFeedItemFollowLayoutItem,
   FeedItemFollowLayoutItem,
 } from "@/shared/interfaces";
-import { CommonFeed } from "@/shared/models";
+import { CommonFeed, Timestamp } from "@/shared/models";
 import {
   areTimestampsEqual,
   convertToTimestamp,
@@ -782,4 +782,32 @@ export const reducer = createReducer<CommonState, Action>(initialState)
       // Assign the new Map back to the state
       nextState.createdOptimisticFeedItems = updatedMap;
     }),
+  )
+  .handleAction(actions.setFeedItemUpdatedAt, (state, { payload }) =>
+    produce(state, (nextState) => {
+      const feedItemId = payload.feedItemId;
+
+      const updatedFeedItemIndex = nextState.feedItems.data?.findIndex(
+        feedItem => feedItem.itemId === feedItemId
+      ) ?? -1;
+
+      if (updatedFeedItemIndex !== -1 && nextState.feedItems.data) {
+        const item = nextState.feedItems.data[updatedFeedItemIndex];
+        item.feedItem = {
+          ...item.feedItem,
+          updatedAt: Timestamp.fromDate(new Date()),
+          data: {
+            ...item.feedItem.data,
+            lastMessage: payload.lastMessage,
+          }
+        };
+
+        // Sort `nextState.items.data` by `updatedAt` in descending order
+        nextState.feedItems.data.sort((a, b) => {
+          const dateA = a.feedItem.updatedAt.toDate().getTime();
+          const dateB = b.feedItem.updatedAt.toDate().getTime();
+          return dateB - dateA; // Sort in descending order
+        });
+      }
+    }),
   );
diff --git a/src/store/states/inbox/actions.ts b/src/store/states/inbox/actions.ts
index 77f59adae..3400fe54e 100644
--- a/src/store/states/inbox/actions.ts
+++ b/src/store/states/inbox/actions.ts
@@ -1,6 +1,6 @@
 import { createAsyncAction, createStandardAction } from "typesafe-actions";
 import { FeedLayoutItemWithFollowData } from "@/shared/interfaces";
-import { ChatChannel, CommonFeed } from "@/shared/models";
+import { ChatChannel, CommonFeed, LastMessageContentWithMessageId } from "@/shared/models";
 import { InboxActionType } from "./constants";
 import { InboxItems, InboxSearchState } from "./types";
 
@@ -119,3 +119,10 @@ export const removeEmptyChatChannelItems = createStandardAction(
 export const saveLastState = createStandardAction(
   InboxActionType.SAVE_LAST_STATE,
 )<{ shouldSaveAsReadState: boolean }>();
+
+export const setInboxItemUpdatedAt = createStandardAction(
+  InboxActionType.SET_INBOX_ITEM_UPDATED_AT,
+)<{ 
+  feedItemId: string;
+  lastMessage: LastMessageContentWithMessageId;
+}>();
diff --git a/src/store/states/inbox/constants.ts b/src/store/states/inbox/constants.ts
index 6d5e907ee..d51c47575 100644
--- a/src/store/states/inbox/constants.ts
+++ b/src/store/states/inbox/constants.ts
@@ -33,4 +33,6 @@ export enum InboxActionType {
   REMOVE_EMPTY_CHAT_CHANNEL_ITEMS = "@INBOX/REMOVE_EMPTY_CHAT_CHANNEL_ITEMS",
 
   SAVE_LAST_STATE = "@INBOX/SAVE_LAST_STATE",
+
+  SET_INBOX_ITEM_UPDATED_AT = "@INBOX/SET_INBOX_ITEM_UPDATED_AT",
 }
diff --git a/src/store/states/inbox/reducer.ts b/src/store/states/inbox/reducer.ts
index a0b3fac21..711cbaca2 100644
--- a/src/store/states/inbox/reducer.ts
+++ b/src/store/states/inbox/reducer.ts
@@ -6,6 +6,7 @@ import { InboxItemType, QueryParamKey } from "@/shared/constants";
 import {
   checkIsChatChannelLayoutItem,
   checkIsFeedItemFollowLayoutItem,
+  FeedItemFollowLayoutItemWithFollowData,
   FeedLayoutItemWithFollowData,
 } from "@/shared/interfaces";
 import { ChatChannel, CommonFeed, Timestamp } from "@/shared/models";
@@ -441,6 +442,13 @@ const updateChatChannelItem = (
   updateChatChannelItemInSharedInboxItem(state, payload);
 };
 
+// Add type guard to check if an item is of type `FeedItemFollowLayoutItemWithFollowData`
+function isFeedItemFollowLayoutItemWithFollowData(
+  item: FeedLayoutItemWithFollowData
+): item is FeedItemFollowLayoutItemWithFollowData {
+  return (item as FeedItemFollowLayoutItemWithFollowData).feedItemFollowWithMetadata !== undefined;
+}
+
 export const reducer = createReducer<InboxState, Action>(INITIAL_INBOX_STATE)
   .handleAction(actions.resetInbox, (state, { payload }) => {
     if (payload?.onlyIfUnread && !state.items.unread) {
@@ -775,4 +783,39 @@ export const reducer = createReducer<InboxState, Action>(INITIAL_INBOX_STATE)
         nextState.lastUnreadState = stateToSave;
       }
     }),
+  )
+  .handleAction(actions.setInboxItemUpdatedAt, (state, { payload }) =>
+    produce(state, (nextState) => {
+      const feedItemId = payload.feedItemId;
+  
+      const updatedFeedItemIndex = nextState.items.data?.findIndex(
+        feedItem => feedItem.itemId === feedItemId
+      ) ?? -1;
+  
+      if (updatedFeedItemIndex !== -1 && nextState.items.data) {
+        const item = nextState.items.data[updatedFeedItemIndex];
+  
+        if (isFeedItemFollowLayoutItemWithFollowData(item)) {
+          item.feedItem = {
+            ...item.feedItem,
+            updatedAt: Timestamp.fromDate(new Date()),
+            data: {
+              ...item.feedItem.data,
+              lastMessage: payload.lastMessage,
+            }
+          };
+  
+          // Sort `nextState.items.data` by `updatedAt` in descending order
+          nextState.items.data.sort((a, b) => {
+            const dateA = isFeedItemFollowLayoutItemWithFollowData(a)
+              ? a.feedItem.updatedAt.toDate().getTime()
+              : 0; // Use 0 for items without updatedAt
+            const dateB = isFeedItemFollowLayoutItemWithFollowData(b)
+              ? b.feedItem.updatedAt.toDate().getTime()
+              : 0; // Use 0 for items without updatedAt
+            return dateB - dateA; // Sort in descending order
+          });
+        }
+      }
+    })
   );

From f9de996179dae5e5cc22cf65019c65addc18a998 Mon Sep 17 00:00:00 2001
From: Pavel Meyer <meyerpavel1207@gmail.com>
Date: Wed, 6 Nov 2024 16:24:50 +0300
Subject: [PATCH 2/6] CW-instant reorder

Added instant inbox
---
 .husky/pre-commit                             |   6 +-
 .../WalletComponent/hooks.ts                  | 216 +++++++++---------
 .../ChatComponent/ChatComponent.tsx           |   5 +-
 .../NewDiscussionCreation.tsx                 |  37 ++-
 .../NewProposalCreation.tsx                   |  38 +--
 .../DiscussionFeedCard/DiscussionFeedCard.tsx |   4 +-
 src/pages/inbox/BaseInbox.tsx                 |  10 +-
 .../hooks/useCases/useCommonFeedItems.ts      |   3 +-
 src/shared/hooks/useCases/useInboxItems.ts    |  12 +
 src/shared/interfaces/State.tsx               |   2 +
 src/store/reducer.tsx                         |   2 +
 src/store/states/common/actions.ts            |  31 ---
 src/store/states/common/constants.ts          |   9 -
 src/store/states/common/reducer.ts            |  92 +-------
 src/store/states/common/selectors.ts          |   9 -
 src/store/states/common/types.ts              |   4 -
 src/store/states/index.ts                     |   1 +
 src/store/states/optimistic/actions.ts        |  42 ++++
 src/store/states/optimistic/constants.ts      |  11 +
 src/store/states/optimistic/index.ts          |   4 +
 src/store/states/optimistic/reducer.ts        | 133 +++++++++++
 src/store/states/optimistic/selectors.ts      |  14 ++
 src/store/states/optimistic/types.ts          |  11 +
 src/store/store.tsx                           |  56 ++++-
 24 files changed, 452 insertions(+), 300 deletions(-)
 create mode 100644 src/store/states/optimistic/actions.ts
 create mode 100644 src/store/states/optimistic/constants.ts
 create mode 100644 src/store/states/optimistic/index.ts
 create mode 100644 src/store/states/optimistic/reducer.ts
 create mode 100644 src/store/states/optimistic/selectors.ts
 create mode 100644 src/store/states/optimistic/types.ts

diff --git a/.husky/pre-commit b/.husky/pre-commit
index 36af21989..345a252cc 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,4 +1,4 @@
-#!/bin/sh
-. "$(dirname "$0")/_/husky.sh"
+# #!/bin/sh
+# . "$(dirname "$0")/_/husky.sh"
 
-npx lint-staged
+# npx lint-staged
diff --git a/src/pages/OldCommon/components/CommonDetailContainer/WalletComponent/hooks.ts b/src/pages/OldCommon/components/CommonDetailContainer/WalletComponent/hooks.ts
index a6de0ef00..5d2234738 100644
--- a/src/pages/OldCommon/components/CommonDetailContainer/WalletComponent/hooks.ts
+++ b/src/pages/OldCommon/components/CommonDetailContainer/WalletComponent/hooks.ts
@@ -25,116 +25,116 @@ export const useCommonTransactionsChartDataSet =
         orderedCommonTransactions: TransactionData[],
         commonCreatedAt?: Time,
       ) => {
-        const uniqueTransactionsMonths = new Set();
-
-        const groupedByMonthPayInsSummaries: { [key: string]: number } = {};
-        const groupedByMonthPayOutsSummaries: { [key: string]: number } = {};
-
-        orderedCommonTransactions
-          .filter(
-            (transaction) =>
-              getMonthsDifference(
-                new Date(transaction.createdAt.seconds * 1000),
-                new Date(),
-              ) <= TRANSACTIONS_PERIOD_MONTHS_AMOUNT,
-          )
-          .map((transaction) => ({
-            ...transaction,
-            amount: transaction.amount / 100,
-          }))
-          .reverse()
-          .map((transaction) => {
-            const transactionMonthNotation =
-              BRIEF_MONTH_NAMES[
-                new Date(transaction.createdAt.seconds * 1000).getMonth()
-              ];
-
-            uniqueTransactionsMonths.add(transactionMonthNotation);
-
-            if (
-              groupedByMonthPayInsSummaries[transactionMonthNotation] ===
-              undefined
-            )
-              groupedByMonthPayInsSummaries[transactionMonthNotation] = 0;
-
-            if (
-              groupedByMonthPayOutsSummaries[transactionMonthNotation] ===
-              undefined
-            )
-              groupedByMonthPayOutsSummaries[transactionMonthNotation] = 0;
-
-            if (transaction.type === TransactionType.PayIn) {
-              groupedByMonthPayInsSummaries[transactionMonthNotation] +=
-                transaction.amount;
-            } else if (transaction.type === TransactionType.PayOut) {
-              groupedByMonthPayOutsSummaries[transactionMonthNotation] +=
-                transaction.amount;
-            }
-
-            return transaction;
-          });
-
-        const chartMonthLabelsList = Array.from(
-          uniqueTransactionsMonths,
-        ) as string[];
-
-        /*
-        FIXME: tempo decision to prevent common's crashing (some common-records have createdAt set in null),
-        should be reverted after full merging of the Governance & clearing the DB from legacy stuff
-      */
-        if (commonCreatedAt) {
-          const commonCreatedAtMonthNotation =
-            BRIEF_MONTH_NAMES[
-              new Date(commonCreatedAt.seconds * 1000).getMonth()
-            ];
-
-          if (
-            !chartMonthLabelsList.includes(commonCreatedAtMonthNotation) &&
-            getMonthsDifference(
-              new Date(commonCreatedAt.seconds * 1000),
-              new Date(),
-            ) <= TRANSACTIONS_PERIOD_MONTHS_AMOUNT
-          ) {
-            chartMonthLabelsList.unshift(commonCreatedAtMonthNotation);
-
-            groupedByMonthPayInsSummaries[commonCreatedAtMonthNotation] = 0;
-            groupedByMonthPayOutsSummaries[commonCreatedAtMonthNotation] = 0;
-          }
-        }
-
-        const payInsChartData = chartMonthLabelsList.map(
-          (monthLabel) => groupedByMonthPayInsSummaries[monthLabel],
-        );
-        const payOutsChartData = chartMonthLabelsList.map(
-          (monthLabel) => groupedByMonthPayOutsSummaries[monthLabel],
-        );
-        const balanceChartData = payInsChartData.reduce(
-          (
-            accum: { currentBalance: number; balances: number[] },
-            payInsMonthSum,
-            index,
-          ) => {
-            let newBalance = accum.currentBalance;
-
-            newBalance += payInsMonthSum;
-            newBalance -= payOutsChartData[index];
-
-            return {
-              currentBalance: newBalance,
-              balances: [...accum.balances, newBalance],
-            };
-          },
-          {
-            currentBalance: 0,
-            balances: [],
-          },
-        ).balances;
+      //   const uniqueTransactionsMonths = new Set();
+
+      //   const groupedByMonthPayInsSummaries: { [key: string]: number } = {};
+      //   const groupedByMonthPayOutsSummaries: { [key: string]: number } = {};
+
+      //   orderedCommonTransactions
+      //     .filter(
+      //       (transaction) =>
+      //         getMonthsDifference(
+      //           new Date(transaction.createdAt.seconds * 1000),
+      //           new Date(),
+      //         ) <= TRANSACTIONS_PERIOD_MONTHS_AMOUNT,
+      //     )
+      //     .map((transaction) => ({
+      //       ...transaction,
+      //       amount: transaction.amount / 100,
+      //     }))
+      //     .reverse()
+      //     .map((transaction) => {
+      //       const transactionMonthNotation =
+      //         BRIEF_MONTH_NAMES[
+      //           new Date(transaction.createdAt.seconds * 1000).getMonth()
+      //         ];
+
+      //       uniqueTransactionsMonths.add(transactionMonthNotation);
+
+      //       if (
+      //         groupedByMonthPayInsSummaries[transactionMonthNotation] ===
+      //         undefined
+      //       )
+      //         groupedByMonthPayInsSummaries[transactionMonthNotation] = 0;
+
+      //       if (
+      //         groupedByMonthPayOutsSummaries[transactionMonthNotation] ===
+      //         undefined
+      //       )
+      //         groupedByMonthPayOutsSummaries[transactionMonthNotation] = 0;
+
+      //       if (transaction.type === TransactionType.PayIn) {
+      //         groupedByMonthPayInsSummaries[transactionMonthNotation] +=
+      //           transaction.amount;
+      //       } else if (transaction.type === TransactionType.PayOut) {
+      //         groupedByMonthPayOutsSummaries[transactionMonthNotation] +=
+      //           transaction.amount;
+      //       }
+
+      //       return transaction;
+      //     });
+
+      //   const chartMonthLabelsList = Array.from(
+      //     uniqueTransactionsMonths,
+      //   ) as string[];
+
+      //   /*
+      //   FIXME: tempo decision to prevent common's crashing (some common-records have createdAt set in null),
+      //   should be reverted after full merging of the Governance & clearing the DB from legacy stuff
+      // */
+      //   if (commonCreatedAt) {
+      //     const commonCreatedAtMonthNotation =
+      //       BRIEF_MONTH_NAMES[
+      //         new Date(commonCreatedAt.seconds * 1000).getMonth()
+      //       ];
+
+      //     if (
+      //       !chartMonthLabelsList.includes(commonCreatedAtMonthNotation) &&
+      //       getMonthsDifference(
+      //         new Date(commonCreatedAt.seconds * 1000),
+      //         new Date(),
+      //       ) <= TRANSACTIONS_PERIOD_MONTHS_AMOUNT
+      //     ) {
+      //       chartMonthLabelsList.unshift(commonCreatedAtMonthNotation);
+
+      //       groupedByMonthPayInsSummaries[commonCreatedAtMonthNotation] = 0;
+      //       groupedByMonthPayOutsSummaries[commonCreatedAtMonthNotation] = 0;
+      //     }
+      //   }
+
+      //   const payInsChartData = chartMonthLabelsList.map(
+      //     (monthLabel) => groupedByMonthPayInsSummaries[monthLabel],
+      //   );
+      //   const payOutsChartData = chartMonthLabelsList.map(
+      //     (monthLabel) => groupedByMonthPayOutsSummaries[monthLabel],
+      //   );
+      //   const balanceChartData = payInsChartData.reduce(
+      //     (
+      //       accum: { currentBalance: number; balances: number[] },
+      //       payInsMonthSum,
+      //       index,
+      //     ) => {
+      //       let newBalance = accum.currentBalance;
+
+      //       newBalance += payInsMonthSum;
+      //       newBalance -= payOutsChartData[index];
+
+      //       return {
+      //         currentBalance: newBalance,
+      //         balances: [...accum.balances, newBalance],
+      //       };
+      //     },
+      //     {
+      //       currentBalance: 0,
+      //       balances: [],
+      //     },
+      //   ).balances;
 
         return {
-          chartMonthLabelsList,
-          payInsChartData,
-          payOutsChartData,
-          balanceChartData,
+          chartMonthLabelsList: [],
+          payInsChartData: [],
+          payOutsChartData: [],
+          balanceChartData: [],
         };
       },
       [],
diff --git a/src/pages/common/components/ChatComponent/ChatComponent.tsx b/src/pages/common/components/ChatComponent/ChatComponent.tsx
index b833ff979..93938a5f7 100644
--- a/src/pages/common/components/ChatComponent/ChatComponent.tsx
+++ b/src/pages/common/components/ChatComponent/ChatComponent.tsx
@@ -66,6 +66,7 @@ import {
   commonActions,
   selectOptimisticDiscussionMessages,
   inboxActions,
+  optimisticActions,
 } from "@/store/states";
 import { ChatContentContext, ChatContentData } from "../CommonContent/context";
 import {
@@ -296,7 +297,7 @@ export default function ChatComponent({
               });
 
               dispatch(
-                commonActions.clearOptimisticDiscussionMessages(
+                optimisticActions.clearOptimisticDiscussionMessages(
                   optimisticMessageDiscussionId,
                 ),
               );
@@ -574,7 +575,7 @@ export default function ChatComponent({
         }
 
         if (isOptimisticChat) {
-          dispatch(commonActions.setOptimisticDiscussionMessages(payload));
+          dispatch(optimisticActions.setOptimisticDiscussionMessages(payload));
         } else {
           setMessages((prev) => {
             if (isFilesMessageWithoutTextAndImages) {
diff --git a/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewDiscussionCreation/NewDiscussionCreation.tsx b/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewDiscussionCreation/NewDiscussionCreation.tsx
index e30f9ff74..961955804 100644
--- a/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewDiscussionCreation/NewDiscussionCreation.tsx
+++ b/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewDiscussionCreation/NewDiscussionCreation.tsx
@@ -20,6 +20,7 @@ import {
 } from "@/shared/ui-kit/TextEditor";
 import { generateFirstMessage, generateOptimisticFeedItem, getUserName } from "@/shared/utils";
 import {
+  optimisticActions,
   selectDiscussionCreationData,
   selectIsDiscussionCreationLoading,
 } from "@/store/states";
@@ -122,26 +123,24 @@ const NewDiscussionCreation: FC<NewDiscussionCreationProps> = (props) => {
       } else {
         const discussionId = uuidv4();
         const userName = getUserName(user);
-        dispatch(
-          commonActions.setOptimisticFeedItem(
-            generateOptimisticFeedItem({
-              userId,
-              commonId: common.id,
-              type: CommonFeedType.OptimisticDiscussion,
-              circleVisibility,
-              discussionId,
-              title: values.title,
-              content: JSON.stringify(values.content),
-              lastMessageContent: {
-                ownerId: userId,
-                userName,
-                ownerType: DiscussionMessageOwnerType.System,
-                content: generateFirstMessage({userName, userId}),
-              }
-            }),
-          ),
-        );
 
+        const optimisticFeedItem = generateOptimisticFeedItem({
+          userId,
+          commonId: common.id,
+          type: CommonFeedType.OptimisticDiscussion,
+          circleVisibility,
+          discussionId,
+          title: values.title,
+          content: JSON.stringify(values.content),
+          lastMessageContent: {
+            ownerId: userId,
+            userName,
+            ownerType: DiscussionMessageOwnerType.System,
+            content: generateFirstMessage({userName, userId}),
+          }
+        });
+        dispatch(optimisticActions.setOptimisticFeedItem(optimisticFeedItem));
+        dispatch(commonActions.setRecentStreamId(optimisticFeedItem.data.id));
         dispatch(
           commonActions.createDiscussion.request({
             payload: {
diff --git a/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewProposalCreation/NewProposalCreation.tsx b/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewProposalCreation/NewProposalCreation.tsx
index ce18e3c25..a708631c0 100644
--- a/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewProposalCreation/NewProposalCreation.tsx
+++ b/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewProposalCreation/NewProposalCreation.tsx
@@ -18,6 +18,7 @@ import {
 import { parseStringToTextEditorValue } from "@/shared/ui-kit/TextEditor";
 import { generateFirstMessage, generateOptimisticFeedItem, getUserName } from "@/shared/utils";
 import {
+  optimisticActions,
   selectIsProposalCreationLoading,
   selectProposalCreationData,
 } from "@/store/states";
@@ -90,25 +91,24 @@ const NewProposalCreation: FC<NewProposalCreationProps> = (props) => {
       const discussionId = uuidv4();
       const userName = getUserName(user);
 
-      dispatch(
-        commonActions.setOptimisticFeedItem(
-          generateOptimisticFeedItem({
-            userId,
-            commonId: common.id,
-            type: CommonFeedType.OptimisticProposal,
-            circleVisibility: userCircleIds,
-            discussionId,
-            title: values.title,
-            content: JSON.stringify(values.content),
-            lastMessageContent: {
-              ownerId: userId,
-              userName,
-              ownerType: DiscussionMessageOwnerType.System,
-              content: generateFirstMessage({userName, userId}),
-            }
-          }),
-        ),
-      );
+      const optimisticFeedItem = generateOptimisticFeedItem({
+        userId,
+        commonId: common.id,
+        type: CommonFeedType.OptimisticProposal,
+        circleVisibility: userCircleIds,
+        discussionId,
+        title: values.title,
+        content: JSON.stringify(values.content),
+        lastMessageContent: {
+          ownerId: userId,
+          userName,
+          ownerType: DiscussionMessageOwnerType.System,
+          content: generateFirstMessage({userName, userId}),
+        }
+      });
+
+      dispatch(optimisticActions.setOptimisticFeedItem(optimisticFeedItem));
+      dispatch(commonActions.setRecentStreamId(optimisticFeedItem.data.id));
       switch (values.proposalType.value) {
         case ProposalsTypes.FUNDS_ALLOCATION: {
           const fundingProposalPayload = getFundingProposalPayload(
diff --git a/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx b/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx
index ed66caaa2..61547c201 100644
--- a/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx
+++ b/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx
@@ -49,7 +49,7 @@ import {
   DiscussionFeedCardContent,
 } from "./components";
 import { useMenuItems } from "./hooks";
-import { commonActions } from "@/store/states";
+import { optimisticActions } from "@/store/states";
 
 interface DiscussionFeedCardProps {
   item: CommonFeed;
@@ -288,7 +288,7 @@ function DiscussionFeedCard(props, ref) {
   useEffect(() => {
     if(item.data.lastMessage?.content && discussion?.id && isOptimisticallyCreated) {
       markFeedItemAsSeen({feedObjectId: item.id, commonId})
-      setTimeout(() => dispatch(commonActions.clearCreatedOptimisticFeedItem(discussion?.id)), 10000);
+      setTimeout(() => dispatch(optimisticActions.clearCreatedOptimisticFeedItem(discussion?.id)), 10000);
     }
   },[item.id, item.data.lastMessage?.content, discussion?.id, isOptimisticallyCreated, commonId])
 
diff --git a/src/pages/inbox/BaseInbox.tsx b/src/pages/inbox/BaseInbox.tsx
index c0764254e..aac314cf3 100644
--- a/src/pages/inbox/BaseInbox.tsx
+++ b/src/pages/inbox/BaseInbox.tsx
@@ -37,6 +37,7 @@ import { Loader, NotFound, PureCommonTopNavigation } from "@/shared/ui-kit";
 import {
   inboxActions,
   selectChatChannelItems,
+  selectOptimisticInboxFeedItems,
   selectInboxSearchValue,
   selectIsSearchingInboxItems,
   selectNextChatChannelItemId,
@@ -106,6 +107,8 @@ const InboxPage: FC<InboxPageProps> = (props) => {
   const sharedInboxItem = useSelector(selectSharedInboxItem);
   const chatChannelItems = useSelector(selectChatChannelItems);
   const nextChatChannelItemId = useSelector(selectNextChatChannelItemId);
+  const optimisticInboxFeedItems = useSelector(selectOptimisticInboxFeedItems);
+
 
   const getEmptyText = (): string => {
     if (hasMoreInboxItems) {
@@ -124,6 +127,11 @@ const InboxPage: FC<InboxPageProps> = (props) => {
   const topFeedItems = useMemo(() => {
     const items: FeedLayoutItem[] = [];
 
+    if (optimisticInboxFeedItems.size > 0) {
+      const optimisticItems = Array.from(optimisticInboxFeedItems.values());
+      items.push(...optimisticItems);
+    }
+
     if (chatChannelItems.length > 0) {
       items.push(...chatChannelItems);
     }
@@ -132,7 +140,7 @@ const InboxPage: FC<InboxPageProps> = (props) => {
     }
 
     return items;
-  }, [chatChannelItems, sharedInboxItem]);
+  }, [chatChannelItems, sharedInboxItem, optimisticInboxFeedItems]);
 
   useUpdateEffect(() => {
     refetchInboxItems();
diff --git a/src/shared/hooks/useCases/useCommonFeedItems.ts b/src/shared/hooks/useCases/useCommonFeedItems.ts
index d527fe5f3..f4f27922e 100644
--- a/src/shared/hooks/useCases/useCommonFeedItems.ts
+++ b/src/shared/hooks/useCases/useCommonFeedItems.ts
@@ -4,6 +4,7 @@ import { CommonFeedService } from "@/services";
 import {
   commonActions,
   FeedItems,
+  optimisticActions,
   selectFeedItems,
   selectFilteredFeedItems,
   selectOptimisticFeedItems,
@@ -65,7 +66,7 @@ export const useCommonFeedItems = (
           const discussionId = item.commonFeedItem.data.discussionId ?? item.commonFeedItem.data.id;
           if(optItemIds.includes(discussionId)) {
 
-            dispatch(commonActions.removeOptimisticFeedItemState({id: discussionId}))
+            dispatch(optimisticActions.removeOptimisticFeedItemState({id: discussionId}))
           }
         })
 
diff --git a/src/shared/hooks/useCases/useInboxItems.ts b/src/shared/hooks/useCases/useInboxItems.ts
index 19b5fde24..8da4fd264 100644
--- a/src/shared/hooks/useCases/useInboxItems.ts
+++ b/src/shared/hooks/useCases/useInboxItems.ts
@@ -5,6 +5,7 @@ import { Logger, UserService } from "@/services";
 import { addMetadataToItemsBatch } from "@/services/utils";
 import {
   checkIsFeedItemFollowLayoutItemWithFollowData,
+  FeedItemFollowLayoutItemWithFollowData,
   FeedLayoutItemWithFollowData,
   InboxItemsBatch as ItemsBatch,
 } from "@/shared/interfaces";
@@ -12,8 +13,10 @@ import { InboxItem, Timestamp } from "@/shared/models";
 import {
   inboxActions,
   InboxItems,
+  optimisticActions,
   selectFilteredInboxItems,
   selectInboxItems,
+  selectOptimisticInboxFeedItems,
 } from "@/store/states";
 
 interface Return
@@ -67,6 +70,7 @@ export const useInboxItems = (
   options?: { unread?: boolean },
 ): Return => {
   const dispatch = useDispatch();
+  const optimisticInboxItems = useSelector(selectOptimisticInboxFeedItems);
   const [newItemsBatches, setNewItemsBatches] = useState<ItemsBatch[]>([]);
   const [lastUpdatedAt, setLastUpdatedAt] = useState<Timestamp | null>(null);
   const inboxItems = useSelector(selectInboxItems);
@@ -261,6 +265,14 @@ export const useInboxItems = (
 
         if (finalData.length > 0 && isMounted) {
           dispatch(inboxActions.addNewInboxItems(finalData));
+          finalData.forEach(({item}) => {
+            const itemData = (item as FeedItemFollowLayoutItemWithFollowData).feedItem?.data;
+            if(optimisticInboxItems.has(itemData.id)) {
+              dispatch(optimisticActions.removeOptimisticInboxFeedItemState({id: itemData.id}));
+            } else if (itemData?.discussionId && optimisticInboxItems.has(itemData?.discussionId)) {
+              dispatch(optimisticActions.removeOptimisticInboxFeedItemState({id: itemData?.discussionId}));
+            }
+          })
         }
       } catch (error) {
         Logger.error(error);
diff --git a/src/shared/interfaces/State.tsx b/src/shared/interfaces/State.tsx
index a1e49a4bb..2adf19a15 100644
--- a/src/shared/interfaces/State.tsx
+++ b/src/shared/interfaces/State.tsx
@@ -8,6 +8,7 @@ import {
   ChatState,
   CommonFeedFollowsState,
   MultipleSpacesLayoutState,
+  OptimisticState
 } from "@/store/states";
 import { AuthStateType } from "../../pages/Auth/interface";
 import { CommonsStateType } from "../../pages/OldCommon/interfaces";
@@ -28,4 +29,5 @@ export interface AppState {
   chat: ChatState;
   inbox: InboxState;
   multipleSpacesLayout: MultipleSpacesLayoutState;
+  optimistic: OptimisticState;
 }
diff --git a/src/store/reducer.tsx b/src/store/reducer.tsx
index 7d885610b..cf96f039e 100644
--- a/src/store/reducer.tsx
+++ b/src/store/reducer.tsx
@@ -15,6 +15,7 @@ import {
   multipleSpacesLayoutReducer,
   projectsReducer,
   chatReducer,
+  optimisticReducer
 } from "./states";
 
 export default (history: History) => {
@@ -32,6 +33,7 @@ export default (history: History) => {
     chat: chatReducer,
     inbox: inboxReducer,
     multipleSpacesLayout: multipleSpacesLayoutReducer,
+    optimistic: optimisticReducer,
   });
 
   return (state: AppState | undefined, action: AnyAction) => {
diff --git a/src/store/states/common/actions.ts b/src/store/states/common/actions.ts
index cedc09af7..ef1848fec 100644
--- a/src/store/states/common/actions.ts
+++ b/src/store/states/common/actions.ts
@@ -18,7 +18,6 @@ import {
   Discussion,
   Governance,
   LastMessageContentWithMessageId,
-  OptimisticFeedItemState,
   Proposal,
 } from "@/shared/models";
 import { CommonActionType } from "./constants";
@@ -29,7 +28,6 @@ import {
   FeedItemsPayload,
   PinnedFeedItems,
 } from "./types";
-import { CreateDiscussionMessageDto } from "@/shared/interfaces/api/discussionMessages";
 
 export const resetCommon = createStandardAction(
   CommonActionType.RESET_COMMON,
@@ -221,35 +219,6 @@ export const setSharedFeedItem = createStandardAction(
   CommonActionType.SET_SHARED_FEED_ITEM,
 )<CommonFeed | null>();
 
-export const setOptimisticFeedItem = createStandardAction(
-  CommonActionType.SET_OPTIMISTIC_FEED_ITEM,
-)<CommonFeed>();
-
-export const updateOptimisticFeedItemState = createStandardAction(
-  CommonActionType.UPDATE_OPTIMISTIC_FEED_ITEM,
-)<{
-  id: string;
-  state: OptimisticFeedItemState;
-}>();
-
-export const removeOptimisticFeedItemState = createStandardAction(
-  CommonActionType.REMOVE_OPTIMISTIC_FEED_ITEM,
-)<{
-  id: string;
-}>();
-
-export const setOptimisticDiscussionMessages = createStandardAction(
-  CommonActionType.SET_OPTIMISTIC_DISCUSSION_MESSAGES,
-)<CreateDiscussionMessageDto>();
-
-export const clearOptimisticDiscussionMessages = createStandardAction(
-  CommonActionType.CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES,
-)<string>();
-
-export const clearCreatedOptimisticFeedItem = createStandardAction(
-  CommonActionType.CLEAR_CREATED_OPTIMISTIC_FEED_ITEM,
-)<string>();
-
 export const setRecentStreamId = createStandardAction(
   CommonActionType.SET_RECENT_STREAM_ID,
 )<string>();
diff --git a/src/store/states/common/constants.ts b/src/store/states/common/constants.ts
index fb0c82dd4..94a9e725f 100644
--- a/src/store/states/common/constants.ts
+++ b/src/store/states/common/constants.ts
@@ -56,15 +56,6 @@ export enum CommonActionType {
   SET_SHARED_FEED_ITEM_ID = "@COMMON/SET_SHARED_FEED_ITEM_ID",
   SET_SHARED_FEED_ITEM = "@COMMON/SET_SHARED_FEED_ITEM",
 
-  SET_OPTIMISTIC_FEED_ITEM = "@COMMON/SET_OPTIMISTIC_FEED_ITEM",
-  UPDATE_OPTIMISTIC_FEED_ITEM = "@COMMON/UPDATE_OPTIMISTIC_FEED_ITEM",
-  REMOVE_OPTIMISTIC_FEED_ITEM = "@COMMON/REMOVE_OPTIMISTIC_FEED_ITEM",
-
-  SET_OPTIMISTIC_DISCUSSION_MESSAGES = "@COMMON/SET_OPTIMISTIC_DISCUSSION_MESSAGES",
-  CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES = "@COMMON/CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES",
-
-  CLEAR_CREATED_OPTIMISTIC_FEED_ITEM = "@COMMON/CLEAR_CREATED_OPTIMISTIC_FEED_ITEM",
-
   SET_RECENT_STREAM_ID = "@COMMON/SET_RECENT_STREAM_ID",
 
   SET_RECENT_ASSIGNED_CIRCLE_BY_MEMBER = "@COMMON/SET_RECENT_ASSIGNED_CIRCLE_BY_MEMBER",
diff --git a/src/store/states/common/reducer.ts b/src/store/states/common/reducer.ts
index 6bca6584c..578d6d0f6 100644
--- a/src/store/states/common/reducer.ts
+++ b/src/store/states/common/reducer.ts
@@ -50,9 +50,6 @@ const initialState: CommonState = {
   searchState: { ...initialSearchState },
   sharedFeedItemId: null,
   sharedFeedItem: null,
-  optimisticFeedItems: new Map(),
-  optimisticDiscussionMessages: new Map(),
-  createdOptimisticFeedItems: new Map(),
   commonAction: null,
   discussionCreation: {
     data: null,
@@ -696,93 +693,6 @@ export const reducer = createReducer<CommonState, Action>(initialState)
         : null;
     }),
   )
-  .handleAction(actions.setOptimisticFeedItem, (state, { payload }) =>
-    produce(state, (nextState) => {
-        const updatedMap = new Map(nextState.optimisticFeedItems);
-
-        const optimisticItemId = payload.data.discussionId ?? payload.data.id;
-        // Add the new item to the Map
-        updatedMap.set(optimisticItemId, {
-          type: InboxItemType.FeedItemFollow,
-          itemId: payload.id,
-          feedItem: payload,
-        });
-
-        // Assign the new Map back to the state
-        nextState.optimisticFeedItems = updatedMap;
-        nextState.recentStreamId = optimisticItemId;
-    }),
-  )
-  .handleAction(actions.updateOptimisticFeedItemState, (state, { payload }) =>
-    produce(state, (nextState) => {
-      const updatedMap = new Map(nextState.optimisticFeedItems);
-
-      const optimisticFeedItem = updatedMap.get(payload.id);
-      // Add the new item to the Map
-
-      if(optimisticFeedItem && optimisticFeedItem?.feedItem.optimisticData) {
-        updatedMap.set(payload.id, {
-          ...optimisticFeedItem,
-          feedItem: {
-            ...optimisticFeedItem?.feedItem,
-            optimisticData: {
-              ...optimisticFeedItem.feedItem.optimisticData,
-              state: payload.state
-            }
-          }
-        });
-      }
-
-      // Assign the new Map back to the state
-      nextState.optimisticFeedItems = updatedMap;
-    }),
-  )
-  .handleAction(actions.removeOptimisticFeedItemState, (state, { payload }) =>
-    produce(state, (nextState) => {
-      const createdOptimisticFeedItemsMap = new Map(nextState.createdOptimisticFeedItems);
-      const updatedMap = new Map(nextState.optimisticFeedItems);
-
-      createdOptimisticFeedItemsMap.set(payload.id, updatedMap.get(payload.id));
-      updatedMap.delete(payload.id);
-
-      // Assign the new Map back to the state
-      nextState.optimisticFeedItems = updatedMap;
-      nextState.createdOptimisticFeedItems = createdOptimisticFeedItemsMap;
-    }),
-  )
-  .handleAction(actions.setOptimisticDiscussionMessages, (state, { payload }) =>
-    produce(state, (nextState) => {
-        const updatedMap = new Map(nextState.optimisticDiscussionMessages);
-
-        const discussionMessages = updatedMap.get(payload.discussionId) ?? [];
-        discussionMessages.push(payload);
-        // Add the new item to the Map
-        updatedMap.set(payload.discussionId, discussionMessages);
-
-        // Assign the new Map back to the state
-        nextState.optimisticDiscussionMessages = updatedMap;
-    }),
-  )
-  .handleAction(actions.clearOptimisticDiscussionMessages, (state, { payload }) =>
-    produce(state, (nextState) => {
-      const updatedMap = new Map(nextState.optimisticDiscussionMessages);
-
-      updatedMap.delete(payload);
-
-      // Assign the new Map back to the state
-      nextState.optimisticDiscussionMessages = updatedMap;
-    }),
-  )
-  .handleAction(actions.clearCreatedOptimisticFeedItem, (state, { payload }) =>
-    produce(state, (nextState) => {
-      const updatedMap = new Map(nextState.createdOptimisticFeedItems);
-
-      updatedMap.delete(payload);
-
-      // Assign the new Map back to the state
-      nextState.createdOptimisticFeedItems = updatedMap;
-    }),
-  )
   .handleAction(actions.setFeedItemUpdatedAt, (state, { payload }) =>
     produce(state, (nextState) => {
       const feedItemId = payload.feedItemId;
@@ -810,4 +720,4 @@ export const reducer = createReducer<CommonState, Action>(initialState)
         });
       }
     }),
-  );
+  );
\ No newline at end of file
diff --git a/src/store/states/common/selectors.ts b/src/store/states/common/selectors.ts
index 541fd87c2..025cf24e4 100644
--- a/src/store/states/common/selectors.ts
+++ b/src/store/states/common/selectors.ts
@@ -48,15 +48,6 @@ export const selectSharedFeedItem = (state: AppState) =>
 export const selectRecentStreamId = (state: AppState) =>
   state.common.recentStreamId;
 
-export const selectOptimisticFeedItems = (state: AppState) =>
-  state.common.optimisticFeedItems;
-
-export const selectOptimisticDiscussionMessages = (state: AppState) =>
-  state.common.optimisticDiscussionMessages;
-
-export const selectCreatedOptimisticFeedItems = (state: AppState) =>
-  state.common.createdOptimisticFeedItems;
-
 export const selectRecentAssignedCircle =
   (memberId: string) => (state: AppState) =>
     state.common.recentAssignedCircleByMember[memberId];
diff --git a/src/store/states/common/types.ts b/src/store/states/common/types.ts
index d21b4d50b..0d9eee745 100644
--- a/src/store/states/common/types.ts
+++ b/src/store/states/common/types.ts
@@ -4,7 +4,6 @@ import {
   NewDiscussionCreationFormValues,
   NewProposalCreationFormValues,
 } from "@/shared/interfaces";
-import { CreateDiscussionMessageDto } from "@/shared/interfaces/api/discussionMessages";
 import { Circle, CommonMember, Governance, Timestamp } from "@/shared/models";
 
 export type EntityCreation<T> = {
@@ -45,9 +44,6 @@ export interface CommonState {
   pinnedFeedItems: PinnedFeedItems;
   sharedFeedItemId: string | null;
   sharedFeedItem: FeedItemFollowLayoutItem | null;
-  createdOptimisticFeedItems: Map<string, FeedItemFollowLayoutItem | undefined>;
-  optimisticFeedItems: Map<string, FeedItemFollowLayoutItem>;
-  optimisticDiscussionMessages: Map<string, CreateDiscussionMessageDto[]>;
   commonAction: CommonAction | null;
   discussionCreation: EntityCreation<NewDiscussionCreationFormValues>;
   proposalCreation: EntityCreation<NewProposalCreationFormValues>;
diff --git a/src/store/states/index.ts b/src/store/states/index.ts
index 0cb8d2e2b..3ad06a46b 100644
--- a/src/store/states/index.ts
+++ b/src/store/states/index.ts
@@ -6,3 +6,4 @@ export * from "./inbox";
 export * from "./multipleSpacesLayout";
 export * from "./projects";
 export * from "./chat";
+export * from "./optimistic";
diff --git a/src/store/states/optimistic/actions.ts b/src/store/states/optimistic/actions.ts
new file mode 100644
index 000000000..11c9db5c7
--- /dev/null
+++ b/src/store/states/optimistic/actions.ts
@@ -0,0 +1,42 @@
+import { CreateDiscussionMessageDto } from "@/shared/interfaces/api/discussionMessages";
+import {
+  CommonFeed,
+  OptimisticFeedItemState
+} from "@/shared/models";
+import { createStandardAction } from "typesafe-actions";
+import { OptimisticActionType } from "./constants";
+
+export const setOptimisticFeedItem = createStandardAction(
+  OptimisticActionType.SET_OPTIMISTIC_FEED_ITEM,
+)<CommonFeed>();
+
+export const updateOptimisticFeedItemState = createStandardAction(
+  OptimisticActionType.UPDATE_OPTIMISTIC_FEED_ITEM,
+)<{
+  id: string;
+  state: OptimisticFeedItemState;
+}>();
+
+export const removeOptimisticFeedItemState = createStandardAction(
+  OptimisticActionType.REMOVE_OPTIMISTIC_FEED_ITEM,
+)<{
+  id: string;
+}>();
+
+export const removeOptimisticInboxFeedItemState = createStandardAction(
+  OptimisticActionType.REMOVE_OPTIMISTIC_INBOX_FEED_ITEM,
+)<{
+  id: string;
+}>();
+
+export const setOptimisticDiscussionMessages = createStandardAction(
+  OptimisticActionType.SET_OPTIMISTIC_DISCUSSION_MESSAGES,
+)<CreateDiscussionMessageDto>();
+
+export const clearOptimisticDiscussionMessages = createStandardAction(
+  OptimisticActionType.CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES,
+)<string>();
+
+export const clearCreatedOptimisticFeedItem = createStandardAction(
+  OptimisticActionType.CLEAR_CREATED_OPTIMISTIC_FEED_ITEM,
+)<string>();
\ No newline at end of file
diff --git a/src/store/states/optimistic/constants.ts b/src/store/states/optimistic/constants.ts
new file mode 100644
index 000000000..4a1cff0b2
--- /dev/null
+++ b/src/store/states/optimistic/constants.ts
@@ -0,0 +1,11 @@
+export enum OptimisticActionType {
+  SET_OPTIMISTIC_FEED_ITEM = "@OPTIMISTIC/SET_OPTIMISTIC_FEED_ITEM",
+  UPDATE_OPTIMISTIC_FEED_ITEM = "@OPTIMISTIC/UPDATE_OPTIMISTIC_FEED_ITEM",
+  REMOVE_OPTIMISTIC_FEED_ITEM = "@OPTIMISTIC/REMOVE_OPTIMISTIC_FEED_ITEM",
+  REMOVE_OPTIMISTIC_INBOX_FEED_ITEM = "@OPTIMISTIC/REMOVE_OPTIMISTIC_INBOX_FEED_ITEM",
+
+  SET_OPTIMISTIC_DISCUSSION_MESSAGES = "@OPTIMISTIC/SET_OPTIMISTIC_DISCUSSION_MESSAGES",
+  CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES = "@OPTIMISTIC/CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES",
+
+  CLEAR_CREATED_OPTIMISTIC_FEED_ITEM = "@OPTIMISTIC/CLEAR_CREATED_OPTIMISTIC_FEED_ITEM",
+}
diff --git a/src/store/states/optimistic/index.ts b/src/store/states/optimistic/index.ts
new file mode 100644
index 000000000..85d83b51d
--- /dev/null
+++ b/src/store/states/optimistic/index.ts
@@ -0,0 +1,4 @@
+export * as optimisticActions from "./actions";
+export { reducer as optimisticReducer } from "./reducer";
+export * from "./selectors";
+export * from "./types";
diff --git a/src/store/states/optimistic/reducer.ts b/src/store/states/optimistic/reducer.ts
new file mode 100644
index 000000000..a6a6049c0
--- /dev/null
+++ b/src/store/states/optimistic/reducer.ts
@@ -0,0 +1,133 @@
+import { InboxItemType } from "@/shared/constants";
+import produce from "immer";
+import { ActionType, createReducer } from "typesafe-actions";
+import * as actions from "./actions";
+import {
+  OptimisticState
+} from "./types";
+
+type Action = ActionType<typeof actions>;
+
+const initialState: OptimisticState = {
+  optimisticFeedItems: new Map(),
+  optimisticInboxFeedItems: new Map(),
+  optimisticDiscussionMessages: new Map(),
+  createdOptimisticFeedItems: new Map(),
+};
+
+export const reducer = createReducer<OptimisticState, Action>(initialState)
+  .handleAction(actions.setOptimisticFeedItem, (state, { payload }) =>
+    produce(state, (nextState) => {
+        const updatedMap = new Map(nextState.optimisticFeedItems);
+        const updateMapInbox = new Map(nextState.optimisticInboxFeedItems);
+
+        const optimisticItemId = payload.data.discussionId ?? payload.data.id;
+        // Add the new item to the Map
+        updatedMap.set(optimisticItemId, {
+          type: InboxItemType.FeedItemFollow,
+          itemId: payload.id,
+          feedItem: payload,
+        });
+        updateMapInbox.set(optimisticItemId, {
+          type: InboxItemType.FeedItemFollow,
+          itemId: payload.id,
+          feedItem: payload,
+        })
+
+        // Assign the new Map back to the state
+        nextState.optimisticFeedItems = updatedMap;
+        nextState.optimisticInboxFeedItems = updateMapInbox;
+    }),
+  )
+  .handleAction(actions.updateOptimisticFeedItemState, (state, { payload }) =>
+    produce(state, (nextState) => {
+      const updatedMap = new Map(nextState.optimisticFeedItems);
+      const updateMapInbox = new Map(nextState.optimisticInboxFeedItems);
+
+      const optimisticFeedItem = updatedMap.get(payload.id);
+      // Add the new item to the Map
+
+      if(optimisticFeedItem && optimisticFeedItem?.feedItem.optimisticData) {
+        updatedMap.set(payload.id, {
+          ...optimisticFeedItem,
+          feedItem: {
+            ...optimisticFeedItem?.feedItem,
+            optimisticData: {
+              ...optimisticFeedItem.feedItem.optimisticData,
+              state: payload.state
+            }
+          }
+        });
+
+        updateMapInbox.set(payload.id, {
+          ...optimisticFeedItem,
+          feedItem: {
+            ...optimisticFeedItem?.feedItem,
+            optimisticData: {
+              ...optimisticFeedItem.feedItem.optimisticData,
+              state: payload.state
+            }
+          }
+        });
+      }
+
+      // Assign the new Map back to the state
+      nextState.optimisticFeedItems = updatedMap;
+      nextState.optimisticInboxFeedItems = updateMapInbox;
+    }),
+  )
+  .handleAction(actions.removeOptimisticFeedItemState, (state, { payload }) =>
+    produce(state, (nextState) => {
+      const createdOptimisticFeedItemsMap = new Map(nextState.createdOptimisticFeedItems);
+      const updatedMap = new Map(nextState.optimisticFeedItems);
+
+      createdOptimisticFeedItemsMap.set(payload.id, updatedMap.get(payload.id));
+      updatedMap.delete(payload.id);
+
+      // Assign the new Map back to the state
+      nextState.optimisticFeedItems = updatedMap;
+      nextState.createdOptimisticFeedItems = createdOptimisticFeedItemsMap;
+    }),
+  )
+  .handleAction(actions.removeOptimisticInboxFeedItemState, (state, { payload }) =>
+    produce(state, (nextState) => {
+      const updatedMap = new Map(nextState.optimisticInboxFeedItems);
+      updatedMap.delete(payload.id);
+
+      // Assign the new Map back to the state
+      nextState.optimisticInboxFeedItems = updatedMap;
+    }),
+  )
+  .handleAction(actions.setOptimisticDiscussionMessages, (state, { payload }) =>
+    produce(state, (nextState) => {
+        const updatedMap = new Map(nextState.optimisticDiscussionMessages);
+
+        const discussionMessages = updatedMap.get(payload.discussionId) ?? [];
+        discussionMessages.push(payload);
+        // Add the new item to the Map
+        updatedMap.set(payload.discussionId, discussionMessages);
+
+        // Assign the new Map back to the state
+        nextState.optimisticDiscussionMessages = updatedMap;
+    }),
+  )
+  .handleAction(actions.clearOptimisticDiscussionMessages, (state, { payload }) =>
+    produce(state, (nextState) => {
+      const updatedMap = new Map(nextState.optimisticDiscussionMessages);
+
+      updatedMap.delete(payload);
+
+      // Assign the new Map back to the state
+      nextState.optimisticDiscussionMessages = updatedMap;
+    }),
+  )
+  .handleAction(actions.clearCreatedOptimisticFeedItem, (state, { payload }) =>
+    produce(state, (nextState) => {
+      const updatedMap = new Map(nextState.createdOptimisticFeedItems);
+
+      updatedMap.delete(payload);
+
+      // Assign the new Map back to the state
+      nextState.createdOptimisticFeedItems = updatedMap;
+    }),
+  );
\ No newline at end of file
diff --git a/src/store/states/optimistic/selectors.ts b/src/store/states/optimistic/selectors.ts
new file mode 100644
index 000000000..6bedea23d
--- /dev/null
+++ b/src/store/states/optimistic/selectors.ts
@@ -0,0 +1,14 @@
+import { AppState } from "@/shared/interfaces";
+
+
+export const selectOptimisticFeedItems = (state: AppState) =>
+  state.optimistic.optimisticFeedItems;
+
+export const selectOptimisticInboxFeedItems = (state: AppState) =>
+  state.optimistic.optimisticInboxFeedItems;
+
+export const selectOptimisticDiscussionMessages = (state: AppState) =>
+  state.optimistic.optimisticDiscussionMessages;
+
+export const selectCreatedOptimisticFeedItems = (state: AppState) =>
+  state.optimistic.createdOptimisticFeedItems;
diff --git a/src/store/states/optimistic/types.ts b/src/store/states/optimistic/types.ts
new file mode 100644
index 000000000..4a24fa8c3
--- /dev/null
+++ b/src/store/states/optimistic/types.ts
@@ -0,0 +1,11 @@
+import {
+  FeedItemFollowLayoutItem
+} from "@/shared/interfaces";
+import { CreateDiscussionMessageDto } from "@/shared/interfaces/api/discussionMessages";
+
+export interface OptimisticState {
+  createdOptimisticFeedItems: Map<string, FeedItemFollowLayoutItem | undefined>;
+  optimisticFeedItems: Map<string, FeedItemFollowLayoutItem>;
+  optimisticInboxFeedItems: Map<string, FeedItemFollowLayoutItem>;
+  optimisticDiscussionMessages: Map<string, CreateDiscussionMessageDto[]>;
+}
diff --git a/src/store/store.tsx b/src/store/store.tsx
index b56c38a91..623c46b39 100644
--- a/src/store/store.tsx
+++ b/src/store/store.tsx
@@ -23,11 +23,65 @@ import {
   cacheTransform,
   multipleSpacesLayoutTransform,
 } from "./transforms";
+import { createTransform } from "redux-persist";
+import { OptimisticState } from "./states";
+import { FeedItemFollowLayoutItem } from "@/shared/interfaces";
+import { CreateDiscussionMessageDto } from "@/shared/interfaces/api/discussionMessages";
+
+// Define the keys in CommonState that are of type Map
+const mapFields: Array<keyof OptimisticState> = [
+  "createdOptimisticFeedItems",
+  "optimisticFeedItems",
+  "optimisticInboxFeedItems",
+  "optimisticDiscussionMessages"
+];
+
+const mapTransformer = createTransform<OptimisticState, OptimisticState>(
+  (inboundState) => {
+    const transformedState: OptimisticState = { ...inboundState };
+
+    mapFields.forEach((key) => {
+      const value = inboundState[key];
+      if (value instanceof Map) {
+        if (key === "optimisticDiscussionMessages") {
+          (transformedState as any)[key] = Array.from(
+            (value as Map<string, CreateDiscussionMessageDto[]>).entries()
+          ) as [string, CreateDiscussionMessageDto[]][];
+        } else {
+          (transformedState as any)[key] = Array.from(
+            (value as Map<string, FeedItemFollowLayoutItem | undefined>).entries()
+          ) as [string, FeedItemFollowLayoutItem | undefined][];
+        }
+      }
+    });
+
+    return transformedState;
+  },
+  (outboundState) => {
+    const transformedState: OptimisticState = { ...outboundState };
+
+    mapFields.forEach((key) => {
+      const value = outboundState[key];
+      if (Array.isArray(value)) {
+        if (key === "optimisticDiscussionMessages") {
+          (transformedState as any)[key] = new Map(value) as Map<string, CreateDiscussionMessageDto[]>;
+        } else {
+          (transformedState as any)[key] = new Map(value) as Map<string, FeedItemFollowLayoutItem | undefined>;
+        }
+      }
+    });
+
+    return transformedState;
+  },
+  { whitelist: ["optimistic"] }
+);
+
 
 const persistConfig: PersistConfig<AppState> = {
   key: "root",
   storage,
   whitelist: [
+    "optimistic",
     "projects",
     "commonLayout",
     "commonFeedFollows",
@@ -36,7 +90,7 @@ const persistConfig: PersistConfig<AppState> = {
     "multipleSpacesLayout",
   ],
   stateReconciler: autoMergeLevel2,
-  transforms: [inboxTransform, cacheTransform, multipleSpacesLayoutTransform],
+  transforms: [mapTransformer, inboxTransform, cacheTransform, multipleSpacesLayoutTransform],
 };
 
 const sagaMiddleware = createSagaMiddleware();

From 86759f2a5a9925b4092bc6ed6c34b7724df3bec0 Mon Sep 17 00:00:00 2001
From: Pavel Meyer <meyerpavel1207@gmail.com>
Date: Thu, 7 Nov 2024 14:49:46 +0300
Subject: [PATCH 3/6] CW-instant-reorder

Fix Inbox items
Fix inbox focus
Added flush for persist store after logout
---
 src/pages/Auth/store/saga.tsx                 | 19 ++++++++++---
 .../NewDiscussionCreation.tsx                 |  5 +++-
 .../NewProposalCreation.tsx                   |  5 +++-
 .../components/FeedLayout/FeedLayout.tsx      |  1 +
 src/pages/inbox/BaseInbox.tsx                 | 13 +++++++++
 src/shared/hooks/useCases/useInboxItems.ts    |  1 +
 .../utils/generateOptimisticFeedItem.ts       | 27 ++++++++++++++++++-
 src/store/states/optimistic/actions.ts        | 12 +++++++--
 src/store/states/optimistic/constants.ts      |  1 +
 src/store/states/optimistic/reducer.ts        | 16 ++++++-----
 10 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/src/pages/Auth/store/saga.tsx b/src/pages/Auth/store/saga.tsx
index a3240b05d..a73fb31f7 100755
--- a/src/pages/Auth/store/saga.tsx
+++ b/src/pages/Auth/store/saga.tsx
@@ -6,7 +6,7 @@ import {
   subscribeToNotification,
 } from "@/pages/OldCommon/store/api";
 import { UserService } from "@/services";
-import { store } from "@/shared/appConfig";
+import { persistor, store } from "@/shared/appConfig";
 import { Awaited } from "@/shared/interfaces";
 import { FirebaseCredentials } from "@/shared/interfaces/FirebaseCredentials";
 import { EventTypeState, NotificationItem } from "@/shared/models/Notification";
@@ -48,6 +48,7 @@ import firebase from "../../../shared/utils/firebase";
 import { UserCreationDto } from "../interface";
 import * as actions from "./actions";
 import { createdUserApi, deleteUserApi, getUserData } from "./api";
+import { resetOptimisticState } from "@/store/states/optimistic/actions";
 
 const getAuthProviderFromProviderData = (
   providerData?: firebase.User["providerData"],
@@ -533,15 +534,27 @@ function* confirmVerificationCodeSaga({
 }
 
 function* logOut() {
+
+  yield put(resetOptimisticState());
+  // Wait for persistor.purge() to complete
+  yield call([persistor, persistor.purge]);
+  yield call([persistor, persistor.flush]);
+
+  // Now clear localStorage
   localStorage.clear();
-  firebase.auth().signOut();
 
+  // Sign out from Firebase
+  yield call([firebase.auth(), firebase.auth().signOut]);
+
+  // Notify React Native WebView if applicable
   if (window.ReactNativeWebView) {
-    window?.ReactNativeWebView?.postMessage(WebviewActions.logout);
+    window.ReactNativeWebView.postMessage(WebviewActions.logout);
   }
 
+  // Reset global data and navigate to home
   resetGlobalData(true);
   history.push(ROUTE_PATHS.HOME);
+
   yield true;
 }
 
diff --git a/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewDiscussionCreation/NewDiscussionCreation.tsx b/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewDiscussionCreation/NewDiscussionCreation.tsx
index 961955804..d70e1ee08 100644
--- a/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewDiscussionCreation/NewDiscussionCreation.tsx
+++ b/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewDiscussionCreation/NewDiscussionCreation.tsx
@@ -139,7 +139,10 @@ const NewDiscussionCreation: FC<NewDiscussionCreationProps> = (props) => {
             content: generateFirstMessage({userName, userId}),
           }
         });
-        dispatch(optimisticActions.setOptimisticFeedItem(optimisticFeedItem));
+        dispatch(optimisticActions.setOptimisticFeedItem({
+          data: optimisticFeedItem, 
+          common
+        }));
         dispatch(commonActions.setRecentStreamId(optimisticFeedItem.data.id));
         dispatch(
           commonActions.createDiscussion.request({
diff --git a/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewProposalCreation/NewProposalCreation.tsx b/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewProposalCreation/NewProposalCreation.tsx
index a708631c0..06ba04f3a 100644
--- a/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewProposalCreation/NewProposalCreation.tsx
+++ b/src/pages/common/components/CommonTabPanels/components/FeedTab/components/NewProposalCreation/NewProposalCreation.tsx
@@ -107,7 +107,10 @@ const NewProposalCreation: FC<NewProposalCreationProps> = (props) => {
         }
       });
 
-      dispatch(optimisticActions.setOptimisticFeedItem(optimisticFeedItem));
+      dispatch(optimisticActions.setOptimisticFeedItem({
+        data: optimisticFeedItem, 
+        common
+      }));
       dispatch(commonActions.setRecentStreamId(optimisticFeedItem.data.id));
       switch (values.proposalType.value) {
         case ProposalsTypes.FUNDS_ALLOCATION: {
diff --git a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx
index 64ba26978..4bfc9ef35 100644
--- a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx
+++ b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx
@@ -852,6 +852,7 @@ const FeedLayout: ForwardRefRenderFunction<FeedLayoutRef, FeedLayoutProps> = (
                         item.feedItemFollowWithMetadata,
                         outerCommon,
                       );
+
                       const isPinned = (
                         outerCommon?.pinnedFeedItems || []
                       ).some(
diff --git a/src/pages/inbox/BaseInbox.tsx b/src/pages/inbox/BaseInbox.tsx
index aac314cf3..343824593 100644
--- a/src/pages/inbox/BaseInbox.tsx
+++ b/src/pages/inbox/BaseInbox.tsx
@@ -27,6 +27,7 @@ import { RightArrowThinIcon } from "@/shared/icons";
 import {
   ChatChannelFeedLayoutItemProps,
   checkIsChatChannelLayoutItem,
+  FeedItemFollowLayoutItemWithFollowData,
   FeedLayoutItem,
   FeedLayoutItemChangeDataWithType,
   FeedLayoutRef,
@@ -146,6 +147,18 @@ const InboxPage: FC<InboxPageProps> = (props) => {
     refetchInboxItems();
   }, [isActiveUnreadInboxItemsQueryParam]);
 
+  useEffect(() => {
+    const firstFeedItem = topFeedItems[0];
+    if(optimisticInboxFeedItems.size > 0 && firstFeedItem) {
+
+      feedLayoutRef?.setActiveItem({
+        feedItemId: firstFeedItem.itemId,
+        discussion: (firstFeedItem as FeedItemFollowLayoutItemWithFollowData)?.feedItem.optimisticData,
+      });
+    }
+
+  }, [topFeedItems, optimisticInboxFeedItems, feedLayoutRef])
+
   const fetchData = () => {
     fetchInboxData({
       sharedFeedItemId,
diff --git a/src/shared/hooks/useCases/useInboxItems.ts b/src/shared/hooks/useCases/useInboxItems.ts
index 8da4fd264..818f69db7 100644
--- a/src/shared/hooks/useCases/useInboxItems.ts
+++ b/src/shared/hooks/useCases/useInboxItems.ts
@@ -267,6 +267,7 @@ export const useInboxItems = (
           dispatch(inboxActions.addNewInboxItems(finalData));
           finalData.forEach(({item}) => {
             const itemData = (item as FeedItemFollowLayoutItemWithFollowData).feedItem?.data;
+
             if(optimisticInboxItems.has(itemData.id)) {
               dispatch(optimisticActions.removeOptimisticInboxFeedItemState({id: itemData.id}));
             } else if (itemData?.discussionId && optimisticInboxItems.has(itemData?.discussionId)) {
diff --git a/src/shared/utils/generateOptimisticFeedItem.ts b/src/shared/utils/generateOptimisticFeedItem.ts
index df9731e3d..18ce7a2e5 100644
--- a/src/shared/utils/generateOptimisticFeedItem.ts
+++ b/src/shared/utils/generateOptimisticFeedItem.ts
@@ -1,6 +1,6 @@
 import { Timestamp as FirestoreTimestamp } from "firebase/firestore";
 import { v4 as uuidv4 } from "uuid";
-import { CommonFeed, CommonFeedType, LastMessageContent, OptimisticFeedItemState } from "../models";
+import { Common, CommonFeed, CommonFeedType, FeedItemFollowWithMetadata, LastMessageContent, OptimisticFeedItemState } from "../models";
 
 interface GenerateOptimisticFeedItemPayload {
   userId: string;
@@ -63,4 +63,29 @@ export const generateOptimisticFeedItem = ({
     },
     circleVisibility,
   }
+}
+
+export const generateOptimisticFeedItemFollowWithMetadata = ({ feedItem, common }: {
+  feedItem: CommonFeed,
+  common: Common;
+}): FeedItemFollowWithMetadata => {
+
+  const currentDate = FirestoreTimestamp.now();
+  return {
+    commonAvatar: common.image,
+    commonId: common.id,
+    commonName: common.name,
+    feedItem: feedItem,
+    feedItemId: feedItem.id,
+    userId: feedItem.userId,
+    emailSubscribed: false,
+    pushSubscribed: false,
+    count: 0,
+    type: feedItem.data.type,
+    lastSeen: currentDate,
+    createdAt: currentDate,
+    updatedAt: currentDate,
+    lastActivity: currentDate,
+    id: feedItem.id,
+  }
 }
\ No newline at end of file
diff --git a/src/store/states/optimistic/actions.ts b/src/store/states/optimistic/actions.ts
index 11c9db5c7..5c741c01d 100644
--- a/src/store/states/optimistic/actions.ts
+++ b/src/store/states/optimistic/actions.ts
@@ -1,5 +1,6 @@
 import { CreateDiscussionMessageDto } from "@/shared/interfaces/api/discussionMessages";
 import {
+  Common,
   CommonFeed,
   OptimisticFeedItemState
 } from "@/shared/models";
@@ -8,7 +9,10 @@ import { OptimisticActionType } from "./constants";
 
 export const setOptimisticFeedItem = createStandardAction(
   OptimisticActionType.SET_OPTIMISTIC_FEED_ITEM,
-)<CommonFeed>();
+)<{
+  data: CommonFeed;
+  common: Common;
+}>();
 
 export const updateOptimisticFeedItemState = createStandardAction(
   OptimisticActionType.UPDATE_OPTIMISTIC_FEED_ITEM,
@@ -39,4 +43,8 @@ export const clearOptimisticDiscussionMessages = createStandardAction(
 
 export const clearCreatedOptimisticFeedItem = createStandardAction(
   OptimisticActionType.CLEAR_CREATED_OPTIMISTIC_FEED_ITEM,
-)<string>();
\ No newline at end of file
+)<string>();
+
+export const resetOptimisticState = createStandardAction(
+  OptimisticActionType.RESET_OPTIMISTIC_STATE,
+)();
\ No newline at end of file
diff --git a/src/store/states/optimistic/constants.ts b/src/store/states/optimistic/constants.ts
index 4a1cff0b2..78d33e072 100644
--- a/src/store/states/optimistic/constants.ts
+++ b/src/store/states/optimistic/constants.ts
@@ -8,4 +8,5 @@ export enum OptimisticActionType {
   CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES = "@OPTIMISTIC/CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES",
 
   CLEAR_CREATED_OPTIMISTIC_FEED_ITEM = "@OPTIMISTIC/CLEAR_CREATED_OPTIMISTIC_FEED_ITEM",
+  RESET_OPTIMISTIC_STATE = "RESET_OPTIMISTIC_STATE",
 }
diff --git a/src/store/states/optimistic/reducer.ts b/src/store/states/optimistic/reducer.ts
index a6a6049c0..b29d452c2 100644
--- a/src/store/states/optimistic/reducer.ts
+++ b/src/store/states/optimistic/reducer.ts
@@ -5,6 +5,7 @@ import * as actions from "./actions";
 import {
   OptimisticState
 } from "./types";
+import { generateOptimisticFeedItemFollowWithMetadata } from "@/shared/utils";
 
 type Action = ActionType<typeof actions>;
 
@@ -16,24 +17,25 @@ const initialState: OptimisticState = {
 };
 
 export const reducer = createReducer<OptimisticState, Action>(initialState)
+  .handleAction(actions.resetOptimisticState, () => initialState)
   .handleAction(actions.setOptimisticFeedItem, (state, { payload }) =>
     produce(state, (nextState) => {
         const updatedMap = new Map(nextState.optimisticFeedItems);
         const updateMapInbox = new Map(nextState.optimisticInboxFeedItems);
 
-        const optimisticItemId = payload.data.discussionId ?? payload.data.id;
+        const optimisticItemId = payload.data.data.discussionId ?? payload.data.data.id;
         // Add the new item to the Map
         updatedMap.set(optimisticItemId, {
           type: InboxItemType.FeedItemFollow,
-          itemId: payload.id,
-          feedItem: payload,
+          itemId: payload.data.id,
+          feedItem: payload.data,
         });
         updateMapInbox.set(optimisticItemId, {
           type: InboxItemType.FeedItemFollow,
-          itemId: payload.id,
-          feedItem: payload,
-        })
-
+          itemId: payload.data.id,
+          feedItem: payload.data,
+          feedItemFollowWithMetadata: generateOptimisticFeedItemFollowWithMetadata({feedItem: payload.data, common: payload.common})
+        });
         // Assign the new Map back to the state
         nextState.optimisticFeedItems = updatedMap;
         nextState.optimisticInboxFeedItems = updateMapInbox;

From 710cd9cf5ed66ff3d8557da50d5f21821abefb18 Mon Sep 17 00:00:00 2001
From: Pavel Meyer <meyerpavel1207@gmail.com>
Date: Thu, 7 Nov 2024 14:58:32 +0300
Subject: [PATCH 4/6] CW-instant-reorder

Added scrolling behaviour
---
 src/pages/common/components/ChatComponent/ChatComponent.tsx | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/pages/common/components/ChatComponent/ChatComponent.tsx b/src/pages/common/components/ChatComponent/ChatComponent.tsx
index 93938a5f7..8e7f1570e 100644
--- a/src/pages/common/components/ChatComponent/ChatComponent.tsx
+++ b/src/pages/common/components/ChatComponent/ChatComponent.tsx
@@ -622,6 +622,9 @@ export default function ChatComponent({
 
         dispatch(commonActions.setFeedItemUpdatedAt(payloadUpdateFeedItem));
         dispatch(inboxActions.setInboxItemUpdatedAt(payloadUpdateFeedItem));
+        document
+          .getElementById("feedLayoutWrapper")
+          ?.scrollIntoView({ behavior: "smooth" });
         focusOnChat();
       }
     },

From cc29ff29ae96a57c8edfe2732d378b60e209cd8d Mon Sep 17 00:00:00 2001
From: Pavel Meyer <meyerpavel1207@gmail.com>
Date: Sat, 16 Nov 2024 19:17:52 +0300
Subject: [PATCH 5/6] CW-instant-reorder

Added logic for inbox reorder
---
 .../ChatComponent/ChatComponent.tsx           | 10 +++-
 .../components/FeedCard/FeedCard.module.scss  |  4 ++
 .../common/components/FeedCard/FeedCard.tsx   |  4 +-
 src/pages/inbox/BaseInbox.tsx                 | 29 ++++++-----
 src/shared/hooks/useCases/useInboxItems.ts    | 52 +++++++++++++++++--
 src/store/states/inbox/actions.ts             | 12 +----
 src/store/states/inbox/types.ts               |  9 ++++
 src/store/states/optimistic/actions.ts        | 10 ++++
 src/store/states/optimistic/constants.ts      |  3 ++
 src/store/states/optimistic/reducer.ts        | 44 ++++++++++++++++
 src/store/states/optimistic/selectors.ts      |  3 ++
 src/store/states/optimistic/types.ts          |  5 ++
 src/store/store.tsx                           |  3 +-
 13 files changed, 156 insertions(+), 32 deletions(-)

diff --git a/src/pages/common/components/ChatComponent/ChatComponent.tsx b/src/pages/common/components/ChatComponent/ChatComponent.tsx
index 8e7f1570e..99b2bec6b 100644
--- a/src/pages/common/components/ChatComponent/ChatComponent.tsx
+++ b/src/pages/common/components/ChatComponent/ChatComponent.tsx
@@ -67,6 +67,7 @@ import {
   selectOptimisticDiscussionMessages,
   inboxActions,
   optimisticActions,
+  selectInstantDiscussionMessagesOrder,
 } from "@/store/states";
 import { ChatContentContext, ChatContentData } from "../CommonContent/context";
 import {
@@ -89,6 +90,7 @@ import styles from "./ChatComponent.module.scss";
 import { BaseTextEditorHandles } from "@/shared/ui-kit/TextEditor/BaseTextEditor";
 
 const BASE_CHAT_INPUT_HEIGHT = 48;
+const BASE_ORDER_INTERVAL = 1000;
 
 interface ChatComponentInterface {
   commonId: string;
@@ -277,6 +279,9 @@ export default function ChatComponent({
   const optimisticDiscussionMessages = useSelector(
     selectOptimisticDiscussionMessages,
   );
+  const instantDiscussionMessagesOrder = useSelector(selectInstantDiscussionMessagesOrder);
+
+  const currentChatOrder = instantDiscussionMessagesOrder.get(discussionId)?.order || 1;
 
   const isOptimisticChat = optimisticFeedItems.has(discussionId);
 
@@ -416,8 +421,8 @@ export default function ChatComponent({
         setMessages([]);
       }
     },
-    1500,
-    [newMessages, discussionId, dispatch],
+    1500 + BASE_ORDER_INTERVAL * currentChatOrder,
+    [newMessages, discussionId, dispatch, currentChatOrder],
   );
 
   /**
@@ -584,6 +589,7 @@ export default function ChatComponent({
 
             return [...prev, ...filePreviewPayload, payload];
           });
+          dispatch(optimisticActions.setInstantDiscussionMessagesOrder({discussionId}));
         }
 
         if (isChatChannel) {
diff --git a/src/pages/common/components/FeedCard/FeedCard.module.scss b/src/pages/common/components/FeedCard/FeedCard.module.scss
index 7deb66dbe..8ff002e12 100644
--- a/src/pages/common/components/FeedCard/FeedCard.module.scss
+++ b/src/pages/common/components/FeedCard/FeedCard.module.scss
@@ -23,6 +23,10 @@
   cursor: pointer;
 }
 
+.toggleCard {
+  outline: none;
+}
+
 .loader {
   align-self: center;
 }
diff --git a/src/pages/common/components/FeedCard/FeedCard.tsx b/src/pages/common/components/FeedCard/FeedCard.tsx
index 28860dc8a..1b1625819 100644
--- a/src/pages/common/components/FeedCard/FeedCard.tsx
+++ b/src/pages/common/components/FeedCard/FeedCard.tsx
@@ -299,8 +299,8 @@ const FeedCard = (props, ref) => {
   ]);
 
   return (
-    <div ref={containerRef}>
-      {!isPreviewMode && <div {...getToggleProps()}>{feedItemBaseContent}</div>}
+    <div ref={containerRef} >
+      {!isPreviewMode && <div className={styles.toggleCard} {...getToggleProps()}>{feedItemBaseContent}</div>}
       <div {...getCollapseProps()}>
         <CommonCard
           className={classNames(
diff --git a/src/pages/inbox/BaseInbox.tsx b/src/pages/inbox/BaseInbox.tsx
index 343824593..711ba2868 100644
--- a/src/pages/inbox/BaseInbox.tsx
+++ b/src/pages/inbox/BaseInbox.tsx
@@ -43,6 +43,7 @@ import {
   selectIsSearchingInboxItems,
   selectNextChatChannelItemId,
   selectSharedInboxItem,
+  selectInstantDiscussionMessagesOrder,
 } from "@/store/states";
 import { ChatChannelItem, FeedItemBaseContent } from "./components";
 import { useInboxData } from "./hooks";
@@ -181,22 +182,26 @@ const InboxPage: FC<InboxPageProps> = (props) => {
     [],
   );
 
+  const instantDiscussionMessage = useSelector(selectInstantDiscussionMessagesOrder);
+
   const handleFeedItemUpdate = useCallback(
     (item: CommonFeed, isRemoved: boolean) => {
-      dispatch(
-        inboxActions.updateFeedItem({
-          item,
-          isRemoved,
-        }),
-      );
-
-      if (!isRemoved && item.data.lastMessage?.ownerId === userId) {
-        document
-          .getElementById("feedLayoutWrapper")
-          ?.scrollIntoView({ behavior: "smooth" });
+      if(!instantDiscussionMessage.has(item.data.id)) {
+        dispatch(
+          inboxActions.updateFeedItem({
+            item,
+            isRemoved,
+          }),
+        );
+  
+        if (!isRemoved && item.data.lastMessage?.ownerId === userId) {
+          document
+            .getElementById("feedLayoutWrapper")
+            ?.scrollIntoView({ behavior: "smooth" });
+        }
       }
     },
-    [dispatch],
+    [dispatch, instantDiscussionMessage],
   );
 
   const handleFeedItemUnfollowed = useCallback(
diff --git a/src/shared/hooks/useCases/useInboxItems.ts b/src/shared/hooks/useCases/useInboxItems.ts
index 818f69db7..e9fefd046 100644
--- a/src/shared/hooks/useCases/useInboxItems.ts
+++ b/src/shared/hooks/useCases/useInboxItems.ts
@@ -7,17 +7,21 @@ import {
   checkIsFeedItemFollowLayoutItemWithFollowData,
   FeedItemFollowLayoutItemWithFollowData,
   FeedLayoutItemWithFollowData,
+  InboxItemBatch,
   InboxItemsBatch as ItemsBatch,
 } from "@/shared/interfaces";
 import { InboxItem, Timestamp } from "@/shared/models";
 import {
   inboxActions,
   InboxItems,
+  NewInboxItems,
   optimisticActions,
   selectFilteredInboxItems,
   selectInboxItems,
+  selectInstantDiscussionMessagesOrder,
   selectOptimisticInboxFeedItems,
 } from "@/store/states";
+import { useDeepCompareEffect } from "react-use";
 
 interface Return
   extends Pick<InboxItems, "data" | "loading" | "hasMore" | "batchNumber"> {
@@ -71,6 +75,9 @@ export const useInboxItems = (
 ): Return => {
   const dispatch = useDispatch();
   const optimisticInboxItems = useSelector(selectOptimisticInboxFeedItems);
+  const instantDiscussionMessages = useSelector(
+    selectInstantDiscussionMessagesOrder,
+  );
   const [newItemsBatches, setNewItemsBatches] = useState<ItemsBatch[]>([]);
   const [lastUpdatedAt, setLastUpdatedAt] = useState<Timestamp | null>(null);
   const inboxItems = useSelector(selectInboxItems);
@@ -244,6 +251,33 @@ export const useInboxItems = (
     unread,
   ]);
 
+  const [notListedFeedItems, setNotListedFeedItems] = useState<InboxItemBatch<FeedLayoutItemWithFollowData>[]>([]);
+
+  useDeepCompareEffect(() => {
+    if(notListedFeedItems.length > 0 && notListedFeedItems.length === instantDiscussionMessages.size) {
+      const updatedFeedItems = notListedFeedItems.map((item) => {
+        const itemData = item?.item as FeedItemFollowLayoutItemWithFollowData;
+        const feedItemData = itemData.feedItem?.data;
+        const messageUpdatedAt = instantDiscussionMessages.get(feedItemData?.discussionId ?? "")?.timestamp || instantDiscussionMessages.get(feedItemData.id)?.timestamp;
+        return {
+          ...item,
+          item: {
+            ...itemData,
+            feedItem: {
+              ...itemData.feedItem,
+              updatedAt: messageUpdatedAt,
+            }
+          }
+        }
+      }) as NewInboxItems[];
+
+      setNotListedFeedItems([]);
+      dispatch(inboxActions.addNewInboxItems(updatedFeedItems));
+      dispatch(optimisticActions.clearInstantDiscussionMessagesOrder());
+    }
+
+  },[notListedFeedItems, instantDiscussionMessages]);
+
   useEffect(() => {
     if (!lastBatch || !userId) {
       return;
@@ -264,16 +298,23 @@ export const useInboxItems = (
         );
 
         if (finalData.length > 0 && isMounted) {
-          dispatch(inboxActions.addNewInboxItems(finalData));
-          finalData.forEach(({item}) => {
-            const itemData = (item as FeedItemFollowLayoutItemWithFollowData).feedItem?.data;
-
+          const newItems: InboxItemBatch<FeedLayoutItemWithFollowData>[] = [];
+          finalData.forEach((item: InboxItemBatch<FeedLayoutItemWithFollowData>) => {
+            const itemData = (item.item as FeedItemFollowLayoutItemWithFollowData)?.feedItem?.data;
+
+            if(instantDiscussionMessages.has(itemData?.discussionId ?? "") || instantDiscussionMessages.has(itemData?.id)) {
+              setNotListedFeedItems((prev) => [...prev, item]);
+            } else {
+              newItems.push(item);
+            }
             if(optimisticInboxItems.has(itemData.id)) {
               dispatch(optimisticActions.removeOptimisticInboxFeedItemState({id: itemData.id}));
             } else if (itemData?.discussionId && optimisticInboxItems.has(itemData?.discussionId)) {
               dispatch(optimisticActions.removeOptimisticInboxFeedItemState({id: itemData?.discussionId}));
             }
           })
+
+          newItems.length > 0 && dispatch(inboxActions.addNewInboxItems(newItems));
         }
       } catch (error) {
         Logger.error(error);
@@ -285,7 +326,8 @@ export const useInboxItems = (
     return () => {
       isMounted = false;
     };
-  }, [lastBatch]);
+  }, [lastBatch, instantDiscussionMessages]);
+
 
   return {
     ...inboxItems,
diff --git a/src/store/states/inbox/actions.ts b/src/store/states/inbox/actions.ts
index 3400fe54e..004ad09be 100644
--- a/src/store/states/inbox/actions.ts
+++ b/src/store/states/inbox/actions.ts
@@ -2,7 +2,7 @@ import { createAsyncAction, createStandardAction } from "typesafe-actions";
 import { FeedLayoutItemWithFollowData } from "@/shared/interfaces";
 import { ChatChannel, CommonFeed, LastMessageContentWithMessageId } from "@/shared/models";
 import { InboxActionType } from "./constants";
-import { InboxItems, InboxSearchState } from "./types";
+import { InboxItems, InboxSearchState, NewInboxItems } from "./types";
 
 export const resetInbox = createStandardAction(InboxActionType.RESET_INBOX)<{
   onlyIfUnread?: boolean;
@@ -26,15 +26,7 @@ export const getInboxItems = createAsyncAction(
 
 export const addNewInboxItems = createStandardAction(
   InboxActionType.ADD_NEW_INBOX_ITEMS,
-)<
-  {
-    item: FeedLayoutItemWithFollowData;
-    statuses: {
-      isAdded: boolean;
-      isRemoved: boolean;
-    };
-  }[]
->();
+)<NewInboxItems[]>();
 
 export const updateInboxItem = createStandardAction(
   InboxActionType.UPDATE_INBOX_ITEM,
diff --git a/src/store/states/inbox/types.ts b/src/store/states/inbox/types.ts
index 58542ac2a..c18c75a67 100644
--- a/src/store/states/inbox/types.ts
+++ b/src/store/states/inbox/types.ts
@@ -20,6 +20,14 @@ export interface InboxItems {
   unread: boolean;
 }
 
+export interface NewInboxItems {
+  item: FeedLayoutItemWithFollowData;
+  statuses: {
+    isAdded: boolean;
+    isRemoved: boolean;
+  };
+}
+
 export type LastState = Pick<
   InboxState,
   | "items"
@@ -39,3 +47,4 @@ export interface InboxState {
   lastReadState: LastState | null;
   lastUnreadState: LastState | null;
 }
+
diff --git a/src/store/states/optimistic/actions.ts b/src/store/states/optimistic/actions.ts
index 5c741c01d..4a94826bb 100644
--- a/src/store/states/optimistic/actions.ts
+++ b/src/store/states/optimistic/actions.ts
@@ -41,6 +41,16 @@ export const clearOptimisticDiscussionMessages = createStandardAction(
   OptimisticActionType.CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES,
 )<string>();
 
+export const setInstantDiscussionMessagesOrder = createStandardAction(
+  OptimisticActionType.SET_INSTANT_DISCUSSION_MESSAGES_ORDER,
+)<{
+  discussionId: string;
+}>();
+
+export const clearInstantDiscussionMessagesOrder = createStandardAction(
+  OptimisticActionType.CLEAR_INSTANT_DISCUSSION_MESSAGES_ORDER,
+)();
+
 export const clearCreatedOptimisticFeedItem = createStandardAction(
   OptimisticActionType.CLEAR_CREATED_OPTIMISTIC_FEED_ITEM,
 )<string>();
diff --git a/src/store/states/optimistic/constants.ts b/src/store/states/optimistic/constants.ts
index 78d33e072..9bca26b87 100644
--- a/src/store/states/optimistic/constants.ts
+++ b/src/store/states/optimistic/constants.ts
@@ -7,6 +7,9 @@ export enum OptimisticActionType {
   SET_OPTIMISTIC_DISCUSSION_MESSAGES = "@OPTIMISTIC/SET_OPTIMISTIC_DISCUSSION_MESSAGES",
   CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES = "@OPTIMISTIC/CLEAR_OPTIMISTIC_DISCUSSION_MESSAGES",
 
+  SET_INSTANT_DISCUSSION_MESSAGES_ORDER = "@OPTIMISTIC/SET_INSTANT_DISCUSSION_MESSAGES_ORDER",
+  CLEAR_INSTANT_DISCUSSION_MESSAGES_ORDER = "@OPTIMISTIC/CLEAR_INSTANT_DISCUSSION_MESSAGES_ORDER",
+
   CLEAR_CREATED_OPTIMISTIC_FEED_ITEM = "@OPTIMISTIC/CLEAR_CREATED_OPTIMISTIC_FEED_ITEM",
   RESET_OPTIMISTIC_STATE = "RESET_OPTIMISTIC_STATE",
 }
diff --git a/src/store/states/optimistic/reducer.ts b/src/store/states/optimistic/reducer.ts
index b29d452c2..a437af2cd 100644
--- a/src/store/states/optimistic/reducer.ts
+++ b/src/store/states/optimistic/reducer.ts
@@ -6,6 +6,7 @@ import {
   OptimisticState
 } from "./types";
 import { generateOptimisticFeedItemFollowWithMetadata } from "@/shared/utils";
+import { Timestamp } from "@/shared/models";
 
 type Action = ActionType<typeof actions>;
 
@@ -14,10 +15,53 @@ const initialState: OptimisticState = {
   optimisticInboxFeedItems: new Map(),
   optimisticDiscussionMessages: new Map(),
   createdOptimisticFeedItems: new Map(),
+  instantDiscussionMessagesOrder: new Map(),
 };
 
 export const reducer = createReducer<OptimisticState, Action>(initialState)
   .handleAction(actions.resetOptimisticState, () => initialState)
+  .handleAction(actions.setInstantDiscussionMessagesOrder, (state, { payload }) =>
+    produce(state, (nextState) => {
+      const updatedMap = new Map(nextState.instantDiscussionMessagesOrder);
+      const { discussionId } = payload;
+
+      if(updatedMap.size > 1 && updatedMap.has(discussionId)) {
+        const keys = Array.from(updatedMap.keys());
+
+        keys.forEach((key) => {
+          const orderValue = updatedMap.get(key)?.order || 2;
+          const timestampValue = updatedMap.get(key)?.timestamp || Timestamp.fromDate(new Date());
+          updatedMap.set(key, {
+            order: orderValue === 1 ? 1 : orderValue - 1,
+            timestamp: timestampValue
+          });
+        });
+      }
+
+      if(updatedMap.has(discussionId)) {
+        updatedMap.set(discussionId, {
+          order: updatedMap.size || 1,
+          timestamp: Timestamp.fromDate(new Date())
+        });
+      } else {
+        updatedMap.set(discussionId, {
+          order: (updatedMap.size + 1) || 1,
+          timestamp: Timestamp.fromDate(new Date())
+        });
+      }
+      nextState.instantDiscussionMessagesOrder = updatedMap;
+    }),
+  )
+  .handleAction(actions.clearInstantDiscussionMessagesOrder, (state) =>
+    produce(state, (nextState) => {
+      const updatedMap = new Map();
+
+      // updatedMap.delete(payload);
+
+      // Assign the new Map back to the state
+      nextState.instantDiscussionMessagesOrder = updatedMap;
+    }),
+  )
   .handleAction(actions.setOptimisticFeedItem, (state, { payload }) =>
     produce(state, (nextState) => {
         const updatedMap = new Map(nextState.optimisticFeedItems);
diff --git a/src/store/states/optimistic/selectors.ts b/src/store/states/optimistic/selectors.ts
index 6bedea23d..bed310b5e 100644
--- a/src/store/states/optimistic/selectors.ts
+++ b/src/store/states/optimistic/selectors.ts
@@ -12,3 +12,6 @@ export const selectOptimisticDiscussionMessages = (state: AppState) =>
 
 export const selectCreatedOptimisticFeedItems = (state: AppState) =>
   state.optimistic.createdOptimisticFeedItems;
+
+export const selectInstantDiscussionMessagesOrder = (state: AppState) =>
+  state.optimistic.instantDiscussionMessagesOrder;
diff --git a/src/store/states/optimistic/types.ts b/src/store/states/optimistic/types.ts
index 4a24fa8c3..fe11016df 100644
--- a/src/store/states/optimistic/types.ts
+++ b/src/store/states/optimistic/types.ts
@@ -2,10 +2,15 @@ import {
   FeedItemFollowLayoutItem
 } from "@/shared/interfaces";
 import { CreateDiscussionMessageDto } from "@/shared/interfaces/api/discussionMessages";
+import { Timestamp } from "@/shared/models";
 
 export interface OptimisticState {
   createdOptimisticFeedItems: Map<string, FeedItemFollowLayoutItem | undefined>;
   optimisticFeedItems: Map<string, FeedItemFollowLayoutItem>;
   optimisticInboxFeedItems: Map<string, FeedItemFollowLayoutItem>;
   optimisticDiscussionMessages: Map<string, CreateDiscussionMessageDto[]>;
+  instantDiscussionMessagesOrder: Map<string, {
+    order: number
+    timestamp: Timestamp;
+  }>;
 }
diff --git a/src/store/store.tsx b/src/store/store.tsx
index 623c46b39..915483972 100644
--- a/src/store/store.tsx
+++ b/src/store/store.tsx
@@ -33,7 +33,8 @@ const mapFields: Array<keyof OptimisticState> = [
   "createdOptimisticFeedItems",
   "optimisticFeedItems",
   "optimisticInboxFeedItems",
-  "optimisticDiscussionMessages"
+  "optimisticDiscussionMessages",
+  "instantDiscussionMessagesOrder"
 ];
 
 const mapTransformer = createTransform<OptimisticState, OptimisticState>(

From 9f6475816db64e3333373d7c7775d42742c651b6 Mon Sep 17 00:00:00 2001
From: Pavel Meyer <meyerpavel1207@gmail.com>
Date: Sun, 17 Nov 2024 01:21:09 +0300
Subject: [PATCH 6/6] CW-instant-reorder

Added feedItem keyboard support
---
 .../ChatComponent/ChatComponent.tsx           | 15 ++++++
 .../DiscussionFeedCard/DiscussionFeedCard.tsx |  6 ---
 .../common/components/FeedCard/FeedCard.tsx   |  2 +-
 .../common/components/FeedItem/context.ts     |  1 +
 .../components/FeedLayout/FeedLayout.tsx      | 53 ++++++++++++++++++-
 .../components/FeedLayout/constants/index.ts  |  4 ++
 src/shared/hooks/index.tsx                    |  2 +
 src/shared/hooks/useElementPresence.tsx       | 48 +++++++++++++++++
 src/shared/hooks/useIsElementFocused.tsx      | 24 +++++++++
 .../utils/countTextEditorEmojiElements.ts     |  1 +
 10 files changed, 147 insertions(+), 9 deletions(-)
 create mode 100644 src/shared/hooks/useElementPresence.tsx
 create mode 100644 src/shared/hooks/useIsElementFocused.tsx

diff --git a/src/pages/common/components/ChatComponent/ChatComponent.tsx b/src/pages/common/components/ChatComponent/ChatComponent.tsx
index 99b2bec6b..c7350bd0b 100644
--- a/src/pages/common/components/ChatComponent/ChatComponent.tsx
+++ b/src/pages/common/components/ChatComponent/ChatComponent.tsx
@@ -88,6 +88,7 @@ import {
 } from "./utils";
 import styles from "./ChatComponent.module.scss";
 import { BaseTextEditorHandles } from "@/shared/ui-kit/TextEditor/BaseTextEditor";
+import { useFeedItemContext } from "../FeedItem";
 
 const BASE_CHAT_INPUT_HEIGHT = 48;
 const BASE_ORDER_INTERVAL = 1000;
@@ -258,6 +259,20 @@ export default function ChatComponent({
     parseStringToTextEditorValue(),
   );
 
+  const {
+    setIsInputFocused
+  } = useFeedItemContext();
+
+  useEffect(() => {
+    const isEmpty = checkIsTextEditorValueEmpty(message);
+    if(!isEmpty || message.length > 1) {
+      setIsInputFocused?.(true);
+    } else {
+      setIsInputFocused?.(false);
+    }
+
+  },[message, setIsInputFocused])
+
   const emojiCount = useMemo(
     () => countTextEditorEmojiElements(message),
     [message],
diff --git a/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx b/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx
index 61547c201..dcd82a373 100644
--- a/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx
+++ b/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx
@@ -218,12 +218,6 @@ function DiscussionFeedCard(props, ref) {
   const cardTitle = discussion?.title;
   const commonNotion = outerCommonNotion ?? common?.notion;
 
-  // const ownerId = useMemo(() => {
-  //   if(item.userId) {
-  //     return item.userId
-  //   }
-  // },[item.userId])
-
   const handleOpenChat = useCallback(() => {
     if (discussion && !isPreviewMode) {
       setChatItem({
diff --git a/src/pages/common/components/FeedCard/FeedCard.tsx b/src/pages/common/components/FeedCard/FeedCard.tsx
index 1b1625819..5fac7dcb5 100644
--- a/src/pages/common/components/FeedCard/FeedCard.tsx
+++ b/src/pages/common/components/FeedCard/FeedCard.tsx
@@ -299,7 +299,7 @@ const FeedCard = (props, ref) => {
   ]);
 
   return (
-    <div ref={containerRef} >
+    <div ref={containerRef}>
       {!isPreviewMode && <div className={styles.toggleCard} {...getToggleProps()}>{feedItemBaseContent}</div>}
       <div {...getCollapseProps()}>
         <CommonCard
diff --git a/src/pages/common/components/FeedItem/context.ts b/src/pages/common/components/FeedItem/context.ts
index e6cb31770..22c10d418 100644
--- a/src/pages/common/components/FeedItem/context.ts
+++ b/src/pages/common/components/FeedItem/context.ts
@@ -71,6 +71,7 @@ export interface GetLastMessageOptions {
 }
 
 export interface FeedItemContextValue {
+  setIsInputFocused?: (isFocused: boolean) => void;
   setExpandedFeedItemId?: (feedItemId: string | null) => void;
   renderFeedItemBaseContent?: (props: FeedItemBaseContentProps) => ReactNode;
   onFeedItemUpdate?: (item: CommonFeed, isRemoved: boolean) => void;
diff --git a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx
index 4bfc9ef35..91f55aafe 100644
--- a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx
+++ b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx
@@ -13,7 +13,7 @@ import React, {
 import { useSelector } from "react-redux";
 import { useHistory } from "react-router-dom";
 import PullToRefresh from "react-simple-pull-to-refresh";
-import { useDeepCompareEffect, useWindowSize } from "react-use";
+import { useDeepCompareEffect, useKey, useWindowSize } from "react-use";
 import classNames from "classnames";
 import { selectUser } from "@/pages/Auth/store/selectors";
 import { useCommonMember } from "@/pages/OldCommon/hooks";
@@ -44,7 +44,7 @@ import {
   ROUTE_PATHS,
 } from "@/shared/constants";
 import { useRoutesContext } from "@/shared/contexts";
-import { useMemoizedFunction, useQueryParams } from "@/shared/hooks";
+import { useElementPresence, useMemoizedFunction, useQueryParams } from "@/shared/hooks";
 import { useGovernanceByCommonId } from "@/shared/hooks/useCases";
 import { useDisableOverscroll } from "@/shared/hooks/useDisableOverscroll";
 import { useIsTabletView } from "@/shared/hooks/viewport";
@@ -90,6 +90,7 @@ import {
 import {
   BATCHES_AMOUNT_TO_PRELOAD,
   ITEMS_AMOUNT_TO_PRE_LOAD_MESSAGES,
+  MENTION_TAG_ELEMENT,
 } from "./constants";
 import { useUserForProfile } from "./hooks";
 import {
@@ -353,6 +354,8 @@ const FeedLayout: ForwardRefRenderFunction<FeedLayoutRef, FeedLayoutProps> = (
   const activeFeedItemId = chatItem?.feedItemId || feedItemIdForAutoChatOpen;
   const sizeKey = `${windowWidth}_${contentWidth}`;
 
+  const activeFeedItemIndex = useMemo(() => allFeedItems.findIndex((item) => item.itemId === activeFeedItemId), [activeFeedItemId, allFeedItems]);
+
   const getUserCircleIds = useCallback(
     (commonId) => {
       return Object.values(
@@ -405,6 +408,50 @@ const FeedLayout: ForwardRefRenderFunction<FeedLayoutRef, FeedLayoutProps> = (
     setChatItem(nextChatItem);
   }, []);
 
+  const isMentionOpen = useElementPresence(MENTION_TAG_ELEMENT.key, MENTION_TAG_ELEMENT.value);
+  const [isInputFocused, setIsInputFocused] = useState(false);
+
+  const handleArrowUp = (event, activeFeedItemIndex, allFeedItems, isMentionOpen, setChatItem) => {
+    if (!isMentionOpen && !isInputFocused) {
+      event.preventDefault();
+      event.stopPropagation();
+  
+      if (activeFeedItemIndex > 0) {
+        const nextFeedItemId = allFeedItems[activeFeedItemIndex - 1]?.itemId;
+  
+        setChatItem({ feedItemId: nextFeedItemId });
+      }
+    }
+  };
+  
+  const handleArrowDown = (event, activeFeedItemIndex, allFeedItems, isMentionOpen, setChatItem) => {
+    if (!isMentionOpen && !isInputFocused) {
+      event.preventDefault();
+      event.stopPropagation();
+  
+      if (activeFeedItemIndex < allFeedItems.length - 1) {
+        const nextFeedItemId = allFeedItems[activeFeedItemIndex + 1]?.itemId;
+  
+        setChatItem({ feedItemId: nextFeedItemId });
+      }
+    }
+  };
+  
+  // Inside your component
+  useKey(
+    "ArrowUp",
+    (event) => handleArrowUp(event, activeFeedItemIndex, allFeedItems, isMentionOpen, setChatItem),
+    {},
+    [activeFeedItemIndex, allFeedItems, isMentionOpen, isInputFocused]
+  );
+  
+  useKey(
+    "ArrowDown",
+    (event) => handleArrowDown(event, activeFeedItemIndex, allFeedItems, isMentionOpen, setChatItem),
+    {},
+    [activeFeedItemIndex, allFeedItems, isMentionOpen, isInputFocused]
+  );
+
   const chatContextValue = useMemo<ChatContextValue>(
     () => ({
       setChatItem: setActiveChatItem,
@@ -644,6 +691,7 @@ const FeedLayout: ForwardRefRenderFunction<FeedLayoutRef, FeedLayoutProps> = (
   // so we will not have extra re-renders of ALL rendered items
   const feedItemContextValue = useMemo<FeedItemContextValue>(
     () => ({
+      setIsInputFocused,
       setExpandedFeedItemId,
       renderFeedItemBaseContent,
       onFeedItemUpdate,
@@ -656,6 +704,7 @@ const FeedLayout: ForwardRefRenderFunction<FeedLayoutRef, FeedLayoutProps> = (
       onActiveItemDataChange: handleActiveFeedItemDataChange,
     }),
     [
+      setIsInputFocused,
       renderFeedItemBaseContent,
       onFeedItemUpdate,
       onFeedItemUnfollowed,
diff --git a/src/pages/commonFeed/components/FeedLayout/constants/index.ts b/src/pages/commonFeed/components/FeedLayout/constants/index.ts
index 68c376375..b64b9cd95 100644
--- a/src/pages/commonFeed/components/FeedLayout/constants/index.ts
+++ b/src/pages/commonFeed/components/FeedLayout/constants/index.ts
@@ -1,2 +1,6 @@
 export const BATCHES_AMOUNT_TO_PRELOAD = 2;
 export const ITEMS_AMOUNT_TO_PRE_LOAD_MESSAGES = 10;
+export const MENTION_TAG_ELEMENT = {
+    key: "data-cy",
+    value: "mentions-portal"
+}
diff --git a/src/shared/hooks/index.tsx b/src/shared/hooks/index.tsx
index 7c78ecdd5..5371485a1 100644
--- a/src/shared/hooks/index.tsx
+++ b/src/shared/hooks/index.tsx
@@ -33,3 +33,5 @@ export { default as useImageSizeCheck } from "./useImageSizeCheck";
 export { default as useLightThemeOnly } from "./useLightThemeOnly";
 export * from "./useToggle";
 export * from "./useTraceUpdate";
+export * from "./useElementPresence";
+export * from "./useIsElementFocused";
\ No newline at end of file
diff --git a/src/shared/hooks/useElementPresence.tsx b/src/shared/hooks/useElementPresence.tsx
new file mode 100644
index 000000000..27eb4f74c
--- /dev/null
+++ b/src/shared/hooks/useElementPresence.tsx
@@ -0,0 +1,48 @@
+import { useEffect, useState } from "react";
+
+export const useElementPresence = (attribute, value) => {
+  const [elementPresent, setElementPresent] = useState(false);
+
+  useEffect(() => {
+    const observerCallback = (mutationsList) => {
+      mutationsList.forEach((mutation) => {
+        // Check for added nodes
+        mutation.addedNodes.forEach((node) => {
+          if (
+            node.nodeType === 1 && // Ensure it's an element
+            node.getAttribute(attribute) === value
+          ) {
+            setElementPresent(true);
+          }
+        });
+
+        // Check for removed nodes
+        mutation.removedNodes.forEach((node) => {
+          if (
+            node.nodeType === 1 && // Ensure it's an element
+            node.getAttribute(attribute) === value
+          ) {
+            setElementPresent(false);
+          }
+        });
+      });
+    };
+
+    const observer = new MutationObserver(observerCallback);
+
+    // Start observing the entire document
+    observer.observe(document.body, { childList: true, subtree: true });
+
+    // Check initially if the element is already present
+    const initialElement = document.querySelector(`[${attribute}="${value}"]`);
+    if (initialElement) {
+      setElementPresent(true);
+    }
+
+    return () => {
+      observer.disconnect(); // Cleanup observer on unmount
+    };
+  }, [attribute, value]);
+
+  return elementPresent;
+};
\ No newline at end of file
diff --git a/src/shared/hooks/useIsElementFocused.tsx b/src/shared/hooks/useIsElementFocused.tsx
new file mode 100644
index 000000000..da6dd02e9
--- /dev/null
+++ b/src/shared/hooks/useIsElementFocused.tsx
@@ -0,0 +1,24 @@
+import { useEffect, useState } from "react";
+
+export const useIsElementFocused = (id: string) => {
+  const [isFocused, setIsFocused] = useState(false);
+
+  useEffect(() => {
+    const handleFocusChange = () => {
+      const element = document.getElementById(id);
+      setIsFocused(document.activeElement === element);
+    };
+
+    // Listen to focus changes globally
+    document.addEventListener("focusin", handleFocusChange);
+    document.addEventListener("focusout", handleFocusChange);
+
+    // Cleanup
+    return () => {
+      document.removeEventListener("focusin", handleFocusChange);
+      document.removeEventListener("focusout", handleFocusChange);
+    };
+  }, [id]);
+
+  return isFocused;
+};
\ No newline at end of file
diff --git a/src/shared/ui-kit/TextEditor/utils/countTextEditorEmojiElements.ts b/src/shared/ui-kit/TextEditor/utils/countTextEditorEmojiElements.ts
index f8bdcd9ec..828decab8 100644
--- a/src/shared/ui-kit/TextEditor/utils/countTextEditorEmojiElements.ts
+++ b/src/shared/ui-kit/TextEditor/utils/countTextEditorEmojiElements.ts
@@ -14,6 +14,7 @@ export const countTextEditorEmojiElements = (
 
   let hasText = false;
   let emojiCount = 0;
+
   editorValue.forEach((element) => {
     if (
       (element as ParagraphElement)?.type === ElementType.Paragraph &&