* Add linter rules for import order and type member delimiters * Remove unneeded group * Group all app/* imports before the internal imports * Move app/ imports before parent imports * Separate @node_modules imports into a different group * Substitute app paths by aliases * Fix @node_modules import order and add test related modules * Add aliases for types and test, and group import types
277 lines
8.8 KiB
TypeScript
277 lines
8.8 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {Client4} from '@client/rest';
|
|
import {ViewTypes} from '@constants';
|
|
import {ThreadTypes, PostTypes, UserTypes} from '@mm-redux/action_types';
|
|
import {getCurrentUserId} from '@mm-redux/selectors/entities/common';
|
|
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
|
|
import {getThread as getThreadSelector, getThreadTeamId} from '@mm-redux/selectors/entities/threads';
|
|
import {ActionResult, batchActions, DispatchFunc, GenericAction, GetStateFunc} from '@mm-redux/types/actions';
|
|
|
|
import {logError} from './errors';
|
|
import {forceLogoutIfNecessary} from './helpers';
|
|
import {getMissingProfilesByIds} from './users';
|
|
|
|
import type {Post} from '@mm-redux/types/posts';
|
|
import type {UserThread, UserThreadList} from '@mm-redux/types/threads';
|
|
|
|
export function getThreads(userId: string, teamId: string, before = '', after = '', perPage = ViewTypes.CRT_CHUNK_SIZE, deleted = false, unread = true, since = 0) {
|
|
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
|
let userThreadList: UserThreadList;
|
|
|
|
try {
|
|
userThreadList = await Client4.getUserThreads(userId, teamId, before, after, perPage, true, deleted, unread, since);
|
|
} catch (error) {
|
|
forceLogoutIfNecessary(error, dispatch, getState);
|
|
dispatch(logError(error));
|
|
return {error};
|
|
}
|
|
|
|
if (userThreadList) {
|
|
const data = {
|
|
threads: [] as UserThread[],
|
|
participants: [] as UserThread['participants'],
|
|
participantIds: [] as string[],
|
|
posts: [] as Post[],
|
|
};
|
|
|
|
userThreadList.threads?.forEach((thread) => {
|
|
// threads
|
|
data.threads.push({
|
|
...thread,
|
|
is_following: true,
|
|
});
|
|
|
|
// participants, participantIds
|
|
thread.participants?.forEach((participant) => {
|
|
data.participantIds.push(participant.id);
|
|
data.participants.push(participant);
|
|
});
|
|
|
|
// posts
|
|
data.posts.push({
|
|
...thread.post,
|
|
participants: thread.participants,
|
|
});
|
|
});
|
|
|
|
const getThreadsActions: Array<GenericAction> = [
|
|
{
|
|
type: ThreadTypes.RECEIVED_THREADS,
|
|
data: {
|
|
...userThreadList,
|
|
threads: data.threads,
|
|
team_id: teamId,
|
|
},
|
|
},
|
|
];
|
|
|
|
if (userThreadList.threads?.length) {
|
|
const flat = require('array.prototype.flat');
|
|
dispatch(
|
|
getMissingProfilesByIds(Array.from(
|
|
new Set(
|
|
flat(data.participantIds) as string[],
|
|
),
|
|
)),
|
|
);
|
|
getThreadsActions.push(
|
|
{
|
|
type: UserTypes.RECEIVED_PROFILES_LIST,
|
|
data: flat(data.participants),
|
|
},
|
|
{
|
|
type: PostTypes.RECEIVED_POSTS,
|
|
data: {posts: data.posts},
|
|
},
|
|
);
|
|
}
|
|
|
|
dispatch(batchActions(getThreadsActions));
|
|
}
|
|
|
|
return {data: userThreadList};
|
|
};
|
|
}
|
|
|
|
export function getThread(userId: string, teamId: string, threadId: string, extended = false) {
|
|
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
|
let thread;
|
|
try {
|
|
thread = await Client4.getUserThread(userId, teamId, threadId, extended);
|
|
} catch (error) {
|
|
forceLogoutIfNecessary(error, dispatch, getState);
|
|
dispatch(logError(error));
|
|
return {error};
|
|
}
|
|
|
|
if (thread) {
|
|
const {data} = dispatch(handleThreadArrived(thread, teamId)) as ActionResult;
|
|
thread = data;
|
|
}
|
|
|
|
return {data: thread};
|
|
};
|
|
}
|
|
|
|
export function handleThreadArrived(threadData: UserThread, teamId: string) {
|
|
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
|
const thread = {...threadData, is_following: true};
|
|
|
|
const state = getState();
|
|
const currentUserId = getCurrentUserId(state);
|
|
const currentTeamId = getCurrentTeamId(state);
|
|
|
|
dispatch(batchActions([
|
|
{
|
|
type: UserTypes.RECEIVED_PROFILES_LIST,
|
|
data: thread.participants?.filter((user) => user.id !== currentUserId),
|
|
},
|
|
{
|
|
type: PostTypes.RECEIVED_POSTS,
|
|
data: {posts: [{...thread.post, participants: thread.participants}]},
|
|
},
|
|
{
|
|
type: ThreadTypes.RECEIVED_THREAD,
|
|
data: {
|
|
thread,
|
|
team_id: teamId,
|
|
},
|
|
},
|
|
]));
|
|
|
|
const oldThreadData = getThreadSelector(state, threadData.id);
|
|
|
|
dispatch(handleReadChanged(
|
|
thread.id,
|
|
teamId || currentTeamId,
|
|
thread.post.channel_id,
|
|
{
|
|
lastViewedAt: thread.last_viewed_at,
|
|
prevUnreadMentions: oldThreadData?.unread_mentions ?? 0,
|
|
newUnreadMentions: thread.unread_mentions,
|
|
prevUnreadReplies: oldThreadData?.unread_replies ?? 0,
|
|
newUnreadReplies: thread.unread_replies,
|
|
},
|
|
));
|
|
|
|
return {data: thread};
|
|
};
|
|
}
|
|
|
|
export function handleAllMarkedRead(teamId: string) {
|
|
return (dispatch: DispatchFunc) => {
|
|
dispatch({
|
|
type: ThreadTypes.ALL_TEAM_THREADS_READ,
|
|
data: {
|
|
team_id: teamId,
|
|
},
|
|
});
|
|
return {data: true};
|
|
};
|
|
}
|
|
|
|
export function markAllThreadsInTeamRead(userId: string, teamId: string) {
|
|
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
|
try {
|
|
await Client4.updateThreadsReadForUser(userId, teamId);
|
|
} catch (error) {
|
|
forceLogoutIfNecessary(error, dispatch, getState);
|
|
dispatch(logError(error));
|
|
return {error};
|
|
}
|
|
|
|
dispatch(handleAllMarkedRead(teamId));
|
|
|
|
return {data: true};
|
|
};
|
|
}
|
|
|
|
export function updateThreadRead(userId: string, threadId: string, timestamp: number) {
|
|
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
|
const teamId = getThreadTeamId(getState(), threadId);
|
|
try {
|
|
await Client4.updateThreadReadForUser(userId, teamId, threadId, timestamp);
|
|
} catch (error) {
|
|
forceLogoutIfNecessary(error, dispatch, getState);
|
|
dispatch(logError(error));
|
|
return {error};
|
|
}
|
|
return {};
|
|
};
|
|
}
|
|
|
|
export function handleFollowChanged(threadId: string, teamId: string, following: boolean) {
|
|
return (dispatch: DispatchFunc) => {
|
|
dispatch({
|
|
type: ThreadTypes.FOLLOW_CHANGED_THREAD,
|
|
data: {
|
|
id: threadId,
|
|
team_id: teamId,
|
|
following,
|
|
},
|
|
});
|
|
return {data: true};
|
|
};
|
|
}
|
|
|
|
export function setThreadFollow(userId: string, threadId: string, newState: boolean) {
|
|
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
|
|
const teamId = getThreadTeamId(getState(), threadId);
|
|
try {
|
|
await Client4.updateThreadFollowForUser(userId, teamId, threadId, newState);
|
|
} catch (error) {
|
|
forceLogoutIfNecessary(error, dispatch, getState);
|
|
dispatch(logError(error));
|
|
return {error};
|
|
}
|
|
|
|
dispatch({
|
|
type: ThreadTypes.FOLLOW_CHANGED_THREAD,
|
|
data: {
|
|
id: threadId,
|
|
team_id: teamId,
|
|
following: newState,
|
|
},
|
|
});
|
|
|
|
return {data: true};
|
|
};
|
|
}
|
|
|
|
export function handleReadChanged(
|
|
threadId: string,
|
|
teamId: string,
|
|
channelId: string,
|
|
{
|
|
lastViewedAt,
|
|
prevUnreadMentions,
|
|
newUnreadMentions,
|
|
prevUnreadReplies,
|
|
newUnreadReplies,
|
|
}: {
|
|
lastViewedAt: number;
|
|
prevUnreadMentions: number;
|
|
newUnreadMentions: number;
|
|
prevUnreadReplies: number;
|
|
newUnreadReplies: number;
|
|
},
|
|
) {
|
|
return (dispatch: DispatchFunc) => {
|
|
dispatch({
|
|
type: ThreadTypes.READ_CHANGED_THREAD,
|
|
data: {
|
|
id: threadId,
|
|
teamId,
|
|
channelId,
|
|
lastViewedAt,
|
|
prevUnreadMentions,
|
|
newUnreadMentions,
|
|
prevUnreadReplies,
|
|
newUnreadReplies,
|
|
},
|
|
});
|
|
return {data: true};
|
|
};
|
|
}
|