UserManagement.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import React, { useEffect, useState, useRef } from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import AdminUsersContainer from '~/client/services/AdminUsersContainer';
  4. import { toastError } from '~/client/util/apiNotification';
  5. import PaginationWrapper from '../PaginationWrapper';
  6. import { withUnstatedContainers } from '../UnstatedUtils';
  7. import InviteUserControl from './Users/InviteUserControl';
  8. import PasswordResetModal from './Users/PasswordResetModal';
  9. import UserTable from './Users/UserTable';
  10. import styles from './UserManagement.module.scss';
  11. type UserManagementProps = {
  12. adminUsersContainer: AdminUsersContainer
  13. }
  14. const UserManagement = (props: UserManagementProps) => {
  15. const { t } = useTranslation('admin');
  16. const { adminUsersContainer } = props;
  17. const [isNotifyCommentShow, setIsNotifyCommentShow] = useState(false);
  18. const inputRef = useRef<HTMLInputElement>(null);
  19. const pagingHandler = (async(selectedPage: number) => {
  20. try {
  21. await adminUsersContainer.retrieveUsersByPagingNum(selectedPage);
  22. }
  23. catch (err) {
  24. toastError(err);
  25. }
  26. })
  27. // componentDidMount
  28. useEffect(() => {
  29. pagingHandler(1);
  30. }, []);
  31. const validateToggleStatus = (statusType: string) => {
  32. return (adminUsersContainer.isSelected(statusType)) ? (
  33. adminUsersContainer.state.selectedStatusList.size > 1
  34. )
  35. : (
  36. true
  37. )
  38. }
  39. const clickHandler = (statusType: string) => {
  40. if (!validateToggleStatus(statusType)) {
  41. return setIsNotifyCommentShow(true);
  42. }
  43. if (isNotifyCommentShow) {
  44. setIsNotifyCommentShow(false);
  45. }
  46. adminUsersContainer.handleClick(statusType);
  47. }
  48. const resetButtonClickHandler = (async() => {
  49. try {
  50. await adminUsersContainer.resetAllChanges();
  51. setIsNotifyCommentShow(false);
  52. (inputRef.current != null) && (inputRef.current.value = '');
  53. }
  54. catch (err) {
  55. toastError(err);
  56. }
  57. })
  58. const changeSearchTextHandler = (async(e: React.FormEvent<HTMLInputElement>) => {
  59. await adminUsersContainer.handleChangeSearchText(e?.currentTarget.value);
  60. })
  61. const renderCheckbox = (status: string, statusLabel: string, statusColor: string) => {
  62. return (
  63. <div className={`custom-control custom-checkbox custom-checkbox-${statusColor} mr-2`}>
  64. <input
  65. className="custom-control-input"
  66. type="checkbox"
  67. id={`c_${status}`}
  68. checked={adminUsersContainer.isSelected(status)}
  69. onChange={() => clickHandler(status)}
  70. />
  71. <label className="custom-control-label" htmlFor={`c_${status}`}>
  72. <span className={`badge badge-pill badge-${statusColor} d-inline-block vt mt-1`}>
  73. {statusLabel}
  74. </span>
  75. </label>
  76. </div>
  77. )
  78. }
  79. const pager = (
  80. <div className="my-3">
  81. <PaginationWrapper
  82. activePage={adminUsersContainer.state.activePage}
  83. changePage={pagingHandler}
  84. totalItemsCount={adminUsersContainer.state.totalUsers}
  85. pagingLimit={adminUsersContainer.state.pagingLimit}
  86. align="center"
  87. size="sm"
  88. />
  89. </div>
  90. );
  91. return (
  92. <div data-testid="admin-users">
  93. { adminUsersContainer.state.userForPasswordResetModal != null
  94. && (
  95. <PasswordResetModal
  96. isOpen={adminUsersContainer.state.isPasswordResetModalShown}
  97. onClose={adminUsersContainer.hidePasswordResetModal}
  98. userForPasswordResetModal={adminUsersContainer.state.userForPasswordResetModal}
  99. />
  100. ) }
  101. <p>
  102. <InviteUserControl />
  103. <a className="btn btn-outline-secondary ml-2" href="/admin/users/external-accounts" role="button">
  104. <i className="icon-user-follow" aria-hidden="true"></i>
  105. {t('admin:user_management.external_account')}
  106. </a>
  107. </p>
  108. <h2>{t('user_management.user_management')}</h2>
  109. <div className="border-top border-bottom">
  110. <div className="row d-flex justify-content-start align-items-center my-2">
  111. <div className="col-md-3 d-flex align-items-center my-2">
  112. <i className="icon-magnifier mr-1"></i>
  113. <span className="search-typeahead">
  114. <input
  115. className="w-100"
  116. type="text"
  117. ref={inputRef}
  118. onChange={changeSearchTextHandler}
  119. />
  120. {/* TODO: Fix position */}
  121. {
  122. adminUsersContainer.state.searchText.length > 0
  123. ? ( <i
  124. className={`icon-close ${styles['search-clear']}`}
  125. onClick={async() => {
  126. await adminUsersContainer.clearSearchText();
  127. (inputRef.current != null) && (inputRef.current.value = '');
  128. }}
  129. />
  130. )
  131. : ''
  132. }
  133. </span>
  134. </div>
  135. <div className="offset-md-1 col-md-6 my-2">
  136. <div className="form-inline">
  137. {renderCheckbox('all', 'All', 'secondary')}
  138. {renderCheckbox('registered', 'Approval Pending', 'info')}
  139. {renderCheckbox('active', 'Active', 'success')}
  140. {renderCheckbox('suspended', 'Suspended', 'warning')}
  141. {renderCheckbox('invited', 'Invited', 'pink')}
  142. </div>
  143. <div>
  144. { isNotifyCommentShow && <span className="text-warning">{t('admin:user_management.click_twice_same_checkbox')}</span> }
  145. </div>
  146. </div>
  147. <div className="col-md-2 my-2">
  148. <button
  149. type="button"
  150. className="btn btn-outline-secondary btn-sm"
  151. onClick={resetButtonClickHandler}
  152. >
  153. <span className="icon-refresh mr-1"></span>
  154. Reset
  155. </button>
  156. </div>
  157. </div>
  158. </div>
  159. {pager}
  160. <UserTable />
  161. {pager}
  162. </div>
  163. )
  164. }
  165. const UserManagementWrapper = withUnstatedContainers(UserManagement, [AdminUsersContainer]);
  166. export default UserManagementWrapper;