import React from 'react'; import PropTypes from 'prop-types'; import { withTranslation } from 'react-i18next'; import FormGroup from 'react-bootstrap/es/FormGroup'; import FormControl from 'react-bootstrap/es/FormControl'; import ListGroup from 'react-bootstrap/es/ListGroup'; import ListGroupItem from 'react-bootstrap/es/ListGroupItem'; import Modal from 'react-bootstrap/es/Modal'; import AppContainer from '../../services/AppContainer'; import { createSubscribedElement } from '../UnstatedUtils'; const SPECIFIED_GROUP_VALUE = 'specifiedGroup'; /** * Page grant select component * * @export * @class GrantSelector * @extends {React.Component} */ class GrantSelector extends React.Component { constructor(props) { super(props); this.availableGrants = [ { grant: 1, iconClass: 'icon-people', styleClass: '', label: 'Public', }, { grant: 2, iconClass: 'icon-link', styleClass: 'text-info', label: 'Anyone with the link', }, // { grant: 3, iconClass: '', label: 'Specified users only' }, { grant: 4, iconClass: 'icon-lock', styleClass: 'text-danger', label: 'Just me', }, { grant: 5, iconClass: 'icon-options', styleClass: '', label: 'Only inside the group', }, // appeared only one of these 'grant: 5' { grant: 5, iconClass: 'icon-options', styleClass: '', label: 'Reselect the group', }, // appeared only one of these 'grant: 5' ]; this.state = { userRelatedGroups: [], isSelectGroupModalShown: false, grant: this.props.grant, grantGroup: null, }; if (this.props.grantGroupId != null) { this.state.grantGroup = { _id: this.props.grantGroupId, name: this.props.grantGroupName, }; } // retrieve xss library from window this.xss = window.xss; this.showSelectGroupModal = this.showSelectGroupModal.bind(this); this.hideSelectGroupModal = this.hideSelectGroupModal.bind(this); this.getGroupName = this.getGroupName.bind(this); this.changeGrantHandler = this.changeGrantHandler.bind(this); this.groupListItemClickHandler = this.groupListItemClickHandler.bind(this); } componentDidUpdate(prevProps, prevState) { /* * set SPECIFIED_GROUP_VALUE to grant selector * cz: bootstrap-select input element has the defferent state to React component */ if (this.state.grantGroup != null) { this.grantSelectorInputEl.value = SPECIFIED_GROUP_VALUE; } // refresh bootstrap-select // see https://silviomoreto.github.io/bootstrap-select/methods/#selectpickerrefresh $('.grant-selector .selectpicker').selectpicker('refresh'); // // DIRTY HACK -- 2018.05.25 Yuki Takei // set group name to the bootstrap-select options // cz: .selectpicker('refresh') doesn't replace data-content $('.grant-selector .group-name').text(this.getGroupName()); } showSelectGroupModal() { this.retrieveUserGroupRelations(); this.setState({ isSelectGroupModalShown: true }); } hideSelectGroupModal() { this.setState({ isSelectGroupModalShown: false }); } getGroupName() { const grantGroup = this.state.grantGroup; return grantGroup ? this.xss.process(grantGroup.name) : ''; } /** * Retrieve user-group-relations data from backend */ retrieveUserGroupRelations() { this.props.appContainer.apiGet('/me/user-group-relations') .then((res) => { return res.userGroupRelations; }) .then((userGroupRelations) => { const userRelatedGroups = userGroupRelations.map((relation) => { return relation.relatedGroup; }); this.setState({ userRelatedGroups }); }); } /** * change event handler for grant selector */ changeGrantHandler() { const grant = +this.grantSelectorInputEl.value; // select group if (grant === 5) { this.showSelectGroupModal(); /* * reset grant selector to state */ this.grantSelectorInputEl.value = this.state.grant; return; } this.setState({ grant, grantGroup: null }); if (this.props.onUpdateGrant != null) { this.props.onUpdateGrant({ grant, grantGroupId: null, grantGroupName: null }); } } groupListItemClickHandler(grantGroup) { this.setState({ grant: 5, grantGroup }); if (this.props.onUpdateGrant != null) { this.props.onUpdateGrant({ grant: 5, grantGroupId: grantGroup._id, grantGroupName: grantGroup.name }); } // hide modal this.hideSelectGroupModal(); } /** * Render grant selector DOM. * @returns * @memberof GrantSelector */ renderGrantSelector() { const { t } = this.props; let index = 0; let selectedValue = this.state.grant; const grantElems = this.availableGrants.map((opt) => { const dataContent = ` ${t(opt.label)}`; return ; }); const grantGroup = this.state.grantGroup; if (grantGroup != null) { selectedValue = SPECIFIED_GROUP_VALUE; // DIRTY HACK -- 2018.05.25 Yuki Takei // remove 'Only inside the group' item // cz: .selectpicker('refresh') doesn't replace data-content grantElems.splice(3, 1); } else { // DIRTY HACK -- 2018.05.25 Yuki Takei // remove 'Reselect the group' item // cz: .selectpicker('refresh') doesn't replace data-content grantElems.splice(4, 1); } /* * react-bootstrap couldn't be rendered only with React feature. * see also 'componentDidUpdate' */ // add specified group option grantElems.push( , ); const bsClassName = 'form-control-dummy'; // set form-control* to shrink width return ( { this.grantSelectorInputEl = el }} > {grantElems} ); } /** * Render select grantgroup modal. * * @returns * @memberof GrantSelector */ renderSelectGroupModal() { const generateGroupListItems = () => { return this.state.userRelatedGroups.map((group) => { return ( { this.groupListItemClickHandler(group) }}> (TBD) List group members ); }); }; const content = this.state.userRelatedGroups.length === 0 ? (

There is no group to which you belong.

{ this.props.appContainer.isAdmin &&

Manage Groups

}
) : ( {generateGroupListItems()} ); return ( Select a Group {content} ); } render() { return ( { this.renderGrantSelector() } { !this.props.disabled && this.renderSelectGroupModal() } ); } } /** * Wrapper component for using unstated */ const GrantSelectorWrapper = (props) => { return createSubscribedElement(GrantSelector, props, [AppContainer]); }; GrantSelector.propTypes = { t: PropTypes.func.isRequired, // i18next appContainer: PropTypes.instanceOf(AppContainer).isRequired, disabled: PropTypes.bool, grant: PropTypes.number.isRequired, grantGroupId: PropTypes.string, grantGroupName: PropTypes.string, onUpdateGrant: PropTypes.func, }; export default withTranslation()(GrantSelectorWrapper);