From 05b7bdb956ab371fd7bd43c27b5715bc2d5c0c62 Mon Sep 17 00:00:00 2001 From: William Grant Date: Thu, 25 Aug 2022 17:23:26 +1000 Subject: [PATCH] fix: show correct count value for open group reactions --- .../message/reactions/Reaction.tsx | 1 + .../message/reactions/ReactionPopup.tsx | 39 +++++++++++++------ ts/models/conversation.ts | 2 - ts/state/selectors/conversations.ts | 2 +- ts/util/readableList.ts | 14 ++++--- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/ts/components/conversation/message/reactions/Reaction.tsx b/ts/components/conversation/message/reactions/Reaction.tsx index 675d24afd..0ef46c532 100644 --- a/ts/components/conversation/message/reactions/Reaction.tsx +++ b/ts/components/conversation/message/reactions/Reaction.tsx @@ -138,6 +138,7 @@ export const Reaction = (props: ReactionProps): ReactElement => { { diff --git a/ts/components/conversation/message/reactions/ReactionPopup.tsx b/ts/components/conversation/message/reactions/ReactionPopup.tsx index dddd277bd..9a694f670 100644 --- a/ts/components/conversation/message/reactions/ReactionPopup.tsx +++ b/ts/components/conversation/message/reactions/ReactionPopup.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { Data } from '../../../../data/data'; import { PubKey } from '../../../../session/types/PubKey'; import { nativeEmojiData } from '../../../../util/emoji'; -import { readableList } from '../../../../util/readableList'; +import { defaultConjunction, defaultWordLimit, readableList } from '../../../../util/readableList'; export type TipPosition = 'center' | 'left' | 'right'; @@ -59,8 +59,12 @@ const StyledOthers = styled.span` color: var(--color-accent); `; -const generateContacts = async (messageId: string, senders: Array) => { - let results = null; +const generateContactsString = async ( + messageId: string, + senders: Array, + count: number +): Promise => { + let results = []; const message = await Data.getMessageById(messageId); if (message) { let meIndex = -1; @@ -75,8 +79,18 @@ const generateContacts = async (messageId: string, senders: Array) => { results.splice(meIndex, 1); results = [window.i18n('you'), ...results]; } + if (results && results.length > 0) { + let contacts = readableList(results); + // This can only happen in an opengroup + if (results.length !== count) { + const [names, others] = contacts.split(`${defaultConjunction} `); + const [_, suffix] = others.split(' '); // i.e. 3 others + contacts = `${names} ${defaultConjunction} ${count - defaultWordLimit} ${suffix}`; + } + return contacts; + } } - return results; + return null; }; const Contacts = (contacts: string) => { @@ -84,8 +98,8 @@ const Contacts = (contacts: string) => { return; } - if (contacts.includes('&') && contacts.includes('other')) { - const [names, others] = contacts.split('&'); + if (contacts.includes(defaultConjunction) && contacts.includes('other')) { + const [names, others] = contacts.split(defaultConjunction); return ( {names} & {others} {window.i18n('reactionTooltip')} @@ -95,7 +109,7 @@ const Contacts = (contacts: string) => { return ( - {contacts} {window.i18n('reactionTooltip')} + {contacts.replace(defaultConjunction, '&')} {window.i18n('reactionTooltip')} ); }; @@ -103,25 +117,26 @@ const Contacts = (contacts: string) => { type Props = { messageId: string; emoji: string; + count: number; senders: Array; tooltipPosition?: TipPosition; onClick: (...args: Array) => void; }; export const ReactionPopup = (props: Props): ReactElement => { - const { messageId, emoji, senders, tooltipPosition = 'center', onClick } = props; + const { messageId, emoji, count, senders, tooltipPosition = 'center', onClick } = props; const [contacts, setContacts] = useState(''); useEffect(() => { let isCancelled = false; - generateContacts(messageId, senders) + generateContactsString(messageId, senders, count) .then(async results => { if (isCancelled) { return; } - if (results && results.length > 0) { - setContacts(readableList(results)); + if (results) { + setContacts(results); } }) .catch(() => { @@ -133,7 +148,7 @@ export const ReactionPopup = (props: Props): ReactElement => { return () => { isCancelled = true; }; - }, [generateContacts]); + }, [count, generateContactsString, messageId, senders]); return ( diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index 3c1aeaa7e..8b8a1907d 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -753,7 +753,6 @@ export class ConversationModel extends Backbone.Model { if (this.id.startsWith('15')) { window.log.info('Sending a blinded message to this user: ', this.id); - // TODO confirm this works with Reacts await this.sendBlindedMessageRequest(chatMessageParams); return; } @@ -789,7 +788,6 @@ export class ConversationModel extends Backbone.Model { const destinationPubkey = new PubKey(destination); if (this.isPrivate()) { - // TODO is this still fine without isMe? const chatMessageMe = new VisibleMessage({ ...chatMessageParams, syncTarget: this.id, diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index 91e87d3dc..a1153e82b 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -918,7 +918,7 @@ export const getMessageReactsProps = createSelector(getMessagePropsByMessageId, ]); if (msgProps.reacts) { - // TODO we don't want to render reactions that have 'senders' as an object this is a deprecated type used during development 25/08/2022 + // NOTE we don't want to render reactions that have 'senders' as an object this is a deprecated type used during development 25/08/2022 const oldReactions = Object.values(msgProps.reacts).filter( reaction => !Array.isArray(reaction.senders) ); diff --git a/ts/util/readableList.ts b/ts/util/readableList.ts index 50f24d810..81d7549b6 100644 --- a/ts/util/readableList.ts +++ b/ts/util/readableList.ts @@ -1,7 +1,11 @@ +// we need to use a character that cannot be used as a display name for string manipulation up until we render the UI +export const defaultConjunction = '\uFFD7'; +export const defaultWordLimit = 3; + export const readableList = ( arr: Array, - conjunction: string = '&', - limit: number = 3 + conjunction: string = defaultConjunction, + wordLimit: number = defaultWordLimit ): string => { if (arr.length === 0) { return ''; @@ -15,11 +19,11 @@ export const readableList = ( let result = ''; let others = 0; for (let i = 0; i < count; i++) { - if (others === 0 && i === count - 1 && i < limit) { + if (others === 0 && i === count - 1 && i < wordLimit) { result += ` ${conjunction} `; - } else if (i !== 0 && i < limit) { + } else if (i !== 0 && i < wordLimit) { result += ', '; - } else if (i >= limit) { + } else if (i >= wordLimit) { others++; }