mattermost-mobile/app/actions/views/post.js
2020-03-30 15:02:35 -03:00

337 lines
No EOL
10 KiB
JavaScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {batchActions} from 'redux-batched-actions';
import {UserTypes} from 'mattermost-redux/action_types';
import {
doPostAction,
getNeededAtMentionedUsernames,
receivedNewPost,
receivedPosts,
receivedPostsBefore,
receivedPostsInChannel,
receivedPostsSince,
receivedPostsInThread,
} from 'mattermost-redux/actions/posts';
import {Client4} from 'mattermost-redux/client';
import {Posts} from 'mattermost-redux/constants';
import {removeUserFromList} from 'mattermost-redux/utils/user_utils';
import {ViewTypes} from 'app/constants';
import {generateId} from 'app/utils/file';
import {getEmojisInPosts} from './emoji';
export function sendAddToChannelEphemeralPost(user, addedUsername, message, channelId, postRootId = '') {
return async (dispatch) => {
const timestamp = Date.now();
const post = {
id: generateId(),
user_id: user.id,
channel_id: channelId,
message,
type: Posts.POST_TYPES.EPHEMERAL_ADD_TO_CHANNEL,
create_at: timestamp,
update_at: timestamp,
root_id: postRootId,
parent_id: postRootId,
props: {
username: user.username,
addedUsername,
},
};
dispatch(receivedNewPost(post));
};
}
export function setAutocompleteSelector(dataSource, onSelect, options) {
return {
type: ViewTypes.SELECTED_ACTION_MENU,
data: {
dataSource,
onSelect,
options,
},
};
}
export function selectAttachmentMenuAction(postId, actionId, text, value) {
return (dispatch) => {
dispatch({
type: ViewTypes.SUBMIT_ATTACHMENT_MENU_ACTION,
postId,
data: {
[actionId]: {
text,
value,
},
},
});
dispatch(doPostAction(postId, actionId, value));
};
}
export function getPosts(channelId, page = 0, perPage = Posts.POST_CHUNK_SIZE) {
return async (dispatch, getState) => {
try {
const state = getState();
const {postsInChannel} = state.entities.posts;
const postForChannel = postsInChannel[channelId];
const data = await Client4.getPosts(channelId, page, perPage);
const posts = Object.values(data.posts);
const actions = [];
if (posts?.length) {
actions.push(receivedPosts(data));
const additional = await dispatch(getPostsAdditionalDataBatch(posts));
if (additional.length) {
actions.push(...additional);
}
}
if (posts?.length || !postForChannel) {
actions.push(receivedPostsInChannel(data, channelId, page === 0, data.prev_post_id === ''));
}
dispatch(batchActions(actions));
return {data};
} catch (error) {
return {error};
}
};
}
export function getPostsSince(channelId, since) {
return async (dispatch) => {
try {
const data = await Client4.getPostsSince(channelId, since);
const posts = Object.values(data.posts);
if (posts?.length) {
const actions = [
receivedPosts(data),
receivedPostsSince(data, channelId),
];
const additional = await dispatch(getPostsAdditionalDataBatch(posts));
if (additional.length) {
actions.push(...additional);
}
dispatch(batchActions(actions));
}
return {data};
} catch (error) {
return {error};
}
};
}
export function getPostsBefore(channelId, postId, page = 0, perPage = Posts.POST_CHUNK_SIZE) {
return async (dispatch) => {
try {
const data = await Client4.getPostsBefore(channelId, postId, page, perPage);
const posts = Object.values(data.posts);
if (posts?.length) {
const actions = [
receivedPosts(data),
receivedPostsBefore(data, channelId, postId, data.prev_post_id === ''),
];
const additional = await dispatch(getPostsAdditionalDataBatch(posts));
if (additional.length) {
actions.push(...additional);
}
dispatch(batchActions(actions));
}
return {data};
} catch (error) {
return {error};
}
};
}
export function getPostThread(rootId) {
return async (dispatch) => {
try {
const data = await Client4.getPostThread(rootId);
const posts = Object.values(data.posts);
if (posts.length) {
const actions = [
receivedPosts(data),
receivedPostsInThread(data, rootId),
];
const additional = await dispatch(getPostsAdditionalDataBatch(posts));
if (additional.length) {
actions.push(...additional);
}
dispatch(batchActions(actions));
}
return {data};
} catch (error) {
return {error};
}
};
}
export function getPostsAround(channelId, postId, perPage = Posts.POST_CHUNK_SIZE / 2) {
return async (dispatch) => {
try {
const [before, thread, after] = await Promise.all([
Client4.getPostsBefore(channelId, postId, 0, perPage),
Client4.getPostThread(postId),
Client4.getPostsAfter(channelId, postId, 0, perPage),
]);
const data = {
posts: {
...after.posts,
...thread.posts,
...before.posts,
},
order: [ // Remember that the order is newest posts first
...after.order,
postId,
...before.order,
],
next_post_id: after.next_post_id,
prev_post_id: before.prev_post_id,
};
const posts = Object.values(data.posts);
if (posts?.length) {
const actions = [
receivedPosts(data),
receivedPostsInChannel(data, channelId, after.next_post_id === '', before.prev_post_id === ''),
];
const additional = await dispatch(getPostsAdditionalDataBatch(posts));
if (additional.length) {
actions.push(...additional);
}
dispatch(batchActions(actions));
}
return {data};
} catch (error) {
return {error};
}
};
}
function getPostsAdditionalDataBatch(posts = []) {
return async (dispatch, getState) => {
const actions = [];
if (!posts.length) {
return actions;
}
// Custom Emojis used in the posts
// Do not wait for this as they need to be loaded one by one
dispatch(getEmojisInPosts(posts));
try {
const state = getState();
const promises = [];
const promiseTrace = [];
const extra = dispatch(profilesStatusesAndToLoadFromPosts(posts));
if (extra?.userIds.length) {
promises.push(Client4.getProfilesByIds(extra.userIds));
promiseTrace.push('ids');
}
if (extra?.usernames.length) {
promises.push(Client4.getProfilesByUsernames(extra.usernames));
promiseTrace.push('usernames');
}
if (extra?.statuses.length) {
promises.push(Client4.getStatusesByIds(extra.statuses));
promiseTrace.push('statuses');
}
if (promises.length) {
const result = await Promise.all(promises);
result.forEach((p, index) => {
if (p.length) {
const type = promiseTrace[index];
switch (type) {
case 'statuses':
actions.push({
type: UserTypes.RECEIVED_STATUSES,
data: p,
});
break;
default: {
const {currentUserId} = state.entities.users;
removeUserFromList(currentUserId, p);
actions.push({
type: UserTypes.RECEIVED_PROFILES_LIST,
data: p,
});
break;
}
}
}
});
}
} catch (error) {
// do nothing
}
return actions;
};
}
function profilesStatusesAndToLoadFromPosts(posts = []) {
return (dispatch, getState) => {
const state = getState();
const {currentUserId, profiles, statuses} = state.entities.users;
// Profiles of users mentioned in the posts
const usernamesToLoad = getNeededAtMentionedUsernames(state, posts);
// Statuses and profiles of the users who made the posts
const userIdsToLoad = new Set();
const statusesToLoad = new Set();
posts.forEach((post) => {
const userId = post.user_id;
if (!statuses[userId]) {
statusesToLoad.add(userId);
}
if (userId === currentUserId) {
return;
}
if (!profiles[userId]) {
userIdsToLoad.add(userId);
}
});
return {
usernames: Array.from(usernamesToLoad),
userIds: Array.from(userIdsToLoad),
statuses: Array.from(statusesToLoad),
};
};
}