Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
567 lines
19 KiB
TypeScript
567 lines
19 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import type {AnyAction} from 'redux';
|
|
import {batchActions} from 'redux-batched-actions';
|
|
|
|
import type {UserAutocomplete} from '@mattermost/types/autocomplete';
|
|
import type {Channel} from '@mattermost/types/channels';
|
|
|
|
import {TeamTypes} from 'mattermost-redux/action_types';
|
|
import {
|
|
leaveChannel as leaveChannelRedux,
|
|
joinChannel,
|
|
markChannelAsRead,
|
|
unfavoriteChannel,
|
|
deleteChannel as deleteChannelRedux,
|
|
getChannel as loadChannel,
|
|
} from 'mattermost-redux/actions/channels';
|
|
import * as PostActions from 'mattermost-redux/actions/posts';
|
|
import {selectTeam} from 'mattermost-redux/actions/teams';
|
|
import {autocompleteUsers} from 'mattermost-redux/actions/users';
|
|
import {Posts, RequestStatus} from 'mattermost-redux/constants';
|
|
import {
|
|
getChannel,
|
|
getChannelsNameMapInCurrentTeam,
|
|
getCurrentChannel,
|
|
getRedirectChannelNameForTeam,
|
|
getMyChannels,
|
|
getMyChannelMemberships,
|
|
getAllDirectChannelsNameMapInCurrentTeam,
|
|
isFavoriteChannel,
|
|
isManuallyUnread,
|
|
getCurrentChannelId,
|
|
} from 'mattermost-redux/selectors/entities/channels';
|
|
import {getMostRecentPostIdInChannel, getPost} from 'mattermost-redux/selectors/entities/posts';
|
|
import {
|
|
getCurrentRelativeTeamUrl,
|
|
getCurrentTeam,
|
|
getCurrentTeamId,
|
|
getRelativeTeamUrl,
|
|
getTeamsList,
|
|
} from 'mattermost-redux/selectors/entities/teams';
|
|
import {getCurrentUserId, getUserByUsername} from 'mattermost-redux/selectors/entities/users';
|
|
import {makeAddLastViewAtToProfiles} from 'mattermost-redux/selectors/entities/utils';
|
|
import {getChannelByName} from 'mattermost-redux/utils/channel_utils';
|
|
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
|
|
|
import {openDirectChannelToUserId} from 'actions/channel_actions';
|
|
import {loadCustomStatusEmojisForPostList} from 'actions/emoji_actions';
|
|
import {closeRightHandSide} from 'actions/views/rhs';
|
|
import {markThreadAsRead} from 'actions/views/threads';
|
|
import {getLastViewedChannelName} from 'selectors/local_storage';
|
|
import {getSelectedPost, getSelectedPostId} from 'selectors/rhs';
|
|
import {getLastPostsApiTimeForChannel} from 'selectors/views/channel';
|
|
import {getSelectedThreadIdInCurrentTeam} from 'selectors/views/threads';
|
|
import {getSocketStatus} from 'selectors/views/websocket';
|
|
import LocalStorageStore from 'stores/local_storage_store';
|
|
|
|
import {getHistory} from 'utils/browser_history';
|
|
import {isArchivedChannel} from 'utils/channel_utils';
|
|
import {Constants, ActionTypes, EventTypes, PostRequestTypes} from 'utils/constants';
|
|
import {stopTryNotificationRing} from 'utils/notification_sounds';
|
|
import {isChannelPopoutWindow} from 'utils/popouts/popout_windows';
|
|
|
|
import type {ActionFuncAsync, ThunkActionFunc} from 'types/store';
|
|
|
|
export function goToLastViewedChannel(): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
const state = getState();
|
|
const currentChannel = getCurrentChannel(state);
|
|
const channelsInTeam = getChannelsNameMapInCurrentTeam(state);
|
|
const directChannel = getAllDirectChannelsNameMapInCurrentTeam(state);
|
|
const channels = Object.assign({}, channelsInTeam, directChannel);
|
|
|
|
let channelToSwitchTo = getChannelByName(channels, getLastViewedChannelName(state));
|
|
|
|
if (currentChannel?.id === channelToSwitchTo!.id) {
|
|
channelToSwitchTo = getChannelByName(channels, getRedirectChannelNameForTeam(state, getCurrentTeamId(state)));
|
|
}
|
|
|
|
const result = await dispatch(switchToChannel(channelToSwitchTo!));
|
|
if (isChannelPopoutWindow()) {
|
|
window.close();
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
|
|
export function switchToChannelById(channelId: string): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
const state = getState();
|
|
const channel = getChannel(state, channelId);
|
|
if (channel) {
|
|
return dispatch(switchToChannel(channel));
|
|
}
|
|
return {data: true};
|
|
};
|
|
}
|
|
|
|
export function loadIfNecessaryAndSwitchToChannelById(channelId: string): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
const state = getState();
|
|
let channel = getChannel(state, channelId);
|
|
if (!channel) {
|
|
const res = await dispatch(loadChannel(channelId));
|
|
channel = res.data!;
|
|
}
|
|
return dispatch(switchToChannel(channel));
|
|
};
|
|
}
|
|
|
|
export function switchToChannel(channel: Channel & {userId?: string}): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
const state = getState();
|
|
const selectedTeamId = channel.team_id;
|
|
const teamUrl = selectedTeamId ? getRelativeTeamUrl(state, selectedTeamId) : getCurrentRelativeTeamUrl(state);
|
|
|
|
if (channel.userId) {
|
|
const username = channel.userId ? channel.name : channel.display_name;
|
|
const user = getUserByUsername(state, username);
|
|
if (!user) {
|
|
return {error: true};
|
|
}
|
|
|
|
const direct = await dispatch(openDirectChannelToUserId(user.id));
|
|
if (direct.error) {
|
|
return {error: true};
|
|
}
|
|
getHistory().push(`${teamUrl}/messages/@${channel.name}`);
|
|
} else if (channel.type === Constants.GM_CHANNEL) {
|
|
const gmChannel = getChannel(state, channel.id);
|
|
if (!gmChannel?.name) {
|
|
return {error: true};
|
|
}
|
|
getHistory().push(`${teamUrl}/channels/${gmChannel.name}`);
|
|
} else if (channel.type === Constants.THREADS) {
|
|
getHistory().push(`${teamUrl}/${channel.name}`);
|
|
} else {
|
|
getHistory().push(`${teamUrl}/channels/${channel.name}`);
|
|
}
|
|
|
|
return {data: true};
|
|
};
|
|
}
|
|
|
|
export function joinChannelById(channelId: string): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
const state = getState();
|
|
const currentUserId = getCurrentUserId(state);
|
|
const currentTeamId = getCurrentTeamId(state);
|
|
|
|
return dispatch(joinChannel(currentUserId, currentTeamId, channelId));
|
|
};
|
|
}
|
|
|
|
export function leaveChannel(channelId: string): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
let state = getState();
|
|
const currentUserId = getCurrentUserId(state);
|
|
const currentTeam = getCurrentTeam(state);
|
|
if (!currentTeam) {
|
|
return {data: false};
|
|
}
|
|
const channel = getChannel(state, channelId);
|
|
const currentChannelId = getCurrentChannelId(state);
|
|
|
|
if (isFavoriteChannel(state, channelId)) {
|
|
dispatch(unfavoriteChannel(channelId));
|
|
}
|
|
|
|
const teamUrl = getCurrentRelativeTeamUrl(state);
|
|
|
|
if (!isArchivedChannel(channel)) {
|
|
LocalStorageStore.removePreviousChannel(currentUserId, currentTeam.id, state);
|
|
}
|
|
const {error} = await dispatch(leaveChannelRedux(channelId));
|
|
if (error) {
|
|
return {error};
|
|
}
|
|
state = getState();
|
|
|
|
const prevChannelName = LocalStorageStore.getPreviousChannelName(currentUserId, currentTeam.id, state);
|
|
const channelsInTeam = getChannelsNameMapInCurrentTeam(state);
|
|
const prevChannel = getChannelByName(channelsInTeam, prevChannelName);
|
|
if (!prevChannel || !getMyChannelMemberships(state)[prevChannel.id]) {
|
|
LocalStorageStore.removePreviousChannel(currentUserId, currentTeam.id, state);
|
|
}
|
|
const selectedPost = getSelectedPost(state);
|
|
const selectedPostId = getSelectedPostId(state);
|
|
if (selectedPostId && selectedPost.exists === false) {
|
|
dispatch(closeRightHandSide());
|
|
}
|
|
|
|
if (getMyChannels(getState()).filter((c) => c.type === Constants.OPEN_CHANNEL || c.type === Constants.PRIVATE_CHANNEL).length === 0) {
|
|
LocalStorageStore.removePreviousChannel(currentUserId, currentTeam.id, state);
|
|
dispatch(selectTeam(''));
|
|
dispatch({type: TeamTypes.LEAVE_TEAM, data: currentTeam});
|
|
getHistory().push('/');
|
|
if (isChannelPopoutWindow()) {
|
|
window.close();
|
|
}
|
|
} else if (channelId === currentChannelId) {
|
|
getHistory().push(teamUrl);
|
|
if (isChannelPopoutWindow()) {
|
|
window.close();
|
|
}
|
|
}
|
|
|
|
return {
|
|
data: true,
|
|
};
|
|
};
|
|
}
|
|
|
|
export function leaveDirectChannel(channelName: string): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
const state = getState();
|
|
const currentUserId = getCurrentUserId(state);
|
|
const teams = getTeamsList(state); // dms are shared across teams but on local storage are set linked to one, we need to look into all.
|
|
teams.forEach((currentTeam) => {
|
|
const previousChannel = LocalStorageStore.getPreviousChannelName(currentUserId, currentTeam.id, state);
|
|
const penultimateChannel = LocalStorageStore.getPenultimateChannelName(currentUserId, currentTeam.id, state);
|
|
if (channelName === previousChannel) {
|
|
LocalStorageStore.removePreviousChannel(currentUserId, currentTeam.id, state);
|
|
} else if (channelName === penultimateChannel) {
|
|
LocalStorageStore.removePenultimateChannelName(currentUserId, currentTeam.id);
|
|
}
|
|
});
|
|
return {
|
|
data: true,
|
|
};
|
|
};
|
|
}
|
|
|
|
export function autocompleteUsersInChannel(prefix: string, channelId: string): ActionFuncAsync<UserAutocomplete> {
|
|
const addLastViewAtToProfiles = makeAddLastViewAtToProfiles();
|
|
return async (dispatch, getState) => {
|
|
const state = getState();
|
|
const currentTeamId = getCurrentTeamId(state);
|
|
|
|
const response = await dispatch(autocompleteUsers(prefix, currentTeamId, channelId));
|
|
|
|
const data = response.data;
|
|
if (data) {
|
|
return {
|
|
...response,
|
|
data: {
|
|
...data,
|
|
users: addLastViewAtToProfiles(state, data.users || []),
|
|
out_of_channel: addLastViewAtToProfiles(state, data.out_of_channel || []),
|
|
},
|
|
};
|
|
}
|
|
|
|
return response;
|
|
};
|
|
}
|
|
|
|
export function loadUnreads(channelId: string, prefetch = false): ActionFuncAsync<{atLatestMessage: boolean; atOldestMessage: boolean}> {
|
|
return async (dispatch) => {
|
|
const time = Date.now();
|
|
if (prefetch) {
|
|
dispatch({
|
|
type: ActionTypes.PREFETCH_POSTS_FOR_CHANNEL,
|
|
channelId,
|
|
status: RequestStatus.STARTED,
|
|
});
|
|
}
|
|
const {data, error} = await dispatch(PostActions.getPostsUnread(channelId));
|
|
if (error) {
|
|
if (prefetch) {
|
|
dispatch({
|
|
type: ActionTypes.PREFETCH_POSTS_FOR_CHANNEL,
|
|
channelId,
|
|
status: RequestStatus.FAILURE,
|
|
});
|
|
}
|
|
return {
|
|
error,
|
|
atLatestMessage: false,
|
|
atOldestmessage: false,
|
|
};
|
|
}
|
|
dispatch(loadCustomStatusEmojisForPostList(data!.posts));
|
|
|
|
const actions = [];
|
|
actions.push({
|
|
type: ActionTypes.INCREASE_POST_VISIBILITY,
|
|
data: channelId,
|
|
amount: data!.order.length,
|
|
});
|
|
|
|
if (prefetch) {
|
|
actions.push({
|
|
type: ActionTypes.PREFETCH_POSTS_FOR_CHANNEL,
|
|
channelId,
|
|
status: RequestStatus.SUCCESS,
|
|
});
|
|
}
|
|
|
|
if (data!.next_post_id === '') {
|
|
actions.push({
|
|
type: ActionTypes.RECEIVED_POSTS_FOR_CHANNEL_AT_TIME,
|
|
channelId,
|
|
time,
|
|
});
|
|
}
|
|
|
|
dispatch(batchActions(actions));
|
|
return {
|
|
atLatestMessage: data!.next_post_id === '',
|
|
atOldestmessage: data!.prev_post_id === '',
|
|
};
|
|
};
|
|
}
|
|
|
|
export function loadPostsAround(channelId: string, focusedPostId: string): ActionFuncAsync {
|
|
return async (dispatch) => {
|
|
const {data, error} = await dispatch(PostActions.getPostsAround(channelId, focusedPostId, Posts.POST_CHUNK_SIZE / 2));
|
|
if (error) {
|
|
return {
|
|
error,
|
|
atLatestMessage: false,
|
|
atOldestmessage: false,
|
|
};
|
|
}
|
|
|
|
dispatch({
|
|
type: ActionTypes.INCREASE_POST_VISIBILITY,
|
|
data: channelId,
|
|
amount: data!.order.length,
|
|
});
|
|
return {
|
|
atLatestMessage: data!.next_post_id === '',
|
|
atOldestmessage: data!.prev_post_id === '',
|
|
};
|
|
};
|
|
}
|
|
|
|
export function loadLatestPosts(channelId: string): ActionFuncAsync {
|
|
return async (dispatch) => {
|
|
const time = Date.now();
|
|
const {data, error} = await dispatch(PostActions.getPosts(channelId, 0, Posts.POST_CHUNK_SIZE / 2));
|
|
|
|
if (error) {
|
|
return {
|
|
error,
|
|
atLatestMessage: false,
|
|
atOldestmessage: false,
|
|
};
|
|
}
|
|
|
|
dispatch({
|
|
type: ActionTypes.RECEIVED_POSTS_FOR_CHANNEL_AT_TIME,
|
|
channelId,
|
|
time,
|
|
});
|
|
|
|
return {
|
|
data,
|
|
atLatestMessage: data!.next_post_id === '',
|
|
atOldestmessage: data!.prev_post_id === '',
|
|
};
|
|
};
|
|
}
|
|
|
|
export interface LoadPostsReturnValue {
|
|
error?: string;
|
|
moreToLoad: boolean;
|
|
}
|
|
|
|
export type CanLoadMorePosts = typeof PostRequestTypes[keyof typeof PostRequestTypes] | undefined;
|
|
|
|
export interface LoadPostsParameters {
|
|
channelId: string;
|
|
postId: string;
|
|
type: CanLoadMorePosts;
|
|
perPage: number;
|
|
}
|
|
|
|
export function loadPosts({
|
|
channelId,
|
|
postId,
|
|
type,
|
|
perPage,
|
|
}: LoadPostsParameters): ThunkActionFunc<Promise<LoadPostsReturnValue>> {
|
|
//type here can be BEFORE_ID or AFTER_ID
|
|
return async (dispatch) => {
|
|
dispatch({
|
|
type: ActionTypes.LOADING_POSTS,
|
|
data: true,
|
|
channelId,
|
|
});
|
|
|
|
const page = 0;
|
|
let result;
|
|
if (type === PostRequestTypes.BEFORE_ID) {
|
|
result = await dispatch(PostActions.getPostsBefore(channelId, postId, page, perPage));
|
|
} else {
|
|
result = await dispatch(PostActions.getPostsAfter(channelId, postId, page, perPage));
|
|
}
|
|
|
|
const {data} = result;
|
|
|
|
const actions: AnyAction[] = [{
|
|
type: ActionTypes.LOADING_POSTS,
|
|
data: false,
|
|
channelId,
|
|
}];
|
|
|
|
if (result.error) {
|
|
return {
|
|
error: result.error,
|
|
moreToLoad: true,
|
|
};
|
|
}
|
|
|
|
dispatch(loadCustomStatusEmojisForPostList(data!.posts));
|
|
actions.push({
|
|
type: ActionTypes.INCREASE_POST_VISIBILITY,
|
|
data: channelId,
|
|
amount: data!.order.length,
|
|
});
|
|
|
|
dispatch(batchActions(actions));
|
|
|
|
return {
|
|
moreToLoad: type === PostRequestTypes.BEFORE_ID ? data!.prev_post_id !== '' : data!.next_post_id !== '',
|
|
};
|
|
};
|
|
}
|
|
|
|
export function syncPostsInChannel(channelId: string, since: number, prefetch = false): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
const time = Date.now();
|
|
const state = getState();
|
|
const socketStatus = getSocketStatus(state);
|
|
let sinceTimeToGetPosts = since;
|
|
const lastPostsApiCallForChannel = getLastPostsApiTimeForChannel(state, channelId);
|
|
const actions = [];
|
|
|
|
if (lastPostsApiCallForChannel && lastPostsApiCallForChannel < socketStatus.lastDisconnectAt) {
|
|
sinceTimeToGetPosts = lastPostsApiCallForChannel;
|
|
}
|
|
|
|
if (prefetch) {
|
|
dispatch({
|
|
type: ActionTypes.PREFETCH_POSTS_FOR_CHANNEL,
|
|
channelId,
|
|
status: RequestStatus.STARTED,
|
|
});
|
|
}
|
|
|
|
const {data, error} = await dispatch(PostActions.getPostsSince(channelId, sinceTimeToGetPosts));
|
|
if (data) {
|
|
actions.push({
|
|
type: ActionTypes.RECEIVED_POSTS_FOR_CHANNEL_AT_TIME,
|
|
channelId,
|
|
time,
|
|
});
|
|
}
|
|
|
|
if (prefetch) {
|
|
if (error) {
|
|
actions.push({
|
|
type: ActionTypes.PREFETCH_POSTS_FOR_CHANNEL,
|
|
channelId,
|
|
status: RequestStatus.FAILURE,
|
|
});
|
|
} else {
|
|
actions.push({
|
|
type: ActionTypes.PREFETCH_POSTS_FOR_CHANNEL,
|
|
channelId,
|
|
status: RequestStatus.SUCCESS,
|
|
});
|
|
}
|
|
}
|
|
|
|
dispatch(batchActions(actions));
|
|
|
|
return {data, error};
|
|
};
|
|
}
|
|
|
|
export function prefetchChannelPosts(channelId: string, jitter?: number): ActionFuncAsync {
|
|
return async (dispatch, getState) => {
|
|
const state = getState();
|
|
const recentPostIdInChannel = getMostRecentPostIdInChannel(state, channelId);
|
|
|
|
if (!state.entities.posts.postsInChannel[channelId] || !recentPostIdInChannel) {
|
|
if (jitter) {
|
|
await new Promise((resolve) => setTimeout(resolve, jitter));
|
|
}
|
|
return dispatch(loadUnreads(channelId, true));
|
|
}
|
|
|
|
const recentPost = getPost(state, recentPostIdInChannel);
|
|
return dispatch(syncPostsInChannel(channelId, recentPost.create_at, true));
|
|
};
|
|
}
|
|
|
|
export function scrollPostListToBottom() {
|
|
return () => {
|
|
EventEmitter.emit(EventTypes.POST_LIST_SCROLL_TO_BOTTOM);
|
|
};
|
|
}
|
|
|
|
export function markAsReadOnFocus(): ThunkActionFunc<void> {
|
|
return (dispatch, getState) => {
|
|
const state = getState();
|
|
const currentChannelId = getCurrentChannelId(state);
|
|
const selectedThreadId = getSelectedThreadIdInCurrentTeam(state);
|
|
const selectedPostId = getSelectedPostId(state);
|
|
|
|
if (!isManuallyUnread(getState(), currentChannelId)) {
|
|
dispatch(markChannelAsRead(currentChannelId));
|
|
}
|
|
|
|
if (selectedThreadId) {
|
|
dispatch(markThreadAsRead(selectedThreadId));
|
|
}
|
|
|
|
if (currentChannelId && selectedPostId) {
|
|
dispatch(markThreadAsRead(selectedPostId));
|
|
}
|
|
};
|
|
}
|
|
|
|
export function updateToastStatus(status: boolean) {
|
|
return {
|
|
type: ActionTypes.UPDATE_TOAST_STATUS,
|
|
data: status,
|
|
};
|
|
}
|
|
|
|
export function deleteChannel(channelId: string): ActionFuncAsync<boolean> {
|
|
return async (dispatch, getState) => {
|
|
// Get state before deletion
|
|
const state = getState();
|
|
const channel = getChannel(state, channelId);
|
|
|
|
// Validate channel ID
|
|
if (!channel || channel.id.length !== Constants.CHANNEL_ID_LENGTH) {
|
|
return {data: false};
|
|
}
|
|
|
|
// Call the delete channel action
|
|
const res = await dispatch(deleteChannelRedux(channelId));
|
|
if (res.error) {
|
|
return {data: false};
|
|
}
|
|
|
|
// Handle RHS state
|
|
const updatedState = getState();
|
|
const selectedPost = getSelectedPost(updatedState);
|
|
const selectedPostId = getSelectedPostId(updatedState);
|
|
if (selectedPostId && !selectedPost.exists) {
|
|
dispatch(closeRightHandSide());
|
|
}
|
|
|
|
// Stop notification sounds
|
|
stopTryNotificationRing();
|
|
|
|
return {data: true};
|
|
};
|
|
}
|