Changeset View
Changeset View
Standalone View
Standalone View
web/modals/chat/sidebar-list-modal.react.js
// @flow | // @flow | ||||
import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; | import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; | ||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||
import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { useSearchSidebars } from 'lib/hooks/search-sidebars'; | import { useSearchSidebars } from 'lib/hooks/search-sidebars'; | ||||
import { sidebarInfoSelector } from 'lib/selectors/thread-selectors'; | |||||
import SearchIndex from 'lib/shared/search-index'; | |||||
import { threadSearchText } from 'lib/shared/thread-utils'; | |||||
import type { ThreadInfo } from 'lib/types/thread-types'; | import type { ThreadInfo } from 'lib/types/thread-types'; | ||||
import chatThreadListCSS from '../../chat/chat-thread-list.css'; | import chatThreadListCSS from '../../chat/chat-thread-list.css'; | ||||
import SidebarItem from '../../chat/sidebar-item.react'; | import SidebarItem from '../../chat/sidebar-item.react'; | ||||
import { useSelector } from '../../redux/redux-utils'; | |||||
import globalCSS from '../../style.css'; | import globalCSS from '../../style.css'; | ||||
import { MagnifyingGlass } from '../../vectors.react'; | import { MagnifyingGlass } from '../../vectors.react'; | ||||
import Input from '../input.react'; | import Input from '../input.react'; | ||||
import { useModalContext } from '../modal-provider.react'; | import { useModalContext } from '../modal-provider.react'; | ||||
import Modal from '../modal.react'; | import Modal from '../modal.react'; | ||||
type Props = { | type Props = { | ||||
+threadInfo: ThreadInfo, | +threadInfo: ThreadInfo, | ||||
}; | }; | ||||
function SidebarListModal(props: Props): React.Node { | function SidebarListModal(props: Props): React.Node { | ||||
const { threadInfo } = props; | const { threadInfo } = props; | ||||
const { listData, searchState, setSearchState } = useSearchSidebars( | const { | ||||
threadInfo, | listData, | ||||
); | searchState, | ||||
setSearchState, | |||||
searchIndex, | |||||
} = useSearchSidebars(threadInfo); | |||||
const { popModal } = useModalContext(); | const { popModal } = useModalContext(); | ||||
const sidebarInfos = useSelector( | |||||
state => sidebarInfoSelector(state)[threadInfo.id] ?? [], | |||||
); | |||||
const userInfos = useSelector(state => state.userStore.userInfos); | |||||
const sidebars = React.useMemo( | const sidebars = React.useMemo( | ||||
() => | () => | ||||
listData.map(item => ( | listData.map(item => ( | ||||
<div | <div | ||||
className={classNames( | className={classNames( | ||||
chatThreadListCSS.thread, | chatThreadListCSS.thread, | ||||
chatThreadListCSS.sidebar, | chatThreadListCSS.sidebar, | ||||
)} | )} | ||||
key={item.threadInfo.id} | key={item.threadInfo.id} | ||||
onClick={popModal} | onClick={popModal} | ||||
> | > | ||||
<SidebarItem sidebarInfo={item} /> | <SidebarItem sidebarInfo={item} /> | ||||
</div> | </div> | ||||
)), | )), | ||||
[popModal, listData], | [popModal, listData], | ||||
); | ); | ||||
const viewerID = useSelector( | |||||
state => state.currentUserInfo && state.currentUserInfo.id, | |||||
); | |||||
const searchIndex = React.useMemo(() => { | |||||
const index = new SearchIndex(); | |||||
for (const sidebarInfo of sidebarInfos) { | |||||
const threadInfoFromSidebarInfo = sidebarInfo.threadInfo; | |||||
index.addEntry( | |||||
threadInfoFromSidebarInfo.id, | |||||
threadSearchText(threadInfoFromSidebarInfo, userInfos, viewerID), | |||||
); | |||||
} | |||||
return index; | |||||
}, [sidebarInfos, userInfos, viewerID]); | |||||
React.useEffect(() => { | |||||
setSearchState(curState => ({ | |||||
...curState, | |||||
results: new Set(searchIndex.getSearchResults(curState.text)), | |||||
})); | |||||
}, [searchIndex, setSearchState]); | |||||
const onChangeSearchText = React.useCallback( | const onChangeSearchText = React.useCallback( | ||||
(event: SyntheticEvent<HTMLInputElement>) => { | (event: SyntheticEvent<HTMLInputElement>) => { | ||||
const searchText = event.currentTarget.value; | const searchText = event.currentTarget.value; | ||||
setSearchState({ | setSearchState({ | ||||
text: searchText, | text: searchText, | ||||
results: new Set(searchIndex.getSearchResults(searchText)), | results: new Set(searchIndex.getSearchResults(searchText)), | ||||
}); | }); | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 50 Lines • Show Last 20 Lines |