diff --git a/src/services/Chat.ts b/src/services/Chat.ts index b46e3a0284..465c4b693f 100644 --- a/src/services/Chat.ts +++ b/src/services/Chat.ts @@ -238,12 +238,16 @@ class ChatService { participantId: string; startAt?: Timestamp; endAt?: Timestamp; + onlyWithMessages?: boolean; }): Promise => { - const { participantId, startAt, endAt } = options; + const { participantId, startAt, endAt, onlyWithMessages = false } = options; let query = this.getChatChannelCollection() .where("participants", "array-contains", participantId) .orderBy("updatedAt", "desc"); + if (onlyWithMessages) { + query = query.where("messageCount", ">", 0); + } if (startAt) { query = query.startAt(startAt); } diff --git a/src/shared/hooks/useCases/useInboxItems.ts b/src/shared/hooks/useCases/useInboxItems.ts index 82805954d4..5966ae3f4d 100644 --- a/src/shared/hooks/useCases/useInboxItems.ts +++ b/src/shared/hooks/useCases/useInboxItems.ts @@ -125,13 +125,14 @@ export const useInboxItems = ( const inboxItems = useSelector(selectInboxItems); const user = useSelector(selectUser()); const userId = user?.uid; + const unread = options?.unread; const lastBatch = newItemsBatches[0]; const fetch = () => { dispatch( inboxActions.getInboxItems.request({ limit: 15, - unread: options?.unread, + unread, }), ); }; @@ -213,6 +214,7 @@ export const useInboxItems = ( participantId: userId, startAt, endAt, + onlyWithMessages: true, }), FeedItemFollowsService.getFollowFeedItems({ userId, @@ -250,7 +252,7 @@ export const useInboxItems = ( }, []); useEffect(() => { - if (!inboxItems.firstDocTimestamp || !userId) { + if (!inboxItems.firstDocTimestamp || !userId || unread) { return; } @@ -263,10 +265,15 @@ export const useInboxItems = ( ); return unsubscribe; - }, [inboxItems.firstDocTimestamp, userId, feedItemIdsForNotListening]); + }, [ + inboxItems.firstDocTimestamp, + userId, + feedItemIdsForNotListening, + unread, + ]); useEffect(() => { - if (!inboxItems.firstDocTimestamp || !userId) { + if (!inboxItems.firstDocTimestamp || !userId || unread) { return; } @@ -280,7 +287,12 @@ export const useInboxItems = ( ); return unsubscribe; - }, [inboxItems.firstDocTimestamp, userId, feedItemIdsForNotListening]); + }, [ + inboxItems.firstDocTimestamp, + userId, + feedItemIdsForNotListening, + unread, + ]); useEffect(() => { if (!lastBatch) { diff --git a/src/shared/utils/queryParams.ts b/src/shared/utils/queryParams.ts index 74587c9b7b..dfa43a515e 100644 --- a/src/shared/utils/queryParams.ts +++ b/src/shared/utils/queryParams.ts @@ -1,6 +1,12 @@ import queryString from "query-string"; import { history } from "@/shared/appConfig"; +export const getQueryParam = (key: string): string | null => { + const urlParams = new URLSearchParams(window.location.search); + + return urlParams.get(key); +}; + export const addQueryParam = (key: string, value: string) => { const params = queryString.parse(window.location.search); const search = queryString.stringify({ diff --git a/src/store/states/inbox/index.ts b/src/store/states/inbox/index.ts index 7877dfa850..d383a80624 100644 --- a/src/store/states/inbox/index.ts +++ b/src/store/states/inbox/index.ts @@ -1,5 +1,9 @@ export * as inboxActions from "./actions"; -export { reducer as inboxReducer } from "./reducer"; +export { + reducer as inboxReducer, + INITIAL_INBOX_ITEMS, + INITIAL_INBOX_STATE, +} from "./reducer"; export { mainSaga as inboxSaga } from "./saga"; export * from "./selectors"; export * from "./types"; diff --git a/src/store/states/inbox/reducer.ts b/src/store/states/inbox/reducer.ts index 87dca602b7..3794a6f44c 100644 --- a/src/store/states/inbox/reducer.ts +++ b/src/store/states/inbox/reducer.ts @@ -1,30 +1,32 @@ import produce from "immer"; import { WritableDraft } from "immer/dist/types/types-external"; import { ActionType, createReducer } from "typesafe-actions"; -import { InboxItemType } from "@/shared/constants"; +import { InboxItemType, QueryParamKey } from "@/shared/constants"; import { checkIsChatChannelLayoutItem, checkIsFeedItemFollowLayoutItem, FeedLayoutItemWithFollowData, } from "@/shared/interfaces"; import { ChatChannel, CommonFeed, Timestamp } from "@/shared/models"; +import { getQueryParam } from "@/shared/utils/queryParams"; import * as actions from "./actions"; import { InboxItems, InboxState } from "./types"; import { getFeedLayoutItemDateForSorting } from "./utils"; type Action = ActionType; -const initialInboxItems: InboxItems = { +export const INITIAL_INBOX_ITEMS: InboxItems = { data: null, loading: false, hasMore: false, firstDocTimestamp: null, lastDocTimestamp: null, batchNumber: 0, + unread: getQueryParam(QueryParamKey.Unread) === "true", }; -const initialState: InboxState = { - items: { ...initialInboxItems }, +export const INITIAL_INBOX_STATE: InboxState = { + items: { ...INITIAL_INBOX_ITEMS }, sharedFeedItemId: null, sharedItem: null, chatChannelItems: [], @@ -410,8 +412,8 @@ const updateChatChannelItem = ( updateChatChannelItemInSharedInboxItem(state, payload); }; -export const reducer = createReducer(initialState) - .handleAction(actions.resetInbox, () => ({ ...initialState })) +export const reducer = createReducer(INITIAL_INBOX_STATE) + .handleAction(actions.resetInbox, () => ({ ...INITIAL_INBOX_STATE })) .handleAction(actions.getInboxItems.request, (state) => produce(state, (nextState) => { nextState.items = { @@ -542,7 +544,7 @@ export const reducer = createReducer(initialState) ) .handleAction(actions.resetInboxItems, (state) => produce(state, (nextState) => { - nextState.items = { ...initialInboxItems }; + nextState.items = { ...INITIAL_INBOX_ITEMS }; nextState.sharedFeedItemId = null; nextState.sharedItem = null; nextState.chatChannelItems = []; diff --git a/src/store/states/inbox/saga/getInboxItems.ts b/src/store/states/inbox/saga/getInboxItems.ts index 28cfb53a54..5d7c94b8b1 100644 --- a/src/store/states/inbox/saga/getInboxItems.ts +++ b/src/store/states/inbox/saga/getInboxItems.ts @@ -29,7 +29,7 @@ export function* getInboxItems( action: ReturnType, ) { const { - payload: { limit, unread }, + payload: { limit, unread = false }, } = action; try { @@ -72,6 +72,7 @@ export function* getInboxItems( firstDocTimestamp: isFirstRequest ? firstDocTimestamp : currentItems.firstDocTimestamp, + unread, }), ); } catch (error) { diff --git a/src/store/states/inbox/types.ts b/src/store/states/inbox/types.ts index 46e97b4137..303b0da8ff 100644 --- a/src/store/states/inbox/types.ts +++ b/src/store/states/inbox/types.ts @@ -11,6 +11,7 @@ export interface InboxItems { firstDocTimestamp: Timestamp | null; lastDocTimestamp: Timestamp | null; batchNumber: number; + unread: boolean; } export interface InboxState { diff --git a/src/store/transforms.ts b/src/store/transforms.ts index 11d3e618b8..dcfa4a9024 100644 --- a/src/store/transforms.ts +++ b/src/store/transforms.ts @@ -3,10 +3,22 @@ import { deserializeFeedLayoutItemWithFollowData } from "@/shared/interfaces"; import { convertObjectDatesToFirestoreTimestamps } from "@/shared/utils"; import { getFeedLayoutItemDateForSorting } from "@/store/states/inbox/utils"; import { CommonLayoutState } from "./states/commonLayout"; -import { InboxItems, InboxState } from "./states/inbox"; +import { + InboxItems, + InboxState, + INITIAL_INBOX_ITEMS, + INITIAL_INBOX_STATE, +} from "./states/inbox"; export const inboxTransform = createTransform( (inboundState: InboxState) => { + if (inboundState.items.unread) { + return { + ...inboundState, + items: { ...INITIAL_INBOX_ITEMS }, + }; + } + const data = inboundState.items.data && inboundState.items.data.slice(0, 30); @@ -26,22 +38,28 @@ export const inboxTransform = createTransform( }, }; }, - (outboundState: InboxState) => ({ - ...outboundState, - sharedItem: - outboundState.sharedItem && - deserializeFeedLayoutItemWithFollowData(outboundState.sharedItem), - chatChannelItems: [], - items: { - ...convertObjectDatesToFirestoreTimestamps( - outboundState.items, - ["firstDocTimestamp", "lastDocTimestamp"], - ), - data: - outboundState.items.data && - outboundState.items.data.map(deserializeFeedLayoutItemWithFollowData), - }, - }), + (outboundState: InboxState) => { + if (outboundState.items.unread !== INITIAL_INBOX_ITEMS.unread) { + return { ...INITIAL_INBOX_STATE }; + } + + return { + ...outboundState, + sharedItem: + outboundState.sharedItem && + deserializeFeedLayoutItemWithFollowData(outboundState.sharedItem), + chatChannelItems: [], + items: { + ...convertObjectDatesToFirestoreTimestamps( + outboundState.items, + ["firstDocTimestamp", "lastDocTimestamp"], + ), + data: + outboundState.items.data && + outboundState.items.data.map(deserializeFeedLayoutItemWithFollowData), + }, + }; + }, { whitelist: ["inbox"] }, );