Skip to content

Commit

Permalink
feat: Implemented orglist sorting functionality (#1076)
Browse files Browse the repository at this point in the history
* feat: Implemented orglist sorting functionality

Changes Made:
- Added a new state variable, `sortingOption`, to manage the current sorting preference. Default is set to 'latest'.
- Introduced a sorting mechanism using the `sortOrgs` function that sorts organizations based on creation date.
- Updated the `useEffect` hook to apply sorting when either `orgsData` or `sortingOption` changes.
- Added two sorting options - latest first and oldest first
- Also added the relevant tests for the correct functionality of the changes.

Fixes issue #1072

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* fix: Removed redundancy

- Removed the new interface instead imported the existing interface.
- Added cleanup function in tests.

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* fix: Highlighted the selected option

- Ensured that the selected option is highlighted in the sort dropdown.
- Made changes to ensure proper translation.
- Changed the variant from "outline success" to "success" when the option is selected,
  making it feasible for the user to know that the option is applied.

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* Removed redundant code

- Removed extra state variable and combined the two state variables into one
  as they perform same functionality.

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* fixed the failing test

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* Update en.json

- Changed the sort option titles
   - Latest first to Latest
   - Oldest first to Earliest

* fix: Translations modified

- Ensured correct translations for oldest first to earliest and latest first to latest in all languages

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* fixed the failing test

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* feat: Implement server-side sorting for organizations

Instead of handling sorting on the client side the GraphQL query for fetching organizations (`ORGANIZATION_CONNECTION_LIST`)
has been enhanced to support ordering based on the `createdAt` field.

- Modified the GraphQL query in `ORGANIZATION_CONNECTION_LIST` to include the `orderBy` parameter.
- Updated the `handleSorting` function to trigger a server-side refetch with the appropriate sorting order.
- Removed the client-side sorting logic in the `sortOrgs` function, as sorting is now handled on the server.
- Corrected the graphql schema for OrganizationOrderByInput enum

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* Fix: fixed the failing test

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

* fix: Changed oldest to earliest

- Altered the oldest key to earliest to avoid confusion

Signed-off-by: Akhilender <akhilenderb9@gmail.com>

---------

Signed-off-by: Akhilender <akhilenderb9@gmail.com>
  • Loading branch information
akhilender-bongirwar authored Dec 27, 2023
1 parent 767a673 commit bf8d298
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 10 deletions.
2 changes: 2 additions & 0 deletions public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
"displayImage": "Display Image",
"enterName": "Enter Name",
"sort": "Sort",
"Latest": "Latest",
"Earliest": "Earliest",
"filter": "Filter",
"cancel": "Cancel",
"noOrgErrorTitle": "Organizations Not Found",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
"displayImage": "Afficher l'image",
"enterName": "Entrez le nom",
"sort": "Trier",
"Earliest": "Le plus tôt",
"Latest": "Dernière",
"filter": "Filtre",
"cancel": "Annuler",
"endOfResults": "Fin des résultats",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
"displayImage": "प्रदर्शन छवि",
"enterName": "नाम दर्ज करें",
"sort": "छांटें",
"Earliest": "सबसे पुराना",
"Latest": "सबसे नवीनतम",
"filter": "फ़िल्टर",
"cancel": "रद्द करना",
"endOfResults": "परिणामों का अंत",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/sp.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
"displayImage": "Mostrar imagen",
"enterName": "Ingrese su nombre",
"sort": "Ordenar",
"Earliest": "Más Temprano",
"Latest": "El último",
"filter": "Filtrar",
"cancel": "Cancelar",
"endOfResults": "Fin de los resultados",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
"displayImage": "顯示圖像",
"enterName": "输入名字",
"sort": "排序",
"Earliest": "最早的",
"Latest": "最新的",
"filter": "過濾",
"cancel": "取消",
"endOfResults": "結果結束",
Expand Down
2 changes: 2 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,8 @@ input OrganizationInput {
enum OrganizationOrderByInput {
apiUrl_ASC
apiUrl_DESC
createdAt_ASC
createdAt_DESC
description_ASC
description_DESC
id_ASC
Expand Down
10 changes: 8 additions & 2 deletions src/GraphQl/Queries/Queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,19 @@ export const ORGANIZATION_LIST = gql`
}
`;

// Query to take the Organization list with filter option
// Query to take the Organization list with filter and sort option
export const ORGANIZATION_CONNECTION_LIST = gql`
query OrganizationsConnection($filter: String, $first: Int, $skip: Int) {
query OrganizationsConnection(
$filter: String
$first: Int
$skip: Int
$orderBy: OrganizationOrderByInput
) {
organizationsConnection(
where: { name_contains: $filter }
first: $first
skip: $skip
orderBy: $orderBy
) {
_id
image
Expand Down
44 changes: 43 additions & 1 deletion src/screens/OrgList/OrgList.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import { act, render, screen } from '@testing-library/react';
import {
act,
render,
screen,
fireEvent,
cleanup,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import 'jest-localstorage-mock';
import 'jest-location-mock';
Expand All @@ -11,6 +17,7 @@ import { store } from 'state/store';
import { StaticMockLink } from 'utils/StaticMockLink';
import i18nForTest from 'utils/i18nForTest';
import OrgList from './OrgList';

import { MOCKS, MOCKS_ADMIN, MOCKS_EMPTY } from './OrgListMocks';

async function wait(ms = 100): Promise<void> {
Expand All @@ -23,6 +30,7 @@ async function wait(ms = 100): Promise<void> {

afterEach(() => {
localStorage.clear();
cleanup();
});

describe('Organisations Page testing as SuperAdmin', () => {
Expand Down Expand Up @@ -199,4 +207,38 @@ describe('Organisations Page testing as Admin', () => {
await wait();
expect(screen.queryByText(/Create Organization/i)).toBeNull();
});

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

await wait();

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

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

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

fireEvent.click(toggleText);

expect(searchInput).toBeInTheDocument();
fireEvent.click(inputText);
const toggleTite = screen.getByTestId('oldest');
fireEvent.click(toggleTite);
expect(searchInput).toBeInTheDocument();
});
});
});
55 changes: 48 additions & 7 deletions src/screens/OrgList/OrgList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ function orgList(): JSX.Element {

const perPageResult = 8;
const [isLoading, setIsLoading] = useState(true);
const [sortingState, setSortingState] = useState({
option: '',
selectedOption: t('sort'),
});
const [hasMore, sethasMore] = useState(true);
const [isLoadingMore, setIsLoadingMore] = useState(false);
const [searchByName, setSearchByName] = useState('');
Expand Down Expand Up @@ -100,6 +104,8 @@ function orgList(): JSX.Element {
first: perPageResult,
skip: 0,
filter: searchByName,
orderBy:
sortingState.option === 'Latest' ? 'createdAt_DESC' : 'createdAt_ASC',
},
notifyOnNetworkStatusChange: true,
});
Expand Down Expand Up @@ -212,6 +218,8 @@ function orgList(): JSX.Element {
filter: '',
first: perPageResult,
skip: 0,
orderBy:
sortingState.option === 'Latest' ? 'createdAt_DESC' : 'createdAt_ASC',
});
sethasMore(true);
};
Expand All @@ -230,7 +238,6 @@ function orgList(): JSX.Element {
});
}
};

/* istanbul ignore next */
const loadMoreOrganizations = (): void => {
console.log('loadMoreOrganizations');
Expand Down Expand Up @@ -268,6 +275,22 @@ function orgList(): JSX.Element {
});
};

const handleSorting = (option: string): void => {
setSortingState({
option,
selectedOption: t(option),
});

const orderBy = option === 'Latest' ? 'createdAt_DESC' : 'createdAt_ASC';

refetchOrgs({
first: perPageResult,
skip: 0,
filter: searchByName,
orderBy,
});
};

return (
<>
<SuperAdminScreen
Expand Down Expand Up @@ -296,15 +319,33 @@ function orgList(): 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 organizations"
data-testid="sort"
>
<Dropdown.Toggle
variant={
sortingState.option === '' ? 'outline-success' : 'success'
}
data-testid="sortOrgs"
>
<SortIcon className={'me-1'} />
{t('sort')}
{sortingState.selectedOption}
</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('Latest')}
data-testid="latest"
>
{t('Latest')}
</Dropdown.Item>
<Dropdown.Item
onClick={(): void => handleSorting('Earliest')}
data-testid="oldest"
>
{t('Earliest')}
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Dropdown aria-expanded="false" title="Filter organizations">
Expand Down
3 changes: 3 additions & 0 deletions src/screens/OrgList/OrgListMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const MOCKS = [
first: 8,
skip: 0,
filter: '',
orderBy: 'createdAt_ASC',
},
notifyOnNetworkStatusChange: true,
},
Expand Down Expand Up @@ -111,6 +112,7 @@ const MOCKS_EMPTY = [
first: 8,
skip: 0,
filter: '',
orderBy: 'createdAt_ASC',
},
notifyOnNetworkStatusChange: true,
},
Expand Down Expand Up @@ -140,6 +142,7 @@ const MOCKS_ADMIN = [
first: 8,
skip: 0,
filter: '',
orderBy: 'createdAt_ASC',
},
notifyOnNetworkStatusChange: true,
},
Expand Down

0 comments on commit bf8d298

Please sign in to comment.