signal-desktop/ts/components/StoriesPane.tsx

169 lines
4.9 KiB
TypeScript
Raw Normal View History

2022-03-04 21:14:52 +00:00
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import Fuse from 'fuse.js';
import React, { useEffect, useState } from 'react';
import classNames from 'classnames';
import { isNotNil } from '../util/isNotNil';
2022-03-04 21:14:52 +00:00
import type { ConversationStoryType, StoryViewType } from './StoryListItem';
import type { LocalizerType } from '../types/Util';
import { SearchInput } from './SearchInput';
import { StoryListItem } from './StoryListItem';
const FUSE_OPTIONS: Fuse.IFuseOptions<ConversationStoryType> = {
2022-03-04 21:14:52 +00:00
getFn: (obj, path) => {
if (path === 'searchNames') {
return obj.stories
.flatMap((story: StoryViewType) => [
story.sender.title,
story.sender.name,
])
.filter(isNotNil);
2022-03-04 21:14:52 +00:00
}
return obj.group?.title ?? '';
2022-03-04 21:14:52 +00:00
},
keys: [
{
name: 'searchNames',
weight: 1,
},
{
name: 'group',
weight: 1,
},
],
threshold: 0.1,
};
function search(
stories: ReadonlyArray<ConversationStoryType>,
searchTerm: string
): Array<ConversationStoryType> {
return new Fuse<ConversationStoryType>(stories, FUSE_OPTIONS)
.search(searchTerm)
.map(result => result.item);
2022-03-04 21:14:52 +00:00
}
2022-03-29 01:10:08 +00:00
function getNewestStory(story: ConversationStoryType): StoryViewType {
return story.stories[story.stories.length - 1];
}
2022-03-04 21:14:52 +00:00
export type PropsType = {
hiddenStories: Array<ConversationStoryType>;
i18n: LocalizerType;
onBack: () => unknown;
onStoryClicked: (conversationId: string) => unknown;
openConversationInternal: (_: { conversationId: string }) => unknown;
2022-03-29 01:10:08 +00:00
queueStoryDownload: (storyId: string) => unknown;
2022-03-04 21:14:52 +00:00
stories: Array<ConversationStoryType>;
toggleHideStories: (conversationId: string) => unknown;
};
export const StoriesPane = ({
2022-04-15 22:31:18 +00:00
hiddenStories,
2022-03-04 21:14:52 +00:00
i18n,
onBack,
onStoryClicked,
openConversationInternal,
2022-03-29 01:10:08 +00:00
queueStoryDownload,
2022-03-04 21:14:52 +00:00
stories,
toggleHideStories,
}: PropsType): JSX.Element => {
const [searchTerm, setSearchTerm] = useState('');
2022-04-15 22:31:18 +00:00
const [isShowingHiddenStories, setIsShowingHiddenStories] = useState(false);
2022-03-04 21:14:52 +00:00
const [renderedStories, setRenderedStories] =
useState<Array<ConversationStoryType>>(stories);
useEffect(() => {
if (searchTerm) {
setRenderedStories(search(stories, searchTerm));
} else {
setRenderedStories(stories);
}
}, [searchTerm, stories]);
return (
<>
<div className="Stories__pane__header">
<button
aria-label={i18n('back')}
className="Stories__pane__header--back"
onClick={onBack}
tabIndex={0}
type="button"
2022-03-04 21:14:52 +00:00
/>
<div className="Stories__pane__header--title">
{i18n('Stories__title')}
2022-03-04 21:14:52 +00:00
</div>
</div>
<SearchInput
i18n={i18n}
moduleClassName="Stories__search"
onChange={event => {
setSearchTerm(event.target.value);
}}
placeholder={i18n('search')}
value={searchTerm}
/>
<div
className={classNames('Stories__pane__list', {
'Stories__pane__list--empty': !stories.length,
})}
>
{renderedStories.map(story => (
<StoryListItem
2022-04-15 00:08:46 +00:00
group={story.group}
i18n={i18n}
2022-04-15 00:08:46 +00:00
key={getNewestStory(story).timestamp}
onClick={() => {
onStoryClicked(story.conversationId);
}}
onHideStory={() => {
toggleHideStories(getNewestStory(story).sender.id);
}}
onGoToConversation={conversationId => {
openConversationInternal({ conversationId });
}}
queueStoryDownload={queueStoryDownload}
story={getNewestStory(story)}
/>
))}
2022-04-15 22:31:18 +00:00
{Boolean(hiddenStories.length) && (
<>
<button
className={classNames('Stories__hidden-stories', {
'Stories__hidden-stories--expanded': isShowingHiddenStories,
})}
onClick={() => setIsShowingHiddenStories(!isShowingHiddenStories)}
type="button"
>
{i18n('Stories__hidden-stories')}
</button>
{isShowingHiddenStories &&
hiddenStories.map(story => (
<StoryListItem
key={getNewestStory(story).timestamp}
i18n={i18n}
isHidden
onClick={() => {
onStoryClicked(story.conversationId);
}}
onHideStory={() => {
toggleHideStories(getNewestStory(story).sender.id);
}}
onGoToConversation={conversationId => {
openConversationInternal({ conversationId });
}}
queueStoryDownload={queueStoryDownload}
story={getNewestStory(story)}
/>
))}
</>
)}
{!stories.length && i18n('Stories__list-empty')}
</div>
</>
2022-03-04 21:14:52 +00:00
);
};