UserTable.jsx 7.0 KB

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