Support for creating New Groups

This commit is contained in:
Evan Hahn 2021-03-03 14:09:58 -06:00 committed by Josh Perez
parent 1934120e46
commit 5de4babc0d
56 changed files with 6222 additions and 526 deletions

View file

@ -7,20 +7,34 @@ import { LocalizerType } from '../../types/Util';
import { Emojify } from './Emojify';
export type PropsType = {
firstName?: string;
i18n: LocalizerType;
title: string;
module?: string;
name?: string;
phoneNumber?: string;
preferFirstName?: boolean;
profileName?: string;
title: string;
};
export const ContactName = ({ module, title }: PropsType): JSX.Element => {
export const ContactName = ({
firstName,
module,
preferFirstName,
title,
}: PropsType): JSX.Element => {
const prefix = module || 'module-contact-name';
let text: string;
if (preferFirstName) {
text = firstName || title || '';
} else {
text = title || '';
}
return (
<span className={prefix} dir="auto">
<Emojify text={title || ''} />
<Emojify text={text} />
</span>
);
};

View file

@ -7,7 +7,6 @@ import { LocalizerType } from '../../types/Util';
import { ConversationType } from '../../state/ducks/conversations';
import { Intl } from '../Intl';
import { ContactName } from './ContactName';
import { ModalHost } from '../ModalHost';
import { GroupV1MigrationDialog } from '../GroupV1MigrationDialog';
export type PropsDataType = {
@ -58,19 +57,17 @@ export function GroupV1Migration(props: PropsType): React.ReactElement {
{i18n('GroupV1--Migration--learn-more')}
</button>
{showingDialog ? (
<ModalHost onClose={dismissDialog}>
<GroupV1MigrationDialog
areWeInvited={areWeInvited}
droppedMembers={droppedMembers}
hasMigrated
i18n={i18n}
invitedMembers={invitedMembers}
migrate={() =>
window.log.warn('GroupV1Migration: Modal called migrate()')
}
onClose={dismissDialog}
/>
</ModalHost>
<GroupV1MigrationDialog
areWeInvited={areWeInvited}
droppedMembers={droppedMembers}
hasMigrated
i18n={i18n}
invitedMembers={invitedMembers}
migrate={() =>
window.log.warn('GroupV1Migration: Modal called migrate()')
}
onClose={dismissDialog}
/>
) : null}
</div>
);

View file

@ -1,4 +1,4 @@
// Copyright 2020 Signal Messenger, LLC
// Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react';
@ -211,6 +211,9 @@ const items: Record<string, TimelineItemType> = {
const actions = () => ({
clearChangedMessages: action('clearChangedMessages'),
clearInvitedConversationsForNewlyCreatedGroup: action(
'clearInvitedConversationsForNewlyCreatedGroup'
),
setLoadCountdownStart: action('setLoadCountdownStart'),
setIsNearBottom: action('setIsNearBottom'),
loadAndScroll: action('loadAndScroll'),
@ -299,6 +302,8 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
oldestUnreadIndex:
number('oldestUnreadIndex', overrideProps.oldestUnreadIndex || 0) ||
undefined,
invitedContactsForNewlyCreatedGroup:
overrideProps.invitedContactsForNewlyCreatedGroup || [],
id: '',
renderItem,
@ -361,3 +366,22 @@ story.add('Without Oldest Message', () => {
return <Timeline {...props} />;
});
story.add('With invited contacts for a newly-created group', () => {
const props = createProps({
invitedContactsForNewlyCreatedGroup: [
{
id: 'abc123',
title: 'John Bon Bon Jovi',
type: 'direct',
},
{
id: 'def456',
title: 'Bon John Bon Jovi',
type: 'direct',
},
],
});
return <Timeline {...props} />;
});

View file

@ -15,9 +15,11 @@ import {
import { ScrollDownButton } from './ScrollDownButton';
import { LocalizerType } from '../../types/Util';
import { ConversationType } from '../../state/ducks/conversations';
import { PropsActions as MessageActionsType } from './Message';
import { PropsActions as SafetyNumberActionsType } from './SafetyNumberNotification';
import { NewlyCreatedGroupInvitedContactsDialog } from '../NewlyCreatedGroupInvitedContactsDialog';
const AT_BOTTOM_THRESHOLD = 15;
const NEAR_BOTTOM_THRESHOLD = 15;
@ -48,6 +50,7 @@ type PropsHousekeepingType = {
isGroupV1AndDisabled?: boolean;
selectedMessageId?: string;
invitedContactsForNewlyCreatedGroup: Array<ConversationType>;
i18n: LocalizerType;
@ -68,6 +71,7 @@ type PropsHousekeepingType = {
type PropsActionsType = {
clearChangedMessages: (conversationId: string) => unknown;
clearInvitedConversationsForNewlyCreatedGroup: () => void;
setLoadCountdownStart: (
conversationId: string,
loadCountdownStart?: number
@ -1063,7 +1067,14 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
};
public render(): JSX.Element | null {
const { i18n, id, items, isGroupV1AndDisabled } = this.props;
const {
clearInvitedConversationsForNewlyCreatedGroup,
i18n,
id,
items,
isGroupV1AndDisabled,
invitedContactsForNewlyCreatedGroup,
} = this.props;
const {
shouldShowScrollDownButton,
areUnreadBelowCurrentPosition,
@ -1077,60 +1088,70 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
}
return (
<div
className={classNames(
'module-timeline',
isGroupV1AndDisabled ? 'module-timeline--disabled' : null
)}
role="presentation"
tabIndex={-1}
onBlur={this.handleBlur}
onKeyDown={this.handleKeyDown}
>
<AutoSizer>
{({ height, width }) => {
if (this.mostRecentWidth && this.mostRecentWidth !== width) {
this.resizeFlag = true;
<>
<div
className={classNames(
'module-timeline',
isGroupV1AndDisabled ? 'module-timeline--disabled' : null
)}
role="presentation"
tabIndex={-1}
onBlur={this.handleBlur}
onKeyDown={this.handleKeyDown}
>
<AutoSizer>
{({ height, width }) => {
if (this.mostRecentWidth && this.mostRecentWidth !== width) {
this.resizeFlag = true;
setTimeout(this.resize, 0);
} else if (
this.mostRecentHeight &&
this.mostRecentHeight !== height
) {
setTimeout(this.onHeightOnlyChange, 0);
}
setTimeout(this.resize, 0);
} else if (
this.mostRecentHeight &&
this.mostRecentHeight !== height
) {
setTimeout(this.onHeightOnlyChange, 0);
}
this.mostRecentWidth = width;
this.mostRecentHeight = height;
this.mostRecentWidth = width;
this.mostRecentHeight = height;
return (
<List
deferredMeasurementCache={this.cellSizeCache}
height={height}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onScroll={this.onScroll as any}
overscanRowCount={10}
ref={this.listRef}
rowCount={rowCount}
rowHeight={this.cellSizeCache.rowHeight}
rowRenderer={this.rowRenderer}
scrollToAlignment="start"
scrollToIndex={scrollToIndex}
tabIndex={-1}
width={width}
/>
);
}}
</AutoSizer>
{shouldShowScrollDownButton ? (
<ScrollDownButton
conversationId={id}
withNewMessages={areUnreadBelowCurrentPosition}
scrollDown={this.onClickScrollDownButton}
return (
<List
deferredMeasurementCache={this.cellSizeCache}
height={height}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onScroll={this.onScroll as any}
overscanRowCount={10}
ref={this.listRef}
rowCount={rowCount}
rowHeight={this.cellSizeCache.rowHeight}
rowRenderer={this.rowRenderer}
scrollToAlignment="start"
scrollToIndex={scrollToIndex}
tabIndex={-1}
width={width}
/>
);
}}
</AutoSizer>
{shouldShowScrollDownButton ? (
<ScrollDownButton
conversationId={id}
withNewMessages={areUnreadBelowCurrentPosition}
scrollDown={this.onClickScrollDownButton}
i18n={i18n}
/>
) : null}
</div>
{Boolean(invitedContactsForNewlyCreatedGroup.length) && (
<NewlyCreatedGroupInvitedContactsDialog
contacts={invitedContactsForNewlyCreatedGroup}
i18n={i18n}
onClose={clearInvitedConversationsForNewlyCreatedGroup}
/>
) : null}
</div>
)}
</>
);
}
}