From e3fcff55f9194e5f9e491644d68a12ca5e2f344c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 2 May 2023 19:11:17 -0500 Subject: [PATCH] Convert EmojiReaction to zod --- .../__tests__/chat-message-reaction.test.tsx | 6 ++---- .../features/chats/components/chat-message.tsx | 2 +- app/soapbox/normalizers/chat-message.ts | 15 +++++---------- app/soapbox/normalizers/emoji-reaction.ts | 14 -------------- app/soapbox/normalizers/index.ts | 1 - app/soapbox/queries/__tests__/chats.test.ts | 7 +++---- app/soapbox/schemas/emoji-reaction.ts | 15 +++++++++++++++ app/soapbox/schemas/index.ts | 1 + app/soapbox/types/entities.ts | 4 +--- app/soapbox/utils/features.ts | 2 +- 10 files changed, 29 insertions(+), 38 deletions(-) delete mode 100644 app/soapbox/normalizers/emoji-reaction.ts create mode 100644 app/soapbox/schemas/emoji-reaction.ts diff --git a/app/soapbox/features/chats/components/__tests__/chat-message-reaction.test.tsx b/app/soapbox/features/chats/components/__tests__/chat-message-reaction.test.tsx index 45fac5383..6ab22d4d5 100644 --- a/app/soapbox/features/chats/components/__tests__/chat-message-reaction.test.tsx +++ b/app/soapbox/features/chats/components/__tests__/chat-message-reaction.test.tsx @@ -1,12 +1,10 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; -import { normalizeEmojiReaction } from 'soapbox/normalizers/emoji-reaction'; - import { render, screen } from '../../../../jest/test-helpers'; import ChatMessageReaction from '../chat-message-reaction'; -const emojiReaction = normalizeEmojiReaction({ +const emojiReaction = ({ name: '👍', count: 1, me: false, @@ -56,7 +54,7 @@ describe('', () => { render( { - {(chatMessage.emoji_reactions?.size) ? ( + {(chatMessage.emoji_reactions?.length) ? (
(), expiration: null as number | null, - emoji_reactions: null as ImmutableList | null, + emoji_reactions: null as readonly EmojiReaction[] | null, id: '', unread: false, deleting: false, @@ -41,13 +41,8 @@ const normalizeMedia = (status: ImmutableMap) => { }; const normalizeChatMessageEmojiReaction = (chatMessage: ImmutableMap) => { - const emojiReactions = chatMessage.get('emoji_reactions'); - - if (emojiReactions) { - return chatMessage.set('emoji_reactions', ImmutableList(emojiReactions.map(normalizeEmojiReaction))); - } else { - return chatMessage; - } + const emojiReactions = chatMessage.get('emoji_reactions') || ImmutableList(); + return chatMessage.set('emoji_reactions', filteredArray(emojiReactionSchema).parse(emojiReactions.toJS())); }; /** Rewrite `

` to empty string. */ diff --git a/app/soapbox/normalizers/emoji-reaction.ts b/app/soapbox/normalizers/emoji-reaction.ts deleted file mode 100644 index 88dcfd1e4..000000000 --- a/app/soapbox/normalizers/emoji-reaction.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Map as ImmutableMap, Record as ImmutableRecord, fromJS } from 'immutable'; - -// https://docs.joinmastodon.org/entities/emoji/ -export const EmojiReactionRecord = ImmutableRecord({ - name: '', - count: null as number | null, - me: false, -}); - -export const normalizeEmojiReaction = (emojiReaction: Record) => { - return EmojiReactionRecord( - ImmutableMap(fromJS(emojiReaction)), - ); -}; diff --git a/app/soapbox/normalizers/index.ts b/app/soapbox/normalizers/index.ts index d22bce0c9..e7100fa9d 100644 --- a/app/soapbox/normalizers/index.ts +++ b/app/soapbox/normalizers/index.ts @@ -7,7 +7,6 @@ export { AttachmentRecord, normalizeAttachment } from './attachment'; export { ChatRecord, normalizeChat } from './chat'; export { ChatMessageRecord, normalizeChatMessage } from './chat-message'; export { EmojiRecord, normalizeEmoji } from './emoji'; -export { EmojiReactionRecord } from './emoji-reaction'; export { FilterRecord, normalizeFilter } from './filter'; export { FilterKeywordRecord, normalizeFilterKeyword } from './filter-keyword'; export { FilterStatusRecord, normalizeFilterStatus } from './filter-status'; diff --git a/app/soapbox/queries/__tests__/chats.test.ts b/app/soapbox/queries/__tests__/chats.test.ts index 981250456..3bcd1b9a7 100644 --- a/app/soapbox/queries/__tests__/chats.test.ts +++ b/app/soapbox/queries/__tests__/chats.test.ts @@ -1,4 +1,4 @@ -import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import { Map as ImmutableMap } from 'immutable'; import sumBy from 'lodash/sumBy'; import { useEffect } from 'react'; @@ -6,7 +6,6 @@ import { __stub } from 'soapbox/api'; import { buildRelationship } from 'soapbox/jest/factory'; import { createTestStore, mockStore, queryClient, renderHook, rootState, waitFor } from 'soapbox/jest/test-helpers'; import { normalizeChatMessage } from 'soapbox/normalizers'; -import { normalizeEmojiReaction } from 'soapbox/normalizers/emoji-reaction'; import { Store } from 'soapbox/store'; import { ChatMessage } from 'soapbox/types/entities'; import { flattenPages } from 'soapbox/utils/queries'; @@ -426,11 +425,11 @@ describe('useChatActions', () => { }); const updatedChatMessage = (queryClient.getQueryData(ChatKeys.chatMessages(chat.id)) as any).pages[0].result[0] as ChatMessage; - expect(updatedChatMessage.emoji_reactions).toEqual(ImmutableList([normalizeEmojiReaction({ + expect(updatedChatMessage.emoji_reactions).toEqual([{ name: '👍', count: 1, me: true, - })])); + }]); }); }); }); diff --git a/app/soapbox/schemas/emoji-reaction.ts b/app/soapbox/schemas/emoji-reaction.ts new file mode 100644 index 000000000..55c1762a0 --- /dev/null +++ b/app/soapbox/schemas/emoji-reaction.ts @@ -0,0 +1,15 @@ +import { z } from 'zod'; + +/** Validates the string as an emoji. */ +const emojiSchema = z.string().refine((v) => /\p{Extended_Pictographic}/u.test(v)); + +/** Pleroma emoji reaction. */ +const emojiReactionSchema = z.object({ + name: emojiSchema, + count: z.number().nullable().catch(null), + me: z.boolean().catch(false), +}); + +type EmojiReaction = z.infer; + +export { emojiReactionSchema, EmojiReaction }; \ No newline at end of file diff --git a/app/soapbox/schemas/index.ts b/app/soapbox/schemas/index.ts index a64ab2942..29b1c2edd 100644 --- a/app/soapbox/schemas/index.ts +++ b/app/soapbox/schemas/index.ts @@ -1,6 +1,7 @@ export { accountSchema, type Account } from './account'; export { cardSchema, type Card } from './card'; export { customEmojiSchema, type CustomEmoji } from './custom-emoji'; +export { emojiReactionSchema, type EmojiReaction } from './emoji-reaction'; export { groupSchema, type Group } from './group'; export { groupMemberSchema, type GroupMember } from './group-member'; export { groupRelationshipSchema, type GroupRelationship } from './group-relationship'; diff --git a/app/soapbox/types/entities.ts b/app/soapbox/types/entities.ts index 27082f76f..e99aa3acf 100644 --- a/app/soapbox/types/entities.ts +++ b/app/soapbox/types/entities.ts @@ -8,7 +8,6 @@ import { ChatRecord, ChatMessageRecord, EmojiRecord, - EmojiReactionRecord, FieldRecord, FilterRecord, FilterKeywordRecord, @@ -38,7 +37,6 @@ type Attachment = ReturnType; type Chat = ReturnType; type ChatMessage = ReturnType; type Emoji = ReturnType; -type EmojiReaction = ReturnType; type Field = ReturnType; type Filter = ReturnType; type FilterKeyword = ReturnType; @@ -81,7 +79,6 @@ export { Chat, ChatMessage, Emoji, - EmojiReaction, Field, Filter, FilterKeyword, @@ -105,6 +102,7 @@ export { export type { Card, + EmojiReaction, Group, GroupMember, GroupRelationship, diff --git a/app/soapbox/utils/features.ts b/app/soapbox/utils/features.ts index 9c5a68bda..dd818ac2b 100644 --- a/app/soapbox/utils/features.ts +++ b/app/soapbox/utils/features.ts @@ -254,7 +254,7 @@ const getInstanceFeatures = (instance: Instance) => { /** * Ability to add reactions to chat messages. */ - chatEmojiReactions: v.software === TRUTHSOCIAL && v.build === UNRELEASED, + chatEmojiReactions: v.software === TRUTHSOCIAL, /** * Pleroma chats API.