// Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { useState, ReactNode } from 'react'; import { ConversationType } from '../../../state/ducks/conversations'; import { assert } from '../../../util/assert'; import { ExpirationTimerOptions, TimerOption, } from '../../../util/ExpirationTimerOptions'; import { LocalizerType } from '../../../types/Util'; import { MediaItemType } from '../../LightboxGallery'; import { missingCaseError } from '../../../util/missingCaseError'; import { PanelRow } from './PanelRow'; import { PanelSection } from './PanelSection'; import { AddGroupMembersModal } from './AddGroupMembersModal'; import { ConversationDetailsActions } from './ConversationDetailsActions'; import { ConversationDetailsHeader } from './ConversationDetailsHeader'; import { ConversationDetailsIcon } from './ConversationDetailsIcon'; import { ConversationDetailsMediaList } from './ConversationDetailsMediaList'; import { ConversationDetailsMembershipList } from './ConversationDetailsMembershipList'; import { EditConversationAttributesModal } from './EditConversationAttributesModal'; import { RequestState } from './util'; enum ModalState { NothingOpen, EditingGroupAttributes, AddingGroupMembers, } export type StateProps = { addMembers: (conversationIds: ReadonlyArray) => Promise; canEditGroupInfo: boolean; candidateContactsToAdd: Array; conversation?: ConversationType; hasGroupLink: boolean; i18n: LocalizerType; isAdmin: boolean; loadRecentMediaItems: (limit: number) => void; setDisappearingMessages: (seconds: number) => void; showAllMedia: () => void; showContactModal: (conversationId: string) => void; showGroupLinkManagement: () => void; showGroupV2Permissions: () => void; showPendingInvites: () => void; showLightboxForMedia: ( selectedMediaItem: MediaItemType, media: Array ) => void; updateGroupAttributes: ( _: Readonly<{ avatar?: undefined | ArrayBuffer; title?: string; }> ) => Promise; onBlockAndDelete: () => void; onDelete: () => void; }; export type Props = StateProps; export const ConversationDetails: React.ComponentType = ({ addMembers, canEditGroupInfo, candidateContactsToAdd, conversation, hasGroupLink, i18n, isAdmin, loadRecentMediaItems, setDisappearingMessages, showAllMedia, showContactModal, showGroupLinkManagement, showGroupV2Permissions, showPendingInvites, showLightboxForMedia, updateGroupAttributes, onBlockAndDelete, onDelete, }) => { const [modalState, setModalState] = useState( ModalState.NothingOpen ); const [ editGroupAttributesRequestState, setEditGroupAttributesRequestState, ] = useState(RequestState.Inactive); const [ addGroupMembersRequestState, setAddGroupMembersRequestState, ] = useState(RequestState.Inactive); const updateExpireTimer = (event: React.ChangeEvent) => { setDisappearingMessages(parseInt(event.target.value, 10)); }; if (conversation === undefined) { throw new Error('ConversationDetails rendered without a conversation'); } const pendingMemberships = conversation.pendingMemberships || []; const pendingApprovalMemberships = conversation.pendingApprovalMemberships || []; const invitesCount = pendingMemberships.length + pendingApprovalMemberships.length; let modalNode: ReactNode; switch (modalState) { case ModalState.NothingOpen: modalNode = undefined; break; case ModalState.EditingGroupAttributes: modalNode = ( ) => { setEditGroupAttributesRequestState(RequestState.Active); try { await updateGroupAttributes(options); setModalState(ModalState.NothingOpen); setEditGroupAttributesRequestState(RequestState.Inactive); } catch (err) { setEditGroupAttributesRequestState( RequestState.InactiveWithError ); } }} onClose={() => { setModalState(ModalState.NothingOpen); setEditGroupAttributesRequestState(RequestState.Inactive); }} requestState={editGroupAttributesRequestState} title={conversation.title} /> ); break; case ModalState.AddingGroupMembers: modalNode = ( { setAddGroupMembersRequestState(oldRequestState => { assert( oldRequestState !== RequestState.Active, 'Should not be clearing an active request state' ); return RequestState.Inactive; }); }} conversationIdsAlreadyInGroup={ new Set( (conversation.memberships || []).map( membership => membership.member.id ) ) } groupTitle={conversation.title} i18n={i18n} makeRequest={async conversationIds => { setAddGroupMembersRequestState(RequestState.Active); try { await addMembers(conversationIds); setModalState(ModalState.NothingOpen); setAddGroupMembersRequestState(RequestState.Inactive); } catch (err) { setAddGroupMembersRequestState(RequestState.InactiveWithError); } }} onClose={() => { setModalState(ModalState.NothingOpen); setEditGroupAttributesRequestState(RequestState.Inactive); }} requestState={addGroupMembersRequestState} /> ); break; default: throw missingCaseError(modalState); } return (
{ setModalState(ModalState.EditingGroupAttributes); }} /> {canEditGroupInfo ? ( } info={i18n('ConversationDetails--disappearing-messages-info')} label={i18n('ConversationDetails--disappearing-messages-label')} right={
} />
) : null} { setModalState(ModalState.AddingGroupMembers); }} /> {isAdmin || hasGroupLink ? ( } label={i18n('ConversationDetails--group-link')} onClick={showGroupLinkManagement} right={hasGroupLink ? i18n('on') : i18n('off')} /> ) : null} } label={i18n('ConversationDetails--requests-and-invites')} onClick={showPendingInvites} right={invitesCount} /> {isAdmin ? ( } label={i18n('permissions')} onClick={showGroupV2Permissions} /> ) : null} {modalNode}
); };