diff --git a/web/modals/search-modal.css b/web/modals/search-modal.css new file mode 100644 --- /dev/null +++ b/web/modals/search-modal.css @@ -0,0 +1,6 @@ +.container { + display: flex; + flex-direction: column; + overflow: hidden; + margin: 16px; +} diff --git a/web/modals/search-modal.react.js b/web/modals/search-modal.react.js new file mode 100644 --- /dev/null +++ b/web/modals/search-modal.react.js @@ -0,0 +1,38 @@ +// @flow + +import * as React from 'react'; + +import Search from '../components/search.react'; +import Modal from './modal.react'; +import css from './search-modal.css'; + +type Props = { + +name: string, + +searchPlaceholder: string, + +onClose: () => void, + +children: (searchText: string) => React.Node, +}; + +function SearchModal(props: Props): React.Node { + const [searchText, setSearchText] = React.useState(''); + const { name, searchPlaceholder, onClose, children } = props; + const child = React.useMemo(() => children(searchText), [ + children, + searchText, + ]); + + return ( + <Modal name={name} onClose={onClose}> + <div className={css.container}> + <Search + onChangeText={setSearchText} + searchText={searchText} + placeholder={searchPlaceholder} + /> + {child} + </div> + </Modal> + ); +} + +export default SearchModal; diff --git a/web/modals/threads/members/members-modal.css b/web/modals/threads/members/members-modal.css --- a/web/modals/threads/members/members-modal.css +++ b/web/modals/threads/members/members-modal.css @@ -1,10 +1,3 @@ -div.membersContainer { - display: flex; - flex-direction: column; - overflow: hidden; - margin: 16px; -} - div.membersList { overflow: scroll; padding: 8px 0; diff --git a/web/modals/threads/members/members-modal.react.js b/web/modals/threads/members/members-modal.react.js --- a/web/modals/threads/members/members-modal.react.js +++ b/web/modals/threads/members/members-modal.react.js @@ -7,22 +7,19 @@ import { memberHasAdminPowers, memberIsAdmin } from 'lib/shared/thread-utils'; import { type RelativeMemberInfo } from 'lib/types/thread-types'; -import Search from '../../../components/search.react'; import Tabs from '../../../components/tabs.react'; import { useSelector } from '../../../redux/redux-utils'; -import Modal from '../../modal.react'; +import SearchModal from '../../search-modal.react'; import ThreadMembersList from './members-list.react'; -import css from './members-modal.css'; -type Props = { +type ContentProps = { + +searchText: string, +threadID: string, - +onClose: () => void, }; -function ThreadMembersModal(props: Props): React.Node { - const { threadID, onClose } = props; +function ThreadMembersModalContent(props: ContentProps): React.Node { + const { threadID, searchText } = props; const [tab, setTab] = React.useState<'All Members' | 'Admins'>('All Members'); - const [searchText, setSearchText] = React.useState(''); const threadInfo = useSelector(state => threadInfoSelector(state)[threadID]); const { members: threadMembersNotFiltered } = threadInfo; @@ -72,19 +69,33 @@ ); return ( - <Modal name="Members" onClose={onClose}> - <div className={css.membersContainer}> - <Search - onChangeText={setSearchText} - searchText={searchText} - placeholder="Search members" - /> - <Tabs.Container activeTab={tab} setTab={setTab}> - {allUsersTab} - {allAdminsTab} - </Tabs.Container> - </div> - </Modal> + <Tabs.Container activeTab={tab} setTab={setTab}> + {allUsersTab} + {allAdminsTab} + </Tabs.Container> + ); +} + +type Props = { + +threadID: string, + +onClose: () => void, +}; +function ThreadMembersModal(props: Props): React.Node { + const { onClose, threadID } = props; + const renderModalContent = React.useCallback( + (searchText: string) => ( + <ThreadMembersModalContent threadID={threadID} searchText={searchText} /> + ), + [threadID], + ); + return ( + <SearchModal + name="Members" + searchPlaceholder="Search members" + onClose={onClose} + > + {renderModalContent} + </SearchModal> ); }