UserTable.jsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import React, { Fragment } from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import dateFnsFormat from 'date-fns/format';
  5. import UserPicture from '../../User/UserPicture';
  6. import UserMenu from './UserMenu';
  7. import { createSubscribedElement } from '../../UnstatedUtils';
  8. import AppContainer from '../../../services/AppContainer';
  9. import AdminUsersContainer from '../../../services/AdminUsersContainer';
  10. class UserTable extends React.Component {
  11. constructor(props) {
  12. super(props);
  13. this.state = {
  14. };
  15. this.getUserStatusLabel = this.getUserStatusLabel.bind(this);
  16. }
  17. /**
  18. * return status label element by `userStatus`
  19. * @param {string} userStatus
  20. * @return status label element
  21. */
  22. getUserStatusLabel(userStatus) {
  23. let additionalClassName;
  24. let text;
  25. switch (userStatus) {
  26. case 1:
  27. additionalClassName = 'label-info';
  28. text = 'Approval Pending';
  29. break;
  30. case 2:
  31. additionalClassName = 'label-success';
  32. text = 'Active';
  33. break;
  34. case 3:
  35. additionalClassName = 'label-warning';
  36. text = 'Suspended';
  37. break;
  38. case 4:
  39. additionalClassName = 'label-danger';
  40. text = 'Deleted';
  41. break;
  42. case 5:
  43. additionalClassName = 'label-info';
  44. text = 'Invited';
  45. break;
  46. }
  47. return (
  48. <span className={`label ${additionalClassName}`}>
  49. {text}
  50. </span>
  51. );
  52. }
  53. /**
  54. * sorting
  55. */
  56. renderSortIcon(columnName) {
  57. return (
  58. <div className="d-flex flex-column text-center">
  59. { this.generateSorting(columnName, 'asc') }
  60. { this.generateSorting(columnName, 'desc') }
  61. </div>
  62. );
  63. }
  64. generateSorting(columnName, sorting) {
  65. const { adminUsersContainer } = this.props;
  66. const upOrDown = (sorting === 'asc' ? 'up' : 'down');
  67. return (
  68. <a
  69. className={`fa ${(
  70. adminUsersContainer.state.sort === columnName)
  71. && (adminUsersContainer.state.sortOrder === sorting) ? `fa-chevron-${upOrDown}` : `fa-angle-${upOrDown}`}`}
  72. aria-hidden="true"
  73. onClick={() => adminUsersContainer.onClickSort(columnName, sorting === 'asc')}
  74. >
  75. </a>
  76. );
  77. }
  78. /**
  79. * return admin label element by `isAdmin`
  80. * @param {string} isAdmin
  81. * @return admin label element
  82. */
  83. getUserAdminLabel(isAdmin) {
  84. const { t } = this.props;
  85. if (isAdmin) {
  86. return <span className="label label-inverse label-admin ml-2">{t('admin:user_management.user_table.administrator')}</span>;
  87. }
  88. }
  89. render() {
  90. const { t, adminUsersContainer } = this.props;
  91. return (
  92. <Fragment>
  93. <table className="table table-default table-bordered table-user-list">
  94. <thead>
  95. <tr>
  96. <th width="100px">#</th>
  97. <th>
  98. <div className="d-flex align-items-center">
  99. <div className="mr-3">
  100. {t('status')}
  101. </div>
  102. { this.renderSortIcon('status') }
  103. </div>
  104. </th>
  105. <th>
  106. <div className="d-flex align-items-center">
  107. <div className="mr-3">
  108. <code>username</code>
  109. </div>
  110. { this.renderSortIcon('username') }
  111. </div>
  112. </th>
  113. <th>
  114. <div className="d-flex align-items-center">
  115. <div className="mr-3">
  116. {t('Name')}
  117. </div>
  118. { this.renderSortIcon('name')}
  119. </div>
  120. </th>
  121. <th>
  122. <div className="d-flex align-items-center">
  123. <div className="mr-3">
  124. {t('Email')}
  125. </div>
  126. { this.renderSortIcon('email')}
  127. </div>
  128. </th>
  129. <th width="100px">
  130. <div className="d-flex align-items-center">
  131. <div className="mr-3">
  132. {t('Created')}
  133. </div>
  134. { this.renderSortIcon('createdAt')}
  135. </div>
  136. </th>
  137. <th width="150px">
  138. <div className="d-flex align-items-center">
  139. <div className="mr-3">
  140. {t('Last_Login')}
  141. </div>
  142. { this.renderSortIcon('lastLoginAt')}
  143. </div>
  144. </th>
  145. <th width="70px"></th>
  146. </tr>
  147. </thead>
  148. <tbody>
  149. {adminUsersContainer.state.users.map((user) => {
  150. return (
  151. <tr key={user._id}>
  152. <td>
  153. <UserPicture user={user} className="picture img-circle" />
  154. </td>
  155. <td>{this.getUserStatusLabel(user.status)} {this.getUserAdminLabel(user.admin)}</td>
  156. <td>
  157. <strong>{user.username}</strong>
  158. </td>
  159. <td>{user.name}</td>
  160. <td>{user.email}</td>
  161. <td>{dateFnsFormat(new Date(user.createdAt), 'yyyy-MM-dd')}</td>
  162. <td>
  163. {user.lastLoginAt && <span>{dateFnsFormat(new Date(user.lastLoginAt), 'yyyy-MM-dd HH:mm')}</span>}
  164. </td>
  165. <td>
  166. <UserMenu user={user} />
  167. </td>
  168. </tr>
  169. );
  170. })}
  171. </tbody>
  172. </table>
  173. </Fragment>
  174. );
  175. }
  176. }
  177. const UserTableWrapper = (props) => {
  178. return createSubscribedElement(UserTable, props, [AppContainer, AdminUsersContainer]);
  179. };
  180. UserTable.propTypes = {
  181. t: PropTypes.func.isRequired, // i18next
  182. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  183. adminUsersContainer: PropTypes.instanceOf(AdminUsersContainer).isRequired,
  184. };
  185. export default withTranslation()(UserTableWrapper);