session-desktop/ts/components/session/SessionGroupSettings.tsx

339 lines
9.1 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
import { Avatar } from '../Avatar';
2020-01-13 05:50:18 +01:00
import {
SessionButton,
SessionButtonColor,
SessionButtonType,
} from './SessionButton';
import { SessionDropdown } from './SessionDropdown';
import { MediaGallery } from '../conversation/media-gallery/MediaGallery';
import _ from 'lodash';
import { TimerOption } from '../conversation/ConversationHeader';
interface Props {
2020-01-13 05:50:18 +01:00
id: string;
name: string;
memberCount: number;
description: string;
avatarPath: string;
timerOptions: Array<TimerOption>;
isPublic: boolean;
isAdmin: boolean;
2020-02-19 01:27:37 +01:00
amMod: boolean;
2020-01-13 05:50:18 +01:00
onGoBack: () => void;
onInviteFriends: () => void;
onLeaveGroup: () => void;
onUpdateGroupName: () => void;
onUpdateGroupMembers: () => void;
onShowLightBox: (options: any) => void;
onSetDisappearingMessages: (seconds: number) => void;
}
export class SessionGroupSettings extends React.Component<Props, any> {
2020-01-13 05:50:18 +01:00
public constructor(props: Props) {
super(props);
this.state = {
documents: Array<any>(),
media: Array<any>(),
onItemClick: undefined,
};
}
public componentWillMount() {
this.getMediaGalleryProps()
.then(({ documents, media, onItemClick }) => {
this.setState({
documents,
media,
onItemClick,
});
})
.ignore();
}
2020-01-30 01:39:46 +01:00
public componentDidUpdate() {
const mediaScanInterval = 1000;
setTimeout(() => {
this.getMediaGalleryProps()
.then(({ documents, media, onItemClick }) => {
this.setState({
documents,
media,
onItemClick,
});
})
.ignore();
}, mediaScanInterval);
2020-01-30 01:39:46 +01:00
}
2020-01-13 05:50:18 +01:00
public async getMediaGalleryProps() {
// We fetch more documents than media as they dont require to be loaded
// into memory right away. Revisit this once we have infinite scrolling:
const DEFAULT_MEDIA_FETCH_COUNT = 50;
const DEFAULT_DOCUMENTS_FETCH_COUNT = 150;
const conversationId = this.props.id;
const rawMedia = await window.Signal.Data.getMessagesWithVisualMediaAttachments(
conversationId,
{
limit: DEFAULT_MEDIA_FETCH_COUNT,
MessageCollection: window.Whisper.MessageCollection,
}
);
const rawDocuments = await window.Signal.Data.getMessagesWithFileAttachments(
conversationId,
{
limit: DEFAULT_DOCUMENTS_FETCH_COUNT,
MessageCollection: window.Whisper.MessageCollection,
}
);
// First we upgrade these messages to ensure that they have thumbnails
const max = rawMedia.length;
for (let i = 0; i < max; i += 1) {
const message = rawMedia[i];
const { schemaVersion } = message;
if (schemaVersion < message.VERSION_NEEDED_FOR_DISPLAY) {
// Yep, we really do want to wait for each of these
// eslint-disable-next-line no-await-in-loop
rawMedia[i] = await window.Signal.Migrations.upgradeMessageSchema(
message
);
2020-01-13 05:50:18 +01:00
// eslint-disable-next-line no-await-in-loop
await window.Signal.Data.saveMessage(rawMedia[i], {
Message: window.Whisper.Message,
});
}
}
2020-01-13 05:50:18 +01:00
// tslint:disable-next-line: underscore-consistent-invocation
const media = _.flatten(
rawMedia.map((message: { attachments: any }) => {
const { attachments } = message;
return (attachments || [])
.filter(
(attachment: { thumbnail: any; pending: any; error: any }) =>
attachment.thumbnail && !attachment.pending && !attachment.error
)
.map(
(
attachment: { path?: any; contentType?: any; thumbnail?: any },
index: any
) => {
const { thumbnail } = attachment;
return {
objectURL: window.Signal.Migrations.getAbsoluteAttachmentPath(
attachment.path
),
thumbnailObjectUrl: thumbnail
? window.Signal.Migrations.getAbsoluteAttachmentPath(
thumbnail.path
)
: null,
contentType: attachment.contentType,
index,
attachment,
message,
};
}
2020-01-13 05:50:18 +01:00
);
})
);
2020-01-13 05:50:18 +01:00
// Unlike visual media, only one non-image attachment is supported
const documents = rawDocuments.map(
(message: { attachments: Array<any> }) => {
const attachments = message.attachments || [];
const attachment = attachments[0];
2020-01-13 05:50:18 +01:00
return {
contentType: attachment.contentType,
index: 0,
attachment,
message,
};
2020-01-13 05:50:18 +01:00
}
);
const saveAttachment = async ({ attachment, message }: any = {}) => {
const timestamp = message.received_at;
window.Signal.Types.Attachment.save({
attachment,
document,
getAbsolutePath: window.Signal.Migrations.getAbsoluteAttachmentPath,
timestamp,
});
};
const onItemClick = async ({ message, attachment, type }: any) => {
switch (type) {
case 'documents': {
2020-01-13 05:50:18 +01:00
saveAttachment({ message, attachment }).ignore();
break;
}
2020-01-13 08:09:31 +01:00
case 'media': {
const lightBoxOptions = {
media,
attachment,
message,
};
this.onShowLightBox(lightBoxOptions);
break;
}
2020-01-13 05:50:18 +01:00
default:
throw new TypeError(`Unknown attachment type: '${type}'`);
}
};
return {
2020-01-13 08:09:31 +01:00
media,
documents,
onItemClick,
2020-01-13 05:50:18 +01:00
};
}
public onShowLightBox(options: any) {
this.props.onShowLightBox(options);
}
2020-01-13 05:50:18 +01:00
public render() {
const {
memberCount,
name,
timerOptions,
onLeaveGroup,
isPublic,
isAdmin,
2020-02-19 01:27:37 +01:00
amMod,
} = this.props;
2020-01-13 05:50:18 +01:00
const { documents, media, onItemClick } = this.state;
2020-01-14 02:01:35 +01:00
const showMemberCount = !!(memberCount && memberCount > 0);
const hasDisappearingMessages = !isPublic;
2020-01-24 01:46:34 +01:00
const leaveGroupString = isPublic
? window.i18n('leaveOpenGroup')
: window.i18n('leaveClosedGroup');
2020-01-13 05:50:18 +01:00
const disappearingMessagesOptions = timerOptions.map(option => {
return {
content: option.name,
onClick: () => {
this.props.onSetDisappearingMessages(option.value);
},
};
});
2020-02-19 01:27:37 +01:00
const showUpdateGroupNameButton = isPublic ? amMod : isAdmin;
const showUpdateGroupMembersButton = !isPublic && isAdmin;
2020-01-13 05:50:18 +01:00
return (
<div className="group-settings">
{this.renderHeader()}
<h2>{name}</h2>
2020-01-14 02:01:35 +01:00
{showMemberCount && (
2020-02-05 00:08:55 +01:00
<>
<div className="spacer-lg" />
<div role="button" className="text-subtle">
2020-02-05 00:08:55 +01:00
{window.i18n('members', memberCount)}
</div>
2020-02-05 04:19:01 +01:00
<div className="spacer-lg" />
2020-02-05 00:08:55 +01:00
</>
2020-01-13 05:50:18 +01:00
)}
<input
className="description"
placeholder={window.i18n('description')}
/>
2020-02-19 01:27:37 +01:00
{showUpdateGroupNameButton && (
<div
className="group-settings-item"
role="button"
onClick={this.props.onUpdateGroupName}
>
2020-02-19 23:24:07 +01:00
{isPublic
? window.i18n('editGroupNameOrPicture')
: window.i18n('editGroupName')}
2020-02-19 01:27:37 +01:00
</div>
)}
{showUpdateGroupMembersButton && (
<div
className="group-settings-item"
role="button"
onClick={this.props.onUpdateGroupMembers}
>
{window.i18n('showMembers')}
</div>
)}
{/*<div className="group-settings-item">
2020-01-13 05:50:18 +01:00
{window.i18n('notifications')}
</div>
*/}
{hasDisappearingMessages && (
<SessionDropdown
label={window.i18n('disappearingMessages')}
options={disappearingMessagesOptions}
/>
)}
2020-01-13 05:50:18 +01:00
<MediaGallery
documents={documents}
media={media}
onItemClick={onItemClick}
/>
<SessionButton
text={leaveGroupString}
2020-01-13 05:50:18 +01:00
buttonColor={SessionButtonColor.Danger}
buttonType={SessionButtonType.SquareOutline}
onClick={onLeaveGroup}
/>
</div>
);
}
private renderHeader() {
const {
id,
onGoBack,
onInviteFriends,
avatarPath,
isAdmin,
isPublic,
} = this.props;
const showInviteFriends = isPublic || isAdmin;
2020-01-13 05:50:18 +01:00
return (
<div className="group-settings-header">
<SessionIconButton
iconType={SessionIconType.Chevron}
iconSize={SessionIconSize.Medium}
iconRotation={90}
onClick={onGoBack}
/>
<Avatar
avatarPath={avatarPath}
phoneNumber={id}
conversationType="group"
size={80}
/>
<div className="invite-friends-container">
{showInviteFriends && (
<SessionIconButton
iconType={SessionIconType.AddUser}
iconSize={SessionIconSize.Medium}
onClick={onInviteFriends}
/>
)}
</div>
2020-01-13 05:50:18 +01:00
</div>
);
}
}