diff --git a/__mocks__/handlers/members.handler.js b/__mocks__/handlers/members.handler.js index 0e9998f27..9dcd406ad 100644 --- a/__mocks__/handlers/members.handler.js +++ b/__mocks__/handlers/members.handler.js @@ -2,52 +2,66 @@ import { rest } from 'msw'; const URL = process.env.NEXT_PUBLIC_BASE_URL; const membersHandlers = [ - rest.get(`${URL}/members/idle`, (_, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - message: 'Idle members returned successfully!', - idleMemberUserNames: [ - 'rohan-rajgupta', - 'sumit', - 'swaraj', - 'rohit', - 'tanya', - 'akshay', - 'shubham', - 'devashish', - 'lakshay', - 'rucha', - 'swebert', - 'nikhil', - 'ishika', - 'rajakvk', - 'moses', - 'prem', - 'bhavesh', - 'ankush', - 'prakash', - 'deipayan', - 'mehul', - 'ashwini', - 'amanA', - 'sagar', - 'shankar', - 'aman-saxena', - 'harshith', - 'pranav', - 'ankur', - 'pujarini', - 'sanyogita', - 'pavan', - 'ankita', - 'shashwat', - 'vividh', - 'rahil', - ], - }) - ); - }), + rest.get(`${URL}/members/idle`, (_, res, ctx) => { + return res( + ctx.status(200), + ctx.json({ + message: 'Idle members returned successfully!', + idleMemberUserNames: [ + 'rohan-rajgupta', + 'sumit', + 'swaraj', + 'rohit', + 'tanya', + 'akshay', + 'shubham', + 'devashish', + 'lakshay', + 'rucha', + 'swebert', + 'nikhil', + 'ishika', + 'rajakvk', + 'moses', + 'prem', + 'bhavesh', + 'ankush', + 'prakash', + 'deipayan', + 'mehul', + 'ashwini', + 'amanA', + 'sagar', + 'shankar', + 'aman-saxena', + 'harshith', + 'pranav', + 'ankur', + 'pujarini', + 'sanyogita', + 'pavan', + 'ankita', + 'shashwat', + 'vividh', + 'rahil', + ], + }) + ); + }), ]; +export const failedIdleMembersHandler = rest.get( + `${URL}/members/idle`, + (_, res, ctx) => { + return res( + ctx.status(500), + ctx.json({ + statusCode: 500, + error: 'Internal Server Error', + message: 'An internal server error occurred', + }) + ); + } +); + export default membersHandlers; diff --git a/__tests__/Unit/hooks/membersApi.test.tsx b/__tests__/Unit/hooks/membersApi.test.tsx new file mode 100644 index 000000000..e8a50320d --- /dev/null +++ b/__tests__/Unit/hooks/membersApi.test.tsx @@ -0,0 +1,73 @@ +import { setupServer } from 'msw/node'; +import handlers, { + failedIdleMembersHandler, +} from '../../../__mocks__/handlers/members.handler.js'; + +import { PropsWithChildren } from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { Provider } from 'react-redux'; +import { store } from '@/app/store'; +import { useGetIdleMembersQuery } from '@/app/services/membersApi'; + +const server = setupServer(...handlers); + +beforeAll(() => { + server.listen(); +}); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +function Wrapper({ + children, +}: PropsWithChildren>): JSX.Element { + return {children}; +} + +describe('useGetIdleMembersQuery', () => { + test('returns idle members', async () => { + const { result, waitForNextUpdate } = renderHook( + () => useGetIdleMembersQuery(), + { + wrapper: Wrapper, + } + ); + + const initialResponse = result.current; + expect(initialResponse.data).toBeUndefined(); + expect(initialResponse.isLoading).toBe(true); + + await act(() => waitForNextUpdate()); + + const nextResponse = result.current; + expect(nextResponse.data).not.toBeUndefined(); + expect(nextResponse.isLoading).toBe(false); + expect(nextResponse.isSuccess).toBe(true); + expect(nextResponse.data).toBeDefined(); + }); + + test('checks for error response', async () => { + server.use(failedIdleMembersHandler); + const { result, waitForNextUpdate } = renderHook( + () => useGetIdleMembersQuery(), + { + wrapper: Wrapper, + } + ); + + const initialResponse = result.current; + expect(initialResponse.data).toBeUndefined(); + expect(initialResponse.isLoading).toBe(true); + + await act(() => waitForNextUpdate()); + + const nextResponse = result.current; + expect(nextResponse.isError).toBe(true); + expect(nextResponse.error).toHaveProperty('status', 500); + + expect(nextResponse.error).toHaveProperty('data', { + statusCode: 500, + error: 'Internal Server Error', + message: 'An internal server error occurred', + }); + }); +}); diff --git a/src/app/services/api.ts b/src/app/services/api.ts index 77733a0c6..3238cb5e5 100644 --- a/src/app/services/api.ts +++ b/src/app/services/api.ts @@ -22,6 +22,7 @@ export const api = createApi({ 'User', 'Tags', 'Levels', + 'Idle_Members', 'User_Standup', ], /** diff --git a/src/app/services/membersApi.ts b/src/app/services/membersApi.ts new file mode 100644 index 000000000..594c2610d --- /dev/null +++ b/src/app/services/membersApi.ts @@ -0,0 +1,22 @@ +import { MEMBERS_IDLE } from '@/constants/url'; +import { api } from './api'; + +type IdleMembersResponse = { idleMemberUserNames: string[] }; +export const membersApi = api.injectEndpoints({ + endpoints: (build) => ({ + getIdleMembers: build.query({ + query: () => MEMBERS_IDLE, + providesTags: ['Idle_Members'], + transformResponse: (response: IdleMembersResponse) => { + const filterMembers = response.idleMemberUserNames.filter( + (username: string) => username + ); + const sortedIdleMembers = filterMembers.sort(); + + return sortedIdleMembers; + }, + }), + }), +}); + +export const { useGetIdleMembersQuery } = membersApi; diff --git a/src/constants/url.ts b/src/constants/url.ts index c04b98f2a..4fd053f5c 100644 --- a/src/constants/url.ts +++ b/src/constants/url.ts @@ -11,6 +11,7 @@ export const LOGIN_URL = `https://github.com/login/oauth/authorize?client_id=23c export const MEMBERS_URL = 'https://members.realdevsquad.com'; export const CHALLENGES_URL = `${BASE_URL}/challenges`; export const USER_SELF = `${BASE_URL}/users/self`; +export const MEMBERS_IDLE = `${BASE_URL}/members/idle`; export const DEFAULT_AVATAR = '/Avatar.png'; export const RDS_LOGO = '/RDSLogo.png'; export const GITHUB_LOGO = '/github-white.png'; diff --git a/src/pages/availability-panel/index.tsx b/src/pages/availability-panel/index.tsx index 054efaa56..580f94583 100644 --- a/src/pages/availability-panel/index.tsx +++ b/src/pages/availability-panel/index.tsx @@ -9,14 +9,19 @@ import updateTasksStatus from '@/helperFunctions/updateTasksStatus'; import { AVAILABLE } from '@/constants/task-status'; import { FEATURE } from '@/constants/task-type'; import { BASE_URL } from '@/constants/url'; +import { useGetIdleMembersQuery } from '@/app/services/membersApi'; const AvailabilityPanel: FC = () => { - const [idleMembersList, setIdleMembersList] = useState([]); const [unAssignedTasks, setUnAssignedTasks] = useState([]); const [error, setError] = useState(false); const [isTaskLoading, setIsTaskLoading] = useState(true); - const [isMemberLoading, setIsMemberLoading] = useState(true); const [refreshData, setRefreshData] = useState(false); + const { + data: idleMembersList = [], + isError: isIdleMembersError, + isLoading: isIdleMemberLoading, + refetch: refreshMemberList, + } = useGetIdleMembersQuery(); useEffect(() => { const fetchTasks = async () => { @@ -36,42 +41,24 @@ const AvailabilityPanel: FC = () => { setIsTaskLoading(false); } }; - const fetchIdleUsers = async () => { - try { - const url = `${process.env.NEXT_PUBLIC_BASE_URL}/members/idle`; - const { requestPromise } = fetch({ url }); - const fetchPromise = await requestPromise; - const { idleMemberUserNames } = fetchPromise.data; - const filterMembers = idleMemberUserNames.filter( - (username: string) => username - ); - const sortedIdleMembers = filterMembers.sort(); - setIdleMembersList(sortedIdleMembers); - setError(false); - } catch (Error) { - setError(true); - } finally { - setIsMemberLoading(false); - } - }; fetchTasks(); - fetchIdleUsers(); }, [refreshData]); let isErrorOrIsLoading; - if (error) { + if (error || isIdleMembersError) { isErrorOrIsLoading = ( Something went wrong, please contact admin! ); - } else if (isTaskLoading || isMemberLoading) { + } else if (isTaskLoading || isIdleMemberLoading) { isErrorOrIsLoading = ( Loading... ); } const getData = () => { + refreshMemberList(); setRefreshData(!refreshData); };