diff --git a/web/modals/threads/subchannels/subchannels-modal.css b/web/modals/threads/subchannels/subchannels-modal.css --- a/web/modals/threads/subchannels/subchannels-modal.css +++ b/web/modals/threads/subchannels/subchannels-modal.css @@ -1,3 +1,24 @@ +div.subchannelsModalContent { + padding: 16px; + display: flex; + flex-direction: column; + row-gap: 8px; + overflow: hidden; +} + +div.subchannelsListContainer { + display: flex; + flex-direction: column; + overflow: scroll; + line-height: var(--line-height-text); + color: var(--subchannels-modal-color); + row-gap: 8px; +} + +div.noSubchannels { + text-align: center; +} + div.subchannelContainer { cursor: pointer; display: flex; diff --git a/web/modals/threads/subchannels/subchannels-modal.react.js b/web/modals/threads/subchannels/subchannels-modal.react.js new file mode 100644 --- /dev/null +++ b/web/modals/threads/subchannels/subchannels-modal.react.js @@ -0,0 +1,83 @@ +// @flow + +import * as React from 'react'; + +import { useFilteredChatListData } from 'lib/selectors/chat-selectors'; +import { threadSearchIndex } from 'lib/selectors/nav-selectors'; +import { childThreadInfos } from 'lib/selectors/thread-selectors'; +import { threadIsChannel } from 'lib/shared/thread-utils'; + +import Search from '../../../components/search.react'; +import { useSelector } from '../../../redux/redux-utils'; +import Modal from '../../modal.react'; +import Subchannel from './subchannel.react'; +import css from './subchannels-modal.css'; + +type Props = { + +threadID: string, + +onClose: () => void, +}; + +function SubchannelsModal(props: Props): React.Node { + const { threadID, onClose } = props; + const [searchText, setSearchText] = React.useState(''); + + const childThreads = useSelector(state => childThreadInfos(state)[threadID]); + const subchannelsIDs = React.useMemo(() => { + if (!childThreads) { + return []; + } + return childThreads + .filter(threadIsChannel) + .map(threadInfo => threadInfo.id); + }, [childThreads]); + + const filterSubchannels = React.useCallback( + thread => subchannelsIDs.includes(thread?.id), + [subchannelsIDs], + ); + const allSubchannelsChatList = useFilteredChatListData(filterSubchannels); + + const searchIndex = useSelector(threadSearchIndex); + + const filteredSubchannelsChatList = React.useMemo(() => { + if (!searchText.length) { + return allSubchannelsChatList; + } + const searchResultsIDs = searchIndex.getSearchResults(searchText); + return allSubchannelsChatList.filter(item => + searchResultsIDs.includes(item.threadInfo.id), + ); + }, [allSubchannelsChatList, searchIndex, searchText]); + + const subchannels = React.useMemo(() => { + if (!filteredSubchannelsChatList.length) { + return ( +
+ No matching subchannels were found in the thread! +
+ ); + } + return filteredSubchannelsChatList.map(childThreadItem => ( + + )); + }, [filteredSubchannelsChatList]); + + return ( + +
+ +
{subchannels}
+
+
+ ); +} + +export default SubchannelsModal;