Filter chats by Unread
This commit is contained in:
parent
45e9c07125
commit
a56e7d0ade
27 changed files with 883 additions and 438 deletions
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type {
|
||||
ConversationType,
|
||||
ShowConversationType,
|
||||
|
@ -10,17 +11,19 @@ import type { LocalizerType } from '../types/Util';
|
|||
import { Avatar, AvatarSize } from './Avatar';
|
||||
import { SearchInput } from './SearchInput';
|
||||
import { usePrevious } from '../hooks/usePrevious';
|
||||
import { Tooltip, TooltipPlacement } from './Tooltip';
|
||||
import { Theme } from '../util/theme';
|
||||
|
||||
type PropsType = {
|
||||
type BasePropsType = {
|
||||
clearConversationSearch: () => void;
|
||||
clearSearch: () => void;
|
||||
clearSearchQuery: () => void;
|
||||
disabled?: boolean;
|
||||
endConversationSearch: () => void;
|
||||
endSearch: () => void;
|
||||
i18n: LocalizerType;
|
||||
isSearchingGlobally: boolean;
|
||||
onEnterKeyDown?: (
|
||||
clearSearch: () => void,
|
||||
clearSearchQuery: () => void,
|
||||
showConversation: ShowConversationType
|
||||
) => void;
|
||||
searchConversation?: ConversationType;
|
||||
|
@ -30,9 +33,23 @@ type PropsType = {
|
|||
updateSearchTerm: (searchTerm: string) => void;
|
||||
};
|
||||
|
||||
type NoFilterPropsType = BasePropsType & {
|
||||
filterButtonEnabled?: false;
|
||||
filterPressed?: false;
|
||||
onFilterClick?: () => void;
|
||||
};
|
||||
|
||||
type WithFilterPropsType = BasePropsType & {
|
||||
filterButtonEnabled: boolean;
|
||||
filterPressed: boolean;
|
||||
onFilterClick: (enabled: boolean) => void;
|
||||
};
|
||||
|
||||
type PropsType = NoFilterPropsType | WithFilterPropsType;
|
||||
|
||||
export function LeftPaneSearchInput({
|
||||
clearConversationSearch,
|
||||
clearSearch,
|
||||
clearSearchQuery,
|
||||
disabled,
|
||||
endConversationSearch,
|
||||
endSearch,
|
||||
|
@ -44,6 +61,9 @@ export function LeftPaneSearchInput({
|
|||
showConversation,
|
||||
startSearchCounter,
|
||||
updateSearchTerm,
|
||||
filterButtonEnabled = false,
|
||||
filterPressed = false,
|
||||
onFilterClick,
|
||||
}: PropsType): JSX.Element {
|
||||
const inputRef = useRef<null | HTMLInputElement>(null);
|
||||
|
||||
|
@ -83,7 +103,7 @@ export function LeftPaneSearchInput({
|
|||
if (searchConversation) {
|
||||
clearConversationSearch();
|
||||
} else {
|
||||
clearSearch();
|
||||
clearSearchQuery();
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -94,79 +114,109 @@ export function LeftPaneSearchInput({
|
|||
}
|
||||
};
|
||||
|
||||
const label = searchConversation ? i18n('icu:searchIn') : i18n('icu:search');
|
||||
let label: string;
|
||||
if (searchConversation) {
|
||||
label = i18n('icu:searchIn');
|
||||
} else if (filterPressed) {
|
||||
label = i18n('icu:searchUnreadChats');
|
||||
} else {
|
||||
label = i18n('icu:search');
|
||||
}
|
||||
|
||||
return (
|
||||
<SearchInput
|
||||
disabled={disabled}
|
||||
label={label}
|
||||
hasSearchIcon={!searchConversation}
|
||||
i18n={i18n}
|
||||
moduleClassName="LeftPaneSearchInput"
|
||||
onBlur={() => {
|
||||
if (!searchConversation && !searchTerm) {
|
||||
endSearch();
|
||||
}
|
||||
}}
|
||||
onKeyDown={event => {
|
||||
if (onEnterKeyDown && event.key === 'Enter') {
|
||||
onEnterKeyDown(clearSearch, showConversation);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}}
|
||||
onChange={event => {
|
||||
changeValue(event.currentTarget.value);
|
||||
}}
|
||||
onClear={() => {
|
||||
if (searchTerm) {
|
||||
clearSearch();
|
||||
inputRef.current?.focus();
|
||||
} else if (searchConversation) {
|
||||
endConversationSearch();
|
||||
inputRef.current?.focus();
|
||||
} else {
|
||||
inputRef.current?.blur();
|
||||
}
|
||||
}}
|
||||
ref={inputRef}
|
||||
placeholder={label}
|
||||
value={searchTerm}
|
||||
>
|
||||
{searchConversation && (
|
||||
// Clicking the non-X part of the pill should focus the input but have a normal
|
||||
// cursor. This effectively simulates `pointer-events: none` while still
|
||||
// letting us change the cursor.
|
||||
// eslint-disable-next-line max-len
|
||||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
||||
<div
|
||||
className="LeftPaneSearchInput__in-conversation-pill"
|
||||
onClick={() => {
|
||||
<>
|
||||
<SearchInput
|
||||
disabled={disabled}
|
||||
label={label}
|
||||
hasSearchIcon={!searchConversation}
|
||||
i18n={i18n}
|
||||
moduleClassName="LeftPaneSearchInput"
|
||||
onBlur={() => {
|
||||
if (!searchConversation && !searchTerm) {
|
||||
endSearch();
|
||||
}
|
||||
}}
|
||||
onKeyDown={event => {
|
||||
if (onEnterKeyDown && event.key === 'Enter') {
|
||||
onEnterKeyDown(clearSearchQuery, showConversation);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}}
|
||||
onChange={event => {
|
||||
changeValue(event.currentTarget.value);
|
||||
}}
|
||||
onClear={() => {
|
||||
if (searchTerm) {
|
||||
clearSearchQuery();
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
} else if (searchConversation) {
|
||||
endConversationSearch();
|
||||
inputRef.current?.focus();
|
||||
} else {
|
||||
inputRef.current?.blur();
|
||||
}
|
||||
}}
|
||||
ref={inputRef}
|
||||
placeholder={label}
|
||||
value={searchTerm}
|
||||
>
|
||||
{searchConversation && (
|
||||
// Clicking the non-X part of the pill should focus the input but have a normal
|
||||
// cursor. This effectively simulates `pointer-events: none` while still
|
||||
// letting us change the cursor.
|
||||
// eslint-disable-next-line max-len
|
||||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
||||
<div
|
||||
className="LeftPaneSearchInput__in-conversation-pill"
|
||||
onClick={() => {
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
acceptedMessageRequest={searchConversation.acceptedMessageRequest}
|
||||
avatarUrl={searchConversation.avatarUrl}
|
||||
badge={undefined}
|
||||
color={searchConversation.color}
|
||||
conversationType={searchConversation.type}
|
||||
i18n={i18n}
|
||||
isMe={searchConversation.isMe}
|
||||
noteToSelf={searchConversation.isMe}
|
||||
sharedGroupNames={searchConversation.sharedGroupNames}
|
||||
size={AvatarSize.TWENTY}
|
||||
title={searchConversation.title}
|
||||
unblurredAvatarUrl={searchConversation.unblurredAvatarUrl}
|
||||
/>
|
||||
<button
|
||||
aria-label={i18n('icu:clearSearch')}
|
||||
className="LeftPaneSearchInput__in-conversation-pill__x-button"
|
||||
onClick={endConversationSearch}
|
||||
type="button"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</SearchInput>
|
||||
{filterButtonEnabled && (
|
||||
<Tooltip
|
||||
direction={TooltipPlacement.Bottom}
|
||||
content={i18n('icu:filterByUnreadButtonLabel')}
|
||||
theme={Theme.Dark}
|
||||
delay={600}
|
||||
>
|
||||
<Avatar
|
||||
acceptedMessageRequest={searchConversation.acceptedMessageRequest}
|
||||
avatarUrl={searchConversation.avatarUrl}
|
||||
badge={undefined}
|
||||
color={searchConversation.color}
|
||||
conversationType={searchConversation.type}
|
||||
i18n={i18n}
|
||||
isMe={searchConversation.isMe}
|
||||
noteToSelf={searchConversation.isMe}
|
||||
sharedGroupNames={searchConversation.sharedGroupNames}
|
||||
size={AvatarSize.TWENTY}
|
||||
title={searchConversation.title}
|
||||
unblurredAvatarUrl={searchConversation.unblurredAvatarUrl}
|
||||
/>
|
||||
<button
|
||||
aria-label={i18n('icu:clearSearch')}
|
||||
className="LeftPaneSearchInput__in-conversation-pill__x-button"
|
||||
onClick={endConversationSearch}
|
||||
className={classNames('LeftPaneSearchInput__FilterButton', {
|
||||
'LeftPaneSearchInput__FilterButton--pressed': filterPressed,
|
||||
})}
|
||||
type="button"
|
||||
/>
|
||||
</div>
|
||||
aria-pressed={filterPressed}
|
||||
onClick={() => onFilterClick?.(!filterPressed)}
|
||||
>
|
||||
<span className="LeftPaneSearchInput__FilterLabel">
|
||||
{i18n('icu:filterByUnreadButtonLabel')}
|
||||
</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</SearchInput>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue