Mark conversation as unread

Co-authored-by: Sidney Keese <sidney@carbonfive.com>
This commit is contained in:
Chris Svenningsen 2020-10-28 15:54:32 -07:00 committed by Evan Hahn
parent 184f7e1bf3
commit c408072576
20 changed files with 169 additions and 62 deletions

View file

@ -37,6 +37,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
name: overrideProps.name || 'Some Person',
type: overrideProps.type || 'direct',
onClick: action('onClick'),
markedUnread: boolean('markedUnread', overrideProps.markedUnread || false),
lastMessage: overrideProps.lastMessage || {
text: text('lastMessage.text', 'Hi there!'),
status: select(
@ -137,18 +138,32 @@ story.add('Message Request', () => {
story.add('Unread', () => {
const counts = [4, 10, 250];
const defaultProps = createProps({
lastMessage: {
text: 'Hey there!',
status: 'delivered',
},
});
return counts.map(unreadCount => {
const props = createProps({
lastMessage: {
text: 'Hey there!',
status: 'delivered',
},
const items = counts.map(unreadCount => {
const props = {
...defaultProps,
unreadCount,
});
};
return <ConversationListItem key={unreadCount} {...props} />;
});
const markedUnreadProps = {
...defaultProps,
markedUnread: true,
};
const markedUnreadItem = [
<ConversationListItem key={5} {...markedUnreadProps} />,
];
return [...items, ...markedUnreadItem];
});
story.add('Selected', () => {

View file

@ -37,6 +37,7 @@ export type PropsData = {
lastUpdated: number;
unreadCount?: number;
markedUnread: boolean;
isSelected: boolean;
acceptedMessageRequest?: boolean;
@ -93,13 +94,19 @@ export class ConversationListItem extends React.PureComponent<Props> {
);
}
isUnread(): boolean {
const { markedUnread, unreadCount } = this.props;
return (isNumber(unreadCount) && unreadCount > 0) || markedUnread;
}
public renderUnread(): JSX.Element | null {
const { unreadCount } = this.props;
if (isNumber(unreadCount) && unreadCount > 0) {
if (this.isUnread()) {
return (
<div className="module-conversation-list-item__unread-count">
{unreadCount}
{unreadCount || ''}
</div>
);
}
@ -109,7 +116,6 @@ export class ConversationListItem extends React.PureComponent<Props> {
public renderHeader(): JSX.Element {
const {
unreadCount,
i18n,
isMe,
lastUpdated,
@ -119,14 +125,12 @@ export class ConversationListItem extends React.PureComponent<Props> {
title,
} = this.props;
const withUnread = isNumber(unreadCount) && unreadCount > 0;
return (
<div className="module-conversation-list-item__header">
<div
className={classNames(
'module-conversation-list-item__header__name',
withUnread
this.isUnread()
? 'module-conversation-list-item__header__name--with-unread'
: null
)}
@ -146,7 +150,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
<div
className={classNames(
'module-conversation-list-item__header__date',
withUnread
this.isUnread()
? 'module-conversation-list-item__header__date--has-unread'
: null
)}
@ -155,7 +159,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
timestamp={lastUpdated}
extended={false}
module="module-conversation-list-item__header__timestamp"
withUnread={withUnread}
withUnread={this.isUnread()}
i18n={i18n}
/>
</div>
@ -172,14 +176,12 @@ export class ConversationListItem extends React.PureComponent<Props> {
muteExpiresAt,
shouldShowDraft,
typingContact,
unreadCount,
} = this.props;
if (!lastMessage && !typingContact) {
return null;
}
const messageBody = lastMessage ? lastMessage.text : '';
const withUnread = isNumber(unreadCount) && unreadCount > 0;
const showingDraft = shouldShowDraft && draftPreview;
const deletedForEveryone = Boolean(
lastMessage && lastMessage.deletedForEveryone
@ -192,7 +194,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
dir="auto"
className={classNames(
'module-conversation-list-item__message__text',
withUnread
this.isUnread()
? 'module-conversation-list-item__message__text--has-unread'
: null
)}
@ -249,8 +251,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
/* eslint-enable no-nested-ternary */
public render(): JSX.Element {
const { unreadCount, onClick, id, isSelected, style } = this.props;
const withUnread = isNumber(unreadCount) && unreadCount > 0;
const { id, isSelected, onClick, style } = this.props;
return (
<button
@ -263,7 +264,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
style={style}
className={classNames(
'module-conversation-list-item',
withUnread ? 'module-conversation-list-item--has-unread' : null,
this.isUnread() ? 'module-conversation-list-item--has-unread' : null,
isSelected ? 'module-conversation-list-item--is-selected' : null
)}
data-id={cleanId(id)}

View file

@ -18,6 +18,7 @@ const defaultConversations: Array<PropsData> = [
id: 'fred-convo',
isSelected: false,
lastUpdated: Date.now(),
markedUnread: false,
title: 'Fred Willard',
type: 'direct',
},
@ -25,6 +26,7 @@ const defaultConversations: Array<PropsData> = [
id: 'marc-convo',
isSelected: true,
lastUpdated: Date.now(),
markedUnread: false,
title: 'Marc Barraca',
type: 'direct',
},
@ -35,6 +37,7 @@ const defaultArchivedConversations: Array<PropsData> = [
id: 'michelle-archive-convo',
isSelected: false,
lastUpdated: Date.now(),
markedUnread: false,
title: 'Michelle Mercure',
type: 'direct',
},
@ -46,6 +49,7 @@ const pinnedConversations: Array<PropsData> = [
isPinned: true,
isSelected: false,
lastUpdated: Date.now(),
markedUnread: false,
title: 'Philip Glass',
type: 'direct',
},
@ -54,6 +58,7 @@ const pinnedConversations: Array<PropsData> = [
isPinned: true,
isSelected: false,
lastUpdated: Date.now(),
markedUnread: false,
title: 'Robert Moog',
type: 'direct',
},
@ -129,6 +134,7 @@ story.add('Search Results', () => {
id: 'fred-convo',
isSelected: false,
lastUpdated: Date.now(),
markedUnread: false,
title: 'People Named Fred',
type: 'group',
},
@ -147,6 +153,7 @@ story.add('Search Results', () => {
id: 'fred-contact',
isSelected: false,
lastUpdated: Date.now(),
markedUnread: false,
title: 'Fred Willard',
type: 'direct',
},

View file

@ -157,6 +157,7 @@ const conversations = [
text: 'The rabbit hopped silently in the night.',
status: SENT,
},
markedUnread: false,
},
},
{
@ -177,6 +178,7 @@ const conversations = [
text: "What's going on?",
status: SENT,
},
markedUnread: false,
},
},
];
@ -196,6 +198,7 @@ const contacts = [
lastUpdated: Date.now() - 10 * 60 * 1000,
unreadCount: 0,
isSelected: false,
markedUnread: false,
},
},
{
@ -211,6 +214,7 @@ const contacts = [
lastUpdated: Date.now() - 11 * 60 * 1000,
unreadCount: 0,
isSelected: false,
markedUnread: false,
},
},
];

View file

@ -44,6 +44,7 @@ const actionProps: PropsActionsType = {
onGoBack: action('onGoBack'),
onArchive: action('onArchive'),
onMarkUnread: action('onMarkUnread'),
onMoveToInbox: action('onMoveToInbox'),
onSetPin: action('onSetPin'),
};

View file

@ -36,6 +36,7 @@ export interface PropsDataType {
isMe?: boolean;
isArchived?: boolean;
isPinned?: boolean;
markedUnread?: boolean;
disableTimerChanges?: boolean;
expirationSettingName?: string;
@ -60,6 +61,7 @@ export interface PropsActionsType {
onGoBack: () => void;
onArchive: () => void;
onMarkUnread: () => void;
onMoveToInbox: () => void;
}
@ -310,6 +312,7 @@ export class ConversationHeader extends React.Component<PropsType> {
isPinned,
type,
isArchived,
markedUnread,
muteExpirationLabel,
onDeleteMessages,
onResetSession,
@ -319,6 +322,7 @@ export class ConversationHeader extends React.Component<PropsType> {
onShowGroupMembers,
onShowSafetyNumber,
onArchive,
onMarkUnread,
onSetPin,
onMoveToInbox,
timerOptions,
@ -350,28 +354,6 @@ export class ConversationHeader extends React.Component<PropsType> {
return (
<ContextMenu id={triggerId}>
<SubMenu title={muteTitle}>
{muteOptions.map(item => (
<MenuItem
key={item.name}
disabled={item.disabled}
onClick={() => {
onSetMuteNotifications(item.value);
}}
>
{item.name}
</MenuItem>
))}
</SubMenu>
{isPinned ? (
<MenuItem onClick={() => onSetPin(false)}>
{i18n('unpinConversation')}
</MenuItem>
) : (
<MenuItem onClick={() => onSetPin(true)}>
{i18n('pinConversation')}
</MenuItem>
)}
{disableTimerChanges ? null : (
<SubMenu title={disappearingTitle}>
{(timerOptions || []).map(item => (
@ -386,21 +368,37 @@ export class ConversationHeader extends React.Component<PropsType> {
))}
</SubMenu>
)}
<MenuItem onClick={onShowAllMedia}>{i18n('viewRecentMedia')}</MenuItem>
<SubMenu title={muteTitle}>
{muteOptions.map(item => (
<MenuItem
key={item.name}
disabled={item.disabled}
onClick={() => {
onSetMuteNotifications(item.value);
}}
>
{item.name}
</MenuItem>
))}
</SubMenu>
{isGroup ? (
<MenuItem onClick={onShowGroupMembers}>
{i18n('showMembers')}
</MenuItem>
) : null}
<MenuItem onClick={onShowAllMedia}>{i18n('viewRecentMedia')}</MenuItem>
{!isGroup && !isMe ? (
<MenuItem onClick={onShowSafetyNumber}>
{i18n('showSafetyNumber')}
</MenuItem>
) : null}
<MenuItem divider />
{!isGroup && acceptedMessageRequest ? (
<MenuItem onClick={onResetSession}>{i18n('resetSession')}</MenuItem>
) : null}
<MenuItem divider />
{!markedUnread ? (
<MenuItem onClick={onMarkUnread}>{i18n('markUnread')}</MenuItem>
) : null}
{isArchived ? (
<MenuItem onClick={onMoveToInbox}>
{i18n('moveConversationToInbox')}
@ -409,6 +407,15 @@ export class ConversationHeader extends React.Component<PropsType> {
<MenuItem onClick={onArchive}>{i18n('archiveConversation')}</MenuItem>
)}
<MenuItem onClick={onDeleteMessages}>{i18n('deleteMessages')}</MenuItem>
{isPinned ? (
<MenuItem onClick={() => onSetPin(false)}>
{i18n('unpinConversation')}
</MenuItem>
) : (
<MenuItem onClick={() => onSetPin(true)}>
{i18n('pinConversation')}
</MenuItem>
)}
</ContextMenu>
);
}

View file

@ -19,6 +19,7 @@ storiesOf('Components/Conversation/ProfileChangeNotification', module)
title: 'Mr. Fire 🔥',
name: 'Mr. Fire 🔥',
lastUpdated: Date.now(),
markedUnread: false,
}}
change={{
type: 'name',
@ -37,6 +38,7 @@ storiesOf('Components/Conversation/ProfileChangeNotification', module)
type: 'direct',
title: 'Mr. Fire 🔥',
lastUpdated: Date.now(),
markedUnread: false,
}}
change={{
type: 'name',