UI fixes for conversation details screen

This commit is contained in:
Josh Perez 2021-02-01 17:57:42 -05:00 committed by GitHub
parent ddebbf8121
commit 267ae80442
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 134 additions and 51 deletions

View file

@ -487,13 +487,15 @@ export class ConversationHeader extends React.Component<PropsType> {
private renderHeader(): JSX.Element {
const {
conversationTitle,
groupVersion,
id,
isMe,
onShowContactModal,
onShowConversationDetails,
type,
} = this.props;
if (conversationTitle) {
if (conversationTitle !== undefined) {
return (
<div className="module-conversation-header__title-flex">
<div className="module-conversation-header__title">
@ -503,6 +505,35 @@ export class ConversationHeader extends React.Component<PropsType> {
);
}
const hasGV2AdminEnabled =
groupVersion === 2 &&
window.Signal.RemoteConfig.isEnabled('desktop.gv2Admin');
if (type === 'group' && hasGV2AdminEnabled) {
const onHeaderClick = () => onShowConversationDetails();
const onKeyDown = (e: React.KeyboardEvent): void => {
if (e.key === 'Enter' || e.key === ' ') {
e.stopPropagation();
e.preventDefault();
onShowConversationDetails();
}
};
return (
<div
className="module-conversation-header__title-flex module-conversation-header__title-clickable"
onClick={onHeaderClick}
onKeyDown={onKeyDown}
role="button"
tabIndex={0}
>
{this.renderAvatar()}
{this.renderTitle()}
</div>
);
}
if (type === 'group' || isMe) {
return (
<div className="module-conversation-header__title-flex">

View file

@ -37,7 +37,11 @@ export const ConversationDetailsActions: React.ComponentType<Props> = ({
icon="leave"
/>
}
label={i18n('ConversationDetailsActions--leave-group')}
label={
<div className="module-conversation-details__leave-group">
{i18n('ConversationDetailsActions--leave-group')}
</div>
}
/>
<PanelRow
onClick={() => setConfirmingBlock(true)}
@ -47,7 +51,11 @@ export const ConversationDetailsActions: React.ComponentType<Props> = ({
icon="block"
/>
}
label={i18n('ConversationDetailsActions--block-group')}
label={
<div className="module-conversation-details__block-group">
{i18n('ConversationDetailsActions--block-group')}
</div>
}
/>
</PanelSection>

View file

@ -45,16 +45,32 @@ const createProps = (overrideProps: Partial<Props>): Props => ({
memberships: overrideProps.memberships || [],
});
story.add('Basic', () => {
const memberships = createMemberships(10);
story.add('Few', () => {
const memberships = createMemberships(3);
const props = createProps({ memberships });
return <ConversationDetailsMembershipList {...props} />;
});
story.add('Few', () => {
const memberships = createMemberships(3);
story.add('Limit', () => {
const memberships = createMemberships(5);
const props = createProps({ memberships });
return <ConversationDetailsMembershipList {...props} />;
});
story.add('Limit +1', () => {
const memberships = createMemberships(6);
const props = createProps({ memberships });
return <ConversationDetailsMembershipList {...props} />;
});
story.add('Limit +2', () => {
const memberships = createMemberships(7);
const props = createProps({ memberships });

View file

@ -24,7 +24,7 @@ export type Props = {
i18n: LocalizerType;
};
const INITIAL_MEMBER_COUNT = 5;
const MAX_MEMBER_COUNT = 5;
export const ConversationDetailsMembershipList: React.ComponentType<Props> = ({
memberships,
@ -33,44 +33,47 @@ export const ConversationDetailsMembershipList: React.ComponentType<Props> = ({
}) => {
const [showAllMembers, setShowAllMembers] = React.useState<boolean>(false);
const shouldHideRestMembers = memberships.length - MAX_MEMBER_COUNT > 1;
const membersToShow =
shouldHideRestMembers && !showAllMembers
? MAX_MEMBER_COUNT
: memberships.length;
return (
<PanelSection
title={i18n('ConversationDetailsMembershipList--title', [
memberships.length.toString(),
])}
>
{memberships
.slice(0, showAllMembers ? undefined : INITIAL_MEMBER_COUNT)
.map(({ isAdmin, member }) => (
<PanelRow
key={member.id}
onClick={() => showContactModal(member.id)}
icon={
<Avatar
conversationType="direct"
i18n={i18n}
size={32}
{...member}
/>
}
label={member.title}
right={isAdmin ? i18n('GroupV2--admin') : ''}
/>
))}
{showAllMembers === false &&
memberships.length > INITIAL_MEMBER_COUNT && (
<PanelRow
className="module-conversation-details-membership-list--show-all"
icon={
<ConversationDetailsIcon
ariaLabel={i18n('ConversationDetailsMembershipList--show-all')}
icon="down"
/>
}
onClick={() => setShowAllMembers(true)}
label={i18n('ConversationDetailsMembershipList--show-all')}
/>
)}
{memberships.slice(0, membersToShow).map(({ isAdmin, member }) => (
<PanelRow
key={member.id}
onClick={() => showContactModal(member.id)}
icon={
<Avatar
conversationType="direct"
i18n={i18n}
size={32}
{...member}
/>
}
label={member.title}
right={isAdmin ? i18n('GroupV2--admin') : ''}
/>
))}
{showAllMembers === false && shouldHideRestMembers && (
<PanelRow
className="module-conversation-details-membership-list--show-all"
icon={
<ConversationDetailsIcon
ariaLabel={i18n('ConversationDetailsMembershipList--show-all')}
icon="down"
/>
}
onClick={() => setShowAllMembers(true)}
label={i18n('ConversationDetailsMembershipList--show-all')}
/>
)}
</PanelSection>
);
};

View file

@ -19,7 +19,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
icon: boolean('with icon', overrideProps.icon !== undefined) ? (
<ConversationDetailsIcon ariaLabel="timer" icon="timer" />
) : null,
label: text('label', overrideProps.label || ''),
label: text('label', (overrideProps.label as string) || ''),
info: text('info', overrideProps.info || ''),
right: text('right', (overrideProps.right as string) || ''),
actions: boolean('with action', overrideProps.actions !== undefined) ? (

View file

@ -9,7 +9,7 @@ export type Props = {
alwaysShowActions?: boolean;
className?: string;
icon?: React.ReactNode;
label: string;
label: string | React.ReactNode;
info?: string;
right?: string | React.ReactNode;
actions?: React.ReactNode;
@ -30,15 +30,15 @@ export const PanelRow: React.ComponentType<Props> = ({
}) => {
const content = (
<>
{icon && <div className={bem('icon')}>{icon}</div>}
{icon !== undefined ? <div className={bem('icon')}>{icon}</div> : null}
<div className={bem('label')}>
<div>{label}</div>
{info && <div className={bem('info')}>{info}</div>}
{info !== undefined ? <div className={bem('info')}>{info}</div> : null}
</div>
{right && <div className={bem('right')}>{right}</div>}
{actions && (
{right !== undefined ? <div className={bem('right')}>{right}</div> : null}
{actions !== undefined ? (
<div className={alwaysShowActions ? '' : bem('actions')}>{actions}</div>
)}
) : null}
</>
);