Skip to content

Commit 80401b9

Browse files
committed
unreadModel: Handle moving messages between topics/streams.
Fixes #4840.
1 parent e0da5ae commit 80401b9

File tree

2 files changed

+120
-1
lines changed

2 files changed

+120
-1
lines changed

src/unread/__tests__/unreadModel-test.js

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
/* @flow strict-local */
22
import Immutable from 'immutable';
33

4-
import { ACCOUNT_SWITCH, EVENT_UPDATE_MESSAGE_FLAGS } from '../../actionConstants';
4+
import {
5+
ACCOUNT_SWITCH,
6+
EVENT_UPDATE_MESSAGE_FLAGS,
7+
EVENT_UPDATE_MESSAGE,
8+
} from '../../actionConstants';
59
import { reducer } from '../unreadModel';
610
import { type UnreadState } from '../unreadModelTypes';
711
import * as eg from '../../__tests__/lib/exampleData';
@@ -63,6 +67,95 @@ describe('stream substate', () => {
6367
});
6468
});
6569

70+
describe('EVENT_UPDATE_MESSAGE', () => {
71+
const mkAction = args => {
72+
const {
73+
message_id,
74+
message_ids = [message_id],
75+
stream_id = 123,
76+
new_stream_id = undefined,
77+
orig_subject = 'foo',
78+
subject = 'foo',
79+
} = args;
80+
return {
81+
id: 1,
82+
type: EVENT_UPDATE_MESSAGE,
83+
edit_timestamp: 10000,
84+
message_id,
85+
message_ids,
86+
stream_id,
87+
new_stream_id,
88+
orig_content: '',
89+
orig_subject,
90+
orig_rendered_content: '',
91+
prev_rendered_content_version: 0,
92+
rendered_content: '',
93+
subject_links: [],
94+
subject,
95+
user_id: eg.selfUser.user_id,
96+
};
97+
};
98+
99+
const baseState = (() => {
100+
const streamAction = args => eg.mkActionEventNewMessage(eg.streamMessage(args));
101+
const r = (state, action) => reducer(state, action, eg.plusReduxState);
102+
let state = initialState;
103+
state = r(state, streamAction({ stream_id: 123, subject: 'foo', id: 1 }));
104+
state = r(state, streamAction({ stream_id: 123, subject: 'foo', id: 2 }));
105+
state = r(state, streamAction({ stream_id: 123, subject: 'foo', id: 3 }));
106+
state = r(state, streamAction({ stream_id: 123, subject: 'foo', id: 4 }));
107+
state = r(state, streamAction({ stream_id: 123, subject: 'foo', id: 5 }));
108+
state = r(state, streamAction({ stream_id: 456, subject: 'zzz', id: 6 }));
109+
state = r(state, streamAction({ stream_id: 456, subject: 'zzz', id: 7 }));
110+
return state;
111+
})();
112+
113+
test('if topic not updated, return original state', () => {
114+
const state = reducer(baseState, mkAction({ message_id: 5 }), eg.plusReduxState);
115+
expect(state.streams).toBe(baseState.streams);
116+
});
117+
118+
test('if topic updated, but no unreads, return original state', () => {
119+
const state = reducer(baseState, mkAction({ message_id: 100 }), eg.plusReduxState);
120+
expect(state.streams).toBe(baseState.streams);
121+
});
122+
123+
test('if topic updated, move unreads', () => {
124+
const state = reducer(
125+
baseState,
126+
mkAction({
127+
message_id: 3,
128+
message_ids: [3, 4, 5],
129+
orig_subject: 'foo',
130+
subject: 'bar',
131+
}),
132+
eg.plusReduxState,
133+
);
134+
// prettier-ignore
135+
expect(summary(state)).toEqual(Immutable.Map([
136+
[123, Immutable.Map([['foo', [1, 2]], ['bar', [3, 4, 5]]])],
137+
[456, Immutable.Map([['zzz', [6, 7]]])],
138+
]));
139+
});
140+
141+
test('if stream updated, move unreads', () => {
142+
const state = reducer(
143+
baseState,
144+
mkAction({
145+
message_id: 3,
146+
message_ids: [3, 4, 5],
147+
new_stream_id: 456,
148+
}),
149+
eg.plusReduxState,
150+
);
151+
// prettier-ignore
152+
expect(summary(state)).toEqual(Immutable.Map([
153+
[123, Immutable.Map([['foo', [1, 2]]])],
154+
[456, Immutable.Map([['zzz', [6, 7]], ['foo', [3, 4, 5]]])],
155+
]));
156+
});
157+
});
158+
66159
describe('EVENT_NEW_MESSAGE', () => {
67160
const action = eg.mkActionEventNewMessage;
68161

src/unread/unreadModel.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
ACCOUNT_SWITCH,
1919
EVENT_MESSAGE_DELETE,
2020
EVENT_NEW_MESSAGE,
21+
EVENT_UPDATE_MESSAGE,
2122
EVENT_UPDATE_MESSAGE_FLAGS,
2223
LOGOUT,
2324
MESSAGE_FETCH_COMPLETE,
@@ -200,6 +201,31 @@ function streamsReducer(
200201
return deleteMessages(state, action.messages);
201202
}
202203

204+
case EVENT_UPDATE_MESSAGE: {
205+
if (
206+
(action.orig_subject !== undefined && action.subject !== action.orig_subject)
207+
|| (action.new_stream_id !== undefined && action.new_stream_id !== action.stream_id)
208+
) {
209+
const moved_ids = new Set(action.message_ids);
210+
const updated_unreads = state
211+
.getIn([action.stream_id, action.orig_subject ?? action.subject], Immutable.List())
212+
.filter(id => moved_ids.has(id));
213+
214+
if (updated_unreads.size > 0) {
215+
return state
216+
.updateIn(
217+
[action.stream_id, action.orig_subject ?? action.subject],
218+
(messages = Immutable.List()) => messages.filter(id => !moved_ids.has(id)),
219+
)
220+
.updateIn(
221+
[action.new_stream_id ?? action.stream_id, action.subject],
222+
(messages = Immutable.List()) => messages.push(...updated_unreads),
223+
);
224+
}
225+
}
226+
return state;
227+
}
228+
203229
default:
204230
return state;
205231
}

0 commit comments

Comments
 (0)