Restore ability to message someone from embedded contact
This commit is contained in:
parent
f77175f6b3
commit
302604f67e
18 changed files with 311 additions and 236 deletions
|
@ -1,179 +0,0 @@
|
|||
// Copyright 2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { boolean, number } from '@storybook/addon-knobs';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
|
||||
import type { Props } from './EmbeddedContact';
|
||||
import { EmbeddedContact } from './EmbeddedContact';
|
||||
import { setupI18n } from '../../util/setupI18n';
|
||||
import enMessages from '../../../_locales/en/messages.json';
|
||||
import { ContactFormType } from '../../types/EmbeddedContact';
|
||||
import { IMAGE_GIF } from '../../types/MIME';
|
||||
|
||||
import { fakeAttachment } from '../../test-both/helpers/fakeAttachment';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
const story = storiesOf('Components/Conversation/EmbeddedContact', module);
|
||||
|
||||
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||
contact: overrideProps.contact || {},
|
||||
i18n,
|
||||
isIncoming: boolean('isIncoming', overrideProps.isIncoming || false),
|
||||
onClick: action('onClick'),
|
||||
tabIndex: number('tabIndex', overrideProps.tabIndex || 0),
|
||||
withContentAbove: boolean(
|
||||
'withContentAbove',
|
||||
overrideProps.withContentAbove || false
|
||||
),
|
||||
withContentBelow: boolean(
|
||||
'withContentBelow',
|
||||
overrideProps.withContentBelow || false
|
||||
),
|
||||
});
|
||||
|
||||
const fullContact = {
|
||||
avatar: {
|
||||
avatar: fakeAttachment({
|
||||
path: '/fixtures/giphy-GVNvOUpeYmI7e.gif',
|
||||
contentType: IMAGE_GIF,
|
||||
}),
|
||||
isProfile: true,
|
||||
},
|
||||
email: [
|
||||
{
|
||||
value: 'jerjor@fakemail.com',
|
||||
type: ContactFormType.HOME,
|
||||
},
|
||||
],
|
||||
name: {
|
||||
givenName: 'Jerry',
|
||||
familyName: 'Jordan',
|
||||
prefix: 'Dr.',
|
||||
suffix: 'Jr.',
|
||||
middleName: 'James',
|
||||
displayName: 'Jerry Jordan',
|
||||
},
|
||||
number: [
|
||||
{
|
||||
value: '555-444-2323',
|
||||
type: ContactFormType.HOME,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
story.add('Full Contact', () => {
|
||||
const props = createProps({
|
||||
contact: fullContact,
|
||||
});
|
||||
return <EmbeddedContact {...props} />;
|
||||
});
|
||||
|
||||
story.add('Only Email', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
email: fullContact.email,
|
||||
},
|
||||
});
|
||||
|
||||
return <EmbeddedContact {...props} />;
|
||||
});
|
||||
|
||||
story.add('Given Name', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: {
|
||||
givenName: 'Jerry',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return <EmbeddedContact {...props} />;
|
||||
});
|
||||
|
||||
story.add('Organization', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
organization: 'Company 5',
|
||||
},
|
||||
});
|
||||
|
||||
return <EmbeddedContact {...props} />;
|
||||
});
|
||||
|
||||
story.add('Given + Family Name', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: {
|
||||
givenName: 'Jerry',
|
||||
familyName: 'FamilyName',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return <EmbeddedContact {...props} />;
|
||||
});
|
||||
|
||||
story.add('Family Name', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: {
|
||||
familyName: 'FamilyName',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return <EmbeddedContact {...props} />;
|
||||
});
|
||||
|
||||
story.add('Loading Avatar', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: {
|
||||
displayName: 'Jerry Jordan',
|
||||
},
|
||||
avatar: {
|
||||
avatar: fakeAttachment({
|
||||
pending: true,
|
||||
contentType: IMAGE_GIF,
|
||||
}),
|
||||
isProfile: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
return <EmbeddedContact {...props} />;
|
||||
});
|
||||
|
||||
story.add('Incoming', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: fullContact.name,
|
||||
},
|
||||
isIncoming: true,
|
||||
});
|
||||
|
||||
// Wrapped in a <div> to provide a background for light color of text
|
||||
return (
|
||||
<div style={{ backgroundColor: 'darkgreen' }}>
|
||||
<EmbeddedContact {...props} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
story.add('Content Above and Below', () => {
|
||||
const props = createProps({
|
||||
withContentAbove: true,
|
||||
withContentBelow: true,
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<div>Content Above</div>
|
||||
<EmbeddedContact {...props} />
|
||||
<div>Content Below</div>
|
||||
</>
|
||||
);
|
||||
});
|
|
@ -20,6 +20,7 @@ import {
|
|||
IMAGE_WEBP,
|
||||
VIDEO_MP4,
|
||||
stringToMIMEType,
|
||||
IMAGE_GIF,
|
||||
} from '../../types/MIME';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import { MessageAudio } from './MessageAudio';
|
||||
|
@ -30,6 +31,7 @@ import { pngUrl } from '../../storybook/Fixtures';
|
|||
import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation';
|
||||
import { WidthBreakpoint } from '../_util';
|
||||
import { MINUTE } from '../../util/durations';
|
||||
import { ContactFormType } from '../../types/EmbeddedContact';
|
||||
|
||||
import {
|
||||
fakeAttachment,
|
||||
|
@ -37,6 +39,7 @@ import {
|
|||
} from '../../test-both/helpers/fakeAttachment';
|
||||
import { getFakeBadge } from '../../test-both/helpers/getFakeBadge';
|
||||
import { ThemeType } from '../../types/Util';
|
||||
import { UUID } from '../../types/UUID';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
|
@ -118,6 +121,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
select('conversationColor', ConversationColors, ConversationColors[0]),
|
||||
conversationId: text('conversationId', overrideProps.conversationId || ''),
|
||||
conversationType: overrideProps.conversationType || 'direct',
|
||||
contact: overrideProps.contact,
|
||||
deletedForEveryone: overrideProps.deletedForEveryone,
|
||||
deleteMessage: action('deleteMessage'),
|
||||
deleteMessageForEveryone: action('deleteMessageForEveryone'),
|
||||
|
@ -191,6 +195,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
showForwardMessageModal: action('showForwardMessageModal'),
|
||||
showMessageDetail: action('showMessageDetail'),
|
||||
showVisualAttachment: action('showVisualAttachment'),
|
||||
startConversation: action('startConversation'),
|
||||
status: overrideProps.status || 'sent',
|
||||
text: overrideProps.text || text('text', ''),
|
||||
textDirection: overrideProps.textDirection || TextDirection.Default,
|
||||
|
@ -1516,3 +1521,139 @@ story.add('Story reply', () => {
|
|||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const fullContact = {
|
||||
avatar: {
|
||||
avatar: fakeAttachment({
|
||||
path: '/fixtures/giphy-GVNvOUpeYmI7e.gif',
|
||||
contentType: IMAGE_GIF,
|
||||
}),
|
||||
isProfile: true,
|
||||
},
|
||||
email: [
|
||||
{
|
||||
value: 'jerjor@fakemail.com',
|
||||
type: ContactFormType.HOME,
|
||||
},
|
||||
],
|
||||
name: {
|
||||
givenName: 'Jerry',
|
||||
familyName: 'Jordan',
|
||||
prefix: 'Dr.',
|
||||
suffix: 'Jr.',
|
||||
middleName: 'James',
|
||||
displayName: 'Jerry Jordan',
|
||||
},
|
||||
number: [
|
||||
{
|
||||
value: '555-444-2323',
|
||||
type: ContactFormType.HOME,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
story.add('EmbeddedContact: Full Contact', () => {
|
||||
const props = createProps({
|
||||
contact: fullContact,
|
||||
});
|
||||
return renderBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: 2x Incoming, with Send Message', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
...fullContact,
|
||||
firstNumber: fullContact.number[0].value,
|
||||
uuid: UUID.generate().toString(),
|
||||
},
|
||||
direction: 'incoming',
|
||||
});
|
||||
return renderMany([props, props]);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: 2x Outgoing, with Send Message', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
...fullContact,
|
||||
firstNumber: fullContact.number[0].value,
|
||||
uuid: UUID.generate().toString(),
|
||||
},
|
||||
direction: 'outgoing',
|
||||
});
|
||||
return renderMany([props, props]);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: Only Email', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
email: fullContact.email,
|
||||
},
|
||||
});
|
||||
|
||||
return renderBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: Given Name', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: {
|
||||
givenName: 'Jerry',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return renderBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: Organization', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
organization: 'Company 5',
|
||||
},
|
||||
});
|
||||
|
||||
return renderBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: Given + Family Name', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: {
|
||||
givenName: 'Jerry',
|
||||
familyName: 'FamilyName',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return renderBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: Family Name', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: {
|
||||
familyName: 'FamilyName',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return renderBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: Loading Avatar', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
name: {
|
||||
displayName: 'Jerry Jordan',
|
||||
},
|
||||
avatar: {
|
||||
avatar: fakeAttachment({
|
||||
pending: true,
|
||||
contentType: IMAGE_GIF,
|
||||
}),
|
||||
isProfile: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
return renderBothDirections(props);
|
||||
});
|
||||
|
|
|
@ -83,6 +83,7 @@ import { getCustomColorStyle } from '../../util/getCustomColorStyle';
|
|||
import { offsetDistanceModifier } from '../../util/popperUtil';
|
||||
import * as KeyboardLayout from '../../services/keyboardLayout';
|
||||
import { StopPropagation } from '../StopPropagation';
|
||||
import type { UUIDStringType } from '../../types/UUID';
|
||||
|
||||
type Trigger = {
|
||||
handleContextClick: (event: React.MouseEvent<HTMLDivElement>) => void;
|
||||
|
@ -279,7 +280,7 @@ export type PropsActions = {
|
|||
clearSelectedMessage: () => unknown;
|
||||
doubleCheckMissingQuoteReference: (messageId: string) => unknown;
|
||||
messageExpanded: (id: string, displayLimit: number) => unknown;
|
||||
checkForAccount: (identifier: string) => unknown;
|
||||
checkForAccount: (phoneNumber: string) => unknown;
|
||||
|
||||
reactToMessage: (
|
||||
id: string,
|
||||
|
@ -293,10 +294,14 @@ export type PropsActions = {
|
|||
deleteMessageForEveryone: (id: string) => void;
|
||||
showMessageDetail: (id: string) => void;
|
||||
|
||||
startConversation: (e164: string, uuid: UUIDStringType) => void;
|
||||
openConversation: (conversationId: string, messageId?: string) => void;
|
||||
showContactDetail: (options: {
|
||||
contact: EmbeddedContactType;
|
||||
signalAccount?: string;
|
||||
signalAccount?: {
|
||||
phoneNumber: string;
|
||||
uuid: UUIDStringType;
|
||||
};
|
||||
}) => void;
|
||||
showContactModal: (contactId: string, conversationId?: string) => void;
|
||||
|
||||
|
@ -501,7 +506,7 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
const { contact, checkForAccount } = this.props;
|
||||
if (contact && contact.firstNumber && !contact.isNumberOnSignal) {
|
||||
if (contact && contact.firstNumber && !contact.uuid) {
|
||||
checkForAccount(contact.firstNumber);
|
||||
}
|
||||
}
|
||||
|
@ -1336,8 +1341,7 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
this.getMetadataPlacement() !== MetadataPlacement.NotRendered;
|
||||
|
||||
const otherContent =
|
||||
(contact && contact.firstNumber && contact.isNumberOnSignal) ||
|
||||
withCaption;
|
||||
(contact && contact.firstNumber && contact.uuid) || withCaption;
|
||||
const tabIndex = otherContent ? 0 : -1;
|
||||
|
||||
return (
|
||||
|
@ -1346,7 +1350,18 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
isIncoming={direction === 'incoming'}
|
||||
i18n={i18n}
|
||||
onClick={() => {
|
||||
showContactDetail({ contact, signalAccount: contact.firstNumber });
|
||||
const signalAccount =
|
||||
contact.firstNumber && contact.uuid
|
||||
? {
|
||||
phoneNumber: contact.firstNumber,
|
||||
uuid: contact.uuid,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
showContactDetail({
|
||||
contact,
|
||||
signalAccount,
|
||||
});
|
||||
}}
|
||||
withContentAbove={withContentAbove}
|
||||
withContentBelow={withContentBelow}
|
||||
|
@ -1356,20 +1371,30 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public renderSendMessageButton(): JSX.Element | null {
|
||||
const { contact, openConversation, i18n } = this.props;
|
||||
const { contact, direction, shouldCollapseBelow, startConversation, i18n } =
|
||||
this.props;
|
||||
const noBottomLeftCurve = direction === 'incoming' && shouldCollapseBelow;
|
||||
const noBottomRightCurve = direction === 'outgoing' && shouldCollapseBelow;
|
||||
|
||||
if (!contact) {
|
||||
return null;
|
||||
}
|
||||
const { firstNumber, isNumberOnSignal } = contact;
|
||||
if (!firstNumber || !isNumberOnSignal) {
|
||||
const { firstNumber, uuid } = contact;
|
||||
if (!firstNumber || !uuid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openConversation(firstNumber)}
|
||||
className="module-message__send-message-button"
|
||||
onClick={() => startConversation(firstNumber, uuid)}
|
||||
className={classNames(
|
||||
'module-message__send-message-button',
|
||||
noBottomLeftCurve &&
|
||||
'module-message__send-message-button--no-bottom-left-curve',
|
||||
noBottomRightCurve &&
|
||||
'module-message__send-message-button--no-bottom-right-curve'
|
||||
)}
|
||||
>
|
||||
{i18n('sendMessageToContact')}
|
||||
</button>
|
||||
|
@ -2484,7 +2509,7 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
this.audioButtonRef.current.click();
|
||||
}
|
||||
|
||||
if (contact && contact.firstNumber && contact.isNumberOnSignal) {
|
||||
if (contact && contact.firstNumber && contact.uuid) {
|
||||
openConversation(contact.firstNumber);
|
||||
|
||||
event.preventDefault();
|
||||
|
@ -2492,7 +2517,14 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
if (contact) {
|
||||
showContactDetail({ contact, signalAccount: contact.firstNumber });
|
||||
const signalAccount =
|
||||
contact.firstNumber && contact.uuid
|
||||
? {
|
||||
phoneNumber: contact.firstNumber,
|
||||
uuid: contact.uuid,
|
||||
}
|
||||
: undefined;
|
||||
showContactDetail({ contact, signalAccount });
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
|
|
@ -99,6 +99,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
),
|
||||
showForwardMessageModal: action('showForwardMessageModal'),
|
||||
showVisualAttachment: action('showVisualAttachment'),
|
||||
startConversation: action('startConversation'),
|
||||
});
|
||||
|
||||
story.add('Delivered Incoming', () => {
|
||||
|
|
|
@ -87,6 +87,7 @@ export type PropsBackboneActions = Pick<
|
|||
| 'showExpiredOutgoingTapToViewToast'
|
||||
| 'showForwardMessageModal'
|
||||
| 'showVisualAttachment'
|
||||
| 'startConversation'
|
||||
>;
|
||||
|
||||
export type PropsReduxActions = Pick<
|
||||
|
@ -297,6 +298,7 @@ export class MessageDetail extends React.Component<Props> {
|
|||
showExpiredOutgoingTapToViewToast,
|
||||
showForwardMessageModal,
|
||||
showVisualAttachment,
|
||||
startConversation,
|
||||
theme,
|
||||
} = this.props;
|
||||
|
||||
|
@ -364,6 +366,7 @@ export class MessageDetail extends React.Component<Props> {
|
|||
log.warn('MessageDetail: deleteMessageForEveryone called!');
|
||||
}}
|
||||
showVisualAttachment={showVisualAttachment}
|
||||
startConversation={startConversation}
|
||||
theme={theme}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -96,6 +96,7 @@ const defaultMessageProps: MessagesProps = {
|
|||
showForwardMessageModal: action('default--showForwardMessageModal'),
|
||||
showMessageDetail: action('default--showMessageDetail'),
|
||||
showVisualAttachment: action('default--showVisualAttachment'),
|
||||
startConversation: action('default--startConversation'),
|
||||
status: 'sent',
|
||||
text: 'This is really interesting.',
|
||||
textDirection: TextDirection.Default,
|
||||
|
|
|
@ -398,6 +398,7 @@ const actions = () => ({
|
|||
downloadNewVersion: action('downloadNewVersion'),
|
||||
|
||||
startCallingLobby: action('startCallingLobby'),
|
||||
startConversation: action('startConversation'),
|
||||
returnToActiveCall: action('returnToActiveCall'),
|
||||
|
||||
contactSupport: action('contactSupport'),
|
||||
|
|
|
@ -253,6 +253,7 @@ const getActions = createSelector(
|
|||
'scrollToQuotedMessage',
|
||||
'showExpiredIncomingTapToViewToast',
|
||||
'showExpiredOutgoingTapToViewToast',
|
||||
'startConversation',
|
||||
|
||||
'showIdentity',
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ const getDefaultProps = () => ({
|
|||
downloadNewVersion: action('downloadNewVersion'),
|
||||
showIdentity: action('showIdentity'),
|
||||
startCallingLobby: action('startCallingLobby'),
|
||||
startConversation: action('startConversation'),
|
||||
returnToActiveCall: action('returnToActiveCall'),
|
||||
shouldCollapseAbove: false,
|
||||
shouldCollapseBelow: false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue