Skip to content

Commit

Permalink
feat: Implemented Sorting Functionality for Users Screen (#1081)
Browse files Browse the repository at this point in the history
* feat: Implemented Sorting Functionality for Users Screen

Changes Made:
- Implemented sorting functionality for the users screen.
- Added options for sorting users by latest first and oldest first.
- Wrote corresponding tests to ensure the sorting behavior is accurate.
- Tested the sorting feature by logging into the Talawa admin dashboard,
  navigating to the users option, and checking the sort button.

Signed-off-by: Akhilender <[email protected]>

* fix: altering the words

- Made Latest to Newest

Signed-off-by: Akhilender <[email protected]>

---------

Signed-off-by: Akhilender <[email protected]>
  • Loading branch information
akhilender-bongirwar authored Nov 24, 2023
1 parent 6023584 commit 29b87a9
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 12 deletions.
2 changes: 2 additions & 0 deletions public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@
"loadingUsers": "Loading Users...",
"noUserFound": "No User Found",
"sort": "Sort",
"Newest": "Newest First",
"Oldest": "Oldest First",
"filter": "Filter",
"noOrgError": "Organizations not found, please create an organization through dashboard",
"roleUpdated": "Role Updated.",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@
"loadingUsers": "Chargement des utilisateurs...",
"noUserFound": "Aucun utilisateur trouvé",
"sort": "Trier",
"Oldest": "Les plus anciennes d'abord",
"Newest": "Les plus récentes d'abord",
"filter": "Filtre",
"roleUpdated": "Rôle mis à jour.",
"noResultsFoundFor": "Aucun résultat trouvé pour ",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
"loadingUsers": "उपयोगकर्ता लोड हो रहा है ...",
"noUserFound": "कोई उपयोगकर्ता नहीं मिला।",
"sort": "छांटें",
"Oldest": "सबसे पुराना पहले",
"Newest": "सबसे नवीनतम पहले",
"filter": "फ़िल्टर",
"roleUpdated": "भूमिका अपडेट की गई।",
"noResultsFoundFor": "के लिए कोई परिणाम नहीं मिला ",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/sp.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
"loadingUsers": "Cargando usuarios ...",
"noUserFound": "No se encontró ningún usuario.",
"sort": "Ordenar",
"Oldest": "Más Antiguas Primero",
"Newest": "Más Recientes Primero",
"filter": "Filtrar",
"roleUpdated": "Rol actualizado.",
"noResultsFoundFor": "No se encontraron resultados para ",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
"loadingUsers": "正在加載用戶...",
"noUserFound": "找不到用戶。",
"sort": "排序",
"Oldest": "最旧的优先",
"Newest": "最新的优先",
"filter": "過濾",
"roleUpdated": "角色已更新。",
"noResultsFoundFor": "未找到结果 ",
Expand Down
38 changes: 36 additions & 2 deletions src/screens/Users/Users.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { act, render, screen } from '@testing-library/react';
import { act, fireEvent, render, screen } from '@testing-library/react';
import 'jest-localstorage-mock';
import 'jest-location-mock';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';

import userEvent from '@testing-library/user-event';
import { store } from 'state/store';
import { StaticMockLink } from 'utils/StaticMockLink';
Expand Down Expand Up @@ -179,4 +178,39 @@ describe('Testing Users screen', () => {
'Organizations not found, please create an organization through dashboard'
);
});

test('Testing sort Newest and oldest toggle', async () => {
await act(async () => {
render(
<MockedProvider addTypename={false} link={link}>
<BrowserRouter>
<Provider store={store}>
<I18nextProvider i18n={i18nForTest}>
<ToastContainer />
<Users />
</I18nextProvider>
</Provider>
</BrowserRouter>
</MockedProvider>
);

await wait();

const searchInput = screen.getByTestId('sort');
expect(searchInput).toBeInTheDocument();

const inputText = screen.getByTestId('sortUsers');

fireEvent.click(inputText);
const toggleText = screen.getByTestId('newest');

fireEvent.click(toggleText);

expect(searchInput).toBeInTheDocument();
fireEvent.click(inputText);
const toggleTite = screen.getByTestId('oldest');
fireEvent.click(toggleTite);
expect(searchInput).toBeInTheDocument();
});
});
});
68 changes: 58 additions & 10 deletions src/screens/Users/Users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const Users = (): JSX.Element => {
const [hasMore, setHasMore] = useState(true);
const [isLoadingMore, setIsLoadingMore] = useState(false);
const [searchByName, setSearchByName] = useState('');
const [sortingOption, setSortingOption] = useState('newest');

const userType = localStorage.getItem('UserType');
const loggedInUserId = localStorage.getItem('id');
Expand All @@ -57,6 +58,7 @@ const Users = (): JSX.Element => {
});

const { data: dataOrgs } = useQuery(ORGANIZATION_CONNECTION_LIST);
const [displayedUsers, setDisplayedUsers] = useState(usersData?.users || []);

// Manage loading more state
useEffect(() => {
Expand All @@ -66,7 +68,11 @@ const Users = (): JSX.Element => {
if (usersData.users.length < perPageResult) {
setHasMore(false);
}
}, [usersData]);
if (usersData && usersData.users) {
const newDisplayedUsers = sortUsers(usersData.users, sortingOption);
setDisplayedUsers(newDisplayedUsers);
}
}, [usersData, sortingOption]);

// To clear the search when the component is unmounted
useEffect(() => {
Expand Down Expand Up @@ -155,6 +161,32 @@ const Users = (): JSX.Element => {
});
};
const debouncedHandleSearchByName = debounce(handleSearchByName);
// console.log(usersData);

const handleSorting = (option: string): void => {
setSortingOption(option);
};

const sortUsers = (
allUsers: InterfaceQueryUserListItem[],
sortingOption: string
): InterfaceQueryUserListItem[] => {
const sortedUsers = [...allUsers];

if (sortingOption === 'newest') {
sortedUsers.sort(
(a, b) =>
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
);
} else if (sortingOption === 'oldest') {
sortedUsers.sort(
(a, b) =>
new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
);
}

return sortedUsers;
};

const headerTitles: string[] = [
'#',
Expand Down Expand Up @@ -196,15 +228,31 @@ const Users = (): JSX.Element => {
</div>
<div className={styles.btnsBlock}>
<div className="d-flex">
<Dropdown aria-expanded="false" title="Sort organizations">
<Dropdown.Toggle variant="outline-success">
<Dropdown
aria-expanded="false"
title="Sort Users"
data-testid="sort"
>
<Dropdown.Toggle
variant="outline-success"
data-testid="sortUsers"
>
<SortIcon className={'me-1'} />
{t('sort')}
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item href="#/action-1">Action 1</Dropdown.Item>
<Dropdown.Item href="#/action-2">Action 2</Dropdown.Item>
<Dropdown.Item href="#/action-3">Action 3</Dropdown.Item>
<Dropdown.Item
onClick={(): void => handleSorting('newest')}
data-testid="newest"
>
{t('Newest')}
</Dropdown.Item>
<Dropdown.Item
onClick={(): void => handleSorting('oldest')}
data-testid="oldest"
>
{t('Oldest')}
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Dropdown aria-expanded="false" title="Filter organizations">
Expand All @@ -223,14 +271,14 @@ const Users = (): JSX.Element => {
</div>
{isLoading == false &&
usersData &&
usersData.users.length === 0 &&
displayedUsers.length === 0 &&
searchByName.length > 0 ? (
<div className={styles.notFound}>
<h4>
{t('noResultsFoundFor')} &quot;{searchByName}&quot;
</h4>
</div>
) : isLoading == false && usersData && usersData.users.length === 0 ? (
) : isLoading == false && usersData && displayedUsers.length === 0 ? (
// eslint-disable-next-line react/jsx-indent
<div className={styles.notFound}>
<h4>{t('noUserFound')}</h4>
Expand All @@ -244,7 +292,7 @@ const Users = (): JSX.Element => {
/>
) : (
<InfiniteScroll
dataLength={usersData?.users.length ?? 0}
dataLength={displayedUsers.length ?? 0}
next={loadMoreUsers}
loader={
<TableLoader
Expand Down Expand Up @@ -275,7 +323,7 @@ const Users = (): JSX.Element => {
</thead>
<tbody>
{usersData &&
usersData?.users.map((user, index) => {
displayedUsers.map((user, index) => {
return (
<UsersTableItem
key={user._id}
Expand Down

0 comments on commit 29b87a9

Please sign in to comment.