| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- import React, { useCallback } from 'react';
- import type { IUserHasId } from '@growi/core';
- import { UserPicture } from '@growi/ui/dist/components';
- import { format as dateFnsFormat } from 'date-fns/format';
- import { useTranslation } from 'next-i18next';
- import AdminUsersContainer from '~/client/services/AdminUsersContainer';
- import { withUnstatedContainers } from '../../UnstatedUtils';
- import { SortIcons } from './SortIcons';
- import UserMenu from './UserMenu';
- type UserTableExternalProps = Record<string, never>;
- type UserTableProps = UserTableExternalProps & {
- adminUsersContainer: AdminUsersContainer;
- };
- const UserTable = (props: UserTableProps) => {
- const { t } = useTranslation('admin');
- const { adminUsersContainer } = props;
- const getUserStatusLabel = (userStatus: number) => {
- let additionalClassName = 'text-bg-info';
- let text = 'Approval Pending';
- switch (userStatus) {
- case 1:
- additionalClassName = 'text-bg-info';
- text = 'Approval Pending';
- break;
- case 2:
- additionalClassName = 'text-bg-success';
- text = 'Active';
- break;
- case 3:
- additionalClassName = 'text-bg-warning';
- text = 'Suspended';
- break;
- case 4:
- additionalClassName = 'text-bg-danger';
- text = 'Deleted';
- break;
- case 5:
- additionalClassName = 'text-bg-secondary';
- text = 'Invited';
- break;
- }
- return <span className={`badge ${additionalClassName}`}>{text}</span>;
- };
- const sortIconsClickedHandler = useCallback(
- async (sort: string, sortOrder: string) => {
- const isAsc = sortOrder === 'asc';
- await adminUsersContainer.sort(sort, isAsc);
- },
- [adminUsersContainer],
- );
- const isCurrentSortOrderAsc = adminUsersContainer.state.sortOrder === 'asc';
- return (
- <div className="table-responsive text-nowrap h-100">
- <table className="table table-default table-bordered table-user-list">
- <thead>
- <tr>
- <th style={{ width: '100px' }}>#</th>
- <th>
- <div className="d-flex align-items-center">
- <div className="me-3">{t('user_management.status')}</div>
- <SortIcons
- isSelected={adminUsersContainer.state.sort === 'status'}
- isAsc={isCurrentSortOrderAsc}
- onClick={(sortOrder) =>
- sortIconsClickedHandler('status', sortOrder)
- }
- />
- </div>
- </th>
- <th>
- <div className="d-flex align-items-center">
- <div className="me-3">
- <code>username</code>
- </div>
- <SortIcons
- isSelected={adminUsersContainer.state.sort === 'username'}
- isAsc={isCurrentSortOrderAsc}
- onClick={(sortOrder) =>
- sortIconsClickedHandler('username', sortOrder)
- }
- />
- </div>
- </th>
- <th>
- <div className="d-flex align-items-center">
- <div className="me-3">{t('Name')}</div>
- <SortIcons
- isSelected={adminUsersContainer.state.sort === 'name'}
- isAsc={isCurrentSortOrderAsc}
- onClick={(sortOrder) =>
- sortIconsClickedHandler('name', sortOrder)
- }
- />
- </div>
- </th>
- <th>
- <div className="d-flex align-items-center">
- <div className="me-3">{t('Email')}</div>
- <SortIcons
- isSelected={adminUsersContainer.state.sort === 'email'}
- isAsc={isCurrentSortOrderAsc}
- onClick={(sortOrder) =>
- sortIconsClickedHandler('email', sortOrder)
- }
- />
- </div>
- </th>
- <th style={{ width: '100px' }}>
- <div className="d-flex align-items-center">
- <div className="me-3">{t('Created')}</div>
- <SortIcons
- isSelected={adminUsersContainer.state.sort === 'createdAt'}
- isAsc={isCurrentSortOrderAsc}
- onClick={(sortOrder) =>
- sortIconsClickedHandler('createdAt', sortOrder)
- }
- />
- </div>
- </th>
- <th style={{ width: '150px' }}>
- <div className="d-flex align-items-center">
- <div className="me-3">{t('last_login')}</div>
- <SortIcons
- isSelected={adminUsersContainer.state.sort === 'lastLoginAt'}
- isAsc={isCurrentSortOrderAsc}
- onClick={(sortOrder) =>
- sortIconsClickedHandler('lastLoginAt', sortOrder)
- }
- />
- </div>
- </th>
- <th style={{ width: '70px' }}></th>
- </tr>
- </thead>
- <tbody>
- {adminUsersContainer.state.users.map((user: IUserHasId) => {
- return (
- <tr data-testid="user-table-tr" key={user._id}>
- <td>
- <UserPicture user={user} />
- </td>
- <td>
- {getUserStatusLabel(user.status)}
- {user.admin && (
- <span className="badge text-bg-secondary ms-2">
- {t('admin:user_management.user_table.administrator')}
- </span>
- )}
- {user.readOnly && (
- <span className="badge text-bg-light ms-2">
- {t('admin:user_management.user_table.read_only')}
- </span>
- )}
- </td>
- <td>
- <strong>{user.username}</strong>
- </td>
- <td>{user.name}</td>
- <td>{user.email}</td>
- <td>{dateFnsFormat(user.createdAt, 'yyyy-MM-dd')}</td>
- <td>
- {user.lastLoginAt && (
- <span>
- {dateFnsFormat(
- new Date(user.lastLoginAt),
- 'yyyy-MM-dd HH:mm',
- )}
- </span>
- )}
- </td>
- <td>
- <UserMenu user={user} />
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- </div>
- );
- };
- const UserTableWrapper = withUnstatedContainers<
- UserTableExternalProps,
- UserTableProps
- >(UserTable, [AdminUsersContainer]);
- export default UserTableWrapper;
|