From b23628a16e88c6ca9e2f996a871f6fb2c197d6be Mon Sep 17 00:00:00 2001 From: Boris Yankov Date: Fri, 6 Oct 2017 14:47:47 +0300 Subject: [PATCH] Do not show outbox if not caught up (#1262) --- src/caughtup/caughtUpReducers.js | 4 +-- src/caughtup/caughtUpSelectors.js | 4 +-- src/chat/__tests__/chatSelectors-test.js | 31 ++++++++++++++++++++++-- src/chat/chatReducers.js | 6 ++--- src/chat/chatSelectors.js | 25 +++++++++++++------ src/chat/fetchingReducers.js | 4 +-- src/drafts/draftsReducers.js | 3 ++- src/nullObjects.js | 2 ++ src/presence/presenceReducers.js | 3 ++- src/typing/typingReducers.js | 4 +-- 10 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/caughtup/caughtUpReducers.js b/src/caughtup/caughtUpReducers.js index c8e88f0738d..8653e27879e 100644 --- a/src/caughtup/caughtUpReducers.js +++ b/src/caughtup/caughtUpReducers.js @@ -7,9 +7,9 @@ import { ACCOUNT_SWITCH, MESSAGE_FETCH_COMPLETE, } from '../actionConstants'; -import { NULL_CAUGHTUP } from '../nullObjects'; +import { NULL_CAUGHTUP, NULL_OBJECT } from '../nullObjects'; -const initialState: CaughtUpState = {}; +const initialState: CaughtUpState = NULL_OBJECT; export default (state: CaughtUpState = initialState, action: Action) => { switch (action.type) { diff --git a/src/caughtup/caughtUpSelectors.js b/src/caughtup/caughtUpSelectors.js index 21cf622bccd..8c8a938c236 100644 --- a/src/caughtup/caughtUpSelectors.js +++ b/src/caughtup/caughtUpSelectors.js @@ -2,10 +2,10 @@ import { createSelector } from 'reselect'; import type { GlobalState } from '../types'; -import { NULL_CAUGHTUP } from '../nullObjects'; +import { NULL_CAUGHTUP, NULL_OBJECT } from '../nullObjects'; import { getActiveNarrowString } from '../directSelectors'; -export const getCaughtUp = (state: GlobalState): Object => state.caughtUp; +export const getCaughtUp = (state: GlobalState): Object => state.caughtUp || NULL_OBJECT; export const getCaughtUpForActiveNarrow = createSelector( getCaughtUp, diff --git a/src/chat/__tests__/chatSelectors-test.js b/src/chat/__tests__/chatSelectors-test.js index 90b0332b693..ce925c64ccb 100644 --- a/src/chat/__tests__/chatSelectors-test.js +++ b/src/chat/__tests__/chatSelectors-test.js @@ -25,7 +25,7 @@ describe('getMessagesInActiveNarrow', () => { expect(anchor).toBe(state.chat.messages['[]']); }); - test('combine messages & outbox in same narrow', () => { + test('combine messages and outbox in same narrow', () => { const state = deepFreeze({ chat: { narrow: homeNarrow, @@ -42,6 +42,9 @@ describe('getMessagesInActiveNarrow', () => { timestamp: 12, }, ], + caughtUp: { + [homeNarrowStr]: { older: false, newer: true }, + }, }); const anchor = getMessagesInActiveNarrow(state); @@ -60,7 +63,31 @@ describe('getMessagesInActiveNarrow', () => { expect(anchor).toEqual(expectedState); }); - test('do not combine messages & outbox in different narrow', () => { + test('do not combine messages and outbox if not caught up', () => { + const state = deepFreeze({ + chat: { + narrow: homeNarrow, + messages: { + [homeNarrowStr]: [{ id: 123 }], + }, + }, + outbox: [ + { + email: 'donald@zulip.com', + narrow: homeNarrow, + parsedContent: '

Hello

', + sender_full_name: 'donald', + timestamp: 12, + }, + ], + }); + + const anchor = getMessagesInActiveNarrow(state); + + expect(anchor).toBe(state.chat.messages[homeNarrowStr]); + }); + + test('do not combine messages and outbox in different narrow', () => { const state = deepFreeze({ chat: { narrow: privateNarrow('john@example.com'), diff --git a/src/chat/chatReducers.js b/src/chat/chatReducers.js index 8beb6fb16de..fe195695795 100644 --- a/src/chat/chatReducers.js +++ b/src/chat/chatReducers.js @@ -14,14 +14,14 @@ import { EVENT_REACTION_REMOVE, EVENT_UPDATE_MESSAGE, } from '../actionConstants'; -import { homeNarrow, isMessageInNarrow, getNarrowFromMessage } from '../utils/narrow'; +import { homeNarrow, isMessageInNarrow } from '../utils/narrow'; import chatUpdater from './chatUpdater'; import { getMessagesById } from '../selectors'; -import { NULL_ARRAY } from '../nullObjects'; +import { NULL_ARRAY, NULL_OBJECT } from '../nullObjects'; const initialState: ChatState = { narrow: homeNarrow, - messages: {}, + messages: NULL_OBJECT, }; export default (state: ChatState = initialState, action: Action) => { diff --git a/src/chat/chatSelectors.js b/src/chat/chatSelectors.js index b860ec7677d..f009cbd8a73 100644 --- a/src/chat/chatSelectors.js +++ b/src/chat/chatSelectors.js @@ -11,6 +11,7 @@ import { getStreams, getOutbox, } from '../directSelectors'; +import { getCaughtUpForActiveNarrow } from '../caughtup/caughtUpSelectors'; import { isAllPrivateNarrow, isPrivateOrGroupNarrow, @@ -27,16 +28,24 @@ const getMessagesFromChatState = state => export const outboxMessagesForCurrentNarrow = createSelector( getActiveNarrow, + getCaughtUpForActiveNarrow, getActiveNarrowString, getOutbox, - (narrow, activeNarrowString, outboxMessages) => - isHomeNarrow(narrow) - ? outboxMessages - : outboxMessages.filter(item => { - if (isAllPrivateNarrow(narrow) && isPrivateOrGroupNarrow(item.narrow)) return true; - if (isStreamNarrow(narrow) && item.narrow[0].operand === narrow[0].operand) return true; - return JSON.stringify(item.narrow) === activeNarrowString; - }), + (narrow, caughtUp, activeNarrowString, outboxMessages) => { + if (!caughtUp.newer) { + return []; + } + + if (isHomeNarrow(narrow)) { + return outboxMessages; + } + + return outboxMessages.filter(item => { + if (isAllPrivateNarrow(narrow) && isPrivateOrGroupNarrow(item.narrow)) return true; + if (isStreamNarrow(narrow) && item.narrow[0].operand === narrow[0].operand) return true; + return JSON.stringify(item.narrow) === activeNarrowString; + }); + }, ); export const getFetchedMessagesInActiveNarrow = createSelector( diff --git a/src/chat/fetchingReducers.js b/src/chat/fetchingReducers.js index 905b1741a7c..af1d584a6bf 100644 --- a/src/chat/fetchingReducers.js +++ b/src/chat/fetchingReducers.js @@ -9,9 +9,9 @@ import { MESSAGE_FETCH_START, MESSAGE_FETCH_COMPLETE, } from '../actionConstants'; -import { NULL_FETCHING } from '../nullObjects'; +import { NULL_FETCHING, NULL_OBJECT } from '../nullObjects'; -const initialState: FetchingState = {}; +const initialState: FetchingState = NULL_OBJECT; export default (state: FetchingState = initialState, action: Action) => { switch (action.type) { diff --git a/src/drafts/draftsReducers.js b/src/drafts/draftsReducers.js index f5b4f63c703..9ba29ed674c 100644 --- a/src/drafts/draftsReducers.js +++ b/src/drafts/draftsReducers.js @@ -1,8 +1,9 @@ /* @flow */ import type { DraftState, Action } from '../types'; import { DRAFT_ADD, DRAFT_REMOVE, LOGOUT } from '../actionConstants'; +import { NULL_OBJECT } from '../nullObjects'; -const initialState = {}; +const initialState = NULL_OBJECT; export default (state: DraftState = initialState, action: Action): DraftState => { switch (action.type) { diff --git a/src/nullObjects.js b/src/nullObjects.js index 87a3dd8848c..a7cadec9917 100644 --- a/src/nullObjects.js +++ b/src/nullObjects.js @@ -12,6 +12,8 @@ import type { export const nullFunction = () => {}; +export const NULL_OBJECT = Object.freeze({}); + export const NULL_ARRAY = Object.freeze([]); export const NULL_ACCOUNT: Account = { diff --git a/src/presence/presenceReducers.js b/src/presence/presenceReducers.js index 7fb91c015b2..9cd1de4c9c9 100644 --- a/src/presence/presenceReducers.js +++ b/src/presence/presenceReducers.js @@ -8,8 +8,9 @@ import { EVENT_PRESENCE, PRESENCE_RESPONSE, } from '../actionConstants'; +import { NULL_OBJECT } from '../nullObjects'; -const initialState: Object = {}; +const initialState: Object = NULL_OBJECT; export default (state: UsersState = initialState, action: Action): UsersState => { switch (action.type) { diff --git a/src/typing/typingReducers.js b/src/typing/typingReducers.js index 00053841f2e..a36c0086c30 100644 --- a/src/typing/typingReducers.js +++ b/src/typing/typingReducers.js @@ -2,9 +2,9 @@ import type { Action, TypingState } from '../types'; import { EVENT_TYPING_START, EVENT_TYPING_STOP } from '../actionConstants'; import { normalizeRecipientsSansMe } from '../utils/message'; -import { NULL_ARRAY } from '../nullObjects'; +import { NULL_ARRAY, NULL_OBJECT } from '../nullObjects'; -const initialState: TypingState = {}; +const initialState: TypingState = NULL_OBJECT; export default (state: TypingState = initialState, action: Action): TypingState => { switch (action.type) {