GrantSelector.jsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import {
  5. UncontrolledDropdown,
  6. DropdownToggle, DropdownMenu, DropdownItem,
  7. Modal, ModalHeader, ModalBody,
  8. } from 'reactstrap';
  9. import AppContainer from '../../services/AppContainer';
  10. import { withUnstatedContainers } from '../UnstatedUtils';
  11. /**
  12. * Page grant select component
  13. *
  14. * @export
  15. * @class GrantSelector
  16. * @extends {React.Component}
  17. */
  18. class GrantSelector extends React.Component {
  19. constructor(props) {
  20. super(props);
  21. this.availableGrants = [
  22. {
  23. grant: 1, iconClass: 'icon-people', btnStyleClass: 'outline-info', label: 'Public',
  24. },
  25. {
  26. grant: 2, iconClass: 'icon-link', btnStyleClass: 'outline-teal', label: 'Anyone with the link',
  27. },
  28. // { grant: 3, iconClass: '', label: 'Specified users only' },
  29. {
  30. grant: 4, iconClass: 'icon-lock', btnStyleClass: 'outline-danger', label: 'Only me',
  31. },
  32. {
  33. grant: 5, iconClass: 'icon-options', btnStyleClass: 'outline-purple', label: 'Only inside the group', reselectLabel: 'Reselect the group',
  34. },
  35. ];
  36. this.state = {
  37. userRelatedGroups: [],
  38. isSelectGroupModalShown: false,
  39. };
  40. this.showSelectGroupModal = this.showSelectGroupModal.bind(this);
  41. this.hideSelectGroupModal = this.hideSelectGroupModal.bind(this);
  42. this.changeGrantHandler = this.changeGrantHandler.bind(this);
  43. this.groupListItemClickHandler = this.groupListItemClickHandler.bind(this);
  44. }
  45. showSelectGroupModal() {
  46. this.retrieveUserGroupRelations();
  47. this.setState({ isSelectGroupModalShown: true });
  48. }
  49. hideSelectGroupModal() {
  50. this.setState({ isSelectGroupModalShown: false });
  51. }
  52. /**
  53. * Retrieve user-group-relations data from backend
  54. */
  55. retrieveUserGroupRelations() {
  56. this.props.appContainer.apiGet('/me/user-group-relations')
  57. .then((res) => {
  58. return res.userGroupRelations;
  59. })
  60. .then((userGroupRelations) => {
  61. const userRelatedGroups = userGroupRelations.map((relation) => {
  62. return relation.relatedGroup;
  63. });
  64. this.setState({ userRelatedGroups });
  65. });
  66. }
  67. /**
  68. * change event handler for grant selector
  69. */
  70. changeGrantHandler(grant) {
  71. // select group
  72. if (grant === 5) {
  73. this.showSelectGroupModal();
  74. return;
  75. }
  76. if (this.props.onUpdateGrant != null) {
  77. this.props.onUpdateGrant({ grant, grantGroupId: null, grantGroupName: null });
  78. }
  79. }
  80. groupListItemClickHandler(grantGroup) {
  81. if (this.props.onUpdateGrant != null) {
  82. this.props.onUpdateGrant({ grant: 5, grantGroupId: grantGroup._id, grantGroupName: grantGroup.name });
  83. }
  84. // hide modal
  85. this.hideSelectGroupModal();
  86. }
  87. /**
  88. * Render grant selector DOM.
  89. * @returns
  90. * @memberof GrantSelector
  91. */
  92. renderGrantSelector() {
  93. const { t } = this.props;
  94. const { grant: currentGrant, grantGroupId } = this.props;
  95. let dropdownToggleBtnColor = null;
  96. let dropdownToggleLabelElm = null;
  97. const dropdownMenuElems = this.availableGrants.map((opt) => {
  98. const label = (opt.grant === 5 && grantGroupId != null)
  99. ? opt.reselectLabel // when grantGroup is selected
  100. : opt.label;
  101. const labelElm = (
  102. <span>
  103. <i className={`icon icon-fw ${opt.iconClass}`}></i>
  104. <span className="label">{t(label)}</span>
  105. </span>
  106. );
  107. // set dropdownToggleBtnColor, dropdownToggleLabelElm
  108. if (opt.grant === 1 || opt.grant === currentGrant) {
  109. dropdownToggleBtnColor = opt.btnStyleClass;
  110. dropdownToggleLabelElm = labelElm;
  111. }
  112. return <DropdownItem key={opt.grant} onClick={() => this.changeGrantHandler(opt.grant)}>{labelElm}</DropdownItem>;
  113. });
  114. // add specified group option
  115. if (grantGroupId != null) {
  116. const labelElm = (
  117. <span>
  118. <i className="icon icon-fw icon-organization"></i>
  119. <span className="label">{this.props.grantGroupName}</span>
  120. </span>
  121. );
  122. // set dropdownToggleLabelElm
  123. dropdownToggleLabelElm = labelElm;
  124. dropdownMenuElems.push(<DropdownItem key="groupSelected">{labelElm}</DropdownItem>);
  125. }
  126. return (
  127. <div className="form-group grw-grant-selector mb-0">
  128. <UncontrolledDropdown direction="up">
  129. <DropdownToggle color={dropdownToggleBtnColor} caret className="d-flex justify-content-between align-items-center" disabled={this.props.disabled}>
  130. {dropdownToggleLabelElm}
  131. </DropdownToggle>
  132. <DropdownMenu>
  133. {dropdownMenuElems}
  134. </DropdownMenu>
  135. </UncontrolledDropdown>
  136. </div>
  137. );
  138. }
  139. /**
  140. * Render select grantgroup modal.
  141. *
  142. * @returns
  143. * @memberof GrantSelector
  144. */
  145. renderSelectGroupModal() {
  146. const generateGroupListItems = () => {
  147. return this.state.userRelatedGroups.map((group) => {
  148. return (
  149. <button key={group._id} type="button" className="list-group-item list-group-item-action" onClick={() => { this.groupListItemClickHandler(group) }}>
  150. <h5>{group.name}</h5>
  151. <div className="small">(TBD) List group members</div>
  152. </button>
  153. );
  154. });
  155. };
  156. const content = this.state.userRelatedGroups.length === 0
  157. ? (
  158. <div>
  159. <h4>There is no group to which you belong.</h4>
  160. { this.props.appContainer.isAdmin
  161. && <p><a href="/admin/user-groups"><i className="icon icon-fw icon-login"></i> Manage Groups</a></p>
  162. }
  163. </div>
  164. )
  165. : (
  166. <div className="list-group">
  167. {generateGroupListItems()}
  168. </div>
  169. );
  170. return (
  171. <Modal
  172. className="select-grant-group"
  173. container={this}
  174. isOpen={this.state.isSelectGroupModalShown}
  175. toggle={this.hideSelectGroupModal}
  176. >
  177. <ModalHeader tag="h4" toggle={this.hideSelectGroupModal} className="bg-purple text-light">
  178. Select a Group
  179. </ModalHeader>
  180. <ModalBody>
  181. {content}
  182. </ModalBody>
  183. </Modal>
  184. );
  185. }
  186. render() {
  187. return (
  188. <React.Fragment>
  189. { this.renderGrantSelector() }
  190. { !this.props.disabled && this.renderSelectGroupModal() }
  191. </React.Fragment>
  192. );
  193. }
  194. }
  195. /**
  196. * Wrapper component for using unstated
  197. */
  198. const GrantSelectorWrapper = withUnstatedContainers(GrantSelector, [AppContainer]);
  199. GrantSelector.propTypes = {
  200. t: PropTypes.func.isRequired, // i18next
  201. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  202. disabled: PropTypes.bool,
  203. grant: PropTypes.number.isRequired,
  204. grantGroupId: PropTypes.string,
  205. grantGroupName: PropTypes.string,
  206. onUpdateGrant: PropTypes.func,
  207. };
  208. export default withTranslation()(GrantSelectorWrapper);