From 4026c472db0edb276b697745588d2bff157f54b3 Mon Sep 17 00:00:00 2001 From: rahul Date: Sun, 12 May 2024 00:06:05 +0530 Subject: [PATCH 1/5] bugfixed 1979 admin --- schema.graphql | 2 ++ src/GraphQl/Queries/Queries.ts | 2 ++ src/screens/Users/Users.tsx | 63 +++++++++++++++++++++------------- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/schema.graphql b/schema.graphql index 0030ec7fc3..018d3e02cb 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1440,6 +1440,8 @@ enum UserOrderByInput { id_DESC lastName_ASC lastName_DESC + createdAt_ASC + createdAt_DESC } type UserPhone { diff --git a/src/GraphQl/Queries/Queries.ts b/src/GraphQl/Queries/Queries.ts index 101d020285..e9c3866ad4 100644 --- a/src/GraphQl/Queries/Queries.ts +++ b/src/GraphQl/Queries/Queries.ts @@ -108,6 +108,7 @@ export const USER_LIST = gql` $lastName_contains: String $skip: Int $first: Int + $order: UserOrderByInput ) { users( where: { @@ -116,6 +117,7 @@ export const USER_LIST = gql` } skip: $skip first: $first + orderBy: $order ) { user { _id diff --git a/src/screens/Users/Users.tsx b/src/screens/Users/Users.tsx index 1158658532..de8554a745 100644 --- a/src/screens/Users/Users.tsx +++ b/src/screens/Users/Users.tsx @@ -34,43 +34,52 @@ const Users = (): JSX.Element => { const [searchByName, setSearchByName] = useState(''); const [sortingOption, setSortingOption] = useState('newest'); const [filteringOption, setFilteringOption] = useState('cancel'); - const superAdmin = getItem('SuperAdmin'); - const adminFor = getItem('AdminFor'); - const userRole = superAdmin + const userType = getItem('SuperAdmin') ? 'SUPERADMIN' - : adminFor?.length > 0 + : getItem('AdminFor') ? 'ADMIN' : 'USER'; - const loggedInUserId = getItem('id'); - const { data, loading, fetchMore, refetch } = useQuery(USER_LIST, { + const { + data: usersData, + loading: loading, + fetchMore, + refetch: refetchUsers, + }: { + data?: { users: InterfaceQueryUserListItem[] }; + loading: boolean; + fetchMore: any; + refetch: any; + error?: ApolloError; + } = useQuery(USER_LIST, { variables: { first: perPageResult, skip: 0, firstName_contains: '', lastName_contains: '', + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC' }, notifyOnNetworkStatusChange: true, }); const { data: dataOrgs } = useQuery(ORGANIZATION_CONNECTION_LIST); - const [displayedUsers, setDisplayedUsers] = useState(data?.users || []); + const [displayedUsers, setDisplayedUsers] = useState(usersData?.users || []); // Manage loading more state useEffect(() => { - if (!data) { + if (!usersData) { return; } - if (data.users.length < perPageResult) { + if (usersData.users.length < perPageResult) { setHasMore(false); } - if (data && data.users) { - let newDisplayedUsers = sortUsers(data.users, sortingOption); + if (usersData && usersData.users) { + let newDisplayedUsers = sortUsers(usersData.users, sortingOption); newDisplayedUsers = filterUsers(newDisplayedUsers, filteringOption); setDisplayedUsers(newDisplayedUsers); } - }, [data, sortingOption, filteringOption]); + }, [usersData, sortingOption, filteringOption]); // To clear the search when the component is unmounted useEffect(() => { @@ -92,7 +101,7 @@ const Users = (): JSX.Element => { // Send to orgList page if user is not superadmin useEffect(() => { - if (userRole != 'SUPERADMIN') { + if (userType != 'SUPERADMIN') { window.location.assign('/orglist'); } }, []); @@ -112,18 +121,17 @@ const Users = (): JSX.Element => { resetAndRefetch(); return; } - refetch({ + refetchUsers({ firstName_contains: value, lastName_contains: '', // Later on we can add several search and filter options }); + setHasMore(true); }; - const handleSearchByEnter = ( - e: React.KeyboardEvent, - ): void => { + const handleSearchByEnter = (e: any): void => { if (e.key === 'Enter') { - const { value } = e.currentTarget; + const { value } = e.target; handleSearch(value); } }; @@ -137,11 +145,12 @@ const Users = (): JSX.Element => { }; /* istanbul ignore next */ const resetAndRefetch = (): void => { - refetch({ + refetchUsers({ first: perPageResult, skip: 0, firstName_contains: '', lastName_contains: '', + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC' }); setHasMore(true); }; @@ -150,8 +159,10 @@ const Users = (): JSX.Element => { setIsLoadingMore(true); fetchMore({ variables: { - skip: data?.users.length || 0, + skip: usersData?.users.length || 0, + userType: 'ADMIN', filter: searchByName, + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC' }, updateQuery: ( prev: { users: InterfaceQueryUserListItem[] } | undefined, @@ -174,6 +185,8 @@ const Users = (): JSX.Element => { }; const handleSorting = (option: string): void => { + setDisplayedUsers([]); + setHasMore(true); setSortingOption(option); }; @@ -201,6 +214,7 @@ const Users = (): JSX.Element => { }; const handleFiltering = (option: string): void => { + setDisplayedUsers([]); setFilteringOption(option); }; @@ -224,6 +238,7 @@ const Users = (): JSX.Element => { user.appUserProfile.adminFor.length !== 0 ); }); + console.log(output) return output; } else { const output = filteredUsers.filter((user) => { @@ -249,7 +264,7 @@ const Users = (): JSX.Element => {
{
{isLoading == false && - data && + usersData && displayedUsers.length === 0 && searchByName.length > 0 ? (
@@ -350,7 +365,7 @@ const Users = (): JSX.Element => { {t('noResultsFoundFor')} "{searchByName}"
- ) : isLoading == false && data && displayedUsers.length === 0 ? ( + ) : isLoading == false && usersData === undefined && displayedUsers.length === 0 ? (

{t('noUserFound')}

@@ -393,7 +408,7 @@ const Users = (): JSX.Element => { - {data && + {usersData && displayedUsers.map( (user: InterfaceQueryUserListItem, index: number) => { return ( From 161f9b3badaf5c97bffce1e815dc871e1de18733 Mon Sep 17 00:00:00 2001 From: rahul Date: Sun, 12 May 2024 00:58:56 +0530 Subject: [PATCH 2/5] additional changes in bug 1979 --- src/screens/Users/Users.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/screens/Users/Users.tsx b/src/screens/Users/Users.tsx index d5ca45f2a1..267a2dfd5f 100644 --- a/src/screens/Users/Users.tsx +++ b/src/screens/Users/Users.tsx @@ -18,6 +18,7 @@ import InfiniteScroll from 'react-infinite-scroll-component'; import type { InterfaceQueryUserListItem } from 'utils/interfaces'; import styles from './Users.module.css'; import useLocalStorage from 'utils/useLocalstorage'; +import type { ApolloError } from '@apollo/client'; const Users = (): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'users' }); From c56af0c9ab78afafe68463bf3c7bedde42c147c2 Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 20 May 2024 01:04:38 +0530 Subject: [PATCH 3/5] Formatting Fixed --- src/screens/Users/Users.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/screens/Users/Users.tsx b/src/screens/Users/Users.tsx index 267a2dfd5f..2cd99e2416 100644 --- a/src/screens/Users/Users.tsx +++ b/src/screens/Users/Users.tsx @@ -58,7 +58,7 @@ const Users = (): JSX.Element => { skip: 0, firstName_contains: '', lastName_contains: '', - order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC' + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC', }, notifyOnNetworkStatusChange: true, }); @@ -150,7 +150,7 @@ const Users = (): JSX.Element => { skip: 0, firstName_contains: '', lastName_contains: '', - order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC' + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC', }); setHasMore(true); }; @@ -162,7 +162,7 @@ const Users = (): JSX.Element => { skip: usersData?.users.length || 0, userType: 'ADMIN', filter: searchByName, - order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC' + order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC', }, updateQuery: ( prev: { users: InterfaceQueryUserListItem[] } | undefined, @@ -238,7 +238,6 @@ const Users = (): JSX.Element => { user.appUserProfile.adminFor.length !== 0 ); }); - console.log(output) return output; } else { const output = filteredUsers.filter((user) => { @@ -365,7 +364,9 @@ const Users = (): JSX.Element => { {t('noResultsFoundFor')} "{searchByName}" - ) : isLoading == false && usersData === undefined && displayedUsers.length === 0 ? ( + ) : isLoading == false && + usersData === undefined && + displayedUsers.length === 0 ? (

{t('noUserFound')}

From b452856947f1984b37461eaaf1bcf1d702895eef Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 4 Jun 2024 19:47:01 +0530 Subject: [PATCH 4/5] added test cases --- src/screens/Users/Users.test.tsx | 479 +++++++++++++++++++++++++++---- 1 file changed, 425 insertions(+), 54 deletions(-) diff --git a/src/screens/Users/Users.test.tsx b/src/screens/Users/Users.test.tsx index 59e16a7878..1a07250f55 100644 --- a/src/screens/Users/Users.test.tsx +++ b/src/screens/Users/Users.test.tsx @@ -12,16 +12,280 @@ import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18nForTest from 'utils/i18nForTest'; import Users from './Users'; -import { EMPTY_MOCKS, MOCKS, MOCKS2 } from './UsersMocks'; +import { EMPTY_MOCKS, MOCKS, MOCKS2, MOCKS4 } from './UsersMocks'; import useLocalStorage from 'utils/useLocalstorage'; +import { + USER_LIST, + ORGANIZATION_CONNECTION_LIST, +} from 'GraphQl/Queries/Queries'; + const { setItem, removeItem } = useLocalStorage(); +const MOCK_USERS = [ + { + user: { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, + }, + ], + }, + appUserProfile: { + _id: 'user1', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '21/06/2022', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: '456', + name: 'ABC', + image: null, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + createdAt: '21/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '21/06/2022', + }, + }, + ], + joinedOrganizations: [ + { + _id: '123', + name: 'Palisadoes', + image: null, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + createdAt: '21/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '21/06/2022', + }, + }, + ], + }, + appUserProfile: { + _id: 'user2', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user3', + firstName: 'Jack', + lastName: 'Smith', + image: null, + email: 'jack@example.com', + createdAt: '19/06/2022', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + createdAt: '19/06/2022', + creator: { + _id: '123', + firstName: 'Jack', + lastName: 'Smith', + image: null, + email: 'jack@example.com', + createdAt: '19/06/2022', + }, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + createdAt: '19/06/2022', + creator: { + _id: '123', + firstName: 'Jack', + lastName: 'Smith', + image: null, + email: 'jack@example.com', + createdAt: '19/06/2022', + }, + }, + ], + }, + appUserProfile: { + _id: 'user3', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, +]; + +const MOCKS_NEW = [ + { + request: { + query: USER_LIST, + variables: { + first: 12, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: 'createdAt_DESC', + }, + }, + result: { + data: { + users: MOCK_USERS, + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [], + }, + }, + }, +]; + const link = new StaticMockLink(MOCKS, true); +const link4 = new StaticMockLink(MOCKS4, true); const link2 = new StaticMockLink(EMPTY_MOCKS, true); const link3 = new StaticMockLink(MOCKS2, true); +const link5 = new StaticMockLink(MOCKS_NEW, true); -async function wait(ms = 100): Promise { +async function wait(ms = 1000): Promise { await act(() => { return new Promise((resolve) => { setTimeout(resolve, ms); @@ -132,6 +396,7 @@ describe('Testing Users screen', () => { userEvent.type(screen.getByTestId(/searchByName/i), search1); userEvent.click(searchBtn); await wait(); + expect(screen.queryByText(/not found/i)).not.toBeInTheDocument(); const search2 = 'Pete{backspace}{backspace}{backspace}{backspace}'; userEvent.type(screen.getByTestId(/searchByName/i), search2); @@ -152,24 +417,34 @@ describe('Testing Users screen', () => { }); test('testing search not found', async () => { - render( - - - - - - - - - , - ); + await act(async () => { + render( + + + + + + + + + , + ); - await wait(); + await wait(); - const search = 'hello{enter}'; - await act(() => - userEvent.type(screen.getByTestId(/searchByName/i), search), - ); + const searchBtn = screen.getByTestId('searchButton'); + + const searchInput = screen.getByTestId(/searchByName/i); + + // Clear the search input + userEvent.clear(searchInput); + + // Search for a name that doesn't exist + userEvent.type(screen.getByTestId(/searchByName/i), 'NonexistentName'); + userEvent.click(searchBtn); + + expect(screen.queryByText(/No User Found/i)).toBeInTheDocument(); + }); }); test('Testing User data is not present', async () => { @@ -230,42 +505,6 @@ describe('Testing Users screen', () => { ); }); - test('Testing sorting functionality', async () => { - await act(async () => { - render( - - - - - - - - - - , - ); - - await wait(); - - const searchInput = screen.getByTestId('sort'); - expect(searchInput).toBeInTheDocument(); - - const inputText = screen.getByTestId('sortUsers'); - - fireEvent.click(inputText); - const toggleText = screen.getByTestId('oldest'); - fireEvent.click(toggleText); - - expect(searchInput).toBeInTheDocument(); - - fireEvent.click(inputText); - const toggleTite = screen.getByTestId('newest'); - fireEvent.click(toggleTite); - - expect(searchInput).toBeInTheDocument(); - }); - }); - test('Testing filter functionality', async () => { await act(async () => { render( @@ -345,4 +584,136 @@ describe('Testing Users screen', () => { ); await wait(); }); + + test('should set hasMore to false if users length is less than perPageResult', async () => { + const link = new StaticMockLink(EMPTY_MOCKS, true); + + render( + + + + + + + + + + , + ); + + await wait(200); + + // Check if "No User Found" is displayed + expect(screen.getByText(/No User Found/i)).toBeInTheDocument(); + }); + + test('should filter users correctly', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + + await wait(); + + const filterButton = screen.getByTestId('filterUsers'); + fireEvent.click(filterButton); + + const filterAdmin = screen.getByTestId('admin'); + fireEvent.click(filterAdmin); + await wait(); + let rows = screen.getAllByRole('row'); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + + fireEvent.click(filterButton); + const filterSuperAdmin = screen.getByTestId('superAdmin'); + fireEvent.click(filterSuperAdmin); + await wait(); + rows = screen.getAllByRole('row'); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + + fireEvent.click(filterButton); + const filterUser = screen.getByTestId('user'); + fireEvent.click(filterUser); + await wait(); + rows = screen.getAllByRole('row'); + expect(screen.getByText('Jack Smith')).toBeInTheDocument(); + + fireEvent.click(filterButton); + const filterCancel = screen.getByTestId('cancel'); + fireEvent.click(filterCancel); + await wait(); + rows = screen.getAllByRole('row'); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + expect(screen.getByText('Jack Smith')).toBeInTheDocument(); + }); + }); + + test('Users should be sorted and filtered correctly', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + + await wait(); + + // Check if the sorting and filtering logic was applied correctly + const rows = screen.getAllByRole('row'); + + const firstRow = rows[1]; + const secondRow = rows[2]; + + expect(firstRow).toHaveTextContent('John Doe'); + expect(secondRow).toHaveTextContent('Jane Doe'); + + await wait(); + + const inputText = screen.getByTestId('sortUsers'); + + fireEvent.click(inputText); + const toggleText = screen.getByTestId('oldest'); + fireEvent.click(toggleText); + + fireEvent.click(inputText); + const toggleTite = screen.getByTestId('newest'); + fireEvent.click(toggleTite); + + // Verify the users are sorted by oldest + await wait(); + + const displayedUsers = screen.getAllByRole('row'); + expect(displayedUsers[1]).toHaveTextContent('John Doe'); // assuming User1 is the oldest + expect(displayedUsers[displayedUsers.length - 1]).toHaveTextContent( + 'Jack Smith', + ); // assuming UserN is the newest + + await wait(); + + fireEvent.click(inputText); + const toggleOld = screen.getByTestId('oldest'); + fireEvent.click(toggleOld); + + fireEvent.click(inputText); + const toggleNewest = screen.getByTestId('newest'); + fireEvent.click(toggleNewest); + }); + }); }); From 889cb5a22551b48f8b86ba45ed546db1c5d1de33 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 4 Jun 2024 20:24:01 +0530 Subject: [PATCH 5/5] updated test cases --- src/screens/Users/Users.test.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/screens/Users/Users.test.tsx b/src/screens/Users/Users.test.tsx index 1a07250f55..f130ed1df9 100644 --- a/src/screens/Users/Users.test.tsx +++ b/src/screens/Users/Users.test.tsx @@ -12,7 +12,7 @@ import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18nForTest from 'utils/i18nForTest'; import Users from './Users'; -import { EMPTY_MOCKS, MOCKS, MOCKS2, MOCKS4 } from './UsersMocks'; +import { EMPTY_MOCKS, MOCKS, MOCKS2 } from './UsersMocks'; import useLocalStorage from 'utils/useLocalstorage'; import { @@ -280,7 +280,6 @@ const MOCKS_NEW = [ ]; const link = new StaticMockLink(MOCKS, true); -const link4 = new StaticMockLink(MOCKS4, true); const link2 = new StaticMockLink(EMPTY_MOCKS, true); const link3 = new StaticMockLink(MOCKS2, true); const link5 = new StaticMockLink(MOCKS_NEW, true); @@ -630,28 +629,24 @@ describe('Testing Users screen', () => { const filterAdmin = screen.getByTestId('admin'); fireEvent.click(filterAdmin); await wait(); - let rows = screen.getAllByRole('row'); expect(screen.getByText('Jane Doe')).toBeInTheDocument(); fireEvent.click(filterButton); const filterSuperAdmin = screen.getByTestId('superAdmin'); fireEvent.click(filterSuperAdmin); await wait(); - rows = screen.getAllByRole('row'); expect(screen.getByText('John Doe')).toBeInTheDocument(); fireEvent.click(filterButton); const filterUser = screen.getByTestId('user'); fireEvent.click(filterUser); await wait(); - rows = screen.getAllByRole('row'); expect(screen.getByText('Jack Smith')).toBeInTheDocument(); fireEvent.click(filterButton); const filterCancel = screen.getByTestId('cancel'); fireEvent.click(filterCancel); await wait(); - rows = screen.getAllByRole('row'); expect(screen.getByText('John Doe')).toBeInTheDocument(); expect(screen.getByText('Jane Doe')).toBeInTheDocument(); expect(screen.getByText('Jack Smith')).toBeInTheDocument();