/* * Wire * Copyright (C) 2023 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * */ import {MemberLeaveReason} from '@wireapp/api-client/lib/conversation/data/'; import {CONVERSATION_EVENT} from '@wireapp/api-client/lib/event/'; import {Config} from 'src/script/Config'; import {MemberMessage as MemberMessageEntity} from 'src/script/entity/message/MemberMessage'; import {User} from 'src/script/entity/User'; import {ClientEvent} from 'src/script/event/Client'; import {SystemMessageType} from 'src/script/message/SystemMessageType'; import {Declension, joinNames, replaceLink, t} from 'Util/LocalizerUtil'; import {replaceReactComponents} from 'Util/LocalizerUtil/ReactLocalizerUtil'; import {matchQualifiedIds} from 'Util/QualifiedId'; export const CONFIG = { MAX_USERS_VISIBLE: 17, MAX_WHOLE_TEAM_USERS_VISIBLE: 10, REDUCED_USERS_COUNT: 15, } as const; function generateNames(users: User[], declension = Declension.ACCUSATIVE, hasExtra = false) { const visibleUsers = hasExtra ? getVisibleUsers(users) : users; return joinNames(visibleUsers, declension, hasExtra, true); } function getVisibleUsers(users: User[]) { return users.slice(0, CONFIG.REDUCED_USERS_COUNT); } function ShowMoreButton({children, onClick}: {children: React.ReactNode; onClick: () => void}) { return ( ); } function getContent(message: MemberMessageEntity) { if (!message.hasUsers()) { return ''; } /** the users that are impacted by the member event */ const targetedUsers = message.targetedUsers(); /** the user that triggered the action */ const actor = message.user(); const exceedsMaxVisibleUsers = targetedUsers.length > CONFIG.MAX_USERS_VISIBLE; /** the number of users that will not be displayed on screen */ const hiddenUsersCount = exceedsMaxVisibleUsers ? targetedUsers.length - CONFIG.REDUCED_USERS_COUNT : 0; const dativeUsers = generateNames(targetedUsers, Declension.DATIVE, exceedsMaxVisibleUsers); const accusativeUsers = generateNames(targetedUsers, Declension.ACCUSATIVE, exceedsMaxVisibleUsers); const name = message.senderName(); switch (message.memberMessageType) { case SystemMessageType.CONVERSATION_CREATE: { if (message.name().length) { const exceedsMaxTeam = targetedUsers.length > CONFIG.MAX_WHOLE_TEAM_USERS_VISIBLE; if (message.allTeamMembers && exceedsMaxTeam) { const guestCount = targetedUsers.filter(userEntity => userEntity.isGuest()).length; if (!guestCount) { return t('conversationCreateTeam', {}); } const hasSingleGuest = guestCount === 1; return hasSingleGuest ? t('conversationCreateTeamGuest', {}) : t('conversationCreateTeamGuests', guestCount); } return exceedsMaxVisibleUsers ? t('conversationCreateWithMore', {count: hiddenUsersCount.toString(), users: dativeUsers}, {}, true) : t('conversationCreateWith', dativeUsers, {}, true); } if (actor.isMe) { return exceedsMaxVisibleUsers ? t('conversationCreatedYouMore', {count: hiddenUsersCount.toString(), users: dativeUsers}, {}, true) : t('conversationCreatedYou', dativeUsers, {}, true); } return exceedsMaxVisibleUsers ? t('conversationCreatedMore', {count: hiddenUsersCount.toString(), name, users: dativeUsers}, {}, true) : t('conversationCreated', {name, users: dativeUsers}, {}, true); } case SystemMessageType.CONVERSATION_RESUME: { return t('conversationResume', generateNames(targetedUsers, Declension.DATIVE, false), {}, true); } default: break; } switch (message.type) { case CONVERSATION_EVENT.MEMBER_JOIN: { const senderJoined = matchQualifiedIds(message.otherUser(), actor); if (senderJoined) { return message.user().isMe ? t('conversationMemberJoinedSelfYou') : t('conversationMemberJoinedSelf', message.senderName(), {}, true); } if (message.user().isMe) { return exceedsMaxVisibleUsers ? t('conversationMemberJoinedYouMore', {count: hiddenUsersCount.toString(), users: accusativeUsers}, {}, true) : t('conversationMemberJoinedYou', accusativeUsers, {}, true); } return exceedsMaxVisibleUsers ? t( 'conversationMemberJoinedMore', {count: hiddenUsersCount.toString(), name, users: accusativeUsers}, {}, true, ) : t('conversationMemberJoined', {name, users: accusativeUsers}, {}, true); } case CONVERSATION_EVENT.MEMBER_LEAVE: { if (message.reason === MemberLeaveReason.LEGAL_HOLD_POLICY_CONFLICT) { const replaceLinkLegalHold = replaceLink( Config.getConfig().URL.SUPPORT.LEGAL_HOLD_BLOCK, '', 'read-more-legal-hold', ); if (message.userEntities().some(user => user.isMe)) { return t('conversationYouRemovedMissingLegalHoldConsent', {}, replaceLinkLegalHold); } const users = generateNames(targetedUsers); if (message.userEntities().length === 1) { return t('conversationMemberRemovedMissingLegalHoldConsent', users, replaceLinkLegalHold); } if (exceedsMaxVisibleUsers) { return t( 'conversationMultipleMembersRemovedMissingLegalHoldConsentMore', { count: hiddenUsersCount.toString(10), users, }, replaceLinkLegalHold, true, ); } return t('conversationMultipleMembersRemovedMissingLegalHoldConsent', users, replaceLinkLegalHold); } const temporaryGuestRemoval = message.otherUser().isMe && message.otherUser().isTemporaryGuest(); if (temporaryGuestRemoval) { return t('temporaryGuestLeaveMessage'); } const senderLeft = matchQualifiedIds(message.otherUser(), actor); if (senderLeft) { return message.user().isMe ? t('conversationMemberLeftYou') : t('conversationMemberLeft', name, {}, true); } const allUsers = generateNames(targetedUsers); if (!actor.id) { return t('conversationMemberWereRemoved', allUsers, {}, true); } return actor.isMe ? t('conversationMemberRemovedYou', allUsers, {}, true) : t('conversationMemberRemoved', {name, users: allUsers}, {}, true); } case ClientEvent.CONVERSATION.TEAM_MEMBER_LEAVE: { return t('conversationTeamLeft', name, {}, true); } default: break; } return ''; } export function MessageContent({ message, onClickParticipants, }: { message: MemberMessageEntity; onClickParticipants: (participants: User[]) => void; }) { const htmlCaption = getContent(message); const content = replaceReactComponents(htmlCaption, [ {start: '', end: '', render: text => {text}}, { start: '[showmore]', end: '[/showmore]', render: text => ( onClickParticipants(message.targetedUsers())}> {text} ), }, ]); return

{content}

; }