UserGroupPage.jsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* eslint-disable react/no-multi-comp */
  2. import React, { Fragment } from 'react';
  3. import PropTypes from 'prop-types';
  4. import { Subscribe } from 'unstated';
  5. import UserGroupTable from './UserGroupTable';
  6. import UserGroupCreateForm from './UserGroupCreateForm';
  7. import UserGroupDeleteModal from './UserGroupDeleteModal';
  8. import { apiErrorHandler, apiSuccessHandler } from '../../../util/apiNotification';
  9. class UserGroupPage extends React.Component {
  10. constructor(props) {
  11. super(props);
  12. this.state = {
  13. userGroups: props.userGroups,
  14. userGroupRelations: props.userGroupRelations,
  15. selectedUserGroup: undefined, // not null but undefined (to use defaultProps in UserGroupDeleteModal)
  16. isDeleteModalShow: false,
  17. };
  18. this.xss = window.xss;
  19. this.showDeleteModal = this.showDeleteModal.bind(this);
  20. this.hideDeleteModal = this.hideDeleteModal.bind(this);
  21. this.addUserGroup = this.addUserGroup.bind(this);
  22. this.deleteUserGroupById = this.deleteUserGroupById.bind(this);
  23. }
  24. async showDeleteModal(group) {
  25. await this.syncUserGroupAndRelations();
  26. this.setState({
  27. selectedUserGroup: group,
  28. isDeleteModalShow: true,
  29. });
  30. }
  31. hideDeleteModal() {
  32. this.setState({
  33. selectedUserGroup: undefined,
  34. isDeleteModalShow: false,
  35. });
  36. }
  37. addUserGroup(userGroup, users) {
  38. this.setState((prevState) => {
  39. const userGroupRelations = Object.assign(prevState.userGroupRelations, {
  40. [userGroup._id]: users,
  41. });
  42. return {
  43. userGroups: [...prevState.userGroups, userGroup],
  44. userGroupRelations,
  45. };
  46. });
  47. }
  48. async deleteUserGroupById({ deleteGroupId, actionName, transferToUserGroupId }) {
  49. try {
  50. const res = await this.props.crowi.apiv3.post(`/user-groups/${deleteGroupId}/delete`, {
  51. actionName,
  52. transferToUserGroupId,
  53. });
  54. if (res.errors) {
  55. return apiErrorHandler(res.errors);
  56. }
  57. this.setState((prevState) => {
  58. const userGroups = prevState.userGroups.filter((userGroup) => {
  59. return userGroup._id !== deleteGroupId;
  60. });
  61. delete prevState.userGroupRelations[deleteGroupId];
  62. return {
  63. userGroups,
  64. userGroupRelations: prevState.userGroupRelations,
  65. selectedUserGroup: undefined,
  66. isDeleteModalShow: false,
  67. };
  68. });
  69. apiSuccessHandler(`Deleted a group "${this.xss.process(res.data.userGroup.name)}"`);
  70. }
  71. catch (err) {
  72. apiErrorHandler(new Error('Unable to delete the group'));
  73. }
  74. }
  75. async syncUserGroupAndRelations() {
  76. let userGroups = [];
  77. let userGroupRelations = [];
  78. try {
  79. const responses = await Promise.all([
  80. this.props.crowi.apiv3.get('/user-groups'),
  81. this.props.crowi.apiv3.get('/user-group-relations'),
  82. ]);
  83. const isAllOk = responses.reduce((isAllOk, res) => {
  84. return isAllOk && !res.errors;
  85. }, true);
  86. if (isAllOk) {
  87. const [userGroupsRes, userGroupRelationsRes] = responses;
  88. userGroups = userGroupsRes.data.userGroups;
  89. userGroupRelations = userGroupRelationsRes.data.userGroupRelations;
  90. }
  91. else {
  92. throw new Error('Unable to fetch groups from server');
  93. }
  94. }
  95. catch (err) {
  96. apiErrorHandler(err);
  97. }
  98. this.setState({
  99. userGroups,
  100. userGroupRelations,
  101. });
  102. }
  103. render() {
  104. return (
  105. <Fragment>
  106. <UserGroupCreateForm
  107. crowi={this.props.crowi}
  108. isAclEnabled={this.props.isAclEnabled}
  109. onCreate={this.addUserGroup}
  110. />
  111. <UserGroupTable
  112. crowi={this.props.crowi}
  113. userGroups={this.state.userGroups}
  114. userGroupRelations={this.state.userGroupRelations}
  115. isAclEnabled={this.props.isAclEnabled}
  116. onDelete={this.showDeleteModal}
  117. />
  118. <UserGroupDeleteModal
  119. crowi={this.props.crowi}
  120. userGroups={this.state.userGroups}
  121. deleteUserGroup={this.state.selectedUserGroup}
  122. onDelete={this.deleteUserGroupById}
  123. isShow={this.state.isDeleteModalShow}
  124. onShow={this.showDeleteModal}
  125. onHide={this.hideDeleteModal}
  126. />
  127. </Fragment>
  128. );
  129. }
  130. }
  131. /**
  132. * Wrapper component for using unstated
  133. */
  134. class UserGroupPageWrapper extends React.PureComponent {
  135. render() {
  136. return (
  137. <Subscribe to={[]}>
  138. {() => (
  139. // eslint-disable-next-line arrow-body-style
  140. <UserGroupPage {...this.props} />
  141. )}
  142. </Subscribe>
  143. );
  144. }
  145. }
  146. UserGroupPage.propTypes = {
  147. crowi: PropTypes.object.isRequired,
  148. userGroups: PropTypes.arrayOf(PropTypes.object).isRequired,
  149. userGroupRelations: PropTypes.object.isRequired,
  150. isAclEnabled: PropTypes.bool,
  151. };
  152. UserGroupPageWrapper.propTypes = {
  153. crowi: PropTypes.object.isRequired,
  154. userGroups: PropTypes.arrayOf(PropTypes.object).isRequired,
  155. userGroupRelations: PropTypes.object.isRequired,
  156. isAclEnabled: PropTypes.bool,
  157. };
  158. export default UserGroupPageWrapper;