Add badges to avatars in group dialogs
This commit is contained in:
parent
7bb37dc63b
commit
e490d91cc4
11 changed files with 121 additions and 39 deletions
|
@ -4,8 +4,9 @@
|
||||||
import type { ReactChild, ReactNode } from 'react';
|
import type { ReactChild, ReactNode } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType, ThemeType } from '../types/Util';
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
|
import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
|
||||||
import { ModalHost } from './ModalHost';
|
import { ModalHost } from './ModalHost';
|
||||||
import { Button, ButtonVariant } from './Button';
|
import { Button, ButtonVariant } from './Button';
|
||||||
import { Avatar, AvatarSize } from './Avatar';
|
import { Avatar, AvatarSize } from './Avatar';
|
||||||
|
@ -92,20 +93,29 @@ GroupDialog.Paragraph = ({
|
||||||
|
|
||||||
type ContactsPropsType = {
|
type ContactsPropsType = {
|
||||||
contacts: Array<ConversationType>;
|
contacts: Array<ConversationType>;
|
||||||
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
theme: ThemeType;
|
||||||
};
|
};
|
||||||
|
|
||||||
GroupDialog.Contacts = ({ contacts, i18n }: Readonly<ContactsPropsType>) => (
|
GroupDialog.Contacts = ({
|
||||||
|
contacts,
|
||||||
|
getPreferredBadge,
|
||||||
|
i18n,
|
||||||
|
theme,
|
||||||
|
}: Readonly<ContactsPropsType>) => (
|
||||||
<ul className="module-GroupDialog__contacts">
|
<ul className="module-GroupDialog__contacts">
|
||||||
{contacts.map(contact => (
|
{contacts.map(contact => (
|
||||||
<li key={contact.id} className="module-GroupDialog__contacts__contact">
|
<li key={contact.id} className="module-GroupDialog__contacts__contact">
|
||||||
<Avatar
|
<Avatar
|
||||||
acceptedMessageRequest={contact.acceptedMessageRequest}
|
acceptedMessageRequest={contact.acceptedMessageRequest}
|
||||||
avatarPath={contact.avatarPath}
|
avatarPath={contact.avatarPath}
|
||||||
|
badge={getPreferredBadge(contact.badges)}
|
||||||
color={contact.color}
|
color={contact.color}
|
||||||
conversationType={contact.type}
|
conversationType={contact.type}
|
||||||
isMe={contact.isMe}
|
isMe={contact.isMe}
|
||||||
noteToSelf={contact.isMe}
|
noteToSelf={contact.isMe}
|
||||||
|
theme={theme}
|
||||||
title={contact.title}
|
title={contact.title}
|
||||||
unblurredAvatarPath={contact.unblurredAvatarPath}
|
unblurredAvatarPath={contact.unblurredAvatarPath}
|
||||||
sharedGroupNames={contact.sharedGroupNames}
|
sharedGroupNames={contact.sharedGroupNames}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import type { ConversationType } from '../state/ducks/conversations';
|
||||||
import { setupI18n } from '../util/setupI18n';
|
import { setupI18n } from '../util/setupI18n';
|
||||||
import enMessages from '../../_locales/en/messages.json';
|
import enMessages from '../../_locales/en/messages.json';
|
||||||
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
|
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
|
||||||
|
import { ThemeType } from '../types/Util';
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
booleanOr(overrideProps.areWeInvited, false)
|
booleanOr(overrideProps.areWeInvited, false)
|
||||||
),
|
),
|
||||||
droppedMembers: overrideProps.droppedMembers || [contact3, contact1],
|
droppedMembers: overrideProps.droppedMembers || [contact3, contact1],
|
||||||
|
getPreferredBadge: () => undefined,
|
||||||
hasMigrated: boolean(
|
hasMigrated: boolean(
|
||||||
'hasMigrated',
|
'hasMigrated',
|
||||||
booleanOr(overrideProps.hasMigrated, false)
|
booleanOr(overrideProps.hasMigrated, false)
|
||||||
|
@ -52,6 +54,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
invitedMembers: overrideProps.invitedMembers || [contact2],
|
invitedMembers: overrideProps.invitedMembers || [contact2],
|
||||||
migrate: action('migrate'),
|
migrate: action('migrate'),
|
||||||
onClose: action('onClose'),
|
onClose: action('onClose'),
|
||||||
|
theme: ThemeType.light,
|
||||||
});
|
});
|
||||||
|
|
||||||
const stories = storiesOf('Components/GroupV1MigrationDialog', module);
|
const stories = storiesOf('Components/GroupV1MigrationDialog', module);
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
// Copyright 2019-2020 Signal Messenger, LLC
|
// Copyright 2019-2021 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType, ThemeType } from '../types/Util';
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
|
import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
|
||||||
import { GroupDialog } from './GroupDialog';
|
import { GroupDialog } from './GroupDialog';
|
||||||
import { sortByTitle } from '../util/sortByTitle';
|
import { sortByTitle } from '../util/sortByTitle';
|
||||||
|
|
||||||
|
@ -19,7 +20,9 @@ export type DataPropsType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HousekeepingPropsType = {
|
export type HousekeepingPropsType = {
|
||||||
|
readonly getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
readonly i18n: LocalizerType;
|
readonly i18n: LocalizerType;
|
||||||
|
readonly theme: ThemeType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PropsType = DataPropsType & HousekeepingPropsType;
|
export type PropsType = DataPropsType & HousekeepingPropsType;
|
||||||
|
@ -29,11 +32,13 @@ export const GroupV1MigrationDialog: React.FunctionComponent<PropsType> =
|
||||||
const {
|
const {
|
||||||
areWeInvited,
|
areWeInvited,
|
||||||
droppedMembers,
|
droppedMembers,
|
||||||
|
getPreferredBadge,
|
||||||
hasMigrated,
|
hasMigrated,
|
||||||
i18n,
|
i18n,
|
||||||
invitedMembers,
|
invitedMembers,
|
||||||
migrate,
|
migrate,
|
||||||
onClose,
|
onClose,
|
||||||
|
theme,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const title = hasMigrated
|
const title = hasMigrated
|
||||||
|
@ -84,23 +89,39 @@ export const GroupV1MigrationDialog: React.FunctionComponent<PropsType> =
|
||||||
</GroupDialog.Paragraph>
|
</GroupDialog.Paragraph>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{renderMembers(
|
{renderMembers({
|
||||||
invitedMembers,
|
getPreferredBadge,
|
||||||
'GroupV1--Migration--info--invited',
|
i18n,
|
||||||
i18n
|
members: invitedMembers,
|
||||||
)}
|
prefix: 'GroupV1--Migration--info--invited',
|
||||||
{renderMembers(droppedMembers, droppedMembersKey, i18n)}
|
theme,
|
||||||
|
})}
|
||||||
|
{renderMembers({
|
||||||
|
getPreferredBadge,
|
||||||
|
i18n,
|
||||||
|
members: droppedMembers,
|
||||||
|
prefix: droppedMembersKey,
|
||||||
|
theme,
|
||||||
|
})}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</GroupDialog>
|
</GroupDialog>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
function renderMembers(
|
function renderMembers({
|
||||||
members: Array<ConversationType>,
|
getPreferredBadge,
|
||||||
prefix: string,
|
i18n,
|
||||||
i18n: LocalizerType
|
members,
|
||||||
): React.ReactNode {
|
prefix,
|
||||||
|
theme,
|
||||||
|
}: Readonly<{
|
||||||
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
|
i18n: LocalizerType;
|
||||||
|
members: Array<ConversationType>;
|
||||||
|
prefix: string;
|
||||||
|
theme: ThemeType;
|
||||||
|
}>): React.ReactNode {
|
||||||
if (!members.length) {
|
if (!members.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +132,12 @@ function renderMembers(
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GroupDialog.Paragraph>{i18n(key)}</GroupDialog.Paragraph>
|
<GroupDialog.Paragraph>{i18n(key)}</GroupDialog.Paragraph>
|
||||||
<GroupDialog.Contacts contacts={sortByTitle(members)} i18n={i18n} />
|
<GroupDialog.Contacts
|
||||||
|
contacts={sortByTitle(members)}
|
||||||
|
getPreferredBadge={getPreferredBadge}
|
||||||
|
i18n={i18n}
|
||||||
|
theme={theme}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { setupI18n } from '../util/setupI18n';
|
||||||
import enMessages from '../../_locales/en/messages.json';
|
import enMessages from '../../_locales/en/messages.json';
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
|
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
|
||||||
|
import { ThemeType } from '../types/Util';
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
|
@ -27,15 +28,19 @@ const story = storiesOf(
|
||||||
story.add('One contact', () => (
|
story.add('One contact', () => (
|
||||||
<NewlyCreatedGroupInvitedContactsDialog
|
<NewlyCreatedGroupInvitedContactsDialog
|
||||||
contacts={[conversations[0]]}
|
contacts={[conversations[0]]}
|
||||||
|
getPreferredBadge={() => undefined}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={action('onClose')}
|
onClose={action('onClose')}
|
||||||
|
theme={ThemeType.light}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
story.add('Two contacts', () => (
|
story.add('Two contacts', () => (
|
||||||
<NewlyCreatedGroupInvitedContactsDialog
|
<NewlyCreatedGroupInvitedContactsDialog
|
||||||
contacts={conversations}
|
contacts={conversations}
|
||||||
|
getPreferredBadge={() => undefined}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={action('onClose')}
|
onClose={action('onClose')}
|
||||||
|
theme={ThemeType.light}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
import type { FunctionComponent, ReactNode } from 'react';
|
import type { FunctionComponent, ReactNode } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType, ThemeType } from '../types/Util';
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
|
import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
|
||||||
import { Intl } from './Intl';
|
import { Intl } from './Intl';
|
||||||
import { ContactName } from './conversation/ContactName';
|
import { ContactName } from './conversation/ContactName';
|
||||||
import { GroupDialog } from './GroupDialog';
|
import { GroupDialog } from './GroupDialog';
|
||||||
|
@ -13,12 +14,14 @@ import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
contacts: Array<ConversationType>;
|
contacts: Array<ConversationType>;
|
||||||
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
theme: ThemeType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NewlyCreatedGroupInvitedContactsDialog: FunctionComponent<PropsType> =
|
export const NewlyCreatedGroupInvitedContactsDialog: FunctionComponent<PropsType> =
|
||||||
({ contacts, i18n, onClose }) => {
|
({ contacts, getPreferredBadge, i18n, onClose, theme }) => {
|
||||||
let title: string;
|
let title: string;
|
||||||
let body: ReactNode;
|
let body: ReactNode;
|
||||||
if (contacts.length === 1) {
|
if (contacts.length === 1) {
|
||||||
|
@ -57,7 +60,12 @@ export const NewlyCreatedGroupInvitedContactsDialog: FunctionComponent<PropsType
|
||||||
'NewlyCreatedGroupInvitedContactsDialog--body--info-paragraph'
|
'NewlyCreatedGroupInvitedContactsDialog--body--info-paragraph'
|
||||||
)}
|
)}
|
||||||
</GroupDialog.Paragraph>
|
</GroupDialog.Paragraph>
|
||||||
<GroupDialog.Contacts contacts={contacts} i18n={i18n} />
|
<GroupDialog.Contacts
|
||||||
|
contacts={contacts}
|
||||||
|
getPreferredBadge={getPreferredBadge}
|
||||||
|
i18n={i18n}
|
||||||
|
theme={theme}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { setupI18n } from '../../util/setupI18n';
|
||||||
import enMessages from '../../../_locales/en/messages.json';
|
import enMessages from '../../../_locales/en/messages.json';
|
||||||
import type { PropsType } from './GroupV1Migration';
|
import type { PropsType } from './GroupV1Migration';
|
||||||
import { GroupV1Migration } from './GroupV1Migration';
|
import { GroupV1Migration } from './GroupV1Migration';
|
||||||
|
import { ThemeType } from '../../types/Util';
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
|
@ -33,8 +34,10 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
isBoolean(overrideProps.areWeInvited) ? overrideProps.areWeInvited : false
|
isBoolean(overrideProps.areWeInvited) ? overrideProps.areWeInvited : false
|
||||||
),
|
),
|
||||||
droppedMembers: overrideProps.droppedMembers || [contact1],
|
droppedMembers: overrideProps.droppedMembers || [contact1],
|
||||||
|
getPreferredBadge: () => undefined,
|
||||||
i18n,
|
i18n,
|
||||||
invitedMembers: overrideProps.invitedMembers || [contact2],
|
invitedMembers: overrideProps.invitedMembers || [contact2],
|
||||||
|
theme: ThemeType.light,
|
||||||
});
|
});
|
||||||
|
|
||||||
const stories = storiesOf('Components/Conversation/GroupV1Migration', module);
|
const stories = storiesOf('Components/Conversation/GroupV1Migration', module);
|
||||||
|
|
|
@ -5,8 +5,9 @@ import * as React from 'react';
|
||||||
|
|
||||||
import { Button, ButtonSize, ButtonVariant } from '../Button';
|
import { Button, ButtonSize, ButtonVariant } from '../Button';
|
||||||
import { SystemMessage } from './SystemMessage';
|
import { SystemMessage } from './SystemMessage';
|
||||||
import type { LocalizerType } from '../../types/Util';
|
import type { LocalizerType, ThemeType } from '../../types/Util';
|
||||||
import type { ConversationType } from '../../state/ducks/conversations';
|
import type { ConversationType } from '../../state/ducks/conversations';
|
||||||
|
import type { PreferredBadgeSelectorType } from '../../state/selectors/badges';
|
||||||
import { Intl } from '../Intl';
|
import { Intl } from '../Intl';
|
||||||
import { ContactName } from './ContactName';
|
import { ContactName } from './ContactName';
|
||||||
import { GroupV1MigrationDialog } from '../GroupV1MigrationDialog';
|
import { GroupV1MigrationDialog } from '../GroupV1MigrationDialog';
|
||||||
|
@ -19,13 +20,22 @@ export type PropsDataType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PropsHousekeepingType = {
|
export type PropsHousekeepingType = {
|
||||||
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
theme: ThemeType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PropsType = PropsDataType & PropsHousekeepingType;
|
export type PropsType = PropsDataType & PropsHousekeepingType;
|
||||||
|
|
||||||
export function GroupV1Migration(props: PropsType): React.ReactElement {
|
export function GroupV1Migration(props: PropsType): React.ReactElement {
|
||||||
const { areWeInvited, droppedMembers, i18n, invitedMembers } = props;
|
const {
|
||||||
|
areWeInvited,
|
||||||
|
droppedMembers,
|
||||||
|
getPreferredBadge,
|
||||||
|
i18n,
|
||||||
|
invitedMembers,
|
||||||
|
theme,
|
||||||
|
} = props;
|
||||||
const [showingDialog, setShowingDialog] = React.useState(false);
|
const [showingDialog, setShowingDialog] = React.useState(false);
|
||||||
|
|
||||||
const showDialog = React.useCallback(() => {
|
const showDialog = React.useCallback(() => {
|
||||||
|
@ -77,11 +87,13 @@ export function GroupV1Migration(props: PropsType): React.ReactElement {
|
||||||
<GroupV1MigrationDialog
|
<GroupV1MigrationDialog
|
||||||
areWeInvited={areWeInvited}
|
areWeInvited={areWeInvited}
|
||||||
droppedMembers={droppedMembers}
|
droppedMembers={droppedMembers}
|
||||||
|
getPreferredBadge={getPreferredBadge}
|
||||||
hasMigrated
|
hasMigrated
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
invitedMembers={invitedMembers}
|
invitedMembers={invitedMembers}
|
||||||
migrate={() => log.warn('GroupV1Migration: Modal called migrate()')}
|
migrate={() => log.warn('GroupV1Migration: Modal called migrate()')}
|
||||||
onClose={dismissDialog}
|
onClose={dismissDialog}
|
||||||
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -457,8 +457,10 @@ const renderTypingBubble = () => (
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
const useProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
|
getPreferredBadge: () => undefined,
|
||||||
i18n,
|
i18n,
|
||||||
|
theme: React.useContext(StorybookThemeContext),
|
||||||
|
|
||||||
haveNewest: boolean('haveNewest', overrideProps.haveNewest !== false),
|
haveNewest: boolean('haveNewest', overrideProps.haveNewest !== false),
|
||||||
haveOldest: boolean('haveOldest', overrideProps.haveOldest !== false),
|
haveOldest: boolean('haveOldest', overrideProps.haveOldest !== false),
|
||||||
|
@ -494,13 +496,13 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('Oldest and Newest', () => {
|
story.add('Oldest and Newest', () => {
|
||||||
const props = createProps();
|
const props = useProps();
|
||||||
|
|
||||||
return <Timeline {...props} />;
|
return <Timeline {...props} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('With active message request', () => {
|
story.add('With active message request', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
isIncomingMessageRequest: true,
|
isIncomingMessageRequest: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -508,7 +510,7 @@ story.add('With active message request', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('Without Newest Message', () => {
|
story.add('Without Newest Message', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
haveNewest: false,
|
haveNewest: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -516,7 +518,7 @@ story.add('Without Newest Message', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('Without newest message, active message request', () => {
|
story.add('Without newest message, active message request', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
haveOldest: false,
|
haveOldest: false,
|
||||||
isIncomingMessageRequest: true,
|
isIncomingMessageRequest: true,
|
||||||
});
|
});
|
||||||
|
@ -525,7 +527,7 @@ story.add('Without newest message, active message request', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('Without Oldest Message', () => {
|
story.add('Without Oldest Message', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
haveOldest: false,
|
haveOldest: false,
|
||||||
scrollToIndex: -1,
|
scrollToIndex: -1,
|
||||||
});
|
});
|
||||||
|
@ -534,7 +536,7 @@ story.add('Without Oldest Message', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('Empty (just hero)', () => {
|
story.add('Empty (just hero)', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
items: [],
|
items: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -542,7 +544,7 @@ story.add('Empty (just hero)', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('Last Seen', () => {
|
story.add('Last Seen', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
oldestUnreadIndex: 13,
|
oldestUnreadIndex: 13,
|
||||||
totalUnread: 2,
|
totalUnread: 2,
|
||||||
});
|
});
|
||||||
|
@ -551,7 +553,7 @@ story.add('Last Seen', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('Target Index to Top', () => {
|
story.add('Target Index to Top', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
scrollToIndex: 0,
|
scrollToIndex: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -559,7 +561,7 @@ story.add('Target Index to Top', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('Typing Indicator', () => {
|
story.add('Typing Indicator', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
typingContactId: UUID.generate().toString(),
|
typingContactId: UUID.generate().toString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -567,7 +569,7 @@ story.add('Typing Indicator', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('With invited contacts for a newly-created group', () => {
|
story.add('With invited contacts for a newly-created group', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
invitedContactsForNewlyCreatedGroup: [
|
invitedContactsForNewlyCreatedGroup: [
|
||||||
getDefaultConversation({
|
getDefaultConversation({
|
||||||
id: 'abc123',
|
id: 'abc123',
|
||||||
|
@ -584,7 +586,7 @@ story.add('With invited contacts for a newly-created group', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('With "same name in direct conversation" warning', () => {
|
story.add('With "same name in direct conversation" warning', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
warning: {
|
warning: {
|
||||||
type: ContactSpoofingType.DirectConversationWithSameTitle,
|
type: ContactSpoofingType.DirectConversationWithSameTitle,
|
||||||
safeConversation: getDefaultConversation(),
|
safeConversation: getDefaultConversation(),
|
||||||
|
@ -596,7 +598,7 @@ story.add('With "same name in direct conversation" warning', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
story.add('With "same name in group conversation" warning', () => {
|
story.add('With "same name in group conversation" warning', () => {
|
||||||
const props = createProps({
|
const props = useProps({
|
||||||
warning: {
|
warning: {
|
||||||
type: ContactSpoofingType.MultipleGroupMembersWithSameTitle,
|
type: ContactSpoofingType.MultipleGroupMembersWithSameTitle,
|
||||||
acknowledgedGroupNameCollisions: {},
|
acknowledgedGroupNameCollisions: {},
|
||||||
|
|
|
@ -17,8 +17,9 @@ import Measure from 'react-measure';
|
||||||
|
|
||||||
import { ScrollDownButton } from './ScrollDownButton';
|
import { ScrollDownButton } from './ScrollDownButton';
|
||||||
|
|
||||||
import type { AssertProps, LocalizerType } from '../../types/Util';
|
import type { AssertProps, LocalizerType, ThemeType } from '../../types/Util';
|
||||||
import type { ConversationType } from '../../state/ducks/conversations';
|
import type { ConversationType } from '../../state/ducks/conversations';
|
||||||
|
import type { PreferredBadgeSelectorType } from '../../state/selectors/badges';
|
||||||
import { assert } from '../../util/assert';
|
import { assert } from '../../util/assert';
|
||||||
import { missingCaseError } from '../../util/missingCaseError';
|
import { missingCaseError } from '../../util/missingCaseError';
|
||||||
import { createRefMerger } from '../../util/refMerger';
|
import { createRefMerger } from '../../util/refMerger';
|
||||||
|
@ -102,7 +103,9 @@ type PropsHousekeepingType = {
|
||||||
warning?: WarningType;
|
warning?: WarningType;
|
||||||
contactSpoofingReview?: ContactSpoofingReviewPropType;
|
contactSpoofingReview?: ContactSpoofingReviewPropType;
|
||||||
|
|
||||||
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
theme: ThemeType;
|
||||||
|
|
||||||
renderItem: (props: {
|
renderItem: (props: {
|
||||||
actionProps: PropsActionsType;
|
actionProps: PropsActionsType;
|
||||||
|
@ -1312,6 +1315,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
clearInvitedUuidsForNewlyCreatedGroup,
|
clearInvitedUuidsForNewlyCreatedGroup,
|
||||||
closeContactSpoofingReview,
|
closeContactSpoofingReview,
|
||||||
contactSpoofingReview,
|
contactSpoofingReview,
|
||||||
|
getPreferredBadge,
|
||||||
i18n,
|
i18n,
|
||||||
id,
|
id,
|
||||||
invitedContactsForNewlyCreatedGroup,
|
invitedContactsForNewlyCreatedGroup,
|
||||||
|
@ -1325,6 +1329,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
removeMember,
|
removeMember,
|
||||||
reviewGroupMemberNameCollision,
|
reviewGroupMemberNameCollision,
|
||||||
reviewMessageRequestNameCollision,
|
reviewMessageRequestNameCollision,
|
||||||
|
theme,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const {
|
const {
|
||||||
shouldShowScrollDownButton,
|
shouldShowScrollDownButton,
|
||||||
|
@ -1561,8 +1566,10 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
{Boolean(invitedContactsForNewlyCreatedGroup.length) && (
|
{Boolean(invitedContactsForNewlyCreatedGroup.length) && (
|
||||||
<NewlyCreatedGroupInvitedContactsDialog
|
<NewlyCreatedGroupInvitedContactsDialog
|
||||||
contacts={invitedContactsForNewlyCreatedGroup}
|
contacts={invitedContactsForNewlyCreatedGroup}
|
||||||
|
getPreferredBadge={getPreferredBadge}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={clearInvitedUuidsForNewlyCreatedGroup}
|
onClose={clearInvitedUuidsForNewlyCreatedGroup}
|
||||||
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2020 Signal Messenger, LLC
|
// Copyright 2020-2021 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
@ -7,9 +7,10 @@ import type { PropsType as GroupV1MigrationDialogPropsType } from '../../compone
|
||||||
import { GroupV1MigrationDialog } from '../../components/GroupV1MigrationDialog';
|
import { GroupV1MigrationDialog } from '../../components/GroupV1MigrationDialog';
|
||||||
import type { ConversationType } from '../ducks/conversations';
|
import type { ConversationType } from '../ducks/conversations';
|
||||||
import type { StateType } from '../reducer';
|
import type { StateType } from '../reducer';
|
||||||
|
import { getPreferredBadgeSelector } from '../selectors/badges';
|
||||||
import { getConversationSelector } from '../selectors/conversations';
|
import { getConversationSelector } from '../selectors/conversations';
|
||||||
|
|
||||||
import { getIntl } from '../selectors/user';
|
import { getIntl, getTheme } from '../selectors/user';
|
||||||
import * as log from '../../logging/log';
|
import * as log from '../../logging/log';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
|
@ -17,7 +18,7 @@ export type PropsType = {
|
||||||
readonly invitedMemberIds: Array<string>;
|
readonly invitedMemberIds: Array<string>;
|
||||||
} & Omit<
|
} & Omit<
|
||||||
GroupV1MigrationDialogPropsType,
|
GroupV1MigrationDialogPropsType,
|
||||||
'i18n' | 'droppedMembers' | 'invitedMembers'
|
'i18n' | 'droppedMembers' | 'invitedMembers' | 'theme' | 'getPreferredBadge'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const mapStateToProps = (
|
const mapStateToProps = (
|
||||||
|
@ -44,8 +45,10 @@ const mapStateToProps = (
|
||||||
return {
|
return {
|
||||||
...props,
|
...props,
|
||||||
droppedMembers,
|
droppedMembers,
|
||||||
|
getPreferredBadge: getPreferredBadgeSelector(state),
|
||||||
invitedMembers,
|
invitedMembers,
|
||||||
i18n: getIntl(state),
|
i18n: getIntl(state),
|
||||||
|
theme: getTheme(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { Timeline } from '../../components/conversation/Timeline';
|
||||||
import type { StateType } from '../reducer';
|
import type { StateType } from '../reducer';
|
||||||
import type { ConversationType } from '../ducks/conversations';
|
import type { ConversationType } from '../ducks/conversations';
|
||||||
|
|
||||||
import { getIntl } from '../selectors/user';
|
import { getIntl, getTheme } from '../selectors/user';
|
||||||
import {
|
import {
|
||||||
getConversationByUuidSelector,
|
getConversationByUuidSelector,
|
||||||
getConversationMessagesSelector,
|
getConversationMessagesSelector,
|
||||||
|
@ -48,6 +48,7 @@ import {
|
||||||
} from '../../util/groupMemberNameCollisions';
|
} from '../../util/groupMemberNameCollisions';
|
||||||
import { ContactSpoofingType } from '../../util/contactSpoofing';
|
import { ContactSpoofingType } from '../../util/contactSpoofing';
|
||||||
import type { WidthBreakpoint } from '../../components/_util';
|
import type { WidthBreakpoint } from '../../components/_util';
|
||||||
|
import { getPreferredBadgeSelector } from '../selectors/badges';
|
||||||
|
|
||||||
type ExternalProps = {
|
type ExternalProps = {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -313,7 +314,9 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => {
|
||||||
warning: getWarning(conversation, state),
|
warning: getWarning(conversation, state),
|
||||||
contactSpoofingReview: getContactSpoofingReview(id, state),
|
contactSpoofingReview: getContactSpoofingReview(id, state),
|
||||||
|
|
||||||
|
getPreferredBadge: getPreferredBadgeSelector(state),
|
||||||
i18n: getIntl(state),
|
i18n: getIntl(state),
|
||||||
|
theme: getTheme(state),
|
||||||
renderItem,
|
renderItem,
|
||||||
renderLastSeenIndicator,
|
renderLastSeenIndicator,
|
||||||
renderHeroRow,
|
renderHeroRow,
|
||||||
|
|
Loading…
Add table
Reference in a new issue