// Copyright 2018-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { ReactNode } from 'react'; import React from 'react'; import { compact, flatten } from 'lodash'; import { ContactName } from './ContactName'; import { SystemMessage } from './SystemMessage'; import { Intl } from '../Intl'; import type { LocalizerType } from '../../types/Util'; import { missingCaseError } from '../../util/missingCaseError'; import type { ConversationType } from '../../state/ducks/conversations'; export type ChangeType = 'add' | 'remove' | 'name' | 'avatar' | 'general'; type Change = { type: ChangeType; newName?: string; contacts?: Array; }; export type PropsData = { from: ConversationType; changes: Array; }; type PropsHousekeeping = { i18n: LocalizerType; }; export type Props = PropsData & PropsHousekeeping; export class GroupNotification extends React.Component { public renderChange( change: Change, from: ConversationType ): JSX.Element | string | null | undefined { const { contacts, type, newName } = change; const { i18n } = this.props; const otherPeople: Array = compact( (contacts || []).map(contact => { if (contact.isMe) { return null; } return ( ); }) ); const otherPeopleWithCommas: Array = compact( flatten( otherPeople.map((person, index) => [index > 0 ? ', ' : null, person]) ) ); const contactsIncludesMe = (contacts || []).length !== otherPeople.length; switch (type) { case 'name': return ( ); case 'avatar': return ; case 'add': if (!contacts || !contacts.length) { throw new Error('Group update is missing contacts'); } // eslint-disable-next-line no-case-declarations const otherPeopleNotifMsg = otherPeople.length === 1 ? 'joinedTheGroup' : 'multipleJoinedTheGroup'; return ( <> {otherPeople.length > 0 && ( )} {contactsIncludesMe && (
)} ); case 'remove': if (from && from.isMe) { return i18n('youLeftTheGroup'); } if (!contacts || !contacts.length) { throw new Error('Group update is missing contacts'); } // eslint-disable-next-line no-case-declarations const leftKey = contacts.length > 1 ? 'multipleLeftTheGroup' : 'leftTheGroup'; return ( ); case 'general': return; default: throw missingCaseError(type); } } public render(): JSX.Element { const { changes: rawChanges, i18n, from } = this.props; // This check is just to be extra careful, and can probably be removed. const changes: Array = Array.isArray(rawChanges) ? rawChanges : []; // Leave messages are always from the person leaving, so we omit the fromLabel if // the change is a 'leave.' const firstChange: undefined | Change = changes[0]; const isLeftOnly = changes.length === 1 && firstChange?.type === 'remove'; const fromLabel = from.isMe ? ( ) : ( ]} /> ); let contents: ReactNode; if (isLeftOnly) { contents = this.renderChange(firstChange, from); } else { contents = ( <>

{fromLabel}

{changes.map((change, i) => ( // eslint-disable-next-line react/no-array-index-key

{this.renderChange(change, from)}

))} ); } return ; } }