Show common groups in contact modal
This commit is contained in:
parent
8ac2d8fcec
commit
885ff5fe42
6 changed files with 121 additions and 88 deletions
|
@ -3064,8 +3064,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConversationHero--membership-1": {
|
"member-of-1-group": {
|
||||||
"message": "Member of $group$.",
|
"message": "Member of $group$",
|
||||||
"description": "Shown in the conversation hero to indicate this user is a member of a mutual group",
|
"description": "Shown in the conversation hero to indicate this user is a member of a mutual group",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"group": {
|
"group": {
|
||||||
|
@ -3074,8 +3074,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConversationHero--membership-2": {
|
"member-of-2-groups": {
|
||||||
"message": "Member of $group1$ and $group2$.",
|
"message": "Member of $group1$ and $group2$",
|
||||||
"description": "Shown in the conversation hero to indicate this user is a member of at least two mutual groups",
|
"description": "Shown in the conversation hero to indicate this user is a member of at least two mutual groups",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"group1": {
|
"group1": {
|
||||||
|
@ -3088,8 +3088,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConversationHero--membership-3": {
|
"member-of-3-groups": {
|
||||||
"message": "Member of $group1$, $group2$, and $group3$.",
|
"message": "Member of $group1$, $group2$, and $group3$",
|
||||||
"description": "Shown in the conversation hero to indicate this user is a member of at least three mutual groups",
|
"description": "Shown in the conversation hero to indicate this user is a member of at least three mutual groups",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"group1": {
|
"group1": {
|
||||||
|
@ -3106,8 +3106,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConversationHero--membership-extra": {
|
"member-of-more-than-3-groups": {
|
||||||
"message": "Member of $group1$, $group2$, $group3$ and $remainingCount$ more.",
|
"message": "Member of $group1$, $group2$, $group3$ and $remainingCount$ more",
|
||||||
"description": "Shown in the conversation hero to indicate this user is a member of at least three mutual groups",
|
"description": "Shown in the conversation hero to indicate this user is a member of at least three mutual groups",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"group1": {
|
"group1": {
|
||||||
|
@ -3139,7 +3139,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"no-groups-in-common": {
|
"no-groups-in-common": {
|
||||||
"message": "No groups in common.",
|
"message": "No groups in common",
|
||||||
"description": "Shown to indicate this user is not a member of any groups"
|
"description": "Shown to indicate this user is not a member of any groups"
|
||||||
},
|
},
|
||||||
"acceptCall": {
|
"acceptCall": {
|
||||||
|
|
|
@ -2115,7 +2115,6 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05',
|
||||||
|
|
||||||
.module-about {
|
.module-about {
|
||||||
&__container {
|
&__container {
|
||||||
margin-bottom: 8px;
|
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
max-width: 248px;
|
max-width: 248px;
|
||||||
|
@ -10484,9 +10483,14 @@ $contact-modal-padding: 18px;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-contact-modal__profile-and-number {
|
.module-contact-modal__info {
|
||||||
color: $color-gray-60;
|
text-align: center;
|
||||||
|
max-width: 248px;
|
||||||
|
margin-top: 8px;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-60;
|
||||||
|
}
|
||||||
@include dark-theme {
|
@include dark-theme {
|
||||||
color: $color-gray-25;
|
color: $color-gray-25;
|
||||||
}
|
}
|
||||||
|
|
83
ts/components/SharedGroupNames.tsx
Normal file
83
ts/components/SharedGroupNames.tsx
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import { take } from 'lodash';
|
||||||
|
|
||||||
|
import { Emojify } from './conversation/Emojify';
|
||||||
|
import { Intl } from './Intl';
|
||||||
|
import { LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
|
type PropsType = {
|
||||||
|
i18n: LocalizerType;
|
||||||
|
nameClassName?: string;
|
||||||
|
sharedGroupNames: Array<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SharedGroupNames: FunctionComponent<PropsType> = ({
|
||||||
|
i18n,
|
||||||
|
nameClassName,
|
||||||
|
sharedGroupNames,
|
||||||
|
}) => {
|
||||||
|
const firstThreeGroups = take(sharedGroupNames, 3).map((group, i) => (
|
||||||
|
// We cannot guarantee uniqueness of group names
|
||||||
|
// eslint-disable-next-line react/no-array-index-key
|
||||||
|
<strong key={i} className={nameClassName}>
|
||||||
|
<Emojify text={group} />
|
||||||
|
</strong>
|
||||||
|
));
|
||||||
|
|
||||||
|
if (sharedGroupNames.length > 3) {
|
||||||
|
const remainingCount = sharedGroupNames.length - 3;
|
||||||
|
return (
|
||||||
|
<Intl
|
||||||
|
i18n={i18n}
|
||||||
|
id="member-of-more-than-3-groups"
|
||||||
|
components={{
|
||||||
|
group1: firstThreeGroups[0],
|
||||||
|
group2: firstThreeGroups[1],
|
||||||
|
group3: firstThreeGroups[2],
|
||||||
|
remainingCount: remainingCount.toString(),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (firstThreeGroups.length === 3) {
|
||||||
|
return (
|
||||||
|
<Intl
|
||||||
|
i18n={i18n}
|
||||||
|
id="member-of-3-groups"
|
||||||
|
components={{
|
||||||
|
group1: firstThreeGroups[0],
|
||||||
|
group2: firstThreeGroups[1],
|
||||||
|
group3: firstThreeGroups[2],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (firstThreeGroups.length >= 2) {
|
||||||
|
return (
|
||||||
|
<Intl
|
||||||
|
i18n={i18n}
|
||||||
|
id="member-of-2-groups"
|
||||||
|
components={{
|
||||||
|
group1: firstThreeGroups[0],
|
||||||
|
group2: firstThreeGroups[1],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (firstThreeGroups.length >= 1) {
|
||||||
|
return (
|
||||||
|
<Intl
|
||||||
|
i18n={i18n}
|
||||||
|
id="member-of-1-group"
|
||||||
|
components={{
|
||||||
|
group: firstThreeGroups[0],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>{i18n('no-groups-in-common')}</>;
|
||||||
|
};
|
|
@ -7,6 +7,7 @@ import { createPortal } from 'react-dom';
|
||||||
import { ConversationType } from '../../state/ducks/conversations';
|
import { ConversationType } from '../../state/ducks/conversations';
|
||||||
import { About } from './About';
|
import { About } from './About';
|
||||||
import { Avatar } from '../Avatar';
|
import { Avatar } from '../Avatar';
|
||||||
|
import { SharedGroupNames } from '../SharedGroupNames';
|
||||||
import { LocalizerType } from '../../types/Util';
|
import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
|
@ -119,10 +120,16 @@ export const ContactModal = ({
|
||||||
<About text={contact.about} />
|
<About text={contact.about} />
|
||||||
</div>
|
</div>
|
||||||
{contact.phoneNumber && (
|
{contact.phoneNumber && (
|
||||||
<div className="module-contact-modal__profile-and-number">
|
<div className="module-contact-modal__info">
|
||||||
{contact.phoneNumber}
|
{contact.phoneNumber}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="module-contact-modal__info">
|
||||||
|
<SharedGroupNames
|
||||||
|
i18n={i18n}
|
||||||
|
sharedGroupNames={contact.sharedGroupNames || []}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="module-contact-modal__button-container">
|
<div className="module-contact-modal__button-container">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
@ -2,12 +2,10 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { take } from 'lodash';
|
|
||||||
import { Avatar, Props as AvatarProps } from '../Avatar';
|
import { Avatar, Props as AvatarProps } from '../Avatar';
|
||||||
import { ContactName } from './ContactName';
|
import { ContactName } from './ContactName';
|
||||||
import { About } from './About';
|
import { About } from './About';
|
||||||
import { Emojify } from './Emojify';
|
import { SharedGroupNames } from '../SharedGroupNames';
|
||||||
import { Intl } from '../Intl';
|
|
||||||
import { LocalizerType } from '../../types/Util';
|
import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
|
@ -32,7 +30,6 @@ const renderMembershipRow = ({
|
||||||
'i18n' | 'phoneNumber' | 'sharedGroupNames' | 'conversationType' | 'isMe'
|
'i18n' | 'phoneNumber' | 'sharedGroupNames' | 'conversationType' | 'isMe'
|
||||||
>) => {
|
>) => {
|
||||||
const className = 'module-conversation-hero__membership';
|
const className = 'module-conversation-hero__membership';
|
||||||
const nameClassName = `${className}__name`;
|
|
||||||
|
|
||||||
if (conversationType !== 'direct') {
|
if (conversationType !== 'direct') {
|
||||||
return null;
|
return null;
|
||||||
|
@ -43,73 +40,15 @@ const renderMembershipRow = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedGroupNames.length > 0) {
|
if (sharedGroupNames.length > 0) {
|
||||||
const firstThreeGroups = take(sharedGroupNames, 3).map((group, i) => (
|
return (
|
||||||
// We cannot guarantee uniqueness of group names
|
<div className={className}>
|
||||||
// eslint-disable-next-line react/no-array-index-key
|
<SharedGroupNames
|
||||||
<strong key={i} className={nameClassName}>
|
i18n={i18n}
|
||||||
<Emojify text={group} />
|
nameClassName={`${className}__name`}
|
||||||
</strong>
|
sharedGroupNames={sharedGroupNames}
|
||||||
));
|
/>
|
||||||
|
</div>
|
||||||
if (sharedGroupNames.length > 3) {
|
);
|
||||||
const remainingCount = sharedGroupNames.length - 3;
|
|
||||||
return (
|
|
||||||
<div className={className}>
|
|
||||||
<Intl
|
|
||||||
i18n={i18n}
|
|
||||||
id="ConversationHero--membership-extra"
|
|
||||||
components={{
|
|
||||||
group1: firstThreeGroups[0],
|
|
||||||
group2: firstThreeGroups[1],
|
|
||||||
group3: firstThreeGroups[2],
|
|
||||||
remainingCount: remainingCount.toString(),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (firstThreeGroups.length === 3) {
|
|
||||||
return (
|
|
||||||
<div className={className}>
|
|
||||||
<Intl
|
|
||||||
i18n={i18n}
|
|
||||||
id="ConversationHero--membership-3"
|
|
||||||
components={{
|
|
||||||
group1: firstThreeGroups[0],
|
|
||||||
group2: firstThreeGroups[1],
|
|
||||||
group3: firstThreeGroups[2],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (firstThreeGroups.length >= 2) {
|
|
||||||
return (
|
|
||||||
<div className={className}>
|
|
||||||
<Intl
|
|
||||||
i18n={i18n}
|
|
||||||
id="ConversationHero--membership-2"
|
|
||||||
components={{
|
|
||||||
group1: firstThreeGroups[0],
|
|
||||||
group2: firstThreeGroups[1],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (firstThreeGroups.length >= 1) {
|
|
||||||
return (
|
|
||||||
<div className={className}>
|
|
||||||
<Intl
|
|
||||||
i18n={i18n}
|
|
||||||
id="ConversationHero--membership-1"
|
|
||||||
components={{
|
|
||||||
group: firstThreeGroups[0],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!phoneNumber) {
|
if (!phoneNumber) {
|
||||||
|
|
|
@ -16492,7 +16492,7 @@
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/conversation/ContactModal.js",
|
"path": "ts/components/conversation/ContactModal.js",
|
||||||
"line": " const overlayRef = react_1.default.useRef(null);",
|
"line": " const overlayRef = react_1.default.useRef(null);",
|
||||||
"lineNumber": 18,
|
"lineNumber": 19,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-11-09T17:48:12.173Z"
|
"updated": "2020-11-09T17:48:12.173Z"
|
||||||
},
|
},
|
||||||
|
@ -16500,7 +16500,7 @@
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/conversation/ContactModal.js",
|
"path": "ts/components/conversation/ContactModal.js",
|
||||||
"line": " const closeButtonRef = react_1.default.useRef(null);",
|
"line": " const closeButtonRef = react_1.default.useRef(null);",
|
||||||
"lineNumber": 19,
|
"lineNumber": 20,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-11-10T21:27:04.909Z"
|
"updated": "2020-11-10T21:27:04.909Z"
|
||||||
},
|
},
|
||||||
|
@ -16526,7 +16526,7 @@
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/conversation/ConversationHero.js",
|
"path": "ts/components/conversation/ConversationHero.js",
|
||||||
"line": " const firstRenderRef = React.useRef(true);",
|
"line": " const firstRenderRef = React.useRef(true);",
|
||||||
"lineNumber": 85,
|
"lineNumber": 48,
|
||||||
"reasonCategory": "falseMatch",
|
"reasonCategory": "falseMatch",
|
||||||
"updated": "2020-10-26T19:12:24.410Z",
|
"updated": "2020-10-26T19:12:24.410Z",
|
||||||
"reasonDetail": "Doesn't refer to a DOM element."
|
"reasonDetail": "Doesn't refer to a DOM element."
|
||||||
|
@ -16535,7 +16535,7 @@
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/conversation/ConversationHero.tsx",
|
"path": "ts/components/conversation/ConversationHero.tsx",
|
||||||
"line": " const firstRenderRef = React.useRef(true);",
|
"line": " const firstRenderRef = React.useRef(true);",
|
||||||
"lineNumber": 138,
|
"lineNumber": 77,
|
||||||
"reasonCategory": "falseMatch",
|
"reasonCategory": "falseMatch",
|
||||||
"updated": "2020-10-26T19:12:24.410Z",
|
"updated": "2020-10-26T19:12:24.410Z",
|
||||||
"reasonDetail": "Doesn't refer to a DOM element."
|
"reasonDetail": "Doesn't refer to a DOM element."
|
||||||
|
|
Loading…
Reference in a new issue