/* @flow */ import React from 'react'; import Flux from '../../lib/flux'; import i18n from '../../i18n'; import lodash from 'lodash'; import classNames from 'classnames'; import fuzzysearch from 'fuzzysearch'; import GuildSettingsStore from '../../stores/GuildSettingsStore'; import GuildMemberStore from '../../stores/GuildMemberStore'; import UserSettingsStore from '../../stores/UserSettingsStore'; import UserStore from '../../stores/UserStore'; import PermissionStore from '../../stores/PermissionStore'; import StreamerModeStore from '../../stores/StreamerModeStore'; import PopoutActionCreators from '../../actions/PopoutActionCreators'; import GuildSettingsActionCreators from '../../actions/GuildSettingsActionCreators'; import PruneGuildModalActionCreators from '../../actions/PruneGuildModalActionCreators'; import {LazyContentScroller} from '../common/StandardSidebarView'; import ContextMenu from '../common/ContextMenu'; import UserContextMenu from '../contextmenus/UserContextMenu'; import RoleList from '../common/RoleList'; import SearchableQuickSelect from '../common/SearchableQuickSelect'; import Tooltip from '../common/Tooltip'; import IconButton from '../../uikit/IconButton'; import OverflowMenuIcon from '../../uikit/icons/OverflowMenuIcon'; import BotTag from '../../uikit/BotTag'; import Avatar from '../../uikit/Avatar'; import Flex from '../../uikit/Flex'; import {FormTitle, FormTitleTags, FormText, FormTextTypes, FormDivider, FormSection} from '../../uikit/form'; import SearchBar from '../../uikit/SearchBar'; import {ContextMenuTypes, Permissions, ThemeTypes} from '../../Constants'; import './GuildSettingsMembers.styl'; import '../../styles/shared/hover_card.styl'; const ROLE_FILTER_POPOUT_ID = 'quick-roles--select'; class Member extends React.PureComponent { _isMounted = false; state: { overflowShown: boolean, }; constructor(props) { super(props); this.state = { overflowShown: false, }; (this: any).showOverflow = this.showOverflow.bind(this); (this: any).handleOverflowClose = this.handleOverflowClose.bind(this); } componentDidMount() { this._isMounted = true; } componentWillUnmount() { this._isMounted = false; } showOverflow(e: Event) { const {guild, user} = this.props; this.setState({overflowShown: true}); ContextMenu.openContextMenu( e, props => , { onClose: this.handleOverflowClose, } ); } renderOwnerHelpIcon() { const {user, theme, guild} = this.props; if (user.id !== guild.ownerId) { return null; } const iconSrc = theme === ThemeTypes.DARK ? require('../../images/ic_crown_dark_24px.svg') : require('../../images/ic_crown_light_24px.svg'); return ( ); } render() { const {user, member, streamerMode, guild} = this.props; const {overflowShown} = this.state; const style = { color: member.colorString, }; return ( {member.nick || user.toString()} {user.bot ? : null} {this.renderOwnerHelpIcon()} {streamerMode ? null : @{user.tag}}
); } handleOverflowClose() { if (this._isMounted) { this.setState({overflowShown: false}); } } } class GuildSettingsMembers extends React.PureComponent { state: { roleFilterQuery: string, }; constructor(props) { super(props); this.state = { roleFilterQuery: '', }; (this: any).renderHeader = this.renderHeader.bind(this); (this: any).renderPruneAction = this.renderPruneAction.bind(this); (this: any).handleQueryChange = this.handleQueryChange.bind(this); (this: any).handleQueryClear = this.handleQueryClear.bind(this); (this: any).handlePruneClick = this.handlePruneClick.bind(this); (this: any).handleRoleFilterQueryChange = this.handleRoleFilterQueryChange.bind(this); (this: any).handleRoleFilterQueryClear = this.handleRoleFilterQueryClear.bind(this); } componentDidUpdate(prevProps, prevState) { if (this.state.roleFilterQuery !== prevState.roleFilterQuery) { PopoutActionCreators.rerender(ROLE_FILTER_POPOUT_ID); } } handlePruneClick() { PruneGuildModalActionCreators.open(this.props.guild.id); } renderPruneAction() { const {canPrune} = this.props; if (!canPrune) { return null; } return ( {' — '} {i18n.Messages.PRUNE} ); } renderHeader(filteredMembers) { const {roleFilterQuery} = this.state; const {guild, searchQuery, selectedRoleId} = this.props; const value = {}; const items = lodash(guild.roles) .sortBy(role => -role.position) .filter(role => { if (role.id === selectedRoleId) { value.label = role.name; } return fuzzysearch(roleFilterQuery.toLowerCase(), role.name.toLowerCase()); }) .map(role => ({ value: role.id, color: role.colorString, children: role.name, selected: role.id === selectedRoleId, })) .value(); const searchProps = { query: roleFilterQuery, onChange: this.handleRoleFilterQueryChange, onClear: this.handleRoleFilterQueryClear, placeholder: i18n.Messages.SEARCH_ROLES, }; return ( {i18n.Messages.GUILD_SETTINGS_MEMBERS_SERVER_MEMBERS} {i18n.Messages.MEMBERS_HEADER.format({members: filteredMembers.length})} {this.renderPruneAction()} ); } makeSearchFilter() { let {searchQuery} = this.props; if (searchQuery == null || searchQuery.length === 0) { return () => true; } else { return ({user, member}) => { searchQuery = searchQuery.toLowerCase(); const username = user.username.toLowerCase(); const nick = member.nick != null ? member.nick.toLowerCase() : null; return fuzzysearch(searchQuery, username) || (nick != null && fuzzysearch(searchQuery, nick)); }; } } makeRoleFilter() { const {guild, selectedRoleId} = this.props; return ({member}) => selectedRoleId === guild.id || member.roles.indexOf(selectedRoleId) !== -1; } renderMembers(filteredMembers) { const {guild, currentUser, streamerMode, theme} = this.props; return lodash(filteredMembers) .sortBy(({comparator}) => comparator) .map(({member, user}) => ) .value(); } render() { const {members} = this.props; const filteredMembers = lodash(members) .map(member => { const user = UserStore.getUser(member.userId); return { member, user, comparator: (user != null ? member.nick || user.username : '').toLowerCase(), }; }) .filter(this.makeSearchFilter()) .filter(this.makeRoleFilter()) .value(); return ( {this.renderMembers(filteredMembers)} ); } handleQueryChange(query) { GuildSettingsActionCreators.setSearchQuery(query); } handleQueryClear() { GuildSettingsActionCreators.setSearchQuery(''); } handleRoleChange({value}) { GuildSettingsActionCreators.selectRole(value); } handleRoleFilterQueryChange(roleFilterQuery) { this.setState({roleFilterQuery}); } handleRoleFilterQueryClear() { this.setState({ roleFilterQuery: '', }); } } const GuildSettingsMembersWrapped = Flux.connectStores( [GuildSettingsStore, UserSettingsStore, GuildMemberStore, StreamerModeStore], () => { const {guild, searchQuery, selectedRoleId} = GuildSettingsStore.getProps(); return { guild, selectedRoleId, searchQuery: searchQuery || '', members: GuildMemberStore.getMembers(guild.id), theme: UserSettingsStore.theme, currentUser: UserStore.getCurrentUser(), canPrune: PermissionStore.can(Permissions.KICK_MEMBERS, guild), streamerMode: StreamerModeStore.enabled, }; } )(GuildSettingsMembers); export default GuildSettingsMembersWrapped; // WEBPACK FOOTER // // ./discord_app/components/guild_settings/GuildSettingsMembers.js