combine reactions by their first alias

This commit is contained in:
Elias Nahum
2022-03-18 13:30:28 -03:00
parent 3e94958ab0
commit 7431fd4120
5 changed files with 78 additions and 40 deletions

View File

@@ -3,6 +3,7 @@
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
import DatabaseManager from '@database/manager';
import {getEmojiFirstAlias} from '@utils/emoji/helpers';
import {safeParseJSON} from '@utils/helpers';
import type SystemModel from '@typings/database/models/servers/system';
@@ -29,16 +30,17 @@ export const addRecentReaction = async (serverUrl: string, emojiNames: string[],
try {
const recentEmojis = new Set(recent);
for (const name of emojiNames) {
if (recentEmojis.has(name)) {
recentEmojis.delete(name);
const aliases = emojiNames.map((e) => getEmojiFirstAlias(e));
for (const alias of aliases) {
if (recentEmojis.has(alias)) {
recentEmojis.delete(alias);
}
}
recent = Array.from(recentEmojis);
for (const name of emojiNames) {
recent.unshift(name);
for (const alias of aliases) {
recent.unshift(alias);
}
return operator.handleSystem({
systems: [{

View File

@@ -1,14 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model, Q} from '@nozbe/watermelondb';
import {Model} from '@nozbe/watermelondb';
import {addRecentReaction} from '@actions/local/reactions';
import {MM_TABLES} from '@constants/database';
import DatabaseManager from '@database/manager';
import NetworkManager from '@init/network_manager';
import {queryRecentPostsInChannel, queryRecentPostsInThread} from '@queries/servers/post';
import {queryReaction} from '@queries/servers/reaction';
import {queryCurrentChannelId, queryCurrentUserId} from '@queries/servers/system';
import {getEmojiFirstAlias} from '@utils/emoji/helpers';
import {forceLogoutIfNecessary} from './session';
@@ -30,29 +31,41 @@ export const addReaction = async (serverUrl: string, postId: string, emojiName:
try {
const currentUserId = await queryCurrentUserId(operator.database);
const reaction = await client.addReaction(currentUserId, postId, emojiName);
const models: Model[] = [];
const emojiAlias = getEmojiFirstAlias(emojiName);
const reacted = await queryReaction(operator.database, emojiAlias, postId, currentUserId).fetchCount() > 0;
if (!reacted) {
const reaction = await client.addReaction(currentUserId, postId, emojiAlias);
const models: Model[] = [];
const reactions = await operator.handleReactions({
postsReactions: [{
const reactions = await operator.handleReactions({
postsReactions: [{
post_id: postId,
reactions: [reaction],
}],
prepareRecordsOnly: true,
skipSync: true, // this prevents the handler from deleting previous reactions
});
models.push(...reactions);
const recent = await addRecentReaction(serverUrl, [emojiName], true);
if (Array.isArray(recent)) {
models.push(...recent);
}
if (models.length) {
await operator.batchRecords(models);
}
return {reaction};
}
return {
reaction: {
user_id: currentUserId,
post_id: postId,
reactions: [reaction],
}],
prepareRecordsOnly: true,
skipSync: true, // this prevents the handler from deleting previous reactions
});
models.push(...reactions);
const recent = await addRecentReaction(serverUrl, [emojiName], true);
if (Array.isArray(recent)) {
models.push(...recent);
}
if (models.length) {
await operator.batchRecords(models);
}
return {reaction};
emoji_name: emojiAlias,
create_at: Date.now(),
} as Reaction,
};
} catch (error) {
forceLogoutIfNecessary(serverUrl, error as ClientErrorProps);
return {error};
@@ -74,14 +87,11 @@ export const removeReaction = async (serverUrl: string, postId: string, emojiNam
try {
const currentUserId = await queryCurrentUserId(database);
await client.removeReaction(currentUserId, postId, emojiName);
const emojiAlias = getEmojiFirstAlias(emojiName);
await client.removeReaction(currentUserId, postId, emojiAlias);
// should return one or no reaction
const reaction = await database.get(MM_TABLES.SERVER.REACTION).query(
Q.where('emoji_name', emojiName),
Q.where('post_id', postId),
Q.where('user_id', currentUserId),
).fetch();
const reaction = await queryReaction(database, emojiAlias, postId, currentUserId).fetch();
if (reaction.length) {
await database.write(async () => {

View File

@@ -10,6 +10,7 @@ import CompassIcon from '@components/compass_icon';
import {MAX_ALLOWED_REACTIONS} from '@constants/emoji';
import {useServerUrl} from '@context/server';
import {showModal, showModalOverCurrentContext} from '@screens/navigation';
import {getEmojiFirstAlias} from '@utils/emoji/helpers';
import {preventDoubleTap} from '@utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
@@ -59,12 +60,12 @@ const Reactions = ({currentUserId, canAddReaction, canRemoveReaction, disabled,
const intl = useIntl();
const serverUrl = useServerUrl();
const pressed = useRef(false);
const [sortedReactions, setSortedReactions] = useState(new Set(reactions.map((r) => r.emojiName)));
const [sortedReactions, setSortedReactions] = useState(new Set(reactions.map((r) => getEmojiFirstAlias(r.emojiName))));
const styles = getStyleSheet(theme);
useEffect(() => {
// This helps keep the reactions in the same position at all times until unmounted
const rs = reactions.map((r) => r.emojiName);
const rs = reactions.map((r) => getEmojiFirstAlias(r.emojiName));
const sorted = new Set([...sortedReactions]);
const added = rs.filter((r) => !sorted.has(r));
added.forEach(sorted.add, sorted);
@@ -78,14 +79,20 @@ const Reactions = ({currentUserId, canAddReaction, canRemoveReaction, disabled,
const reactionsByName = reactions.reduce((acc, reaction) => {
if (reaction) {
if (acc.has(reaction.emojiName)) {
acc.get(reaction.emojiName)!.push(reaction);
const emojiAlias = getEmojiFirstAlias(reaction.emojiName);
if (acc.has(emojiAlias)) {
const rs = acc.get(emojiAlias);
// eslint-disable-next-line max-nested-callbacks
const present = rs!.findIndex((r) => r.userId === reaction.userId) > -1;
if (!present) {
rs!.push(reaction);
}
} else {
acc.set(reaction.emojiName, [reaction]);
acc.set(emojiAlias, [reaction]);
}
if (reaction.userId === currentUserId) {
highlightedReactions.push(reaction.emojiName);
highlightedReactions.push(emojiAlias);
}
}

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Database, Q} from '@nozbe/watermelondb';
import {MM_TABLES} from '@constants/database';
const {SERVER: {REACTION}} = MM_TABLES;
export const queryReaction = (database: Database, emojiName: string, postId: string, userId: string) => {
return database.get(REACTION).query(
Q.where('emoji_name', emojiName),
Q.where('post_id', postId),
Q.where('user_id', userId),
);
};

View File

@@ -193,6 +193,10 @@ export function doesMatchNamedEmoji(emojiName: string) {
return false;
}
export const getEmojiFirstAlias = (emoji: string) => {
return getEmojiByName(emoji, [])?.short_names?.[0] || emoji;
};
export function getEmojiByName(emojiName: string, customEmojis: CustomEmojiModel[]) {
if (EmojiIndicesByAlias.has(emojiName)) {
return Emojis[EmojiIndicesByAlias.get(emojiName)!];