First-class profile name rendering
This commit is contained in:
parent
632cd0e87e
commit
d07b8e82b2
63 changed files with 1044 additions and 454 deletions
|
@ -715,6 +715,10 @@
|
||||||
"message": "Typing animation for this conversation",
|
"message": "Typing animation for this conversation",
|
||||||
"description": "Used as the 'title' attibute for the typing animation"
|
"description": "Used as the 'title' attibute for the typing animation"
|
||||||
},
|
},
|
||||||
|
"contactInAddressBook": {
|
||||||
|
"message": "This person is in your contacts.",
|
||||||
|
"description": "Description of icon denoting that contact is from your address book"
|
||||||
|
},
|
||||||
"contactAvatarAlt": {
|
"contactAvatarAlt": {
|
||||||
"message": "Avatar for contact $name$",
|
"message": "Avatar for contact $name$",
|
||||||
"description": "Used in the alt tag for the image avatar of a contact",
|
"description": "Used in the alt tag for the image avatar of a contact",
|
||||||
|
|
|
@ -467,6 +467,7 @@
|
||||||
uuid: this.get('uuid'),
|
uuid: this.get('uuid'),
|
||||||
e164: this.get('e164'),
|
e164: this.get('e164'),
|
||||||
|
|
||||||
|
isAccepted: this.getAccepted(),
|
||||||
isArchived: this.get('isArchived'),
|
isArchived: this.get('isArchived'),
|
||||||
isBlocked: this.isBlocked(),
|
isBlocked: this.isBlocked(),
|
||||||
isVerified: this.isVerified(),
|
isVerified: this.isVerified(),
|
||||||
|
@ -477,7 +478,7 @@
|
||||||
isMe: this.isMe(),
|
isMe: this.isMe(),
|
||||||
typingContact: typingContact ? typingContact.format() : null,
|
typingContact: typingContact ? typingContact.format() : null,
|
||||||
lastUpdated: this.get('timestamp'),
|
lastUpdated: this.get('timestamp'),
|
||||||
name: this.getName(),
|
name: this.get('name'),
|
||||||
profileName: this.getProfileName(),
|
profileName: this.getProfileName(),
|
||||||
timestamp,
|
timestamp,
|
||||||
inboxPosition,
|
inboxPosition,
|
||||||
|
@ -589,10 +590,9 @@
|
||||||
const receiptSpecs = readMessages.map(m => ({
|
const receiptSpecs = readMessages.map(m => ({
|
||||||
senderE164: m.get('source'),
|
senderE164: m.get('source'),
|
||||||
senderUuid: m.get('sourceUuid'),
|
senderUuid: m.get('sourceUuid'),
|
||||||
senderId: ConversationController.get({
|
senderId: ConversationController.ensureContactIds({
|
||||||
e164: m.get('source'),
|
e164: m.get('source'),
|
||||||
uuid: m.get('sourceUuid'),
|
uuid: m.get('sourceUuid'),
|
||||||
lowTrust: true,
|
|
||||||
}),
|
}),
|
||||||
timestamp: m.get('sent_at'),
|
timestamp: m.get('sent_at'),
|
||||||
hasErrors: m.hasErrors(),
|
hasErrors: m.hasErrors(),
|
||||||
|
@ -2651,16 +2651,14 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getName() {
|
|
||||||
if (this.isPrivate()) {
|
|
||||||
return this.get('name');
|
|
||||||
}
|
|
||||||
return this.get('name') || i18n('unknownGroup');
|
|
||||||
},
|
|
||||||
|
|
||||||
getTitle() {
|
getTitle() {
|
||||||
if (this.isPrivate()) {
|
if (this.isPrivate()) {
|
||||||
return this.get('name') || this.getNumber() || i18n('unknownContact');
|
return (
|
||||||
|
this.get('name') ||
|
||||||
|
this.getProfileName() ||
|
||||||
|
this.getNumber() ||
|
||||||
|
i18n('unknownContact')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return this.get('name') || i18n('unknownGroup');
|
return this.get('name') || i18n('unknownGroup');
|
||||||
},
|
},
|
||||||
|
@ -2675,24 +2673,6 @@
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
getDisplayName() {
|
|
||||||
if (!this.isPrivate()) {
|
|
||||||
return this.getTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
const name = this.get('name');
|
|
||||||
if (name) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const profileName = this.get('profileName');
|
|
||||||
if (profileName) {
|
|
||||||
return `${this.getNumber()} ~${profileName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.getNumber();
|
|
||||||
},
|
|
||||||
|
|
||||||
getNumber() {
|
getNumber() {
|
||||||
if (!this.isPrivate()) {
|
if (!this.isPrivate()) {
|
||||||
return '';
|
return '';
|
||||||
|
|
|
@ -594,6 +594,7 @@
|
||||||
status: this.getMessagePropStatus(),
|
status: this.getMessagePropStatus(),
|
||||||
contact: this.getPropsForEmbeddedContact(),
|
contact: this.getPropsForEmbeddedContact(),
|
||||||
canReply: this.canReply(),
|
canReply: this.canReply(),
|
||||||
|
authorTitle: contact.title,
|
||||||
authorColor,
|
authorColor,
|
||||||
authorName: contact.name,
|
authorName: contact.name,
|
||||||
authorProfileName: contact.profileName,
|
authorProfileName: contact.profileName,
|
||||||
|
@ -781,7 +782,8 @@
|
||||||
ourRegionCode: regionCode,
|
ourRegionCode: regionCode,
|
||||||
});
|
});
|
||||||
const authorProfileName = contact ? contact.getProfileName() : null;
|
const authorProfileName = contact ? contact.getProfileName() : null;
|
||||||
const authorName = contact ? contact.getName() : null;
|
const authorName = contact ? contact.get('name') : null;
|
||||||
|
const authorTitle = contact ? contact.getTitle() : null;
|
||||||
const isFromMe = contact ? contact.isMe() : false;
|
const isFromMe = contact ? contact.isMe() : false;
|
||||||
const firstAttachment = quote.attachments && quote.attachments[0];
|
const firstAttachment = quote.attachments && quote.attachments[0];
|
||||||
|
|
||||||
|
@ -795,6 +797,7 @@
|
||||||
authorId: author,
|
authorId: author,
|
||||||
authorPhoneNumber,
|
authorPhoneNumber,
|
||||||
authorProfileName,
|
authorProfileName,
|
||||||
|
authorTitle,
|
||||||
authorName,
|
authorName,
|
||||||
authorColor,
|
authorColor,
|
||||||
referencedMessageNotFound,
|
referencedMessageNotFound,
|
||||||
|
@ -891,7 +894,7 @@
|
||||||
if (fromContact.isMe()) {
|
if (fromContact.isMe()) {
|
||||||
messages.push(i18n('youUpdatedTheGroup'));
|
messages.push(i18n('youUpdatedTheGroup'));
|
||||||
} else {
|
} else {
|
||||||
messages.push(i18n('updatedTheGroup', fromContact.getDisplayName()));
|
messages.push(i18n('updatedTheGroup', fromContact.getTitle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupUpdate.joined && groupUpdate.joined.length) {
|
if (groupUpdate.joined && groupUpdate.joined.length) {
|
||||||
|
@ -906,9 +909,7 @@
|
||||||
messages.push(
|
messages.push(
|
||||||
i18n(
|
i18n(
|
||||||
'multipleJoinedTheGroup',
|
'multipleJoinedTheGroup',
|
||||||
_.map(joinedWithoutMe, contact =>
|
_.map(joinedWithoutMe, contact => contact.getTitle()).join(', ')
|
||||||
contact.getDisplayName()
|
|
||||||
).join(', ')
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -924,7 +925,7 @@
|
||||||
messages.push(i18n('youJoinedTheGroup'));
|
messages.push(i18n('youJoinedTheGroup'));
|
||||||
} else {
|
} else {
|
||||||
messages.push(
|
messages.push(
|
||||||
i18n('joinedTheGroup', joinedContacts[0].getDisplayName())
|
i18n('joinedTheGroup', joinedContacts[0].getTitle())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1018,7 +1019,7 @@
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
return conversation.getDisplayName();
|
return conversation.getTitle();
|
||||||
},
|
},
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
|
@ -2346,11 +2347,11 @@
|
||||||
|
|
||||||
if (
|
if (
|
||||||
// Avatar added
|
// Avatar added
|
||||||
!existingAvatar ||
|
(!existingAvatar && avatarAttachment) ||
|
||||||
// Avatar changed
|
// Avatar changed
|
||||||
(existingAvatar && existingAvatar.hash !== hash) ||
|
(existingAvatar && existingAvatar.hash !== hash) ||
|
||||||
// Avatar removed
|
// Avatar removed
|
||||||
avatarAttachment === null
|
(existingAvatar && !avatarAttachment)
|
||||||
) {
|
) {
|
||||||
// Removes existing avatar from disk
|
// Removes existing avatar from disk
|
||||||
if (existingAvatar && existingAvatar.path) {
|
if (existingAvatar && existingAvatar.path) {
|
||||||
|
@ -2396,10 +2397,11 @@
|
||||||
conversation.set({ addedBy: message.getContactId() });
|
conversation.set({ addedBy: message.getContactId() });
|
||||||
}
|
}
|
||||||
} else if (dataMessage.group.type === GROUP_TYPES.QUIT) {
|
} else if (dataMessage.group.type === GROUP_TYPES.QUIT) {
|
||||||
const sender = ConversationController.ensureContactIds({
|
const senderId = ConversationController.ensureContactIds({
|
||||||
e164: source,
|
e164: source,
|
||||||
uuid: sourceUuid,
|
uuid: sourceUuid,
|
||||||
});
|
});
|
||||||
|
const sender = ConversationController.get(senderId);
|
||||||
const inGroup = Boolean(
|
const inGroup = Boolean(
|
||||||
sender &&
|
sender &&
|
||||||
(conversation.get('members') || []).includes(sender.id)
|
(conversation.get('members') || []).includes(sender.id)
|
||||||
|
|
|
@ -26,21 +26,12 @@
|
||||||
this.contactView = null;
|
this.contactView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMe = this.model.isMe();
|
|
||||||
|
|
||||||
this.contactView = new Whisper.ReactWrapperView({
|
this.contactView = new Whisper.ReactWrapperView({
|
||||||
className: 'contact-wrapper',
|
className: 'contact-wrapper',
|
||||||
Component: window.Signal.Components.ContactListItem,
|
Component: window.Signal.Components.ContactListItem,
|
||||||
props: {
|
props: {
|
||||||
isMe,
|
...this.model.cachedProps,
|
||||||
color: this.model.getColor(),
|
|
||||||
avatarPath: this.model.getAvatarPath(),
|
|
||||||
phoneNumber: this.model.getNumber(),
|
|
||||||
name: this.model.getName(),
|
|
||||||
profileName: this.model.getProfileName(),
|
|
||||||
verified: this.model.isVerified(),
|
|
||||||
onClick: this.showIdentity.bind(this),
|
onClick: this.showIdentity.bind(this),
|
||||||
disabled: this.loading,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.$el.append(this.contactView.el);
|
this.$el.append(this.contactView.el);
|
||||||
|
|
|
@ -360,18 +360,8 @@
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: this.model.id,
|
...this.model.cachedProps,
|
||||||
name: this.model.getName(),
|
|
||||||
phoneNumber: this.model.getNumber(),
|
|
||||||
profileName: this.model.getProfileName(),
|
|
||||||
color: this.model.getColor(),
|
|
||||||
avatarPath: this.model.getAvatarPath(),
|
|
||||||
|
|
||||||
isAccepted: this.model.getAccepted(),
|
|
||||||
isVerified: this.model.isVerified(),
|
|
||||||
isMe: this.model.isMe(),
|
|
||||||
isGroup: !this.model.isPrivate(),
|
|
||||||
isArchived: this.model.get('isArchived'),
|
|
||||||
leftGroup: this.model.get('left'),
|
leftGroup: this.model.get('left'),
|
||||||
|
|
||||||
expirationSettingName,
|
expirationSettingName,
|
||||||
|
|
60
patches/react-tooltip-lite+1.12.0.patch
Normal file
60
patches/react-tooltip-lite+1.12.0.patch
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
diff --git a/node_modules/react-tooltip-lite/dist/index.js b/node_modules/react-tooltip-lite/dist/index.js
|
||||||
|
index 32ce07d..6461913 100644
|
||||||
|
--- a/node_modules/react-tooltip-lite/dist/index.js
|
||||||
|
+++ b/node_modules/react-tooltip-lite/dist/index.js
|
||||||
|
@@ -80,7 +80,7 @@ function (_React$Component) {
|
||||||
|
|
||||||
|
_this.state = {
|
||||||
|
showTip: false,
|
||||||
|
- hasHover: false,
|
||||||
|
+ hasHover: 0,
|
||||||
|
ignoreShow: false,
|
||||||
|
hasBeenShown: false
|
||||||
|
};
|
||||||
|
@@ -232,7 +232,7 @@ function (_React$Component) {
|
||||||
|
var _this3 = this;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
- hasHover: false
|
||||||
|
+ hasHover: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.state.showTip) {
|
||||||
|
@@ -250,7 +250,7 @@ function (_React$Component) {
|
||||||
|
value: function startHover() {
|
||||||
|
if (!this.state.ignoreShow) {
|
||||||
|
this.setState({
|
||||||
|
- hasHover: true
|
||||||
|
+ hasHover: (this.state.hasHover || 0) + 1,
|
||||||
|
});
|
||||||
|
clearTimeout(this.hoverTimeout);
|
||||||
|
this.hoverTimeout = setTimeout(this.checkHover, this.props.hoverDelay);
|
||||||
|
@@ -260,7 +260,7 @@ function (_React$Component) {
|
||||||
|
key: "endHover",
|
||||||
|
value: function endHover() {
|
||||||
|
this.setState({
|
||||||
|
- hasHover: false
|
||||||
|
+ hasHover: Math.max((this.state.hasHover || 0) - 1, 0),
|
||||||
|
});
|
||||||
|
clearTimeout(this.hoverTimeout);
|
||||||
|
this.hoverTimeout = setTimeout(this.checkHover, this.props.mouseOutDelay || this.props.hoverDelay);
|
||||||
|
@@ -268,7 +268,7 @@ function (_React$Component) {
|
||||||
|
}, {
|
||||||
|
key: "checkHover",
|
||||||
|
value: function checkHover() {
|
||||||
|
- this.state.hasHover ? this.showTip() : this.hideTip();
|
||||||
|
+ this.state.hasHover > 0 ? this.showTip() : this.hideTip();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "render",
|
||||||
|
@@ -330,7 +330,9 @@ function (_React$Component) {
|
||||||
|
props[eventToggle] = this.toggleTip; // only use hover if they don't have a toggle event
|
||||||
|
} else if (useHover && !isControlledByProps) {
|
||||||
|
props.onMouseEnter = this.startHover;
|
||||||
|
- props.onMouseLeave = tipContentHover || mouseOutDelay ? this.endHover : this.hideTip;
|
||||||
|
+ props.onMouseLeave = this.endHover;
|
||||||
|
+ props.onFocus = this.startHover;
|
||||||
|
+ props.onBlur = this.endHover;
|
||||||
|
props.onTouchStart = this.targetTouchStart;
|
||||||
|
props.onTouchEnd = this.targetTouchEnd;
|
||||||
|
|
|
@ -152,6 +152,18 @@
|
||||||
@content;
|
@content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin dark-mouse-mode() {
|
||||||
|
.dark-theme.mouse-mode & {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@mixin ios-mouse-mode() {
|
||||||
|
.ios-theme.mouse-mode & {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@mixin dark-ios-keyboard-mode() {
|
@mixin dark-ios-keyboard-mode() {
|
||||||
.dark-theme.ios-theme.keyboard-mode & {
|
.dark-theme.ios-theme.keyboard-mode & {
|
||||||
@content;
|
@content;
|
||||||
|
|
|
@ -36,12 +36,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module: Contact Name
|
|
||||||
|
|
||||||
.module-contact-name__profile-name {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module: Message
|
// Module: Message
|
||||||
|
|
||||||
// Note: this does the same thing as module-timeline__message-container but
|
// Note: this does the same thing as module-timeline__message-container but
|
||||||
|
@ -2389,6 +2383,10 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-safety-number__bold-name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.module-message-calling {
|
.module-message-calling {
|
||||||
&--audio {
|
&--audio {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -2612,18 +2610,40 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05',
|
||||||
|
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
|
|
||||||
padding-top: 8px;
|
padding: 8px;
|
||||||
padding-bottom: 8px;
|
width: 100%;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
@include light-theme {
|
@include light-theme {
|
||||||
color: $color-gray-60;
|
color: $color-gray-60;
|
||||||
|
|
||||||
|
@include mouse-mode {
|
||||||
|
&:hover {
|
||||||
|
background-color: $color-gray-02;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include keyboard-mode {
|
||||||
|
&:focus {
|
||||||
|
background-color: $color-gray-02;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@include dark-theme {
|
@include dark-theme {
|
||||||
color: $color-gray-15;
|
color: $color-gray-15;
|
||||||
}
|
}
|
||||||
|
@include dark-mouse-mode {
|
||||||
|
&:hover {
|
||||||
|
background-color: $color-gray-80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include dark-keyboard-mode {
|
||||||
|
&:focus {
|
||||||
|
background-color: $color-gray-80;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-contact-list-item--with-click-handler {
|
.module-contact-list-item--with-click-handler {
|
||||||
|
@ -2665,6 +2685,61 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Module: In Contacts Icon
|
||||||
|
|
||||||
|
.module-in-contacts-icon__icon {
|
||||||
|
display: inline-block;
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
|
||||||
|
margin-bottom: 2px;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/profile-circle-outline-24.svg',
|
||||||
|
$color-gray-60
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/profile-circle-outline-24.svg',
|
||||||
|
$color-gray-25
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyboard-mode {
|
||||||
|
&:focus {
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/profile-circle-outline-24.svg',
|
||||||
|
$ultramarine-ui-light
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-in-contacts-icon__tooltip {
|
||||||
|
.react-tooltip-lite {
|
||||||
|
color: $color-white;
|
||||||
|
background-color: $ultramarine-ui-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-tooltip-lite-arrow {
|
||||||
|
border-color: $ultramarine-ui-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
.react-tooltip-lite {
|
||||||
|
color: $color-white;
|
||||||
|
background-color: $ultramarine-ui-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-tooltip-lite-arrow {
|
||||||
|
border-color: $ultramarine-ui-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Module: Conversation Header
|
// Module: Conversation Header
|
||||||
|
|
||||||
.module-conversation-header {
|
.module-conversation-header {
|
||||||
|
@ -2771,6 +2846,37 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-conversation-header__contacts-icon {
|
||||||
|
display: inline-block;
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
|
||||||
|
margin-bottom: 3px;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/profile-circle-outline-24.svg',
|
||||||
|
$color-gray-60
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/profile-circle-outline-24.svg',
|
||||||
|
$color-gray-25
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyboard-mode {
|
||||||
|
&:focus {
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/profile-circle-outline-24.svg',
|
||||||
|
$ultramarine-ui-light
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.module-conversation-header__title__profile-name {
|
.module-conversation-header__title__profile-name {
|
||||||
@include font-body-1-bold-italic;
|
@include font-body-1-bold-italic;
|
||||||
}
|
}
|
||||||
|
@ -4380,7 +4486,10 @@ button.module-image__border-overlay:focus {
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 2;
|
z-index: 3;
|
||||||
|
|
||||||
|
// This allows click-through to the overlay button behind it
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
|
|
||||||
|
|
|
@ -228,11 +228,10 @@ export class ConversationController {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Given a UUID and/or an E164, resolves to a string representing the local
|
* Given a UUID and/or an E164, resolves to a string representing the local
|
||||||
* database id of the given contact. It may create new contacts, and it may merge
|
* database id of the given contact. In high trust mode, it may create new contacts,
|
||||||
* contacts.
|
* and it may merge contacts.
|
||||||
*
|
*
|
||||||
* lowTrust = uuid/e164 pairing came from source like GroupV1 member list
|
* highTrust = uuid/e164 pairing came from CDS, the server, or your own device
|
||||||
* highTrust = uuid/e164 pairing came from source like CDS
|
|
||||||
*/
|
*/
|
||||||
// tslint:disable-next-line cyclomatic-complexity max-func-body-length
|
// tslint:disable-next-line cyclomatic-complexity max-func-body-length
|
||||||
ensureContactIds({
|
ensureContactIds({
|
||||||
|
|
|
@ -10,6 +10,7 @@ export type Props = {
|
||||||
|
|
||||||
conversationType: 'group' | 'direct';
|
conversationType: 'group' | 'direct';
|
||||||
noteToSelf?: boolean;
|
noteToSelf?: boolean;
|
||||||
|
title: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
phoneNumber?: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
@ -63,17 +64,13 @@ export class Avatar extends React.Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderImage() {
|
public renderImage() {
|
||||||
const { avatarPath, i18n, name, phoneNumber, profileName } = this.props;
|
const { avatarPath, i18n, title } = this.props;
|
||||||
const { imageBroken } = this.state;
|
const { imageBroken } = this.state;
|
||||||
|
|
||||||
if (!avatarPath || imageBroken) {
|
if (!avatarPath || imageBroken) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = `${name || phoneNumber}${
|
|
||||||
!name && profileName ? ` ~${profileName}` : ''
|
|
||||||
}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
onError={this.handleImageErrorBound}
|
onError={this.handleImageErrorBound}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isEmpty } from 'lodash';
|
|
||||||
|
|
||||||
import { Avatar, Props as AvatarProps } from './Avatar';
|
import { Avatar, Props as AvatarProps } from './Avatar';
|
||||||
import { useRestoreFocus } from '../util/hooks';
|
import { useRestoreFocus } from '../util/hooks';
|
||||||
|
@ -22,14 +21,16 @@ export const AvatarPopup = (props: Props) => {
|
||||||
const focusRef = React.useRef<HTMLButtonElement>(null);
|
const focusRef = React.useRef<HTMLButtonElement>(null);
|
||||||
const {
|
const {
|
||||||
i18n,
|
i18n,
|
||||||
|
name,
|
||||||
profileName,
|
profileName,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
|
title,
|
||||||
onViewPreferences,
|
onViewPreferences,
|
||||||
onViewArchive,
|
onViewArchive,
|
||||||
style,
|
style,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const hasProfileName = !isEmpty(profileName);
|
const shouldShowNumber = Boolean(name || profileName);
|
||||||
|
|
||||||
// Note: mechanisms to dismiss this view are all in its host, MainHeader
|
// Note: mechanisms to dismiss this view are all in its host, MainHeader
|
||||||
|
|
||||||
|
@ -41,10 +42,8 @@ export const AvatarPopup = (props: Props) => {
|
||||||
<div className="module-avatar-popup__profile">
|
<div className="module-avatar-popup__profile">
|
||||||
<Avatar {...props} size={52} />
|
<Avatar {...props} size={52} />
|
||||||
<div className="module-avatar-popup__profile__text">
|
<div className="module-avatar-popup__profile__text">
|
||||||
<div className="module-avatar-popup__profile__name">
|
<div className="module-avatar-popup__profile__name">{title}</div>
|
||||||
{hasProfileName ? profileName : phoneNumber}
|
{shouldShowNumber ? (
|
||||||
</div>
|
|
||||||
{hasProfileName ? (
|
|
||||||
<div className="module-avatar-popup__profile__number">
|
<div className="module-avatar-popup__profile__number">
|
||||||
{phoneNumber}
|
{phoneNumber}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,11 +14,13 @@ import { action } from '@storybook/addon-actions';
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
const callDetails = {
|
const callDetails = {
|
||||||
avatarPath: undefined,
|
|
||||||
callId: 0,
|
callId: 0,
|
||||||
contactColor: 'ultramarine' as ColorType,
|
|
||||||
isIncoming: true,
|
isIncoming: true,
|
||||||
isVideoCall: true,
|
isVideoCall: true,
|
||||||
|
|
||||||
|
avatarPath: undefined,
|
||||||
|
color: 'ultramarine' as ColorType,
|
||||||
|
title: 'Rick Sanchez',
|
||||||
name: 'Rick Sanchez',
|
name: 'Rick Sanchez',
|
||||||
phoneNumber: '3051234567',
|
phoneNumber: '3051234567',
|
||||||
profileName: 'Rick Sanchez',
|
profileName: 'Rick Sanchez',
|
||||||
|
|
|
@ -15,11 +15,13 @@ import { action } from '@storybook/addon-actions';
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
const callDetails = {
|
const callDetails = {
|
||||||
avatarPath: undefined,
|
|
||||||
callId: 0,
|
callId: 0,
|
||||||
contactColor: 'ultramarine' as ColorType,
|
|
||||||
isIncoming: true,
|
isIncoming: true,
|
||||||
isVideoCall: true,
|
isVideoCall: true,
|
||||||
|
|
||||||
|
avatarPath: undefined,
|
||||||
|
color: 'ultramarine' as ColorType,
|
||||||
|
title: 'Rick Sanchez',
|
||||||
name: 'Rick Sanchez',
|
name: 'Rick Sanchez',
|
||||||
phoneNumber: '3051234567',
|
phoneNumber: '3051234567',
|
||||||
profileName: 'Rick Sanchez',
|
profileName: 'Rick Sanchez',
|
||||||
|
|
|
@ -275,22 +275,24 @@ export class CallScreen extends React.Component<PropsType, StateType> {
|
||||||
const { i18n } = this.props;
|
const { i18n } = this.props;
|
||||||
const {
|
const {
|
||||||
avatarPath,
|
avatarPath,
|
||||||
contactColor,
|
color,
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
} = callDetails;
|
} = callDetails;
|
||||||
return (
|
return (
|
||||||
<div className="module-ongoing-call__remote-video-disabled">
|
<div className="module-ongoing-call__remote-video-disabled">
|
||||||
<Avatar
|
<Avatar
|
||||||
avatarPath={avatarPath}
|
avatarPath={avatarPath}
|
||||||
color={contactColor || 'ultramarine'}
|
color={color || 'ultramarine'}
|
||||||
noteToSelf={false}
|
noteToSelf={false}
|
||||||
conversationType="direct"
|
conversationType="direct"
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
size={112}
|
size={112}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -114,18 +114,19 @@ export const CompositionArea = ({
|
||||||
showPickerHint,
|
showPickerHint,
|
||||||
clearShowPickerHint,
|
clearShowPickerHint,
|
||||||
// Message Requests
|
// Message Requests
|
||||||
messageRequestsEnabled,
|
|
||||||
acceptedMessageRequest,
|
acceptedMessageRequest,
|
||||||
conversationType,
|
conversationType,
|
||||||
isBlocked,
|
isBlocked,
|
||||||
|
messageRequestsEnabled,
|
||||||
name,
|
name,
|
||||||
onAccept,
|
onAccept,
|
||||||
onBlock,
|
onBlock,
|
||||||
onBlockAndDelete,
|
onBlockAndDelete,
|
||||||
onUnblock,
|
|
||||||
onDelete,
|
onDelete,
|
||||||
profileName,
|
onUnblock,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
|
profileName,
|
||||||
|
title,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [disabled, setDisabled] = React.useState(false);
|
const [disabled, setDisabled] = React.useState(false);
|
||||||
const [showMic, setShowMic] = React.useState(!startingText);
|
const [showMic, setShowMic] = React.useState(!startingText);
|
||||||
|
@ -333,6 +334,7 @@ export const CompositionArea = ({
|
||||||
name={name}
|
name={name}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
|
title={title}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
#### It's me!
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
isMe
|
|
||||||
name="Someone 🔥 Somewhere"
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
verified
|
|
||||||
profileName="🔥Flames🔥"
|
|
||||||
avatarPath={util.gifObjectUrl}
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### With name and profile
|
|
||||||
|
|
||||||
Note the proper spacing between these two.
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<div>
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
name="Someone 🔥 Somewhere"
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
profileName="🔥Flames🔥"
|
|
||||||
avatarPath={util.gifObjectUrl}
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
name="Another ❄️ Yes"
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
profileName="❄️Ice❄️"
|
|
||||||
avatarPath={util.gifObjectUrl}
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### With name and profile, verified
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
name="Someone 🔥 Somewhere"
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
profileName="🔥Flames🔥"
|
|
||||||
verified
|
|
||||||
avatarPath={util.gifObjectUrl}
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### With name and profile, no avatar
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
name="Someone 🔥 Somewhere"
|
|
||||||
color="teal"
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
profileName="🔥Flames🔥"
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Profile, no name, no avatar
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
profileName="🔥Flames🔥"
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Verified, profile, no name, no avatar
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
profileName="🔥Flames🔥"
|
|
||||||
verified
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### No name, no profile, no avatar
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Verified, no name, no profile, no avatar
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactListItem
|
|
||||||
i18n={util.i18n}
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
verified
|
|
||||||
onClick={() => console.log('onClick')}
|
|
||||||
/>
|
|
||||||
```
|
|
133
ts/components/ContactListItem.stories.tsx
Normal file
133
ts/components/ContactListItem.stories.tsx
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
|
import { action } from '@storybook/addon-actions';
|
||||||
|
|
||||||
|
import { gifUrl } from '../storybook/Fixtures';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||||
|
// @ts-ignore
|
||||||
|
import enMessages from '../../\_locales/en/messages.json';
|
||||||
|
|
||||||
|
import { ContactListItem } from './ContactListItem';
|
||||||
|
|
||||||
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
const onClick = action('onClick');
|
||||||
|
|
||||||
|
storiesOf('Components/ContactListItem', module)
|
||||||
|
.add("It's me!", () => {
|
||||||
|
return (
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
isMe
|
||||||
|
title="Someone 🔥 Somewhere"
|
||||||
|
name="Someone 🔥 Somewhere"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
isVerified
|
||||||
|
profileName="🔥Flames🔥"
|
||||||
|
avatarPath={gifUrl}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('With name and profile (note vertical spacing)', () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
title="Someone 🔥 Somewhere"
|
||||||
|
name="Someone 🔥 Somewhere"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
profileName="🔥Flames🔥"
|
||||||
|
avatarPath={gifUrl}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
title="Another ❄️ Yes"
|
||||||
|
name="Another ❄️ Yes"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
profileName="❄️Ice❄️"
|
||||||
|
avatarPath={gifUrl}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('With name and profile, verified', () => {
|
||||||
|
return (
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
title="Someone 🔥 Somewhere"
|
||||||
|
name="Someone 🔥 Somewhere"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
profileName="🔥Flames🔥"
|
||||||
|
isVerified
|
||||||
|
avatarPath={gifUrl}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('With name and profile, no avatar', () => {
|
||||||
|
return (
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
title="Someone 🔥 Somewhere"
|
||||||
|
name="Someone 🔥 Somewhere"
|
||||||
|
color="teal"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
profileName="🔥Flames🔥"
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Profile, no name, no avatar', () => {
|
||||||
|
return (
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
title="🔥Flames🔥"
|
||||||
|
profileName="🔥Flames🔥"
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Verified, profile, no name, no avatar', () => {
|
||||||
|
return (
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
title="🔥Flames🔥"
|
||||||
|
profileName="🔥Flames🔥"
|
||||||
|
isVerified
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('No name, no profile, no avatar', () => {
|
||||||
|
return (
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
title="(202) 555-0011"
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Verified, no name, no profile, no avatar', () => {
|
||||||
|
return (
|
||||||
|
<ContactListItem
|
||||||
|
i18n={i18n}
|
||||||
|
title="(202) 555-0011"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
isVerified
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('No name, no profile, no number', () => {
|
||||||
|
return (
|
||||||
|
<ContactListItem i18n={i18n} title="Unknown contact" onClick={onClick} />
|
||||||
|
);
|
||||||
|
});
|
|
@ -3,15 +3,17 @@ import classNames from 'classnames';
|
||||||
|
|
||||||
import { Avatar } from './Avatar';
|
import { Avatar } from './Avatar';
|
||||||
import { Emojify } from './conversation/Emojify';
|
import { Emojify } from './conversation/Emojify';
|
||||||
|
import { InContactsIcon } from './InContactsIcon';
|
||||||
|
|
||||||
import { ColorType, LocalizerType } from '../types/Util';
|
import { ColorType, LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
phoneNumber: string;
|
title: string;
|
||||||
|
phoneNumber?: string;
|
||||||
isMe?: boolean;
|
isMe?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
color: ColorType;
|
color?: ColorType;
|
||||||
verified: boolean;
|
isVerified?: boolean;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
avatarPath?: string;
|
avatarPath?: string;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
@ -27,6 +29,7 @@ export class ContactListItem extends React.Component<Props> {
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -38,6 +41,7 @@ export class ContactListItem extends React.Component<Props> {
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
size={52}
|
size={52}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -51,21 +55,15 @@ export class ContactListItem extends React.Component<Props> {
|
||||||
isMe,
|
isMe,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
verified,
|
title,
|
||||||
|
isVerified,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const title = name ? name : phoneNumber;
|
|
||||||
const displayName = isMe ? i18n('you') : title;
|
const displayName = isMe ? i18n('you') : title;
|
||||||
|
const shouldShowIcon = Boolean(name);
|
||||||
|
|
||||||
const profileElement =
|
const showNumber = Boolean(isMe || name || profileName);
|
||||||
!isMe && profileName && !name ? (
|
const showVerified = !isMe && isVerified;
|
||||||
<span className="module-contact-list-item__text__profile-name">
|
|
||||||
~<Emojify text={profileName} />
|
|
||||||
</span>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
const showNumber = isMe || name;
|
|
||||||
const showVerified = !isMe && verified;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
@ -78,7 +76,13 @@ export class ContactListItem extends React.Component<Props> {
|
||||||
{this.renderAvatar()}
|
{this.renderAvatar()}
|
||||||
<div className="module-contact-list-item__text">
|
<div className="module-contact-list-item__text">
|
||||||
<div className="module-contact-list-item__text__name">
|
<div className="module-contact-list-item__text__name">
|
||||||
<Emojify text={displayName} /> {profileElement}
|
<Emojify text={displayName} />
|
||||||
|
{shouldShowIcon ? (
|
||||||
|
<span>
|
||||||
|
{' '}
|
||||||
|
<InContactsIcon i18n={i18n} />
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="module-contact-list-item__text__additional-data">
|
<div className="module-contact-list-item__text__additional-data">
|
||||||
{showVerified ? (
|
{showVerified ? (
|
||||||
|
|
|
@ -12,9 +12,10 @@ import { ColorType, LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
export type PropsData = {
|
export type PropsData = {
|
||||||
id: string;
|
id: string;
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
color?: ColorType;
|
color?: ColorType;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
title: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
type: 'group' | 'direct';
|
type: 'group' | 'direct';
|
||||||
avatarPath?: string;
|
avatarPath?: string;
|
||||||
|
@ -54,6 +55,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -67,6 +69,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
size={52}
|
size={52}
|
||||||
/>
|
/>
|
||||||
{this.renderUnread()}
|
{this.renderUnread()}
|
||||||
|
@ -97,6 +100,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -116,6 +120,8 @@ export class ConversationListItem extends React.PureComponent<Props> {
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
name={name}
|
name={name}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
16
ts/components/InContactsIcon.stories.tsx
Normal file
16
ts/components/InContactsIcon.stories.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||||
|
// @ts-ignore
|
||||||
|
import enMessages from '../../\_locales/en/messages.json';
|
||||||
|
|
||||||
|
import { InContactsIcon } from './InContactsIcon';
|
||||||
|
|
||||||
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
|
storiesOf('Components/InContactsIcon', module).add('Default', () => {
|
||||||
|
return <InContactsIcon i18n={i18n} />;
|
||||||
|
});
|
31
ts/components/InContactsIcon.tsx
Normal file
31
ts/components/InContactsIcon.tsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Tooltip from 'react-tooltip-lite';
|
||||||
|
|
||||||
|
import { LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
|
type PropsType = {
|
||||||
|
i18n: LocalizerType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InContactsIcon = (props: PropsType): JSX.Element => {
|
||||||
|
const { i18n } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
tagName="span"
|
||||||
|
direction="bottom"
|
||||||
|
className="module-in-contacts-icon__tooltip"
|
||||||
|
arrowSize={8}
|
||||||
|
content={i18n('contactInAddressBook')}
|
||||||
|
distance={13}
|
||||||
|
hoverDelay={0}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
tabIndex={0}
|
||||||
|
role="img"
|
||||||
|
aria-label={i18n('contactInAddressBook')}
|
||||||
|
className="module-in-contacts-icon__icon"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
|
@ -16,14 +16,16 @@ const i18n = setupI18n('en', enMessages);
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
acceptCall: action('accept-call'),
|
acceptCall: action('accept-call'),
|
||||||
callDetails: {
|
callDetails: {
|
||||||
avatarPath: undefined,
|
|
||||||
callId: 0,
|
callId: 0,
|
||||||
contactColor: 'ultramarine' as ColorType,
|
|
||||||
isIncoming: true,
|
isIncoming: true,
|
||||||
isVideoCall: true,
|
isVideoCall: true,
|
||||||
|
|
||||||
|
avatarPath: undefined,
|
||||||
|
contactColor: 'ultramarine' as ColorType,
|
||||||
name: 'Rick Sanchez',
|
name: 'Rick Sanchez',
|
||||||
phoneNumber: '3051234567',
|
phoneNumber: '3051234567',
|
||||||
profileName: 'Rick Sanchez',
|
profileName: 'Rick Sanchez',
|
||||||
|
title: 'Rick Sanchez',
|
||||||
},
|
},
|
||||||
declineCall: action('decline-call'),
|
declineCall: action('decline-call'),
|
||||||
i18n,
|
i18n,
|
||||||
|
@ -72,7 +74,7 @@ const permutations = [
|
||||||
|
|
||||||
storiesOf('Components/IncomingCallBar', module)
|
storiesOf('Components/IncomingCallBar', module)
|
||||||
.add('Knobs Playground', () => {
|
.add('Knobs Playground', () => {
|
||||||
const contactColor = select('contactColor', colors, 'ultramarine');
|
const color = select('color', colors, 'ultramarine');
|
||||||
const isVideoCall = boolean('isVideoCall', false);
|
const isVideoCall = boolean('isVideoCall', false);
|
||||||
const name = text(
|
const name = text(
|
||||||
'name',
|
'name',
|
||||||
|
@ -84,7 +86,7 @@ storiesOf('Components/IncomingCallBar', module)
|
||||||
{...defaultProps}
|
{...defaultProps}
|
||||||
callDetails={{
|
callDetails={{
|
||||||
...defaultProps.callDetails,
|
...defaultProps.callDetails,
|
||||||
contactColor,
|
color,
|
||||||
isVideoCall,
|
isVideoCall,
|
||||||
name,
|
name,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -62,7 +62,8 @@ export const IncomingCallBar = ({
|
||||||
const {
|
const {
|
||||||
avatarPath,
|
avatarPath,
|
||||||
callId,
|
callId,
|
||||||
contactColor,
|
color,
|
||||||
|
title,
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
@ -74,22 +75,25 @@ export const IncomingCallBar = ({
|
||||||
<div className="module-incoming-call__contact--avatar">
|
<div className="module-incoming-call__contact--avatar">
|
||||||
<Avatar
|
<Avatar
|
||||||
avatarPath={avatarPath}
|
avatarPath={avatarPath}
|
||||||
color={contactColor || 'ultramarine'}
|
color={color || 'ultramarine'}
|
||||||
noteToSelf={false}
|
noteToSelf={false}
|
||||||
conversationType="direct"
|
conversationType="direct"
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
size={52}
|
size={52}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="module-incoming-call__contact--name">
|
<div className="module-incoming-call__contact--name">
|
||||||
<div className="module-incoming-call__contact--name-header">
|
<div className="module-incoming-call__contact--name-header">
|
||||||
<ContactName
|
<ContactName
|
||||||
phoneNumber={phoneNumber}
|
|
||||||
name={name}
|
name={name}
|
||||||
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -22,12 +22,13 @@ export interface PropsType {
|
||||||
regionCode: string;
|
regionCode: string;
|
||||||
|
|
||||||
// For display
|
// For display
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
isMe: boolean;
|
isMe: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
color?: ColorType;
|
color?: ColorType;
|
||||||
verified: boolean;
|
isVerified?: boolean;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
title: string;
|
||||||
avatarPath?: string;
|
avatarPath?: string;
|
||||||
|
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
@ -295,6 +296,7 @@ export class MainHeader extends React.Component<PropsType, StateType> {
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
searchConversationId,
|
searchConversationId,
|
||||||
searchConversationName,
|
searchConversationName,
|
||||||
searchTerm,
|
searchTerm,
|
||||||
|
@ -319,6 +321,7 @@ export class MainHeader extends React.Component<PropsType, StateType> {
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
size={28}
|
size={28}
|
||||||
innerRef={ref}
|
innerRef={ref}
|
||||||
onClick={this.showAvatarPopup}
|
onClick={this.showAvatarPopup}
|
||||||
|
@ -338,6 +341,7 @@ export class MainHeader extends React.Component<PropsType, StateType> {
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
avatarPath={avatarPath}
|
avatarPath={avatarPath}
|
||||||
size={28}
|
size={28}
|
||||||
onViewPreferences={() => {
|
onViewPreferences={() => {
|
||||||
|
|
|
@ -19,7 +19,8 @@ export type PropsDataType = {
|
||||||
snippet: string;
|
snippet: string;
|
||||||
|
|
||||||
from: {
|
from: {
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
|
title: string;
|
||||||
isMe?: boolean;
|
isMe?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
color?: ColorType;
|
color?: ColorType;
|
||||||
|
@ -29,7 +30,8 @@ export type PropsDataType = {
|
||||||
|
|
||||||
to: {
|
to: {
|
||||||
groupName?: string;
|
groupName?: string;
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
|
title: string;
|
||||||
isMe?: boolean;
|
isMe?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
@ -70,7 +72,9 @@ export class MessageSearchResult extends React.PureComponent<PropsType> {
|
||||||
phoneNumber={from.phoneNumber}
|
phoneNumber={from.phoneNumber}
|
||||||
name={from.name}
|
name={from.name}
|
||||||
profileName={from.profileName}
|
profileName={from.profileName}
|
||||||
|
title={from.title}
|
||||||
module="module-message-search-result__header__name"
|
module="module-message-search-result__header__name"
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -88,6 +92,8 @@ export class MessageSearchResult extends React.PureComponent<PropsType> {
|
||||||
phoneNumber={to.phoneNumber}
|
phoneNumber={to.phoneNumber}
|
||||||
name={to.name}
|
name={to.name}
|
||||||
profileName={to.profileName}
|
profileName={to.profileName}
|
||||||
|
title={to.title}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -115,6 +121,7 @@ export class MessageSearchResult extends React.PureComponent<PropsType> {
|
||||||
noteToSelf={isNoteToSelf}
|
noteToSelf={isNoteToSelf}
|
||||||
phoneNumber={from.phoneNumber}
|
phoneNumber={from.phoneNumber}
|
||||||
profileName={from.profileName}
|
profileName={from.profileName}
|
||||||
|
title={from.title}
|
||||||
size={52}
|
size={52}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,19 +12,44 @@ import { storiesOf } from '@storybook/react';
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
const contact = {
|
const contactWithAllData = {
|
||||||
|
avatarPath: undefined,
|
||||||
|
color: 'signal-blue',
|
||||||
|
profileName: '-*Smartest Dude*-',
|
||||||
|
name: 'Rick Sanchez',
|
||||||
|
phoneNumber: '(305) 123-4567',
|
||||||
|
} as ConversationType;
|
||||||
|
|
||||||
|
const contactWithJustProfile = {
|
||||||
|
avatarPath: undefined,
|
||||||
|
color: 'signal-blue',
|
||||||
|
profileName: '-*Smartest Dude*-',
|
||||||
|
name: undefined,
|
||||||
|
phoneNumber: '(305) 123-4567',
|
||||||
|
} as ConversationType;
|
||||||
|
|
||||||
|
const contactWithJustNumber = {
|
||||||
avatarPath: undefined,
|
avatarPath: undefined,
|
||||||
color: 'signal-blue',
|
color: 'signal-blue',
|
||||||
profileName: undefined,
|
profileName: undefined,
|
||||||
name: 'Rick Sanchez',
|
name: undefined,
|
||||||
phoneNumber: '3051234567',
|
phoneNumber: '(305) 123-4567',
|
||||||
|
} as ConversationType;
|
||||||
|
|
||||||
|
const contactWithNothing = {
|
||||||
|
id: 'some-guid',
|
||||||
|
avatarPath: undefined,
|
||||||
|
color: 'signal-blue',
|
||||||
|
profileName: undefined,
|
||||||
|
name: undefined,
|
||||||
|
phoneNumber: undefined,
|
||||||
} as ConversationType;
|
} as ConversationType;
|
||||||
|
|
||||||
storiesOf('Components/SafetyNumberChangeDialog', module)
|
storiesOf('Components/SafetyNumberChangeDialog', module)
|
||||||
.add('Single Contact Dialog', () => {
|
.add('Single Contact Dialog', () => {
|
||||||
return (
|
return (
|
||||||
<SafetyNumberChangeDialog
|
<SafetyNumberChangeDialog
|
||||||
contacts={[contact]}
|
contacts={[contactWithAllData]}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onCancel={action('cancel')}
|
onCancel={action('cancel')}
|
||||||
onConfirm={action('confirm')}
|
onConfirm={action('confirm')}
|
||||||
|
@ -38,7 +63,12 @@ storiesOf('Components/SafetyNumberChangeDialog', module)
|
||||||
.add('Multi Contact Dialog', () => {
|
.add('Multi Contact Dialog', () => {
|
||||||
return (
|
return (
|
||||||
<SafetyNumberChangeDialog
|
<SafetyNumberChangeDialog
|
||||||
contacts={[contact, contact, contact, contact]}
|
contacts={[
|
||||||
|
contactWithAllData,
|
||||||
|
contactWithJustProfile,
|
||||||
|
contactWithJustNumber,
|
||||||
|
contactWithNothing,
|
||||||
|
]}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onCancel={action('cancel')}
|
onCancel={action('cancel')}
|
||||||
onConfirm={action('confirm')}
|
onConfirm={action('confirm')}
|
||||||
|
@ -53,16 +83,16 @@ storiesOf('Components/SafetyNumberChangeDialog', module)
|
||||||
return (
|
return (
|
||||||
<SafetyNumberChangeDialog
|
<SafetyNumberChangeDialog
|
||||||
contacts={[
|
contacts={[
|
||||||
contact,
|
contactWithAllData,
|
||||||
contact,
|
contactWithJustProfile,
|
||||||
contact,
|
contactWithJustNumber,
|
||||||
contact,
|
contactWithNothing,
|
||||||
contact,
|
contactWithAllData,
|
||||||
contact,
|
contactWithAllData,
|
||||||
contact,
|
contactWithAllData,
|
||||||
contact,
|
contactWithAllData,
|
||||||
contact,
|
contactWithAllData,
|
||||||
contact,
|
contactWithAllData,
|
||||||
]}
|
]}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onCancel={action('cancel')}
|
onCancel={action('cancel')}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { Avatar } from './Avatar';
|
import { Avatar } from './Avatar';
|
||||||
import { ConfirmationModal } from './ConfirmationModal';
|
import { ConfirmationModal } from './ConfirmationModal';
|
||||||
|
import { InContactsIcon } from './InContactsIcon';
|
||||||
|
|
||||||
import { ConversationType } from '../state/ducks/conversations';
|
import { ConversationType } from '../state/ducks/conversations';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
|
@ -45,8 +48,14 @@ const SafetyDialogContents = ({
|
||||||
{i18n('changedVerificationWarning')}
|
{i18n('changedVerificationWarning')}
|
||||||
</div>
|
</div>
|
||||||
<ul className="module-sfn-dialog__contacts">
|
<ul className="module-sfn-dialog__contacts">
|
||||||
{contacts.map((contact: ConversationType) => (
|
{contacts.map((contact: ConversationType) => {
|
||||||
<li className="module-sfn-dialog__contact" key={contact.phoneNumber}>
|
const shouldShowNumber = Boolean(contact.name || contact.profileName);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
className="module-sfn-dialog__contact"
|
||||||
|
key={contact.phoneNumber}
|
||||||
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
avatarPath={contact.avatarPath}
|
avatarPath={contact.avatarPath}
|
||||||
color={contact.color}
|
color={contact.color}
|
||||||
|
@ -55,24 +64,24 @@ const SafetyDialogContents = ({
|
||||||
name={contact.name}
|
name={contact.name}
|
||||||
phoneNumber={contact.phoneNumber}
|
phoneNumber={contact.phoneNumber}
|
||||||
profileName={contact.profileName}
|
profileName={contact.profileName}
|
||||||
|
title={contact.title}
|
||||||
size={52}
|
size={52}
|
||||||
/>
|
/>
|
||||||
<div className="module-sfn-dialog__contact--wrapper">
|
<div className="module-sfn-dialog__contact--wrapper">
|
||||||
{contact.name && (
|
|
||||||
<>
|
|
||||||
<div className="module-sfn-dialog__contact--name">
|
<div className="module-sfn-dialog__contact--name">
|
||||||
{contact.name}
|
{contact.title}
|
||||||
|
{contact.name ? (
|
||||||
|
<span>
|
||||||
|
{' '}
|
||||||
|
<InContactsIcon i18n={i18n} />
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
{shouldShowNumber ? (
|
||||||
<div className="module-sfn-dialog__contact--number">
|
<div className="module-sfn-dialog__contact--number">
|
||||||
{contact.phoneNumber}
|
{contact.phoneNumber}
|
||||||
</div>
|
</div>
|
||||||
</>
|
) : null}
|
||||||
)}
|
|
||||||
{!contact.name && (
|
|
||||||
<div className="module-sfn-dialog__contact--name">
|
|
||||||
{contact.phoneNumber}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="module-sfn-dialog__contact--view"
|
className="module-sfn-dialog__contact--view"
|
||||||
|
@ -84,7 +93,8 @@ const SafetyDialogContents = ({
|
||||||
{i18n('view')}
|
{i18n('view')}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
<div className="module-sfn-dialog__actions">
|
<div className="module-sfn-dialog__actions">
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -13,11 +13,39 @@ import { storiesOf } from '@storybook/react';
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
const defaultProps = {
|
const contactWithAllData = {
|
||||||
contact: {
|
name: 'Summer Smith',
|
||||||
title: 'Summer Smith',
|
phoneNumber: '(305) 123-4567',
|
||||||
isVerified: true,
|
isVerified: true,
|
||||||
} as ConversationType,
|
} as ConversationType;
|
||||||
|
|
||||||
|
const contactWithJustProfile = {
|
||||||
|
avatarPath: undefined,
|
||||||
|
color: 'signal-blue',
|
||||||
|
profileName: '-*Smartest Dude*-',
|
||||||
|
name: undefined,
|
||||||
|
phoneNumber: '(305) 123-4567',
|
||||||
|
} as ConversationType;
|
||||||
|
|
||||||
|
const contactWithJustNumber = {
|
||||||
|
avatarPath: undefined,
|
||||||
|
color: 'signal-blue',
|
||||||
|
profileName: undefined,
|
||||||
|
name: undefined,
|
||||||
|
phoneNumber: '(305) 123-4567',
|
||||||
|
} as ConversationType;
|
||||||
|
|
||||||
|
const contactWithNothing = {
|
||||||
|
id: 'some-guid',
|
||||||
|
avatarPath: undefined,
|
||||||
|
color: 'signal-blue',
|
||||||
|
profileName: undefined,
|
||||||
|
name: undefined,
|
||||||
|
phoneNumber: undefined,
|
||||||
|
} as ConversationType;
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
contact: contactWithAllData,
|
||||||
generateSafetyNumber: action('generate-safety-number'),
|
generateSafetyNumber: action('generate-safety-number'),
|
||||||
i18n,
|
i18n,
|
||||||
safetyNumber: 'XXX',
|
safetyNumber: 'XXX',
|
||||||
|
@ -35,9 +63,9 @@ const permutations = [
|
||||||
title: 'Safety Number (not verified)',
|
title: 'Safety Number (not verified)',
|
||||||
props: {
|
props: {
|
||||||
contact: {
|
contact: {
|
||||||
title: 'Morty Smith',
|
...contactWithAllData,
|
||||||
isVerified: false,
|
verified: false,
|
||||||
} as ConversationType,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -58,6 +86,24 @@ const permutations = [
|
||||||
onClose: action('close'),
|
onClose: action('close'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Just Profile',
|
||||||
|
props: {
|
||||||
|
contact: contactWithJustProfile,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Just Number',
|
||||||
|
props: {
|
||||||
|
contact: contactWithJustNumber,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'No display info',
|
||||||
|
props: {
|
||||||
|
contact: contactWithNothing,
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
storiesOf('Components/SafetyNumberViewer', module)
|
storiesOf('Components/SafetyNumberViewer', module)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import { ConversationType } from '../state/ducks/conversations';
|
import { ConversationType } from '../state/ducks/conversations';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import { getPlaceholder } from '../util/safetyNumber';
|
import { getPlaceholder } from '../util/safetyNumber';
|
||||||
|
import { Intl } from './Intl';
|
||||||
|
|
||||||
type SafetyNumberViewerProps = {
|
type SafetyNumberViewerProps = {
|
||||||
contact?: ConversationType;
|
contact?: ConversationType;
|
||||||
|
@ -32,11 +33,20 @@ export const SafetyNumberViewer = ({
|
||||||
generateSafetyNumber(contact);
|
generateSafetyNumber(contact);
|
||||||
}, [safetyNumber]);
|
}, [safetyNumber]);
|
||||||
|
|
||||||
const name = contact.title;
|
const showNumber = Boolean(contact.name || contact.profileName);
|
||||||
|
const numberFragment = showNumber ? ` · ${contact.phoneNumber}` : '';
|
||||||
|
const name = `${contact.title}${numberFragment}`;
|
||||||
|
const boldName = (key?: number) => (
|
||||||
|
<span className="module-safety-number__bold-name" key={key}>
|
||||||
|
{name}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
const isVerified = contact.isVerified;
|
const isVerified = contact.isVerified;
|
||||||
const verifiedStatus = isVerified
|
const verifiedStatusKey = isVerified ? 'isVerified' : 'isNotVerified';
|
||||||
? i18n('isVerified', [name])
|
const safetyNumberChangedKey = safetyNumberChanged
|
||||||
: i18n('isNotVerified', [name]);
|
? 'changedRightAfterVerify'
|
||||||
|
: 'yourSafetyNumberWith';
|
||||||
const verifyButtonText = isVerified ? i18n('unverify') : i18n('verify');
|
const verifyButtonText = isVerified ? i18n('unverify') : i18n('verify');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -49,21 +59,23 @@ export const SafetyNumberViewer = ({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="module-safety-number__verification-label">
|
<div className="module-safety-number__verification-label">
|
||||||
{safetyNumberChanged
|
<Intl
|
||||||
? i18n('changedRightAfterVerify', [name, name])
|
i18n={i18n}
|
||||||
: i18n('yourSafetyNumberWith', [name])}
|
id={safetyNumberChangedKey}
|
||||||
|
components={[boldName(1), boldName(2)]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="module-safety-number__number">
|
<div className="module-safety-number__number">
|
||||||
{safetyNumber || getPlaceholder()}
|
{safetyNumber || getPlaceholder()}
|
||||||
</div>
|
</div>
|
||||||
{i18n('verifyHelp', [name])}
|
<Intl i18n={i18n} id="verifyHelp" components={[boldName()]} />
|
||||||
<div className="module-safety-number__verification-status">
|
<div className="module-safety-number__verification-status">
|
||||||
{isVerified ? (
|
{isVerified ? (
|
||||||
<span className="module-safety-number__icon--verified" />
|
<span className="module-safety-number__icon--verified" />
|
||||||
) : (
|
) : (
|
||||||
<span className="module-safety-number__icon--shield" />
|
<span className="module-safety-number__icon--shield" />
|
||||||
)}
|
)}
|
||||||
{verifiedStatus}
|
<Intl i18n={i18n} id={verifiedStatusKey} components={[boldName()]} />
|
||||||
</div>
|
</div>
|
||||||
<div className="module-safety-number__verify-container">
|
<div className="module-safety-number__verify-container">
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -45,12 +45,14 @@ messageLookup.set('1-guid-guid-guid-guid-guid', {
|
||||||
|
|
||||||
from: {
|
from: {
|
||||||
phoneNumber: '(202) 555-0020',
|
phoneNumber: '(202) 555-0020',
|
||||||
|
title: '(202) 555-0020',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
avatarPath: gifUrl,
|
avatarPath: gifUrl,
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
phoneNumber: '(202) 555-0015',
|
phoneNumber: '(202) 555-0015',
|
||||||
|
title: 'Mr. Fire 🔥',
|
||||||
name: 'Mr. Fire 🔥',
|
name: 'Mr. Fire 🔥',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -63,10 +65,12 @@ messageLookup.set('2-guid-guid-guid-guid-guid', {
|
||||||
from: {
|
from: {
|
||||||
phoneNumber: '(202) 555-0016',
|
phoneNumber: '(202) 555-0016',
|
||||||
name: 'Jon ❄️',
|
name: 'Jon ❄️',
|
||||||
|
title: 'Jon ❄️',
|
||||||
color: 'green',
|
color: 'green',
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
phoneNumber: '(202) 555-0020',
|
phoneNumber: '(202) 555-0020',
|
||||||
|
title: '(202) 555-0020',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -79,12 +83,14 @@ messageLookup.set('3-guid-guid-guid-guid-guid', {
|
||||||
from: {
|
from: {
|
||||||
phoneNumber: '(202) 555-0011',
|
phoneNumber: '(202) 555-0011',
|
||||||
name: 'Someone',
|
name: 'Someone',
|
||||||
|
title: 'Someone',
|
||||||
color: 'green',
|
color: 'green',
|
||||||
avatarPath: pngUrl,
|
avatarPath: pngUrl,
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
phoneNumber: '(202) 555-0016',
|
phoneNumber: '(202) 555-0016',
|
||||||
name: "Y'all 🌆",
|
name: "Y'all 🌆",
|
||||||
|
title: "Y'all 🌆",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -95,6 +101,7 @@ messageLookup.set('4-guid-guid-guid-guid-guid', {
|
||||||
snippet: 'Well, <<left>>everyone<<right>>, happy new year!',
|
snippet: 'Well, <<left>>everyone<<right>>, happy new year!',
|
||||||
from: {
|
from: {
|
||||||
phoneNumber: '(202) 555-0020',
|
phoneNumber: '(202) 555-0020',
|
||||||
|
title: '(202) 555-0020',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
color: 'light_green',
|
color: 'light_green',
|
||||||
avatarPath: gifUrl,
|
avatarPath: gifUrl,
|
||||||
|
@ -102,6 +109,7 @@ messageLookup.set('4-guid-guid-guid-guid-guid', {
|
||||||
to: {
|
to: {
|
||||||
phoneNumber: '(202) 555-0016',
|
phoneNumber: '(202) 555-0016',
|
||||||
name: "Y'all 🌆",
|
name: "Y'all 🌆",
|
||||||
|
title: "Y'all 🌆",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -142,6 +150,7 @@ const conversations = [
|
||||||
id: '+12025550011',
|
id: '+12025550011',
|
||||||
phoneNumber: '(202) 555-0011',
|
phoneNumber: '(202) 555-0011',
|
||||||
name: 'Everyone 🌆',
|
name: 'Everyone 🌆',
|
||||||
|
title: 'Everyone 🌆',
|
||||||
type: GROUP,
|
type: GROUP,
|
||||||
color: 'signal-blue' as 'signal-blue',
|
color: 'signal-blue' as 'signal-blue',
|
||||||
avatarPath: landscapeGreenUrl,
|
avatarPath: landscapeGreenUrl,
|
||||||
|
@ -161,6 +170,7 @@ const conversations = [
|
||||||
id: '+12025550012',
|
id: '+12025550012',
|
||||||
phoneNumber: '(202) 555-0012',
|
phoneNumber: '(202) 555-0012',
|
||||||
name: 'Everyone Else 🔥',
|
name: 'Everyone Else 🔥',
|
||||||
|
title: 'Everyone Else 🔥',
|
||||||
color: 'pink' as 'pink',
|
color: 'pink' as 'pink',
|
||||||
type: DIRECT,
|
type: DIRECT,
|
||||||
avatarPath: landscapePurpleUrl,
|
avatarPath: landscapePurpleUrl,
|
||||||
|
@ -183,6 +193,7 @@ const contacts = [
|
||||||
id: '+12025550013',
|
id: '+12025550013',
|
||||||
phoneNumber: '(202) 555-0013',
|
phoneNumber: '(202) 555-0013',
|
||||||
name: 'The one Everyone',
|
name: 'The one Everyone',
|
||||||
|
title: 'The one Everyone',
|
||||||
color: 'blue' as 'blue',
|
color: 'blue' as 'blue',
|
||||||
type: DIRECT,
|
type: DIRECT,
|
||||||
avatarPath: gifUrl,
|
avatarPath: gifUrl,
|
||||||
|
@ -198,6 +209,7 @@ const contacts = [
|
||||||
id: '+12025550014',
|
id: '+12025550014',
|
||||||
phoneNumber: '(202) 555-0014',
|
phoneNumber: '(202) 555-0014',
|
||||||
name: 'No likey everyone',
|
name: 'No likey everyone',
|
||||||
|
title: 'No likey everyone',
|
||||||
type: DIRECT,
|
type: DIRECT,
|
||||||
color: 'red' as 'red',
|
color: 'red' as 'red',
|
||||||
isMe: false,
|
isMe: false,
|
||||||
|
|
|
@ -20,7 +20,7 @@ export class StartNewConversation extends React.PureComponent<Props> {
|
||||||
color="grey"
|
color="grey"
|
||||||
conversationType="direct"
|
conversationType="direct"
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
phoneNumber={phoneNumber}
|
title={phoneNumber}
|
||||||
size={52}
|
size={52}
|
||||||
/>
|
/>
|
||||||
<div className="module-start-new-conversation__content">
|
<div className="module-start-new-conversation__content">
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#### Number, name and profile
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactName
|
|
||||||
name="Someone 🔥 Somewhere"
|
|
||||||
phoneNumber="(202) 555-0011"
|
|
||||||
profileName="🔥Flames🔥"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Number and profile, no name
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactName phoneNumber="(202) 555-0011" profileName="🔥Flames🔥" />
|
|
||||||
```
|
|
||||||
|
|
||||||
#### No name, no profile
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<ContactName phoneNumber="(202) 555-0011" />
|
|
||||||
```
|
|
47
ts/components/conversation/ContactName.stories.tsx
Normal file
47
ts/components/conversation/ContactName.stories.tsx
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { setup as setupI18n } from '../../../js/modules/i18n';
|
||||||
|
// @ts-ignore
|
||||||
|
import enMessages from '../../../\_locales/en/messages.json';
|
||||||
|
|
||||||
|
import { ContactName } from './ContactName';
|
||||||
|
|
||||||
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
|
storiesOf('Components/Conversation/ContactName', module)
|
||||||
|
.add('Number, name and profile', () => {
|
||||||
|
return (
|
||||||
|
<ContactName
|
||||||
|
title="Someone 🔥 Somewhere"
|
||||||
|
name="Someone 🔥 Somewhere"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
profileName="🔥Flames🔥"
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Number and profile, no name', () => {
|
||||||
|
return (
|
||||||
|
<ContactName
|
||||||
|
title="🔥Flames🔥"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
profileName="🔥Flames🔥"
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('No name, no profile', () => {
|
||||||
|
return (
|
||||||
|
<ContactName
|
||||||
|
title="(202) 555-0011"
|
||||||
|
phoneNumber="(202) 555-0011"
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('No data provided', () => {
|
||||||
|
return <ContactName title="unknownContact" i18n={i18n} />;
|
||||||
|
});
|
|
@ -1,32 +1,25 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Emojify } from './Emojify';
|
import { Emojify } from './Emojify';
|
||||||
|
import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
title: string;
|
||||||
phoneNumber?: string;
|
phoneNumber?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
module?: string;
|
module?: string;
|
||||||
|
i18n: LocalizerType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ContactName extends React.Component<Props> {
|
export class ContactName extends React.Component<Props> {
|
||||||
public render() {
|
public render() {
|
||||||
const { phoneNumber, name, profileName, module } = this.props;
|
const { module, title } = this.props;
|
||||||
const prefix = module ? module : 'module-contact-name';
|
const prefix = module ? module : 'module-contact-name';
|
||||||
|
|
||||||
const title = name ? name : phoneNumber;
|
|
||||||
const shouldShowProfile = Boolean(profileName && !name);
|
|
||||||
const profileElement = shouldShowProfile ? (
|
|
||||||
<span className={`${prefix}__profile-name`}>
|
|
||||||
~<Emojify text={profileName || ''} />
|
|
||||||
</span>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={prefix} dir="auto">
|
<span className={prefix} dir="auto">
|
||||||
<Emojify text={title || ''} />
|
<Emojify text={title || ''} />
|
||||||
{shouldShowProfile ? ' ' : null}
|
|
||||||
{profileElement}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ import enMessages from '../../../\_locales/en/messages.json';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ConversationHeader,
|
ConversationHeader,
|
||||||
Props,
|
PropsActionsType,
|
||||||
PropsActions,
|
PropsHousekeepingType,
|
||||||
PropsHousekeeping,
|
PropsType,
|
||||||
} from './ConversationHeader';
|
} from './ConversationHeader';
|
||||||
|
|
||||||
import { gifUrl } from '../../storybook/Fixtures';
|
import { gifUrl } from '../../storybook/Fixtures';
|
||||||
|
@ -25,11 +25,11 @@ type ConversationHeaderStory = {
|
||||||
description: string;
|
description: string;
|
||||||
items: Array<{
|
items: Array<{
|
||||||
title: string;
|
title: string;
|
||||||
props: Props;
|
props: PropsType;
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionProps: PropsActions = {
|
const actionProps: PropsActionsType = {
|
||||||
onSetDisappearingMessages: action('onSetDisappearingMessages'),
|
onSetDisappearingMessages: action('onSetDisappearingMessages'),
|
||||||
onDeleteMessages: action('onDeleteMessages'),
|
onDeleteMessages: action('onDeleteMessages'),
|
||||||
onResetSession: action('onResetSession'),
|
onResetSession: action('onResetSession'),
|
||||||
|
@ -50,7 +50,7 @@ const actionProps: PropsActions = {
|
||||||
onMoveToInbox: action('onMoveToInbox'),
|
onMoveToInbox: action('onMoveToInbox'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const housekeepingProps: PropsHousekeeping = {
|
const housekeepingProps: PropsHousekeepingType = {
|
||||||
i18n,
|
i18n,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,8 +66,10 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
color: 'red',
|
color: 'red',
|
||||||
isVerified: true,
|
isVerified: true,
|
||||||
avatarPath: gifUrl,
|
avatarPath: gifUrl,
|
||||||
|
title: 'Someone 🔥 Somewhere',
|
||||||
name: 'Someone 🔥 Somewhere',
|
name: 'Someone 🔥 Somewhere',
|
||||||
phoneNumber: '(202) 555-0001',
|
phoneNumber: '(202) 555-0001',
|
||||||
|
type: 'direct',
|
||||||
id: '1',
|
id: '1',
|
||||||
profileName: '🔥Flames🔥',
|
profileName: '🔥Flames🔥',
|
||||||
isAccepted: true,
|
isAccepted: true,
|
||||||
|
@ -80,8 +82,25 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
props: {
|
props: {
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
isVerified: false,
|
isVerified: false,
|
||||||
|
title: 'Someone 🔥 Somewhere',
|
||||||
name: 'Someone 🔥 Somewhere',
|
name: 'Someone 🔥 Somewhere',
|
||||||
phoneNumber: '(202) 555-0002',
|
phoneNumber: '(202) 555-0002',
|
||||||
|
type: 'direct',
|
||||||
|
id: '2',
|
||||||
|
isAccepted: true,
|
||||||
|
...actionProps,
|
||||||
|
...housekeepingProps,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'With name, not verified, descenders',
|
||||||
|
props: {
|
||||||
|
color: 'blue',
|
||||||
|
isVerified: false,
|
||||||
|
title: 'Joyrey 🔥 Leppey',
|
||||||
|
name: 'Joyrey 🔥 Leppey',
|
||||||
|
phoneNumber: '(202) 555-0002',
|
||||||
|
type: 'direct',
|
||||||
id: '2',
|
id: '2',
|
||||||
isAccepted: true,
|
isAccepted: true,
|
||||||
...actionProps,
|
...actionProps,
|
||||||
|
@ -94,7 +113,9 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
color: 'teal',
|
color: 'teal',
|
||||||
isVerified: false,
|
isVerified: false,
|
||||||
phoneNumber: '(202) 555-0003',
|
phoneNumber: '(202) 555-0003',
|
||||||
|
type: 'direct',
|
||||||
id: '3',
|
id: '3',
|
||||||
|
title: '🔥Flames🔥',
|
||||||
profileName: '🔥Flames🔥',
|
profileName: '🔥Flames🔥',
|
||||||
isAccepted: true,
|
isAccepted: true,
|
||||||
...actionProps,
|
...actionProps,
|
||||||
|
@ -104,7 +125,9 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
{
|
{
|
||||||
title: 'No name, no profile, no color',
|
title: 'No name, no profile, no color',
|
||||||
props: {
|
props: {
|
||||||
|
title: '(202) 555-0011',
|
||||||
phoneNumber: '(202) 555-0011',
|
phoneNumber: '(202) 555-0011',
|
||||||
|
type: 'direct',
|
||||||
id: '11',
|
id: '11',
|
||||||
isAccepted: true,
|
isAccepted: true,
|
||||||
...actionProps,
|
...actionProps,
|
||||||
|
@ -117,6 +140,8 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
color: 'deep_orange',
|
color: 'deep_orange',
|
||||||
phoneNumber: '(202) 555-0004',
|
phoneNumber: '(202) 555-0004',
|
||||||
|
title: '(202) 555-0004',
|
||||||
|
type: 'direct',
|
||||||
id: '4',
|
id: '4',
|
||||||
isAccepted: true,
|
isAccepted: true,
|
||||||
...actionProps,
|
...actionProps,
|
||||||
|
@ -127,7 +152,9 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
title: 'Disappearing messages set',
|
title: 'Disappearing messages set',
|
||||||
props: {
|
props: {
|
||||||
color: 'indigo',
|
color: 'indigo',
|
||||||
|
title: '(202) 555-0005',
|
||||||
phoneNumber: '(202) 555-0005',
|
phoneNumber: '(202) 555-0005',
|
||||||
|
type: 'direct',
|
||||||
id: '5',
|
id: '5',
|
||||||
expirationSettingName: '10 seconds',
|
expirationSettingName: '10 seconds',
|
||||||
timerOptions: [
|
timerOptions: [
|
||||||
|
@ -156,10 +183,11 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
title: 'Basic',
|
title: 'Basic',
|
||||||
props: {
|
props: {
|
||||||
color: 'signal-blue',
|
color: 'signal-blue',
|
||||||
|
title: 'Typescript support group',
|
||||||
name: 'Typescript support group',
|
name: 'Typescript support group',
|
||||||
phoneNumber: '',
|
phoneNumber: '',
|
||||||
id: '1',
|
id: '1',
|
||||||
isGroup: true,
|
type: 'group',
|
||||||
expirationSettingName: '10 seconds',
|
expirationSettingName: '10 seconds',
|
||||||
timerOptions: [
|
timerOptions: [
|
||||||
{
|
{
|
||||||
|
@ -180,10 +208,11 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
title: 'In a group you left - no disappearing messages',
|
title: 'In a group you left - no disappearing messages',
|
||||||
props: {
|
props: {
|
||||||
color: 'signal-blue',
|
color: 'signal-blue',
|
||||||
|
title: 'Typescript support group',
|
||||||
name: 'Typescript support group',
|
name: 'Typescript support group',
|
||||||
phoneNumber: '',
|
phoneNumber: '',
|
||||||
id: '2',
|
id: '2',
|
||||||
isGroup: true,
|
type: 'group',
|
||||||
leftGroup: true,
|
leftGroup: true,
|
||||||
expirationSettingName: '10 seconds',
|
expirationSettingName: '10 seconds',
|
||||||
timerOptions: [
|
timerOptions: [
|
||||||
|
@ -211,8 +240,10 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
title: 'In chat with yourself',
|
title: 'In chat with yourself',
|
||||||
props: {
|
props: {
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
|
title: '(202) 555-0007',
|
||||||
phoneNumber: '(202) 555-0007',
|
phoneNumber: '(202) 555-0007',
|
||||||
id: '7',
|
id: '7',
|
||||||
|
type: 'direct',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
isAccepted: true,
|
isAccepted: true,
|
||||||
...actionProps,
|
...actionProps,
|
||||||
|
@ -229,8 +260,10 @@ const stories: Array<ConversationHeaderStory> = [
|
||||||
title: '1:1 conversation',
|
title: '1:1 conversation',
|
||||||
props: {
|
props: {
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
|
title: '(202) 555-0007',
|
||||||
phoneNumber: '(202) 555-0007',
|
phoneNumber: '(202) 555-0007',
|
||||||
id: '7',
|
id: '7',
|
||||||
|
type: 'direct',
|
||||||
isMe: false,
|
isMe: false,
|
||||||
isAccepted: false,
|
isAccepted: false,
|
||||||
...actionProps,
|
...actionProps,
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { Emojify } from './Emojify';
|
|
||||||
import { Avatar } from '../Avatar';
|
|
||||||
import { ColorType, LocalizerType } from '../../types/Util';
|
|
||||||
import {
|
import {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
ContextMenuTrigger,
|
ContextMenuTrigger,
|
||||||
|
@ -11,24 +7,31 @@ import {
|
||||||
SubMenu,
|
SubMenu,
|
||||||
} from 'react-contextmenu';
|
} from 'react-contextmenu';
|
||||||
|
|
||||||
|
import { Emojify } from './Emojify';
|
||||||
|
import { Avatar } from '../Avatar';
|
||||||
|
import { InContactsIcon } from '../InContactsIcon';
|
||||||
|
|
||||||
|
import { ColorType, LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
interface TimerOption {
|
interface TimerOption {
|
||||||
name: string;
|
name: string;
|
||||||
value: number;
|
value: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PropsData {
|
export interface PropsDataType {
|
||||||
id: string;
|
id: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
color?: ColorType;
|
color?: ColorType;
|
||||||
avatarPath?: string;
|
avatarPath?: string;
|
||||||
|
type: 'direct' | 'group';
|
||||||
|
title: string;
|
||||||
|
|
||||||
isAccepted?: boolean;
|
isAccepted?: boolean;
|
||||||
isVerified?: boolean;
|
isVerified?: boolean;
|
||||||
isMe?: boolean;
|
isMe?: boolean;
|
||||||
isGroup?: boolean;
|
|
||||||
isArchived?: boolean;
|
isArchived?: boolean;
|
||||||
leftGroup?: boolean;
|
leftGroup?: boolean;
|
||||||
|
|
||||||
|
@ -37,7 +40,7 @@ export interface PropsData {
|
||||||
timerOptions?: Array<TimerOption>;
|
timerOptions?: Array<TimerOption>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PropsActions {
|
export interface PropsActionsType {
|
||||||
onSetDisappearingMessages: (seconds: number) => void;
|
onSetDisappearingMessages: (seconds: number) => void;
|
||||||
onDeleteMessages: () => void;
|
onDeleteMessages: () => void;
|
||||||
onResetSession: () => void;
|
onResetSession: () => void;
|
||||||
|
@ -54,17 +57,19 @@ export interface PropsActions {
|
||||||
onMoveToInbox: () => void;
|
onMoveToInbox: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PropsHousekeeping {
|
export interface PropsHousekeepingType {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Props = PropsData & PropsActions & PropsHousekeeping;
|
export type PropsType = PropsDataType &
|
||||||
|
PropsActionsType &
|
||||||
|
PropsHousekeepingType;
|
||||||
|
|
||||||
export class ConversationHeader extends React.Component<Props> {
|
export class ConversationHeader extends React.Component<PropsType> {
|
||||||
public showMenuBound: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
public showMenuBound: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
||||||
public menuTriggerRef: React.RefObject<any>;
|
public menuTriggerRef: React.RefObject<any>;
|
||||||
|
|
||||||
public constructor(props: Props) {
|
public constructor(props: PropsType) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.menuTriggerRef = React.createRef();
|
this.menuTriggerRef = React.createRef();
|
||||||
|
@ -96,6 +101,8 @@ export class ConversationHeader extends React.Component<Props> {
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
|
title,
|
||||||
|
type,
|
||||||
i18n,
|
i18n,
|
||||||
isMe,
|
isMe,
|
||||||
profileName,
|
profileName,
|
||||||
|
@ -110,19 +117,22 @@ export class ConversationHeader extends React.Component<Props> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shouldShowIcon = Boolean(name && type === 'direct');
|
||||||
|
const shouldShowNumber = Boolean(phoneNumber && (name || profileName));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-conversation-header__title">
|
<div className="module-conversation-header__title">
|
||||||
{name ? <Emojify text={name} /> : null}
|
<Emojify text={title} />
|
||||||
{name && phoneNumber ? ' · ' : null}
|
{shouldShowIcon ? (
|
||||||
{phoneNumber ? phoneNumber : null}{' '}
|
<span>
|
||||||
{profileName && !name ? (
|
{' '}
|
||||||
<span className="module-conversation-header__title__profile-name">
|
<InContactsIcon i18n={i18n} />
|
||||||
~<Emojify text={profileName} />
|
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
{isVerified ? ' · ' : null}
|
{shouldShowNumber ? ` · ${phoneNumber}` : null}
|
||||||
{isVerified ? (
|
{isVerified ? (
|
||||||
<span>
|
<span>
|
||||||
|
{' · '}
|
||||||
<span className="module-conversation-header__title__verified-icon" />
|
<span className="module-conversation-header__title__verified-icon" />
|
||||||
{i18n('verified')}
|
{i18n('verified')}
|
||||||
</span>
|
</span>
|
||||||
|
@ -136,23 +146,23 @@ export class ConversationHeader extends React.Component<Props> {
|
||||||
avatarPath,
|
avatarPath,
|
||||||
color,
|
color,
|
||||||
i18n,
|
i18n,
|
||||||
isGroup,
|
type,
|
||||||
isMe,
|
isMe,
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const conversationType = isGroup ? 'group' : 'direct';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="module-conversation-header__avatar">
|
<span className="module-conversation-header__avatar">
|
||||||
<Avatar
|
<Avatar
|
||||||
avatarPath={avatarPath}
|
avatarPath={avatarPath}
|
||||||
color={color}
|
color={color}
|
||||||
conversationType={conversationType}
|
conversationType={type}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
noteToSelf={isMe}
|
noteToSelf={isMe}
|
||||||
|
title={title}
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
@ -226,7 +236,7 @@ export class ConversationHeader extends React.Component<Props> {
|
||||||
if (!window.CALLING) {
|
if (!window.CALLING) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (this.props.isGroup || this.props.isMe) {
|
if (this.props.type === 'group' || this.props.isMe) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +260,7 @@ export class ConversationHeader extends React.Component<Props> {
|
||||||
if (!window.CALLING) {
|
if (!window.CALLING) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (this.props.isGroup || this.props.isMe) {
|
if (this.props.type === 'group' || this.props.isMe) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +285,7 @@ export class ConversationHeader extends React.Component<Props> {
|
||||||
i18n,
|
i18n,
|
||||||
isAccepted,
|
isAccepted,
|
||||||
isMe,
|
isMe,
|
||||||
isGroup,
|
type,
|
||||||
isArchived,
|
isArchived,
|
||||||
leftGroup,
|
leftGroup,
|
||||||
onDeleteMessages,
|
onDeleteMessages,
|
||||||
|
@ -290,6 +300,7 @@ export class ConversationHeader extends React.Component<Props> {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const disappearingTitle = i18n('disappearingMessages') as any;
|
const disappearingTitle = i18n('disappearingMessages') as any;
|
||||||
|
const isGroup = type === 'group';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContextMenu id={triggerId}>
|
<ContextMenu id={triggerId}>
|
||||||
|
|
|
@ -10,8 +10,9 @@ import enMessages from '../../../_locales/en/messages.json';
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
|
const getTitle = () => text('name', 'Cayce Bollard');
|
||||||
const getName = () => text('name', 'Cayce Bollard');
|
const getName = () => text('name', 'Cayce Bollard');
|
||||||
const getProfileName = () => text('profileName', 'Cayce Bollard');
|
const getProfileName = () => text('profileName', 'Cayce Bollard (profile)');
|
||||||
const getAvatarPath = () =>
|
const getAvatarPath = () =>
|
||||||
text('avatarPath', '/fixtures/kitten-4-112-112.jpg');
|
text('avatarPath', '/fixtures/kitten-4-112-112.jpg');
|
||||||
const getPhoneNumber = () => text('phoneNumber', '+1 (646) 327-2700');
|
const getPhoneNumber = () => text('phoneNumber', '+1 (646) 327-2700');
|
||||||
|
@ -22,6 +23,7 @@ storiesOf('Components/Conversation/ConversationHero', module)
|
||||||
<div style={{ width: '480px' }}>
|
<div style={{ width: '480px' }}>
|
||||||
<ConversationHero
|
<ConversationHero
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
title={getTitle()}
|
||||||
avatarPath={getAvatarPath()}
|
avatarPath={getAvatarPath()}
|
||||||
name={getName()}
|
name={getName()}
|
||||||
profileName={getProfileName()}
|
profileName={getProfileName()}
|
||||||
|
@ -37,6 +39,7 @@ storiesOf('Components/Conversation/ConversationHero', module)
|
||||||
<div style={{ width: '480px' }}>
|
<div style={{ width: '480px' }}>
|
||||||
<ConversationHero
|
<ConversationHero
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
title={getTitle()}
|
||||||
avatarPath={getAvatarPath()}
|
avatarPath={getAvatarPath()}
|
||||||
name={getName()}
|
name={getName()}
|
||||||
profileName={getProfileName()}
|
profileName={getProfileName()}
|
||||||
|
@ -52,6 +55,7 @@ storiesOf('Components/Conversation/ConversationHero', module)
|
||||||
<div style={{ width: '480px' }}>
|
<div style={{ width: '480px' }}>
|
||||||
<ConversationHero
|
<ConversationHero
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
title={getTitle()}
|
||||||
avatarPath={getAvatarPath()}
|
avatarPath={getAvatarPath()}
|
||||||
name={getName()}
|
name={getName()}
|
||||||
profileName={getProfileName()}
|
profileName={getProfileName()}
|
||||||
|
@ -62,13 +66,30 @@ storiesOf('Components/Conversation/ConversationHero', module)
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.add('Direct (No Other Groups)', () => {
|
.add('Direct (No Groups, Name)', () => {
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '480px' }}>
|
<div style={{ width: '480px' }}>
|
||||||
<ConversationHero
|
<ConversationHero
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
title={getTitle()}
|
||||||
avatarPath={getAvatarPath()}
|
avatarPath={getAvatarPath()}
|
||||||
name={getName()}
|
name={getName()}
|
||||||
|
profileName={text('profileName', '')}
|
||||||
|
phoneNumber={getPhoneNumber()}
|
||||||
|
conversationType="direct"
|
||||||
|
groups={[]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Direct (No Groups, Just Profile)', () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '480px' }}>
|
||||||
|
<ConversationHero
|
||||||
|
i18n={i18n}
|
||||||
|
title={text('title', 'Cayce Bollard (profile)')}
|
||||||
|
avatarPath={getAvatarPath()}
|
||||||
|
name={text('name', '')}
|
||||||
profileName={getProfileName()}
|
profileName={getProfileName()}
|
||||||
phoneNumber={getPhoneNumber()}
|
phoneNumber={getPhoneNumber()}
|
||||||
conversationType="direct"
|
conversationType="direct"
|
||||||
|
@ -77,13 +98,45 @@ storiesOf('Components/Conversation/ConversationHero', module)
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
.add('Direct (No Groups, Just Phone Number)', () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '480px' }}>
|
||||||
|
<ConversationHero
|
||||||
|
i18n={i18n}
|
||||||
|
title={text('title', '+1 (646) 327-2700')}
|
||||||
|
avatarPath={getAvatarPath()}
|
||||||
|
name={text('name', '')}
|
||||||
|
profileName={text('profileName', '')}
|
||||||
|
phoneNumber={getPhoneNumber()}
|
||||||
|
conversationType="direct"
|
||||||
|
groups={[]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Direct (No Groups, No Data)', () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '480px' }}>
|
||||||
|
<ConversationHero
|
||||||
|
i18n={i18n}
|
||||||
|
title={text('title', 'Unknown contact')}
|
||||||
|
avatarPath={getAvatarPath()}
|
||||||
|
name={text('name', '')}
|
||||||
|
profileName={text('profileName', '')}
|
||||||
|
phoneNumber={text('phoneNumber', '')}
|
||||||
|
conversationType="direct"
|
||||||
|
groups={[]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
.add('Group (many members)', () => {
|
.add('Group (many members)', () => {
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '480px' }}>
|
<div style={{ width: '480px' }}>
|
||||||
<ConversationHero
|
<ConversationHero
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
title={text('title', 'NYC Rock Climbers')}
|
||||||
name={text('groupName', 'NYC Rock Climbers')}
|
name={text('groupName', 'NYC Rock Climbers')}
|
||||||
phoneNumber={text('phoneNumber', '+1 (646) 327-2700')}
|
|
||||||
conversationType="group"
|
conversationType="group"
|
||||||
membersCount={numberKnob('membersCount', 22)}
|
membersCount={numberKnob('membersCount', 22)}
|
||||||
/>
|
/>
|
||||||
|
@ -95,8 +148,8 @@ storiesOf('Components/Conversation/ConversationHero', module)
|
||||||
<div style={{ width: '480px' }}>
|
<div style={{ width: '480px' }}>
|
||||||
<ConversationHero
|
<ConversationHero
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
title={text('title', 'NYC Rock Climbers')}
|
||||||
name={text('groupName', 'NYC Rock Climbers')}
|
name={text('groupName', 'NYC Rock Climbers')}
|
||||||
phoneNumber={text('phoneNumber', '+1 (646) 327-2700')}
|
|
||||||
conversationType="group"
|
conversationType="group"
|
||||||
membersCount={1}
|
membersCount={1}
|
||||||
/>
|
/>
|
||||||
|
@ -108,8 +161,21 @@ storiesOf('Components/Conversation/ConversationHero', module)
|
||||||
<div style={{ width: '480px' }}>
|
<div style={{ width: '480px' }}>
|
||||||
<ConversationHero
|
<ConversationHero
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
title={text('title', 'NYC Rock Climbers')}
|
||||||
name={text('groupName', 'NYC Rock Climbers')}
|
name={text('groupName', 'NYC Rock Climbers')}
|
||||||
phoneNumber={text('phoneNumber', '+1 (646) 327-2700')}
|
conversationType="group"
|
||||||
|
membersCount={0}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Group (No name)', () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '480px' }}>
|
||||||
|
<ConversationHero
|
||||||
|
i18n={i18n}
|
||||||
|
title={text('title', 'Unknown group')}
|
||||||
|
name={text('groupName', '')}
|
||||||
conversationType="group"
|
conversationType="group"
|
||||||
membersCount={0}
|
membersCount={0}
|
||||||
/>
|
/>
|
||||||
|
@ -122,6 +188,7 @@ storiesOf('Components/Conversation/ConversationHero', module)
|
||||||
<ConversationHero
|
<ConversationHero
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
isMe={true}
|
isMe={true}
|
||||||
|
title={getTitle()}
|
||||||
conversationType="direct"
|
conversationType="direct"
|
||||||
phoneNumber={getPhoneNumber()}
|
phoneNumber={getPhoneNumber()}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,7 +11,7 @@ export type Props = {
|
||||||
isMe?: boolean;
|
isMe?: boolean;
|
||||||
groups?: Array<string>;
|
groups?: Array<string>;
|
||||||
membersCount?: number;
|
membersCount?: number;
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
onHeightChange?: () => unknown;
|
onHeightChange?: () => unknown;
|
||||||
} & Omit<AvatarProps, 'onClick' | 'size' | 'noteToSelf'>;
|
} & Omit<AvatarProps, 'onClick' | 'size' | 'noteToSelf'>;
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ export const ConversationHero = ({
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
onHeightChange,
|
onHeightChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const firstRenderRef = React.useRef(true);
|
const firstRenderRef = React.useRef(true);
|
||||||
|
@ -86,6 +87,12 @@ export const ConversationHero = ({
|
||||||
...groups.map(g => `g-${g}`),
|
...groups.map(g => `g-${g}`),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const displayName =
|
||||||
|
name || (conversationType === 'group' ? i18n('unknownGroup') : undefined);
|
||||||
|
const phoneNumberOnly = Boolean(
|
||||||
|
!name && !profileName && conversationType === 'direct'
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-conversation-hero">
|
<div className="module-conversation-hero">
|
||||||
<Avatar
|
<Avatar
|
||||||
|
@ -96,6 +103,7 @@ export const ConversationHero = ({
|
||||||
conversationType={conversationType}
|
conversationType={conversationType}
|
||||||
name={name}
|
name={name}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
size={112}
|
size={112}
|
||||||
className="module-conversation-hero__avatar"
|
className="module-conversation-hero__avatar"
|
||||||
/>
|
/>
|
||||||
|
@ -104,9 +112,11 @@ export const ConversationHero = ({
|
||||||
i18n('noteToSelf')
|
i18n('noteToSelf')
|
||||||
) : (
|
) : (
|
||||||
<ContactName
|
<ContactName
|
||||||
name={name}
|
title={title}
|
||||||
|
name={displayName}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -116,6 +126,8 @@ export const ConversationHero = ({
|
||||||
? i18n('ConversationHero--members-1')
|
? i18n('ConversationHero--members-1')
|
||||||
: membersCount !== undefined
|
: membersCount !== undefined
|
||||||
? i18n('ConversationHero--members', [`${membersCount}`])
|
? i18n('ConversationHero--members', [`${membersCount}`])
|
||||||
|
: phoneNumberOnly
|
||||||
|
? null
|
||||||
: phoneNumber}
|
: phoneNumber}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -20,6 +20,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -28,12 +29,14 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'add',
|
type: 'add',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Mrs. Ice',
|
||||||
phoneNumber: '(202) 555-1001',
|
phoneNumber: '(202) 555-1001',
|
||||||
profileName: 'Mrs. Ice',
|
profileName: 'Mrs. Ice',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
phoneNumber: '(202) 555-1002',
|
phoneNumber: '(202) 555-1002',
|
||||||
name: 'Ms. Earth',
|
name: 'Ms. Earth',
|
||||||
|
title: 'Ms. Earth',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -44,6 +47,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
|
@ -53,10 +57,12 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'add',
|
type: 'add',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Mrs. Ice',
|
||||||
phoneNumber: '(202) 555-1001',
|
phoneNumber: '(202) 555-1001',
|
||||||
profileName: 'Mrs. Ice',
|
profileName: 'Mrs. Ice',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: 'Ms. Earth',
|
||||||
phoneNumber: '(202) 555-1002',
|
phoneNumber: '(202) 555-1002',
|
||||||
name: 'Ms. Earth',
|
name: 'Ms. Earth',
|
||||||
},
|
},
|
||||||
|
@ -74,6 +80,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -82,13 +89,16 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'add',
|
type: 'add',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: '(202) 555-1000',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: 'Mrs. Ice',
|
||||||
phoneNumber: '(202) 555-1001',
|
phoneNumber: '(202) 555-1001',
|
||||||
profileName: 'Mrs. Ice',
|
profileName: 'Mrs. Ice',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: 'Ms. Earth',
|
||||||
phoneNumber: '(202) 555-1002',
|
phoneNumber: '(202) 555-1002',
|
||||||
name: 'Ms. Earth',
|
name: 'Ms. Earth',
|
||||||
},
|
},
|
||||||
|
@ -99,6 +109,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -107,14 +118,17 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'add',
|
type: 'add',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: '(202) 555-1000',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: 'Mrs. Ice',
|
||||||
phoneNumber: '(202) 555-1001',
|
phoneNumber: '(202) 555-1001',
|
||||||
profileName: 'Mrs. Ice',
|
profileName: 'Mrs. Ice',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: 'Ms. Earth',
|
||||||
phoneNumber: '(202) 555-1002',
|
phoneNumber: '(202) 555-1002',
|
||||||
name: 'Ms. Earth',
|
name: 'Ms. Earth',
|
||||||
},
|
},
|
||||||
|
@ -125,6 +139,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -133,6 +148,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'add',
|
type: 'add',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Mr. Fire',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
profileName: 'Mr. Fire',
|
profileName: 'Mr. Fire',
|
||||||
},
|
},
|
||||||
|
@ -143,6 +159,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
|
@ -152,6 +169,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'add',
|
type: 'add',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Mr. Fire',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
profileName: 'Mr. Fire',
|
profileName: 'Mr. Fire',
|
||||||
},
|
},
|
||||||
|
@ -162,6 +180,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -170,6 +189,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'add',
|
type: 'add',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Mr. Fire',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
profileName: 'Mr. Fire',
|
profileName: 'Mr. Fire',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
|
@ -181,6 +201,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -189,11 +210,13 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'add',
|
type: 'add',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Mr. Fire',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
profileName: 'Mr. Fire',
|
profileName: 'Mr. Fire',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: 'Mrs. Ice',
|
||||||
phoneNumber: '(202) 555-1001',
|
phoneNumber: '(202) 555-1001',
|
||||||
profileName: 'Mrs. Ice',
|
profileName: 'Mrs. Ice',
|
||||||
},
|
},
|
||||||
|
@ -209,6 +232,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -217,14 +241,17 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'remove',
|
type: 'remove',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Mr. Fire',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
profileName: 'Mr. Fire',
|
profileName: 'Mr. Fire',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: 'Mrs. Ice',
|
||||||
phoneNumber: '(202) 555-1001',
|
phoneNumber: '(202) 555-1001',
|
||||||
profileName: 'Mrs. Ice',
|
profileName: 'Mrs. Ice',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: 'Ms. Earth',
|
||||||
phoneNumber: '(202) 555-1002',
|
phoneNumber: '(202) 555-1002',
|
||||||
name: 'Ms. Earth',
|
name: 'Ms. Earth',
|
||||||
},
|
},
|
||||||
|
@ -235,6 +262,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -243,6 +271,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'remove',
|
type: 'remove',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Mr. Fire',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
profileName: 'Mr. Fire',
|
profileName: 'Mr. Fire',
|
||||||
},
|
},
|
||||||
|
@ -253,6 +282,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
|
@ -262,6 +292,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
type: 'remove',
|
type: 'remove',
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
|
@ -278,6 +309,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -291,6 +323,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
|
@ -310,6 +343,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
@ -323,6 +357,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
isMe: true,
|
isMe: true,
|
||||||
|
@ -342,6 +377,7 @@ const stories: Array<GroupNotificationStory> = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
from: {
|
from: {
|
||||||
|
title: 'Alice',
|
||||||
name: 'Alice',
|
name: 'Alice',
|
||||||
phoneNumber: '(202) 555-1000',
|
phoneNumber: '(202) 555-1000',
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,9 +8,10 @@ import { LocalizerType } from '../../types/Util';
|
||||||
import { missingCaseError } from '../../util/missingCaseError';
|
import { missingCaseError } from '../../util/missingCaseError';
|
||||||
|
|
||||||
interface Contact {
|
interface Contact {
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
title: string;
|
||||||
isMe?: boolean;
|
isMe?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,9 +49,11 @@ export class GroupNotification extends React.Component<Props> {
|
||||||
className="module-group-notification__contact"
|
className="module-group-notification__contact"
|
||||||
>
|
>
|
||||||
<ContactName
|
<ContactName
|
||||||
|
title={contact.title}
|
||||||
phoneNumber={contact.phoneNumber}
|
phoneNumber={contact.phoneNumber}
|
||||||
profileName={contact.profileName}
|
profileName={contact.profileName}
|
||||||
name={contact.name}
|
name={contact.name}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
@ -128,9 +131,11 @@ export class GroupNotification extends React.Component<Props> {
|
||||||
|
|
||||||
const fromContact = (
|
const fromContact = (
|
||||||
<ContactName
|
<ContactName
|
||||||
|
title={from.title}
|
||||||
phoneNumber={from.phoneNumber}
|
phoneNumber={from.phoneNumber}
|
||||||
profileName={from.profileName}
|
profileName={from.profileName}
|
||||||
name={from.name}
|
name={from.name}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ const baseDataProps: Pick<
|
||||||
| 'conversationType'
|
| 'conversationType'
|
||||||
| 'previews'
|
| 'previews'
|
||||||
| 'timestamp'
|
| 'timestamp'
|
||||||
| 'authorPhoneNumber'
|
| 'authorTitle'
|
||||||
> = {
|
> = {
|
||||||
id: 'asdf',
|
id: 'asdf',
|
||||||
canReply: true,
|
canReply: true,
|
||||||
|
@ -38,7 +38,7 @@ const baseDataProps: Pick<
|
||||||
conversationType: 'direct',
|
conversationType: 'direct',
|
||||||
previews: [],
|
previews: [],
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
authorPhoneNumber: '(202) 555-2001',
|
authorTitle: '(202) 555-2001',
|
||||||
};
|
};
|
||||||
|
|
||||||
type MessageStory = [
|
type MessageStory = [
|
||||||
|
|
|
@ -73,10 +73,10 @@ export type PropsData = {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
status?: 'sending' | 'sent' | 'delivered' | 'read' | 'error';
|
status?: 'sending' | 'sent' | 'delivered' | 'read' | 'error';
|
||||||
contact?: ContactType;
|
contact?: ContactType;
|
||||||
|
authorTitle: string;
|
||||||
authorName?: string;
|
authorName?: string;
|
||||||
authorProfileName?: string;
|
authorProfileName?: string;
|
||||||
/** Note: this should be formatted for display */
|
authorPhoneNumber?: string;
|
||||||
authorPhoneNumber: string;
|
|
||||||
authorColor?: ColorType;
|
authorColor?: ColorType;
|
||||||
conversationType: 'group' | 'direct';
|
conversationType: 'group' | 'direct';
|
||||||
attachments?: Array<AttachmentType>;
|
attachments?: Array<AttachmentType>;
|
||||||
|
@ -86,8 +86,9 @@ export type PropsData = {
|
||||||
isFromMe: boolean;
|
isFromMe: boolean;
|
||||||
sentAt: number;
|
sentAt: number;
|
||||||
authorId: string;
|
authorId: string;
|
||||||
authorPhoneNumber: string;
|
authorPhoneNumber?: string;
|
||||||
authorProfileName?: string;
|
authorProfileName?: string;
|
||||||
|
authorTitle: string;
|
||||||
authorName?: string;
|
authorName?: string;
|
||||||
authorColor?: ColorType;
|
authorColor?: ColorType;
|
||||||
referencedMessageNotFound: boolean;
|
referencedMessageNotFound: boolean;
|
||||||
|
@ -483,12 +484,14 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
public renderAuthor() {
|
public renderAuthor() {
|
||||||
const {
|
const {
|
||||||
|
authorTitle,
|
||||||
authorName,
|
authorName,
|
||||||
authorPhoneNumber,
|
authorPhoneNumber,
|
||||||
authorProfileName,
|
authorProfileName,
|
||||||
collapseMetadata,
|
collapseMetadata,
|
||||||
conversationType,
|
conversationType,
|
||||||
direction,
|
direction,
|
||||||
|
i18n,
|
||||||
isSticker,
|
isSticker,
|
||||||
isTapToView,
|
isTapToView,
|
||||||
isTapToViewExpired,
|
isTapToViewExpired,
|
||||||
|
@ -498,9 +501,11 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = authorName ? authorName : authorPhoneNumber;
|
if (
|
||||||
|
direction !== 'incoming' ||
|
||||||
if (direction !== 'incoming' || conversationType !== 'group' || !title) {
|
conversationType !== 'group' ||
|
||||||
|
!authorTitle
|
||||||
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,10 +520,12 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
return (
|
return (
|
||||||
<div className={moduleName}>
|
<div className={moduleName}>
|
||||||
<ContactName
|
<ContactName
|
||||||
|
title={authorTitle}
|
||||||
phoneNumber={authorPhoneNumber}
|
phoneNumber={authorPhoneNumber}
|
||||||
name={authorName}
|
name={authorName}
|
||||||
profileName={authorProfileName}
|
profileName={authorProfileName}
|
||||||
module={moduleName}
|
module={moduleName}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -847,6 +854,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
authorProfileName={quote.authorProfileName}
|
authorProfileName={quote.authorProfileName}
|
||||||
authorName={quote.authorName}
|
authorName={quote.authorName}
|
||||||
authorColor={quoteColor}
|
authorColor={quoteColor}
|
||||||
|
authorTitle={quote.authorTitle}
|
||||||
referencedMessageNotFound={referencedMessageNotFound}
|
referencedMessageNotFound={referencedMessageNotFound}
|
||||||
isFromMe={quote.isFromMe}
|
isFromMe={quote.isFromMe}
|
||||||
withContentAbove={withContentAbove}
|
withContentAbove={withContentAbove}
|
||||||
|
@ -917,6 +925,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
authorName,
|
authorName,
|
||||||
authorPhoneNumber,
|
authorPhoneNumber,
|
||||||
authorProfileName,
|
authorProfileName,
|
||||||
|
authorTitle,
|
||||||
collapseMetadata,
|
collapseMetadata,
|
||||||
authorColor,
|
authorColor,
|
||||||
conversationType,
|
conversationType,
|
||||||
|
@ -942,6 +951,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
name={authorName}
|
name={authorName}
|
||||||
phoneNumber={authorPhoneNumber}
|
phoneNumber={authorPhoneNumber}
|
||||||
profileName={authorProfileName}
|
profileName={authorProfileName}
|
||||||
|
title={authorTitle}
|
||||||
size={28}
|
size={28}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,7 +9,9 @@ import { ColorType, LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
interface Contact {
|
interface Contact {
|
||||||
status: string;
|
status: string;
|
||||||
phoneNumber: string;
|
|
||||||
|
title: string;
|
||||||
|
phoneNumber?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
avatarPath?: string;
|
avatarPath?: string;
|
||||||
|
@ -49,7 +51,14 @@ export class MessageDetail extends React.Component<Props> {
|
||||||
|
|
||||||
public renderAvatar(contact: Contact) {
|
public renderAvatar(contact: Contact) {
|
||||||
const { i18n } = this.props;
|
const { i18n } = this.props;
|
||||||
const { avatarPath, color, phoneNumber, name, profileName } = contact;
|
const {
|
||||||
|
avatarPath,
|
||||||
|
color,
|
||||||
|
phoneNumber,
|
||||||
|
name,
|
||||||
|
profileName,
|
||||||
|
title,
|
||||||
|
} = contact;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Avatar
|
<Avatar
|
||||||
|
@ -60,6 +69,7 @@ export class MessageDetail extends React.Component<Props> {
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
size={52}
|
size={52}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -123,6 +133,8 @@ export class MessageDetail extends React.Component<Props> {
|
||||||
phoneNumber={contact.phoneNumber}
|
phoneNumber={contact.phoneNumber}
|
||||||
name={contact.name}
|
name={contact.name}
|
||||||
profileName={contact.profileName}
|
profileName={contact.profileName}
|
||||||
|
title={contact.title}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{errors.map((error, index) => (
|
{errors.map((error, index) => (
|
||||||
|
|
|
@ -17,7 +17,9 @@ const i18n = setupI18n('en', enMessages);
|
||||||
const getBaseProps = (isGroup = false): MessageRequestActionsProps => ({
|
const getBaseProps = (isGroup = false): MessageRequestActionsProps => ({
|
||||||
i18n,
|
i18n,
|
||||||
conversationType: isGroup ? 'group' : 'direct',
|
conversationType: isGroup ? 'group' : 'direct',
|
||||||
profileName: isGroup ? undefined : text('profileName', 'Cayce Bollard'),
|
title: isGroup
|
||||||
|
? text('title', 'NYC Rock Climbers')
|
||||||
|
: text('title', 'Cayce Bollard'),
|
||||||
name: isGroup
|
name: isGroup
|
||||||
? text('name', 'NYC Rock Climbers')
|
? text('name', 'NYC Rock Climbers')
|
||||||
: text('name', 'Cayce Bollard'),
|
: text('name', 'Cayce Bollard'),
|
||||||
|
|
|
@ -12,17 +12,19 @@ import { LocalizerType } from '../../types/Util';
|
||||||
export type Props = {
|
export type Props = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
onAccept(): unknown;
|
onAccept(): unknown;
|
||||||
} & Omit<ContactNameProps, 'module'> &
|
} & Omit<ContactNameProps, 'module' | 'i18n'> &
|
||||||
Omit<
|
Omit<
|
||||||
MessageRequestActionsConfirmationProps,
|
MessageRequestActionsConfirmationProps,
|
||||||
'i18n' | 'state' | 'onChangeState'
|
'i18n' | 'state' | 'onChangeState'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
// tslint:disable-next-line max-func-body-length
|
||||||
export const MessageRequestActions = ({
|
export const MessageRequestActions = ({
|
||||||
i18n,
|
i18n,
|
||||||
name,
|
name,
|
||||||
profileName,
|
profileName,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
|
title,
|
||||||
conversationType,
|
conversationType,
|
||||||
isBlocked,
|
isBlocked,
|
||||||
onBlock,
|
onBlock,
|
||||||
|
@ -45,6 +47,7 @@ export const MessageRequestActions = ({
|
||||||
name={name}
|
name={name}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
|
title={title}
|
||||||
conversationType={conversationType}
|
conversationType={conversationType}
|
||||||
state={mrState}
|
state={mrState}
|
||||||
onChangeState={setMrState}
|
onChangeState={setMrState}
|
||||||
|
@ -66,6 +69,8 @@ export const MessageRequestActions = ({
|
||||||
name={name}
|
name={name}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
|
title={title}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</strong>,
|
</strong>,
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -21,7 +21,7 @@ export type Props = {
|
||||||
onDelete(): unknown;
|
onDelete(): unknown;
|
||||||
state: MessageRequestState;
|
state: MessageRequestState;
|
||||||
onChangeState(state: MessageRequestState): unknown;
|
onChangeState(state: MessageRequestState): unknown;
|
||||||
} & Omit<ContactNameProps, 'module'>;
|
} & Omit<ContactNameProps, 'module' | 'i18n'>;
|
||||||
|
|
||||||
// tslint:disable-next-line: max-func-body-length
|
// tslint:disable-next-line: max-func-body-length
|
||||||
export const MessageRequestActionsConfirmation = ({
|
export const MessageRequestActionsConfirmation = ({
|
||||||
|
@ -29,6 +29,7 @@ export const MessageRequestActionsConfirmation = ({
|
||||||
name,
|
name,
|
||||||
profileName,
|
profileName,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
|
title,
|
||||||
conversationType,
|
conversationType,
|
||||||
onBlock,
|
onBlock,
|
||||||
onBlockAndDelete,
|
onBlockAndDelete,
|
||||||
|
@ -55,6 +56,8 @@ export const MessageRequestActionsConfirmation = ({
|
||||||
name={name}
|
name={name}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
|
title={title}
|
||||||
|
i18n={i18n}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@ -95,6 +98,8 @@ export const MessageRequestActionsConfirmation = ({
|
||||||
name={name}
|
name={name}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
|
title={title}
|
||||||
|
i18n={i18n}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@ -135,6 +140,8 @@ export const MessageRequestActionsConfirmation = ({
|
||||||
name={name}
|
name={name}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
|
title={title}
|
||||||
|
i18n={i18n}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -12,7 +12,8 @@ import { ContactName } from './ContactName';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
attachment?: QuotedAttachmentType;
|
attachment?: QuotedAttachmentType;
|
||||||
authorPhoneNumber: string;
|
authorTitle: string;
|
||||||
|
authorPhoneNumber?: string;
|
||||||
authorProfileName?: string;
|
authorProfileName?: string;
|
||||||
authorName?: string;
|
authorName?: string;
|
||||||
authorColor?: ColorType;
|
authorColor?: ColorType;
|
||||||
|
@ -307,6 +308,7 @@ export class Quote extends React.Component<Props, State> {
|
||||||
const {
|
const {
|
||||||
authorProfileName,
|
authorProfileName,
|
||||||
authorPhoneNumber,
|
authorPhoneNumber,
|
||||||
|
authorTitle,
|
||||||
authorName,
|
authorName,
|
||||||
i18n,
|
i18n,
|
||||||
isFromMe,
|
isFromMe,
|
||||||
|
@ -327,6 +329,8 @@ export class Quote extends React.Component<Props, State> {
|
||||||
phoneNumber={authorPhoneNumber}
|
phoneNumber={authorPhoneNumber}
|
||||||
name={authorName}
|
name={authorName}
|
||||||
profileName={authorProfileName}
|
profileName={authorProfileName}
|
||||||
|
title={authorTitle}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,6 +16,7 @@ export type Reaction = {
|
||||||
avatarPath?: string;
|
avatarPath?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
title: string;
|
||||||
isMe?: boolean;
|
isMe?: boolean;
|
||||||
phoneNumber?: string;
|
phoneNumber?: string;
|
||||||
};
|
};
|
||||||
|
@ -156,6 +157,7 @@ export const ReactionViewer = React.forwardRef<HTMLDivElement, Props>(
|
||||||
name={from.name}
|
name={from.name}
|
||||||
profileName={from.profileName}
|
profileName={from.profileName}
|
||||||
phoneNumber={from.phoneNumber}
|
phoneNumber={from.phoneNumber}
|
||||||
|
title={from.title}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -168,6 +170,8 @@ export const ReactionViewer = React.forwardRef<HTMLDivElement, Props>(
|
||||||
name={from.name}
|
name={from.name}
|
||||||
profileName={from.profileName}
|
profileName={from.profileName}
|
||||||
phoneNumber={from.phoneNumber}
|
phoneNumber={from.phoneNumber}
|
||||||
|
title={from.title}
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,11 @@
|
||||||
<SafetyNumberNotification
|
<SafetyNumberNotification
|
||||||
i18n={util.i18n}
|
i18n={util.i18n}
|
||||||
isGroup={true}
|
isGroup={true}
|
||||||
contact={{ phoneNumber: '(202) 500-1000', profileName: 'Mr. Fire' }}
|
contact={{
|
||||||
|
phoneNumber: '(202) 500-1000',
|
||||||
|
profileName: 'Mr. Fire',
|
||||||
|
title: 'Mr. Fire',
|
||||||
|
}}
|
||||||
onVerify={() => console.log('onVerify')}
|
onVerify={() => console.log('onVerify')}
|
||||||
/>
|
/>
|
||||||
</util.ConversationContext>
|
</util.ConversationContext>
|
||||||
|
@ -18,7 +22,11 @@
|
||||||
<SafetyNumberNotification
|
<SafetyNumberNotification
|
||||||
i18n={util.i18n}
|
i18n={util.i18n}
|
||||||
isGroup={false}
|
isGroup={false}
|
||||||
contact={{ phoneNumber: '(202) 500-1000', profileName: 'Mr. Fire' }}
|
contact={{
|
||||||
|
phoneNumber: '(202) 500-1000',
|
||||||
|
profileName: 'Mr. Fire',
|
||||||
|
title: 'Mr. Fire',
|
||||||
|
}}
|
||||||
onVerify={() => console.log('onVerify')}
|
onVerify={() => console.log('onVerify')}
|
||||||
/>
|
/>
|
||||||
</util.ConversationContext>
|
</util.ConversationContext>
|
||||||
|
|
|
@ -6,8 +6,9 @@ import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
interface ContactType {
|
interface ContactType {
|
||||||
id: string;
|
id: string;
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
title: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +49,9 @@ export class SafetyNumberNotification extends React.Component<Props> {
|
||||||
name={contact.name}
|
name={contact.name}
|
||||||
profileName={contact.profileName}
|
profileName={contact.profileName}
|
||||||
phoneNumber={contact.phoneNumber}
|
phoneNumber={contact.phoneNumber}
|
||||||
|
title={contact.title}
|
||||||
module="module-safety-number-notification__contact"
|
module="module-safety-number-notification__contact"
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</span>,
|
</span>,
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
type="fromOther"
|
type="fromOther"
|
||||||
phoneNumber="(202) 555-1000"
|
phoneNumber="(202) 555-1000"
|
||||||
profileName="Mr. Fire"
|
profileName="Mr. Fire"
|
||||||
|
title="Mr. Fire"
|
||||||
timespan="1 hour"
|
timespan="1 hour"
|
||||||
i18n={util.i18n}
|
i18n={util.i18n}
|
||||||
/>
|
/>
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
type="fromOther"
|
type="fromOther"
|
||||||
phoneNumber="(202) 555-1000"
|
phoneNumber="(202) 555-1000"
|
||||||
profileName="Mr. Fire"
|
profileName="Mr. Fire"
|
||||||
|
title="Mr. Fire"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
timespan="Off"
|
timespan="Off"
|
||||||
i18n={util.i18n}
|
i18n={util.i18n}
|
||||||
|
@ -27,12 +29,14 @@
|
||||||
<TimerNotification
|
<TimerNotification
|
||||||
type="fromMe"
|
type="fromMe"
|
||||||
phoneNumber="(202) 555-1000"
|
phoneNumber="(202) 555-1000"
|
||||||
|
title="(202) 555-1000"
|
||||||
timespan="1 hour"
|
timespan="1 hour"
|
||||||
i18n={util.i18n}
|
i18n={util.i18n}
|
||||||
/>
|
/>
|
||||||
<TimerNotification
|
<TimerNotification
|
||||||
type="fromMe"
|
type="fromMe"
|
||||||
phoneNumber="(202) 555-1000"
|
phoneNumber="(202) 555-1000"
|
||||||
|
title="(202) 555-1000"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
timespan="Off"
|
timespan="Off"
|
||||||
i18n={util.i18n}
|
i18n={util.i18n}
|
||||||
|
@ -47,12 +51,14 @@
|
||||||
<TimerNotification
|
<TimerNotification
|
||||||
type="fromSync"
|
type="fromSync"
|
||||||
phoneNumber="(202) 555-1000"
|
phoneNumber="(202) 555-1000"
|
||||||
|
title="(202) 555-1000"
|
||||||
timespan="1 hour"
|
timespan="1 hour"
|
||||||
i18n={util.i18n}
|
i18n={util.i18n}
|
||||||
/>
|
/>
|
||||||
<TimerNotification
|
<TimerNotification
|
||||||
type="fromSync"
|
type="fromSync"
|
||||||
phoneNumber="(202) 555-1000"
|
phoneNumber="(202) 555-1000"
|
||||||
|
title="(202) 555-1000"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
timespan="Off"
|
timespan="Off"
|
||||||
i18n={util.i18n}
|
i18n={util.i18n}
|
||||||
|
|
|
@ -7,8 +7,9 @@ import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
export type PropsData = {
|
export type PropsData = {
|
||||||
type: 'fromOther' | 'fromMe' | 'fromSync';
|
type: 'fromOther' | 'fromMe' | 'fromSync';
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
title: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
timespan: string;
|
timespan: string;
|
||||||
|
@ -27,6 +28,7 @@ export class TimerNotification extends React.Component<Props> {
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
timespan,
|
timespan,
|
||||||
type,
|
type,
|
||||||
disabled,
|
disabled,
|
||||||
|
@ -46,7 +48,9 @@ export class TimerNotification extends React.Component<Props> {
|
||||||
key="external-1"
|
key="external-1"
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
name={name}
|
name={name}
|
||||||
|
i18n={i18n}
|
||||||
/>,
|
/>,
|
||||||
timespan,
|
timespan,
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -10,8 +10,9 @@ interface Props {
|
||||||
avatarPath?: string;
|
avatarPath?: string;
|
||||||
color: ColorType;
|
color: ColorType;
|
||||||
name?: string;
|
name?: string;
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
title: string;
|
||||||
conversationType: 'group' | 'direct';
|
conversationType: 'group' | 'direct';
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +25,7 @@ export class TypingBubble extends React.PureComponent<Props> {
|
||||||
name,
|
name,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
profileName,
|
profileName,
|
||||||
|
title,
|
||||||
conversationType,
|
conversationType,
|
||||||
i18n,
|
i18n,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -42,6 +44,7 @@ export class TypingBubble extends React.PureComponent<Props> {
|
||||||
name={name}
|
name={name}
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
profileName={profileName}
|
profileName={profileName}
|
||||||
|
title={title}
|
||||||
size={28}
|
size={28}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,8 +7,9 @@ import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
interface ContactType {
|
interface ContactType {
|
||||||
id: string;
|
id: string;
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
title: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
isMe: boolean;
|
isMe: boolean;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +64,9 @@ export class UnsupportedMessage extends React.Component<Props> {
|
||||||
name={contact.name}
|
name={contact.name}
|
||||||
profileName={contact.profileName}
|
profileName={contact.profileName}
|
||||||
phoneNumber={contact.phoneNumber}
|
phoneNumber={contact.phoneNumber}
|
||||||
|
title={contact.title}
|
||||||
module="module-unsupported-message__contact"
|
module="module-unsupported-message__contact"
|
||||||
|
i18n={i18n}
|
||||||
/>
|
/>
|
||||||
</span>,
|
</span>,
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -8,9 +8,10 @@ import { LocalizerType } from '../../types/Util';
|
||||||
import { missingCaseError } from '../../util/missingCaseError';
|
import { missingCaseError } from '../../util/missingCaseError';
|
||||||
|
|
||||||
interface Contact {
|
interface Contact {
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PropsData = {
|
export type PropsData = {
|
||||||
|
@ -56,7 +57,9 @@ export class VerificationNotification extends React.Component<Props> {
|
||||||
name={contact.name}
|
name={contact.name}
|
||||||
profileName={contact.profileName}
|
profileName={contact.profileName}
|
||||||
phoneNumber={contact.phoneNumber}
|
phoneNumber={contact.phoneNumber}
|
||||||
|
title={contact.title}
|
||||||
module="module-verification-notification__contact"
|
module="module-verification-notification__contact"
|
||||||
|
i18n={i18n}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
|
|
@ -24,7 +24,7 @@ export function renderAvatar({
|
||||||
|
|
||||||
const avatarPath = avatar && avatar.avatar && avatar.avatar.path;
|
const avatarPath = avatar && avatar.avatar && avatar.avatar.path;
|
||||||
const pending = avatar && avatar.avatar && avatar.avatar.pending;
|
const pending = avatar && avatar.avatar && avatar.avatar.pending;
|
||||||
const name = getName(contact) || '';
|
const title = getName(contact) || '';
|
||||||
const spinnerSvgSize = size < 50 ? 'small' : 'normal';
|
const spinnerSvgSize = size < 50 ? 'small' : 'normal';
|
||||||
const spinnerSize = size < 50 ? '24px' : undefined;
|
const spinnerSize = size < 50 ? '24px' : undefined;
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export function renderAvatar({
|
||||||
color="grey"
|
color="grey"
|
||||||
conversationType="direct"
|
conversationType="direct"
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
name={name}
|
title={title}
|
||||||
size={size}
|
size={size}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -409,14 +409,11 @@ export class CallingClass {
|
||||||
call: Call
|
call: Call
|
||||||
): CallDetailsType {
|
): CallDetailsType {
|
||||||
return {
|
return {
|
||||||
avatarPath: conversation.getAvatarPath(),
|
...conversation.cachedProps,
|
||||||
|
|
||||||
callId: call.callId,
|
callId: call.callId,
|
||||||
contactColor: conversation.getColor(),
|
|
||||||
isIncoming: call.isIncoming,
|
isIncoming: call.isIncoming,
|
||||||
isVideoCall: call.isVideoCall,
|
isVideoCall: call.isVideoCall,
|
||||||
name: conversation.getName(),
|
|
||||||
phoneNumber: conversation.getNumber(),
|
|
||||||
profileName: conversation.getProfileName(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,16 @@ import {
|
||||||
export type CallId = any;
|
export type CallId = any;
|
||||||
|
|
||||||
export type CallDetailsType = {
|
export type CallDetailsType = {
|
||||||
avatarPath?: string;
|
|
||||||
callId: CallId;
|
callId: CallId;
|
||||||
contactColor?: ColorType;
|
|
||||||
isIncoming: boolean;
|
isIncoming: boolean;
|
||||||
isVideoCall: boolean;
|
isVideoCall: boolean;
|
||||||
|
|
||||||
|
avatarPath?: string;
|
||||||
|
color?: ColorType;
|
||||||
name?: string;
|
name?: string;
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
|
title: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CallingStateType = {
|
export type CallingStateType = {
|
||||||
|
@ -221,10 +223,10 @@ async function showCallNotification(callDetails: CallDetailsType) {
|
||||||
if (!canNotify) {
|
if (!canNotify) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { name, phoneNumber, profileName, isVideoCall } = callDetails;
|
const { title, isVideoCall } = callDetails;
|
||||||
notify({
|
notify({
|
||||||
platform: window.platform,
|
platform: window.platform,
|
||||||
title: `${name || phoneNumber} ${profileName || ''}`,
|
title,
|
||||||
icon: isVideoCall
|
icon: isVideoCall
|
||||||
? 'images/icons/v2/video-solid-24.svg'
|
? 'images/icons/v2/video-solid-24.svg'
|
||||||
: 'images/icons/v2/phone-right-solid-24.svg',
|
: 'images/icons/v2/phone-right-solid-24.svg',
|
||||||
|
|
|
@ -25,7 +25,7 @@ export type DBConversationType = {
|
||||||
export type ConversationType = {
|
export type ConversationType = {
|
||||||
id: string;
|
id: string;
|
||||||
uuid?: string;
|
uuid?: string;
|
||||||
e164: string;
|
e164?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
avatarPath?: string;
|
avatarPath?: string;
|
||||||
|
@ -34,13 +34,13 @@ export type ConversationType = {
|
||||||
isBlocked?: boolean;
|
isBlocked?: boolean;
|
||||||
isVerified?: boolean;
|
isVerified?: boolean;
|
||||||
activeAt?: number;
|
activeAt?: number;
|
||||||
timestamp: number;
|
timestamp?: number;
|
||||||
inboxPosition: number;
|
inboxPosition?: number;
|
||||||
lastMessage?: {
|
lastMessage?: {
|
||||||
status: 'error' | 'sending' | 'sent' | 'delivered' | 'read';
|
status: 'error' | 'sending' | 'sent' | 'delivered' | 'read';
|
||||||
text: string;
|
text: string;
|
||||||
};
|
};
|
||||||
phoneNumber: string;
|
phoneNumber?: string;
|
||||||
membersCount?: number;
|
membersCount?: number;
|
||||||
type: 'direct' | 'group';
|
type: 'direct' | 'group';
|
||||||
isMe: boolean;
|
isMe: boolean;
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import memoizee from 'memoizee';
|
import memoizee from 'memoizee';
|
||||||
import { fromPairs, isNumber } from 'lodash';
|
import { fromPairs, isNumber } from 'lodash';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { format } from '../../types/PhoneNumber';
|
|
||||||
|
|
||||||
import { LocalizerType } from '../../types/Util';
|
|
||||||
import { StateType } from '../reducer';
|
import { StateType } from '../reducer';
|
||||||
import {
|
import {
|
||||||
ConversationLookupType,
|
ConversationLookupType,
|
||||||
|
@ -81,29 +79,11 @@ export const getMessagesByConversation = createSelector(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function getConversationTitle(
|
|
||||||
conversation: ConversationType,
|
|
||||||
options: { i18n: LocalizerType; ourRegionCode: string }
|
|
||||||
): string {
|
|
||||||
if (conversation.name) {
|
|
||||||
return conversation.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conversation.type === 'group') {
|
|
||||||
const { i18n } = options;
|
|
||||||
|
|
||||||
return i18n('unknownGroup');
|
|
||||||
}
|
|
||||||
|
|
||||||
return format(conversation.phoneNumber, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
const collator = new Intl.Collator();
|
const collator = new Intl.Collator();
|
||||||
|
|
||||||
export const _getConversationComparator = (
|
// Note: we will probably want to put i18n and regionCode back when we are formatting
|
||||||
i18n: LocalizerType,
|
// phone numbers and contacts from scratch here again.
|
||||||
ourRegionCode: string
|
export const _getConversationComparator = () => {
|
||||||
) => {
|
|
||||||
return (left: ConversationType, right: ConversationType): number => {
|
return (left: ConversationType, right: ConversationType): number => {
|
||||||
const leftTimestamp = left.timestamp;
|
const leftTimestamp = left.timestamp;
|
||||||
const rightTimestamp = right.timestamp;
|
const rightTimestamp = right.timestamp;
|
||||||
|
@ -132,16 +112,7 @@ export const _getConversationComparator = (
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const leftTitle = getConversationTitle(left, {
|
return collator.compare(left.title, right.title);
|
||||||
i18n,
|
|
||||||
ourRegionCode,
|
|
||||||
});
|
|
||||||
const rightTitle = getConversationTitle(right, {
|
|
||||||
i18n,
|
|
||||||
ourRegionCode,
|
|
||||||
});
|
|
||||||
|
|
||||||
return collator.compare(leftTitle, rightTitle);
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export const getConversationComparator = createSelector(
|
export const getConversationComparator = createSelector(
|
||||||
|
|
|
@ -9,8 +9,6 @@ import {
|
||||||
describe('state/selectors/conversations', () => {
|
describe('state/selectors/conversations', () => {
|
||||||
describe('#getLeftPaneList', () => {
|
describe('#getLeftPaneList', () => {
|
||||||
it('sorts conversations based on timestamp then by intl-friendly title', () => {
|
it('sorts conversations based on timestamp then by intl-friendly title', () => {
|
||||||
const i18n = (key: string) => key;
|
|
||||||
const regionCode = 'US';
|
|
||||||
const data: ConversationLookupType = {
|
const data: ConversationLookupType = {
|
||||||
id1: {
|
id1: {
|
||||||
id: 'id1',
|
id: 'id1',
|
||||||
|
@ -133,7 +131,7 @@ describe('state/selectors/conversations', () => {
|
||||||
acceptedMessageRequest: true,
|
acceptedMessageRequest: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const comparator = _getConversationComparator(i18n, regionCode);
|
const comparator = _getConversationComparator();
|
||||||
const { conversations } = _getLeftPaneLists(data, comparator);
|
const { conversations } = _getLeftPaneLists(data, comparator);
|
||||||
|
|
||||||
assert.strictEqual(conversations[0].name, 'First!');
|
assert.strictEqual(conversations[0].name, 'First!');
|
||||||
|
|
|
@ -353,7 +353,7 @@
|
||||||
"rule": "jQuery-append(",
|
"rule": "jQuery-append(",
|
||||||
"path": "js/views/contact_list_view.js",
|
"path": "js/views/contact_list_view.js",
|
||||||
"line": " this.$el.append(this.contactView.el);",
|
"line": " this.$el.append(this.contactView.el);",
|
||||||
"lineNumber": 46,
|
"lineNumber": 37,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2019-07-31T00:19:18.696Z",
|
"updated": "2019-07-31T00:19:18.696Z",
|
||||||
"reasonDetail": "Known DOM elements"
|
"reasonDetail": "Known DOM elements"
|
||||||
|
@ -11546,7 +11546,7 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/MainHeader.tsx",
|
"path": "ts/components/MainHeader.tsx",
|
||||||
"line": " this.inputRef = React.createRef();",
|
"line": " this.inputRef = React.createRef();",
|
||||||
"lineNumber": 69,
|
"lineNumber": 70,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-02-14T20:02:37.507Z",
|
"updated": "2020-02-14T20:02:37.507Z",
|
||||||
"reasonDetail": "Used only to set focus"
|
"reasonDetail": "Used only to set focus"
|
||||||
|
@ -11555,7 +11555,7 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/SafetyNumberChangeDialog.js",
|
"path": "ts/components/SafetyNumberChangeDialog.js",
|
||||||
"line": " const cancelButtonRef = React.createRef();",
|
"line": " const cancelButtonRef = React.createRef();",
|
||||||
"lineNumber": 14,
|
"lineNumber": 15,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-06-23T06:48:06.829Z",
|
"updated": "2020-06-23T06:48:06.829Z",
|
||||||
"reasonDetail": "Used to focus cancel button when dialog opens"
|
"reasonDetail": "Used to focus cancel button when dialog opens"
|
||||||
|
@ -11573,7 +11573,7 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/conversation/ConversationHeader.js",
|
"path": "ts/components/conversation/ConversationHeader.js",
|
||||||
"line": " this.menuTriggerRef = react_1.default.createRef();",
|
"line": " this.menuTriggerRef = react_1.default.createRef();",
|
||||||
"lineNumber": 14,
|
"lineNumber": 15,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2019-07-31T00:19:18.696Z",
|
"updated": "2019-07-31T00:19:18.696Z",
|
||||||
"reasonDetail": "Used to reference popup menu"
|
"reasonDetail": "Used to reference popup menu"
|
||||||
|
@ -11582,7 +11582,7 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/conversation/ConversationHeader.tsx",
|
"path": "ts/components/conversation/ConversationHeader.tsx",
|
||||||
"line": " this.menuTriggerRef = React.createRef();",
|
"line": " this.menuTriggerRef = React.createRef();",
|
||||||
"lineNumber": 70,
|
"lineNumber": 75,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-05-20T20:10:43.540Z",
|
"updated": "2020-05-20T20:10:43.540Z",
|
||||||
"reasonDetail": "Used to reference popup menu"
|
"reasonDetail": "Used to reference popup menu"
|
||||||
|
@ -11626,7 +11626,7 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/conversation/Message.tsx",
|
"path": "ts/components/conversation/Message.tsx",
|
||||||
"line": " public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();",
|
"line": " public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();",
|
||||||
"lineNumber": 184,
|
"lineNumber": 185,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-05-21T16:56:07.875Z"
|
"updated": "2020-05-21T16:56:07.875Z"
|
||||||
},
|
},
|
||||||
|
@ -11634,7 +11634,7 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/conversation/Message.tsx",
|
"path": "ts/components/conversation/Message.tsx",
|
||||||
"line": " > = React.createRef();",
|
"line": " > = React.createRef();",
|
||||||
"lineNumber": 188,
|
"lineNumber": 189,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-05-21T16:56:07.875Z"
|
"updated": "2020-05-21T16:56:07.875Z"
|
||||||
},
|
},
|
||||||
|
|
|
@ -42,6 +42,13 @@ export async function generateSecurityNumberBlock(
|
||||||
throw new Error('Could not load their key');
|
throw new Error('Could not load their key');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!contact.e164) {
|
||||||
|
window.log.error(
|
||||||
|
'generateSecurityNumberBlock: Attempted to generate security number for contact with no e164'
|
||||||
|
);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const securityNumber = await generateSecurityNumber(
|
const securityNumber = await generateSecurityNumber(
|
||||||
ourNumber,
|
ourNumber,
|
||||||
ourKey,
|
ourKey,
|
||||||
|
|
Loading…
Reference in a new issue