mirror of
https://github.com/mattermost/mattermost.git
synced 2026-09-24 16:05:00 +08:00
feat: Migrate emoji_actions.js to TypeScript with full type support
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {AnyAction} from 'redux';
|
||||
import {ThunkAction} from 'redux-thunk';
|
||||
|
||||
import * as EmojiActions from 'mattermost-redux/actions/emojis';
|
||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||
import {Preferences as ReduxPreferences} from 'mattermost-redux/constants';
|
||||
import {getCustomEmojisByName as selectCustomEmojisByName, getCustomEmojisEnabled} from 'mattermost-redux/selectors/entities/emojis';
|
||||
import {get} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getEmojiName} from 'mattermost-redux/utils/emoji_utils';
|
||||
|
||||
import {getEmojiMap, getRecentEmojisData, getRecentEmojisNames, isCustomEmojiEnabled} from 'selectors/emojis';
|
||||
import {isCustomStatusEnabled, makeGetCustomStatus} from 'selectors/views/custom_status';
|
||||
import LocalStorageStore from 'stores/local_storage_store';
|
||||
|
||||
import Constants, {ActionTypes, Preferences} from 'utils/constants';
|
||||
import {EmojiIndicesByAlias} from 'utils/emoji';
|
||||
|
||||
import {GlobalState} from 'types/store';
|
||||
import {Post} from '@mattermost/types/posts';
|
||||
|
||||
interface RecentEmojiData {
|
||||
name: string;
|
||||
usageCount: number;
|
||||
}
|
||||
|
||||
type ThunkResult<R> = ThunkAction<R, GlobalState, undefined, AnyAction>;
|
||||
|
||||
export function loadRecentlyUsedCustomEmojis(): ThunkResult<{data: boolean}> {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
||||
if (!getCustomEmojisEnabled(state)) {
|
||||
return {data: true};
|
||||
}
|
||||
|
||||
const recentEmojiNames = getRecentEmojisNames(state);
|
||||
|
||||
return dispatch(EmojiActions.getCustomEmojisByName(recentEmojiNames));
|
||||
};
|
||||
}
|
||||
|
||||
export function incrementEmojiPickerPage(): ThunkResult<{data: boolean}> {
|
||||
return async (dispatch) => {
|
||||
dispatch({
|
||||
type: ActionTypes.INCREMENT_EMOJI_PICKER_PAGE,
|
||||
});
|
||||
|
||||
return {data: true};
|
||||
};
|
||||
}
|
||||
|
||||
export function setUserSkinTone(skin: string): ThunkResult<void> {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
const skinTonePreference = [{
|
||||
user_id: currentUserId,
|
||||
name: Preferences.EMOJI_SKINTONE,
|
||||
category: Preferences.CATEGORY_EMOJI,
|
||||
value: skin,
|
||||
}];
|
||||
dispatch(savePreferences(currentUserId, skinTonePreference));
|
||||
};
|
||||
}
|
||||
|
||||
export function addRecentEmoji(alias: string): ThunkResult<{data: boolean}> {
|
||||
return addRecentEmojis([alias]);
|
||||
}
|
||||
|
||||
export const MAXIMUM_RECENT_EMOJI = 27;
|
||||
|
||||
export function addRecentEmojis(aliases: string[]): ThunkResult<{data: boolean}> {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
const recentEmojis = getRecentEmojisData(state);
|
||||
const emojiMap = getEmojiMap(state);
|
||||
|
||||
let updatedRecentEmojis: RecentEmojiData[] = [...recentEmojis];
|
||||
for (const alias of aliases) {
|
||||
const emoji = emojiMap.get(alias);
|
||||
if (!emoji) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const name = getEmojiName(emoji);
|
||||
|
||||
const currentEmojiIndexInRecentList = updatedRecentEmojis.findIndex((recentEmoji) => recentEmoji.name === name);
|
||||
if (currentEmojiIndexInRecentList > -1) {
|
||||
const currentEmojiInRecentList = updatedRecentEmojis[currentEmojiIndexInRecentList];
|
||||
|
||||
const updatedCurrentEmojiData: RecentEmojiData = {
|
||||
name,
|
||||
usageCount: currentEmojiInRecentList.usageCount + 1,
|
||||
};
|
||||
updatedRecentEmojis.splice(currentEmojiIndexInRecentList, 1);
|
||||
updatedRecentEmojis = [...updatedRecentEmojis, updatedCurrentEmojiData].slice(-MAXIMUM_RECENT_EMOJI);
|
||||
} else {
|
||||
const currentEmojiData: RecentEmojiData = {
|
||||
name,
|
||||
usageCount: 1,
|
||||
};
|
||||
updatedRecentEmojis = [...updatedRecentEmojis, currentEmojiData].slice(-MAXIMUM_RECENT_EMOJI);
|
||||
}
|
||||
}
|
||||
|
||||
updatedRecentEmojis.sort(
|
||||
(emojiA, emojiB) => emojiA.usageCount - emojiB.usageCount,
|
||||
);
|
||||
|
||||
dispatch(savePreferences(currentUserId, [{category: Constants.Preferences.RECENT_EMOJIS, name: currentUserId, user_id: currentUserId, value: JSON.stringify(updatedRecentEmojis)}]));
|
||||
|
||||
return {data: true};
|
||||
};
|
||||
}
|
||||
|
||||
export function loadCustomEmojisForCustomStatusesByUserIds(userIds: Set<string>): ThunkResult<{data: boolean}> {
|
||||
const getCustomStatus = makeGetCustomStatus();
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const customEmojiEnabled = isCustomEmojiEnabled(state);
|
||||
const customStatusEnabled = isCustomStatusEnabled(state);
|
||||
if (!customEmojiEnabled || !customStatusEnabled) {
|
||||
return {data: false};
|
||||
}
|
||||
|
||||
const emojisToLoad = new Set<string>();
|
||||
|
||||
userIds.forEach((userId) => {
|
||||
const customStatus = getCustomStatus(state, userId);
|
||||
if (!customStatus || !customStatus.emoji) {
|
||||
return;
|
||||
}
|
||||
|
||||
emojisToLoad.add(customStatus.emoji);
|
||||
});
|
||||
|
||||
return dispatch(loadCustomEmojisIfNeeded(Array.from(emojisToLoad)));
|
||||
};
|
||||
}
|
||||
|
||||
export function loadCustomEmojisForRecentCustomStatuses(): ThunkResult<{data: boolean}> {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const customEmojiEnabled = isCustomEmojiEnabled(state);
|
||||
const customStatusEnabled = isCustomStatusEnabled(state);
|
||||
if (!customEmojiEnabled || !customStatusEnabled) {
|
||||
return {data: false};
|
||||
}
|
||||
|
||||
const recentCustomStatusesValue = get(state, ReduxPreferences.CATEGORY_CUSTOM_STATUS, ReduxPreferences.NAME_RECENT_CUSTOM_STATUSES);
|
||||
if (!recentCustomStatusesValue) {
|
||||
return {data: false};
|
||||
}
|
||||
|
||||
const recentCustomStatuses = JSON.parse(recentCustomStatusesValue);
|
||||
const emojisToLoad = new Set<string>();
|
||||
|
||||
for (const customStatus of recentCustomStatuses) {
|
||||
if (!customStatus || !customStatus.emoji) {
|
||||
continue;
|
||||
}
|
||||
|
||||
emojisToLoad.add(customStatus.emoji);
|
||||
}
|
||||
|
||||
return dispatch(loadCustomEmojisIfNeeded(Array.from(emojisToLoad)));
|
||||
};
|
||||
}
|
||||
|
||||
export function loadCustomEmojisIfNeeded(emojis: string[]): ThunkResult<{data: boolean}> {
|
||||
return (dispatch, getState) => {
|
||||
if (!emojis || emojis.length === 0) {
|
||||
return {data: false};
|
||||
}
|
||||
|
||||
const state = getState();
|
||||
const customEmojiEnabled = isCustomEmojiEnabled(state);
|
||||
if (!customEmojiEnabled) {
|
||||
return {data: false};
|
||||
}
|
||||
|
||||
const systemEmojis = EmojiIndicesByAlias;
|
||||
const customEmojisByName = selectCustomEmojisByName(state);
|
||||
const nonExistentCustomEmoji = state.entities.emojis.nonExistentEmoji;
|
||||
const emojisToLoad: string[] = [];
|
||||
|
||||
emojis.forEach((emoji) => {
|
||||
if (!emoji) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (systemEmojis.has(emoji)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nonExistentCustomEmoji.has(emoji)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (customEmojisByName.has(emoji)) {
|
||||
return;
|
||||
}
|
||||
|
||||
emojisToLoad.push(emoji);
|
||||
});
|
||||
|
||||
return dispatch(EmojiActions.getCustomEmojisByName(emojisToLoad));
|
||||
};
|
||||
}
|
||||
|
||||
export function loadCustomStatusEmojisForPostList(posts: Record<string, Post>): ThunkResult<{data: boolean}> {
|
||||
return (dispatch) => {
|
||||
if (!posts || Object.keys(posts).length === 0) {
|
||||
return {data: false};
|
||||
}
|
||||
|
||||
const userIds = new Set<string>();
|
||||
Object.keys(posts).forEach((postId) => {
|
||||
const post = posts[postId];
|
||||
if (post.user_id) {
|
||||
userIds.add(post.user_id);
|
||||
}
|
||||
});
|
||||
return dispatch(loadCustomEmojisForCustomStatusesByUserIds(userIds));
|
||||
};
|
||||
}
|
||||
|
||||
export function migrateRecentEmojis(): ThunkResult<{data: RecentEmojiData[] | string[]}> {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
const recentEmojisFromPreference = getRecentEmojisData(state);
|
||||
if (recentEmojisFromPreference.length === 0) {
|
||||
const recentEmojisFromLocalStorage = LocalStorageStore.getRecentEmojis(currentUserId);
|
||||
if (recentEmojisFromLocalStorage) {
|
||||
const parsedRecentEmojisFromLocalStorage = JSON.parse(recentEmojisFromLocalStorage);
|
||||
const toSetRecentEmojiData: RecentEmojiData[] = parsedRecentEmojisFromLocalStorage.map((emojiName: string) => ({
|
||||
name: emojiName,
|
||||
usageCount: 1,
|
||||
}));
|
||||
if (toSetRecentEmojiData.length > 0) {
|
||||
dispatch(savePreferences(currentUserId, [{
|
||||
category: Constants.Preferences.RECENT_EMOJIS,
|
||||
name: currentUserId,
|
||||
user_id: currentUserId,
|
||||
value: JSON.stringify(toSetRecentEmojiData),
|
||||
}]));
|
||||
}
|
||||
return {data: parsedRecentEmojisFromLocalStorage};
|
||||
}
|
||||
}
|
||||
return {data: recentEmojisFromPreference};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user