UserTable.jsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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 = 'badge-info';
  29. text = 'Approval Pending';
  30. break;
  31. case 2:
  32. additionalClassName = 'badge-success';
  33. text = 'Active';
  34. break;
  35. case 3:
  36. additionalClassName = 'badge-warning';
  37. text = 'Suspended';
  38. break;
  39. case 4:
  40. additionalClassName = 'badge-danger';
  41. text = 'Deleted';
  42. break;
  43. case 5:
  44. additionalClassName = 'badge-info';
  45. text = 'Invited';
  46. break;
  47. }
  48. return (
  49. <span className={`badge badge-pill ${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="badge badge-primary badge-pill 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. <div className="table-responsive text-nowrap h-100">
  76. <table className="table table-default table-bordered table-user-list">
  77. <thead>
  78. <tr>
  79. <th width="100px">#</th>
  80. <th>
  81. <div className="d-flex align-items-center">
  82. <div className="mr-3">
  83. {t('status')}
  84. </div>
  85. <SortIcons
  86. isSelected={adminUsersContainer.state.sort === 'status'}
  87. isAsc={isCurrentSortOrderAsc}
  88. onClick={(sortOrder) => {
  89. this.sortIconsClickedHandler('status', sortOrder);
  90. }}
  91. />
  92. </div>
  93. </th>
  94. <th>
  95. <div className="d-flex align-items-center">
  96. <div className="mr-3">
  97. <code>username</code>
  98. </div>
  99. <SortIcons
  100. isSelected={adminUsersContainer.state.sort === 'username'}
  101. isAsc={isCurrentSortOrderAsc}
  102. onClick={(sortOrder) => {
  103. this.sortIconsClickedHandler('username', sortOrder);
  104. }}
  105. />
  106. </div>
  107. </th>
  108. <th>
  109. <div className="d-flex align-items-center">
  110. <div className="mr-3">
  111. {t('Name')}
  112. </div>
  113. <SortIcons
  114. isSelected={adminUsersContainer.state.sort === 'name'}
  115. isAsc={isCurrentSortOrderAsc}
  116. onClick={(sortOrder) => {
  117. this.sortIconsClickedHandler('name', sortOrder);
  118. }}
  119. />
  120. </div>
  121. </th>
  122. <th>
  123. <div className="d-flex align-items-center">
  124. <div className="mr-3">
  125. {t('Email')}
  126. </div>
  127. <SortIcons
  128. isSelected={adminUsersContainer.state.sort === 'email'}
  129. isAsc={isCurrentSortOrderAsc}
  130. onClick={(sortOrder) => {
  131. this.sortIconsClickedHandler('email', sortOrder);
  132. }}
  133. />
  134. </div>
  135. </th>
  136. <th width="100px">
  137. <div className="d-flex align-items-center">
  138. <div className="mr-3">
  139. {t('Created')}
  140. </div>
  141. <SortIcons
  142. isSelected={adminUsersContainer.state.sort === 'createdAt'}
  143. isAsc={isCurrentSortOrderAsc}
  144. onClick={(sortOrder) => {
  145. this.sortIconsClickedHandler('createdAt', sortOrder);
  146. }}
  147. />
  148. </div>
  149. </th>
  150. <th width="150px">
  151. <div className="d-flex align-items-center">
  152. <div className="mr-3">
  153. {t('Last_Login')}
  154. </div>
  155. <SortIcons
  156. isSelected={adminUsersContainer.state.sort === 'lastLoginAt'}
  157. isAsc={isCurrentSortOrderAsc}
  158. onClick={(sortOrder) => {
  159. this.sortIconsClickedHandler('lastLoginAt', sortOrder);
  160. }}
  161. />
  162. </div>
  163. </th>
  164. <th width="70px"></th>
  165. </tr>
  166. </thead>
  167. <tbody>
  168. {adminUsersContainer.state.users.map((user) => {
  169. return (
  170. <tr key={user._id}>
  171. <td>
  172. <UserPicture user={user} className="picture rounded-circle" />
  173. </td>
  174. <td>{this.getUserStatusLabel(user.status)} {this.getUserAdminLabel(user.admin)}</td>
  175. <td>
  176. <strong>{user.username}</strong>
  177. </td>
  178. <td>{user.name}</td>
  179. <td>{user.email}</td>
  180. <td>{dateFnsFormat(new Date(user.createdAt), 'yyyy-MM-dd')}</td>
  181. <td>
  182. {user.lastLoginAt && <span>{dateFnsFormat(new Date(user.lastLoginAt), 'yyyy-MM-dd HH:mm')}</span>}
  183. </td>
  184. <td>
  185. <UserMenu user={user} />
  186. </td>
  187. </tr>
  188. );
  189. })}
  190. </tbody>
  191. </table>
  192. </div>
  193. </Fragment>
  194. );
  195. }
  196. }
  197. UserTable.propTypes = {
  198. t: PropTypes.func.isRequired, // i18next
  199. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  200. adminUsersContainer: PropTypes.instanceOf(AdminUsersContainer).isRequired,
  201. };
  202. const UserTableWrapper = (props) => {
  203. return createSubscribedElement(UserTable, props, [AppContainer, AdminUsersContainer]);
  204. };
  205. export default withTranslation()(UserTableWrapper);