import React, { useEffect, useState } from 'react'; import _ from 'lodash'; // tslint:disable-next-line: no-submodule-imports import useInterval from 'react-use/lib/useInterval'; import { useDispatch, useSelector } from 'react-redux'; import { Data } from '../../../../data/data'; import { deleteAllMessagesByConvoIdWithConfirmation, showAddModeratorsByConvoId, showInviteContactByConvoId, showLeaveGroupByConvoId, showRemoveModeratorsByConvoId, showUpdateGroupMembersByConvoId, showUpdateGroupNameByConvoId, } from '../../../../interactions/conversationInteractions'; import { Constants } from '../../../../session'; import { getSelectedConversation, isRightPanelShowing, } from '../../../../state/selectors/conversations'; import { AttachmentTypeWithPath } from '../../../../types/Attachment'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../../../basic/SessionButton'; import { SpacerLG } from '../../../basic/Text'; import { MediaItemType } from '../../../lightbox/LightboxGallery'; import { MediaGallery } from '../../media-gallery/MediaGallery'; import { getAbsoluteAttachmentPath } from '../../../../types/MessageAttachment'; import styled from 'styled-components'; import { SessionIconButton } from '../../../icon'; import { closeRightPanel } from '../../../../state/ducks/conversations'; import { Avatar, AvatarSize } from '../../../avatar/Avatar'; import { setRightOverlayMode } from '../../../../state/ducks/section'; import { PanelButtonGroup, PanelIconButton } from '../../../buttons'; async function getMediaGalleryProps( conversationId: string ): Promise<{ documents: Array; media: Array; }> { // We fetch more documents than media as they don’t require to be loaded // into memory right away. Revisit this once we have infinite scrolling: const rawMedia = await Data.getMessagesWithVisualMediaAttachments( conversationId, Constants.CONVERSATION.DEFAULT_MEDIA_FETCH_COUNT ); const rawDocuments = await Data.getMessagesWithFileAttachments( conversationId, Constants.CONVERSATION.DEFAULT_DOCUMENTS_FETCH_COUNT ); const media = _.flatten( rawMedia.map(attributes => { const { attachments, source, id, timestamp, serverTimestamp, received_at } = attributes; return (attachments || []) .filter( (attachment: AttachmentTypeWithPath) => attachment.thumbnail && !attachment.pending && !attachment.error ) .map((attachment: AttachmentTypeWithPath, index: number) => { const { thumbnail } = attachment; const mediaItem: MediaItemType = { objectURL: getAbsoluteAttachmentPath(attachment.path), thumbnailObjectUrl: thumbnail ? getAbsoluteAttachmentPath(thumbnail.path) : undefined, contentType: attachment.contentType || '', index, messageTimestamp: timestamp || serverTimestamp || received_at || 0, messageSender: source, messageId: id, attachment, }; return mediaItem; }); }) ); // Unlike visual media, only one non-image attachment is supported const documents = rawDocuments.map(attributes => { // this is to not fail if the attachment is invalid (could be a Long Attachment type which is not supported) if (!attributes.attachments?.length) { // window?.log?.info( // 'Got a message with an empty list of attachment. Skipping...' // ); return null; } const attachment = attributes.attachments[0]; const { source, id, timestamp, serverTimestamp, received_at } = attributes; return { contentType: attachment.contentType, index: 0, attachment, messageTimestamp: timestamp || serverTimestamp || received_at || 0, messageSender: source, messageId: id, }; }); return { media, documents: _.compact(documents), // remove null }; } const HeaderItem = () => { const selectedConversation = useSelector(getSelectedConversation); const dispatch = useDispatch(); if (!selectedConversation) { return null; } const { id, isGroup, isKickedFromGroup, isBlocked, left } = selectedConversation; const showInviteContacts = isGroup && !isKickedFromGroup && !isBlocked && !left; return (
{ dispatch(closeRightPanel()); }} style={{ position: 'absolute' }} dataTestId="back-button-conversation-options" /> {showInviteContacts && ( { if (selectedConversation) { showInviteContactByConvoId(selectedConversation.id); } }} dataTestId="add-user-button" /> )}
); }; const StyledLeaveButton = styled.div` width: 100%; .session-button { margin-top: auto; width: 100%; min-height: calc(var(--composition-container-height) + 1px); // include border in height flex-shrink: 0; align-items: center; border-top: 1px solid var(--border-color); border-radius: 0px; &:not(.disabled) { &:hover { background-color: var(--button-solid-background-hover-color); } } } `; const StyledGroupSettingsItem = styled.div` display: flex; align-items: center; min-height: 3rem; font-size: var(--font-size-md); color: var(--right-panel-item-text-color); background-color: var(--right-panel-item-background-color); border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); width: -webkit-fill-available; padding: 0 var(--margins-md); transition: var(--default-duration); cursor: pointer; &:hover { background-color: var(--right-panel-item-background-hover-color); } `; const StyledName = styled.h4` padding-inline: var(--margins-md); font-size: var(--font-size-md); `; // tslint:disable: cyclomatic-complexity // tslint:disable: max-func-body-length export const OverlayRightPanelSettings = () => { const [documents, setDocuments] = useState>([]); const [media, setMedia] = useState>([]); const dispatch = useDispatch(); const selectedConversation = useSelector(getSelectedConversation); const isShowing = useSelector(isRightPanelShowing); useEffect(() => { let isRunning = true; if (isShowing && selectedConversation) { void getMediaGalleryProps(selectedConversation.id).then(results => { if (isRunning) { if (!_.isEqual(documents, results.documents)) { setDocuments(results.documents); } if (!_.isEqual(media, results.media)) { setMedia(results.media); } } }); } return () => { isRunning = false; return; }; }, [isShowing, selectedConversation?.id]); useInterval(async () => { if (isShowing && selectedConversation) { const results = await getMediaGalleryProps(selectedConversation.id); if (results.documents.length !== documents.length || results.media.length !== media.length) { setDocuments(results.documents); setMedia(results.media); } } }, 10000); if (!selectedConversation) { return null; } const { id, subscriberCount, displayNameInProfile, isKickedFromGroup, left, isPublic, weAreAdmin, isBlocked, isGroup, activeAt, } = selectedConversation; const showMemberCount = !!(subscriberCount && subscriberCount > 0); const commonNoShow = isKickedFromGroup || left || isBlocked || !activeAt; const hasDisappearingMessages = !isPublic && !commonNoShow; const leaveGroupString = isPublic ? window.i18n('leaveGroup') : isKickedFromGroup ? window.i18n('youGotKickedFromGroup') : left ? window.i18n('youLeftTheGroup') : window.i18n('leaveGroup'); const showUpdateGroupNameButton = isGroup && (!isPublic || (isPublic && weAreAdmin)) && !commonNoShow; const showAddRemoveModeratorsButton = weAreAdmin && !commonNoShow && isPublic; const showUpdateGroupMembersButton = !isPublic && isGroup && !commonNoShow; const deleteConvoAction = isPublic ? () => { deleteAllMessagesByConvoIdWithConfirmation(id); } : () => { showLeaveGroupByConvoId(id); }; return ( <> {displayNameInProfile} {showMemberCount && ( <>
{window.i18n('members', [`${subscriberCount}`])}
)} {showUpdateGroupNameButton && ( { await showUpdateGroupNameByConvoId(id); }} > {isPublic ? window.i18n('editGroup') : window.i18n('editGroupName')} )} {showAddRemoveModeratorsButton && ( <> { showAddModeratorsByConvoId(id); }} > {window.i18n('addModerators')} { showRemoveModeratorsByConvoId(id); }} > {window.i18n('removeModerators')} )} {showUpdateGroupMembersButton && ( { await showUpdateGroupMembersByConvoId(id); }} > {window.i18n('groupMembers')} )} {hasDisappearingMessages && ( /* TODO Move ButtonGroup around all settings items */ { dispatch(setRightOverlayMode('disappearing-messages')); }} /> )} {isGroup && ( // tslint:disable-next-line: use-simple-attributes )} ); };