src/smart-components/user/users-list-not-selectable.tsx
import React, { useEffect, useState, useContext, useRef, useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useLocation, useNavigate } from 'react-router-dom';
import { mappedProps } from '../../helpers/shared/helpers';
import { TableComposableToolbarView } from '../../presentational-components/shared/table-composable-toolbar-view';
import { fetchUsers, updateUsersFilters } from '../../redux/actions/user-actions';
import UsersRow from '../../presentational-components/shared/UsersRow';
import {
defaultSettings,
defaultAdminSettings,
syncDefaultPaginationWithUrl,
applyPaginationToUrl,
isPaginationPresentInUrl,
} from '../../helpers/shared/pagination';
import { syncDefaultFiltersWithUrl, applyFiltersToUrl, areFiltersPresentInUrl } from '../../helpers/shared/filters';
import { useIntl } from 'react-intl';
import messages from '../../Messages';
import PermissionsContext from '../../utilities/permissions-context';
import { createRows } from './user-table-helpers';
import { ISortBy } from '@patternfly/react-table';
import { UserFilters } from '../../redux/reducers/user-reducer';
interface UsersListNotSelectableI {
userLinks: boolean;
usesMetaInURL: boolean;
props: Record<string, unknown>;
}
const UsersListNotSelectable = ({ userLinks, usesMetaInURL, props }: UsersListNotSelectableI) => {
const intl = useIntl();
const navigate = useNavigate();
const location = useLocation();
const dispatch = useDispatch();
const { orgAdmin } = useContext(PermissionsContext);
// use for text filter to focus
const innerRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null);
// for usesMetaInURL (Users page) store pagination settings in Redux, otherwise use results from meta
const pagination = useSelector(({ userReducer: { users } }) => ({
limit: (usesMetaInURL ? users.pagination.limit : users.meta.limit) ?? (orgAdmin ? defaultAdminSettings : defaultSettings).limit,
offset: (usesMetaInURL ? users.pagination.offset : users.meta.offset) ?? (orgAdmin ? defaultAdminSettings : defaultSettings).offset,
count: (usesMetaInURL ? users.pagination.count : users.meta.count) ?? 0,
redirected: usesMetaInURL && users.pagination.redirected,
itemCount: 0,
}));
const { users, isLoading, stateFilters } = useSelector(
({
userReducer: {
users: { data, filters = {} },
isUserDataLoading,
},
}) => ({
users: data?.map?.((data: any) => ({ ...data, uuid: data.username })),
isLoading: isUserDataLoading,
stateFilters: location.search.length > 0 || Object.keys(filters).length > 0 ? filters : { status: ['Active'] },
})
);
const fetchData = useCallback((apiProps: Parameters<typeof fetchUsers>[0]) => dispatch(fetchUsers(apiProps)), [dispatch]);
const updateStateFilters = useCallback((filters: Parameters<typeof updateUsersFilters>[0]) => dispatch(updateUsersFilters(filters)), [dispatch]);
const columns = [
{ title: intl.formatMessage(messages.orgAdministrator), key: 'org-admin' },
{ title: intl.formatMessage(messages.username), key: 'username', sortable: true },
{ title: intl.formatMessage(messages.email) },
{ title: intl.formatMessage(messages.firstName) },
{ title: intl.formatMessage(messages.lastName) },
{ title: intl.formatMessage(messages.status) },
];
const [sortByState, setSortByState] = useState<ISortBy>({ index: 1, direction: 'asc' });
const [filters, setFilters] = useState<UserFilters>(
usesMetaInURL
? stateFilters
: {
username: '',
email: '',
status: [intl.formatMessage(messages.active)],
}
);
useEffect(() => {
usesMetaInURL && applyPaginationToUrl(location, navigate, pagination.limit, pagination.offset);
}, [pagination.offset, pagination.limit, pagination.count, pagination.redirected]);
useEffect(() => {
const { limit, offset } = syncDefaultPaginationWithUrl(location, navigate, pagination);
const newFilters: UserFilters = usesMetaInURL
? syncDefaultFiltersWithUrl(location, navigate, ['username', 'email', 'status'], filters)
: { status: filters.status };
if (typeof newFilters.status !== 'undefined' && !Array.isArray(newFilters.status)) {
newFilters.status = [newFilters.status];
}
setFilters(newFilters);
fetchData({ ...mappedProps({ limit, offset, filters: newFilters }), usesMetaInURL });
}, []);
useEffect(() => {
if (usesMetaInURL) {
isPaginationPresentInUrl(location) || applyPaginationToUrl(location, navigate, pagination.limit, pagination.offset);
Object.values(filters).some((filter) => filter?.length > 0) &&
!areFiltersPresentInUrl(location, Object.keys(filters)) &&
syncDefaultFiltersWithUrl(location, navigate, Object.keys(filters), filters);
}
});
const updateFilters = (payload: any) => {
usesMetaInURL && updateStateFilters(payload);
setFilters({ username: '', ...payload });
};
return (
<TableComposableToolbarView
isSelectable={false}
isCompact={false}
borders={false}
columns={columns}
rows={createRows(userLinks, users, intl)}
sortBy={sortByState}
onSort={(e, index, direction) => {
const orderBy = `${direction === 'desc' ? '-' : ''}${columns[index].key}`;
setSortByState({ index, direction });
fetchData({ ...pagination, filters, usesMetaInURL, orderBy });
}}
ouiaId="users-table"
fetchData={(config) => {
const status = Object.prototype.hasOwnProperty.call(config, 'status') ? config.status : filters.status;
const { username, email, count, limit, offset, orderBy } = config;
Promise.resolve(fetchData({ ...mappedProps({ count, limit, offset, orderBy, filters: { username, email, status } }), usesMetaInURL })).then(
() => {
if (innerRef !== null && innerRef.current !== null) {
innerRef.current.focus();
}
}
);
applyPaginationToUrl(location, navigate, limit || 0, offset || 0);
usesMetaInURL && applyFiltersToUrl(location, navigate, { username, email, status });
}}
emptyFilters={{ username: '', email: '', status: [] }}
setFilterValue={({ username, email, status }) => {
updateFilters({
username: typeof username === 'undefined' ? filters.username : username,
email: typeof email === 'undefined' ? filters.email : email,
status: typeof status === 'undefined' || status === filters.status ? filters.status : status,
});
}}
isLoading={isLoading}
pagination={pagination}
rowWrapper={UsersRow}
title={{ singular: intl.formatMessage(messages.user), plural: intl.formatMessage(messages.users).toLowerCase() }}
filters={[
{
key: 'username',
value: typeof filters?.username === 'object' || typeof filters?.username === 'undefined' ? '' : filters.username,
placeholder: intl.formatMessage(messages.filterByKey, { key: intl.formatMessage(messages.username).toLowerCase() }),
innerRef,
},
{
key: 'email',
value: filters.email || '',
placeholder: intl.formatMessage(messages.filterByKey, { key: intl.formatMessage(messages.email).toLowerCase() }),
innerRef,
},
{
key: 'status',
value: filters.status || [],
label: intl.formatMessage(messages.status),
type: 'checkbox',
items: [
{ label: intl.formatMessage(messages.active), value: 'Active' },
{ label: intl.formatMessage(messages.inactive), value: 'Inactive' },
],
},
]}
tableId="users-list"
{...props}
/>
);
};
export default UsersListNotSelectable;