From dcb4db629fd6132ca736d882b991eee4d044f3d7 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 06:06:47 -0400 Subject: [PATCH 01/15] #729 - switch to work package count in page block title --- .../upcoming-deadlines/upcoming-deadlines.test.tsx | 8 +------- .../HomePage/upcoming-deadlines/upcoming-deadlines.tsx | 4 ++-- .../work-packages-by-timeline-status.test.tsx | 2 +- .../work-packages-by-timeline-status.tsx | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx index 0c419596..2a1b8cff 100644 --- a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx +++ b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx @@ -40,7 +40,7 @@ describe('upcoming deadlines component', () => { it('renders headers', () => { mockHook(false, false, []); renderComponent(); - expect(screen.getByText('Upcoming Deadlines')).toBeInTheDocument(); + expect(screen.getByText('Upcoming Deadlines (0)')).toBeInTheDocument(); }); it('renders loading indicator', () => { @@ -78,10 +78,4 @@ describe('upcoming deadlines component', () => { renderComponent(); expect(screen.getByText('No upcoming deadlines')).toBeInTheDocument(); }); - - it('renders work package count', () => { - mockHook(false, false, exampleAllWorkPackages); - renderComponent(); - expect(screen.getByText('3 Work Packages')).toBeInTheDocument(); - }); }); diff --git a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx index 8fce4058..a1c5be24 100644 --- a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx +++ b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx @@ -60,8 +60,8 @@ const UpcomingDeadlines: React.FC = () => { return ( : <>{workPackages.data?.length} Work Packages} + title={`Upcoming Deadlines (${workPackages.data?.length})`} + headerRight={<>} body={ {workPackages.isLoading ? : fullDisplay} } diff --git a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.test.tsx b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.test.tsx index 03566a4a..208349e6 100644 --- a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.test.tsx +++ b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.test.tsx @@ -38,7 +38,7 @@ describe('upcoming deadlines component', () => { it('renders headers', () => { mockHook(false, false, []); renderComponent(); - expect(screen.getByText('Work Packages By Timeline Status')).toBeInTheDocument(); + expect(screen.getByText('Work Packages By Timeline Status (0)')).toBeInTheDocument(); }); it('renders loading indicator', () => { diff --git a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx index 75190028..180f9609 100644 --- a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx +++ b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx @@ -64,7 +64,7 @@ const WorkPackagesByTimelineStatus: React.FC = () => { return (
Status:
From c532f80246688a1e6ef94e5448a9fe9ecff50270 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 06:21:58 -0400 Subject: [PATCH 02/15] #729 - add days until deadline work packages filter --- src/backend/functions/work-packages.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/backend/functions/work-packages.ts b/src/backend/functions/work-packages.ts index 50bd413e..b3f567bf 100644 --- a/src/backend/functions/work-packages.ts +++ b/src/backend/functions/work-packages.ts @@ -108,14 +108,17 @@ const workPackageTransformer = (wpInput: Prisma.Work_PackageGetPayload { const { queryStringParameters: eQSP } = event; const workPackages = await prisma.work_Package.findMany(wpQueryArgs); - return buildSuccessResponse( - workPackages.map(workPackageTransformer).filter((wp) => { - let passes = true; - if (eQSP?.status) passes &&= wp.status === eQSP?.status; - if (eQSP?.timelineStatus) passes &&= wp.timelineStatus === eQSP?.timelineStatus; - return passes; - }) - ); + const outputWorkPackages = workPackages.map(workPackageTransformer).filter((wp) => { + let passes = true; + if (eQSP?.status) passes &&= wp.status === eQSP?.status; + if (eQSP?.timelineStatus) passes &&= wp.timelineStatus === eQSP?.timelineStatus; + if (eQSP?.daysUntilDeadline) { + const daysToDeadline = Math.round((wp.endDate.getTime() - new Date().getTime()) / 86400000); + passes &&= daysToDeadline <= parseInt(eQSP?.daysUntilDeadline); + } + return passes; + }); + return buildSuccessResponse(outputWorkPackages); }; // Fetch the work package for the specified WBS number From 8a58323dd4e08f60b066ba6a5847ec2325782bc5 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 06:26:23 -0400 Subject: [PATCH 03/15] #729 - sort changes within work package query --- src/backend/functions/work-packages.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/functions/work-packages.ts b/src/backend/functions/work-packages.ts index b3f567bf..f6a86f6f 100644 --- a/src/backend/functions/work-packages.ts +++ b/src/backend/functions/work-packages.ts @@ -39,7 +39,7 @@ const wpQueryArgs = Prisma.validator()({ include: { projectLead: true, projectManager: true, - changes: { include: { implementer: true } } + changes: { include: { implementer: true }, orderBy: { dateImplemented: 'asc' } } } }, expectedActivities: true, From a4ed8ea9161e04b00157e16e24d1bfcf73ff2aa3 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 06:29:18 -0400 Subject: [PATCH 04/15] #729 - sort all work packages endpoint --- src/backend/functions/work-packages.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/functions/work-packages.ts b/src/backend/functions/work-packages.ts index f6a86f6f..735d9075 100644 --- a/src/backend/functions/work-packages.ts +++ b/src/backend/functions/work-packages.ts @@ -118,6 +118,7 @@ const getAllWorkPackages: ApiRouteFunction = async (_, event) => { } return passes; }); + outputWorkPackages.sort((wpA, wpB) => wpA.endDate.getTime() - wpB.endDate.getTime()); return buildSuccessResponse(outputWorkPackages); }; From 9f9e6a6b7f173e74d4907e0e9b5e80d3bc18e013 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 06:48:40 -0400 Subject: [PATCH 05/15] #729 - convert upcoming deadlines to use all work package endpoint with query parameters --- .../upcoming-deadlines.test.tsx | 6 ++---- .../upcoming-deadlines/upcoming-deadlines.tsx | 5 +++-- src/services/work-packages.api.ts | 15 +++++++++++---- src/services/work-packages.hooks.ts | 8 ++++++-- src/shared/urls.ts | 10 ++++++---- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx index 2a1b8cff..c6b646e6 100644 --- a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx +++ b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx @@ -5,7 +5,7 @@ import { UseQueryResult } from 'react-query'; import { WorkPackage } from 'utils'; -import { useAllWorkPackagesUpcomingDeadlines } from '../../../../services/work-packages.hooks'; +import { useAllWorkPackages } from '../../../../services/work-packages.hooks'; import { datePipe, fullNamePipe } from '../../../../shared/pipes'; import { mockUseQueryResult } from '../../../../test-support/test-data/test-utils.stub'; import { exampleAllWorkPackages } from '../../../../test-support/test-data/work-packages.stub'; @@ -14,9 +14,7 @@ import UpcomingDeadlines from './upcoming-deadlines'; jest.mock('../../../../services/work-packages.hooks'); -const mockedUseAllWPs = useAllWorkPackagesUpcomingDeadlines as jest.Mock< - UseQueryResult ->; +const mockedUseAllWPs = useAllWorkPackages as jest.Mock>; const mockHook = (isLoading: boolean, isError: boolean, data?: WorkPackage[], error?: Error) => { mockedUseAllWPs.mockReturnValue( diff --git a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx index a1c5be24..583636ed 100644 --- a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx +++ b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx @@ -5,8 +5,9 @@ import { Card, Container, Row } from 'react-bootstrap'; import { Link } from 'react-router-dom'; +import { WbsElementStatus } from 'utils'; import { useTheme } from '../../../../services/theme.hooks'; -import { useAllWorkPackagesUpcomingDeadlines } from '../../../../services/work-packages.hooks'; +import { useAllWorkPackages } from '../../../../services/work-packages.hooks'; import { datePipe, wbsPipe, fullNamePipe, percentPipe } from '../../../../shared/pipes'; import { routes } from '../../../../shared/routes'; import LoadingIndicator from '../../../components/loading-indicator/loading-indicator'; @@ -16,7 +17,7 @@ import styles from './upcoming-deadlines.module.css'; const UpcomingDeadlines: React.FC = () => { const theme = useTheme(); - const workPackages = useAllWorkPackagesUpcomingDeadlines(); + const workPackages = useAllWorkPackages(WbsElementStatus.Active, undefined, 14); if (workPackages.isError) { return ; diff --git a/src/services/work-packages.api.ts b/src/services/work-packages.api.ts index 836596f6..9d927cd1 100644 --- a/src/services/work-packages.api.ts +++ b/src/services/work-packages.api.ts @@ -19,10 +19,17 @@ import { workPackageTransformer } from './transformers/work-packages.transformer /** * Fetch all work packages. */ -export const getAllWorkPackages = (status?: WbsElementStatus, timelineStatus?: TimelineStatus) => { - return axios.get(apiUrls.workPackages(status, timelineStatus), { - transformResponse: (data) => JSON.parse(data).map(workPackageTransformer) - }); +export const getAllWorkPackages = ( + status?: WbsElementStatus, + timelineStatus?: TimelineStatus, + daysUntilDeadline?: number +) => { + return axios.get( + apiUrls.workPackages(status, timelineStatus, daysUntilDeadline?.toString()), + { + transformResponse: (data) => JSON.parse(data).map(workPackageTransformer) + } + ); }; /** diff --git a/src/services/work-packages.hooks.ts b/src/services/work-packages.hooks.ts index b2228280..2c825149 100644 --- a/src/services/work-packages.hooks.ts +++ b/src/services/work-packages.hooks.ts @@ -23,9 +23,13 @@ import { /** * Custom React Hook to supply all work packages. */ -export const useAllWorkPackages = (status?: WbsElementStatus, timelineStatus?: TimelineStatus) => { +export const useAllWorkPackages = ( + status?: WbsElementStatus, + timelineStatus?: TimelineStatus, + daysUntilDeadline?: number +) => { return useQuery(['work packages'], async () => { - const { data } = await getAllWorkPackages(status, timelineStatus); + const { data } = await getAllWorkPackages(status, timelineStatus, daysUntilDeadline); return data; }); }; diff --git a/src/shared/urls.ts b/src/shared/urls.ts index baea0c96..ada17c7c 100644 --- a/src/shared/urls.ts +++ b/src/shared/urls.ts @@ -21,10 +21,12 @@ const projectsCreate = () => `${projects()}-new`; const projectsEdit = () => `${projects()}-edit`; /**************** Work Packages Endpoint ****************/ -const workPackages = (status?: string, timelineStatus?: string) => { - const base = `${API_URL}/work-packages`; - if (status && timelineStatus) return `${base}?status=${status}&timelineStatus=${timelineStatus}`; - return base; +const workPackages = (status?: string, timelineStatus?: string, daysUntilDeadline?: string) => { + let url = `${API_URL}/work-packages`; + if (status) url += `?status=${status}&`; + if (timelineStatus) url += `timelineStatus=${timelineStatus}&`; + if (daysUntilDeadline) url += `daysUntilDeadline=${daysUntilDeadline}`; + return url; }; const workPackagesByWbsNum = (wbsNum: string) => `${workPackages()}/${wbsNum}`; const workPackagesUpcomingDeadlines = () => `${workPackages()}/upcoming-deadlines`; From 95c78318389ced43b62793fb094efd4fd2f02c67 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 06:54:37 -0400 Subject: [PATCH 06/15] #729 - remove upcoming deadlines endpoint and update work package query key --- src/backend/functions/work-packages.ts | 28 +------------------------- src/services/work-packages.api.ts | 9 --------- src/services/work-packages.hooks.ts | 22 +++++++------------- src/shared/urls.ts | 2 -- src/utils/src/api-routes.ts | 2 -- 5 files changed, 8 insertions(+), 55 deletions(-) diff --git a/src/backend/functions/work-packages.ts b/src/backend/functions/work-packages.ts index 735d9075..31542694 100644 --- a/src/backend/functions/work-packages.ts +++ b/src/backend/functions/work-packages.ts @@ -104,7 +104,7 @@ const workPackageTransformer = (wpInput: Prisma.Work_PackageGetPayload { const { queryStringParameters: eQSP } = event; const workPackages = await prisma.work_Package.findMany(wpQueryArgs); @@ -142,27 +142,6 @@ const getSingleWorkPackage: ApiRouteFunction = async (params: { wbsNum: string } return buildSuccessResponse(workPackageTransformer(wp)); }; -// Fetch all work packages with an end date in the next 2 weeks -const getAllWorkPackagesUpcomingDeadlines: ApiRouteFunction = async () => { - const workPackages = await prisma.work_Package.findMany({ - where: { - wbsElement: { - status: WBS_Element_Status.ACTIVE - } - }, - ...wpQueryArgs - }); - const outputWorkPackages = workPackages - .filter((wp) => { - const endDate = calculateEndDate(wp.startDate, wp.duration); - const daysFromNow = Math.round((endDate.getTime() - new Date().getTime()) / 86400000); - return daysFromNow <= 14; - }) - .map(workPackageTransformer); - outputWorkPackages.sort((wpA, wpB) => wpA.endDate.getTime() - wpB.endDate.getTime()); - return buildSuccessResponse(outputWorkPackages); -}; - // Define all valid routes for the endpoint const routes: ApiRoute[] = [ { @@ -170,11 +149,6 @@ const routes: ApiRoute[] = [ httpMethod: 'GET', func: getAllWorkPackages }, - { - path: `${API_URL}${apiRoutes.WORK_PACKAGES_UPCOMING_DEADLINES}`, - httpMethod: 'GET', - func: getAllWorkPackagesUpcomingDeadlines - }, { path: `${API_URL}${apiRoutes.WORK_PACKAGES_BY_WBS}`, httpMethod: 'GET', diff --git a/src/services/work-packages.api.ts b/src/services/work-packages.api.ts index 9d927cd1..9a58dd2f 100644 --- a/src/services/work-packages.api.ts +++ b/src/services/work-packages.api.ts @@ -65,12 +65,3 @@ export const editWorkPackage = (payload: EditWorkPackagePayload) => { ...payload }); }; - -/** - * Fetch all work packages with upcoming deadlines. - */ -export const getAllWorkPackagesUpcomingDeadlines = () => { - return axios.get(apiUrls.workPackagesUpcomingDeadlines(), { - transformResponse: (data) => JSON.parse(data).map(workPackageTransformer) - }); -}; diff --git a/src/services/work-packages.hooks.ts b/src/services/work-packages.hooks.ts index 2c825149..ebe770c0 100644 --- a/src/services/work-packages.hooks.ts +++ b/src/services/work-packages.hooks.ts @@ -16,7 +16,6 @@ import { createSingleWorkPackage, editWorkPackage, getAllWorkPackages, - getAllWorkPackagesUpcomingDeadlines, getSingleWorkPackage } from './work-packages.api'; @@ -28,10 +27,13 @@ export const useAllWorkPackages = ( timelineStatus?: TimelineStatus, daysUntilDeadline?: number ) => { - return useQuery(['work packages'], async () => { - const { data } = await getAllWorkPackages(status, timelineStatus, daysUntilDeadline); - return data; - }); + return useQuery( + ['work packages', status, timelineStatus, daysUntilDeadline], + async () => { + const { data } = await getAllWorkPackages(status, timelineStatus, daysUntilDeadline); + return data; + } + ); }; /** @@ -80,13 +82,3 @@ export const useEditWorkPackage = () => { } ); }; - -/** - * Custom React Hook to supply all work packages with an upcoming deadline. - */ -export const useAllWorkPackagesUpcomingDeadlines = () => { - return useQuery(['work packages', 'upcoming deadlines'], async () => { - const { data } = await getAllWorkPackagesUpcomingDeadlines(); - return data; - }); -}; diff --git a/src/shared/urls.ts b/src/shared/urls.ts index ada17c7c..80940dd4 100644 --- a/src/shared/urls.ts +++ b/src/shared/urls.ts @@ -29,7 +29,6 @@ const workPackages = (status?: string, timelineStatus?: string, daysUntilDeadlin return url; }; const workPackagesByWbsNum = (wbsNum: string) => `${workPackages()}/${wbsNum}`; -const workPackagesUpcomingDeadlines = () => `${workPackages()}/upcoming-deadlines`; const workPackagesCreate = () => `${workPackages()}-create`; const workPackagesEdit = () => `${workPackages()}-edit`; @@ -54,7 +53,6 @@ export const apiUrls = { workPackages, workPackagesByWbsNum, - workPackagesUpcomingDeadlines, workPackagesCreate, workPackagesEdit, diff --git a/src/utils/src/api-routes.ts b/src/utils/src/api-routes.ts index 57a16a55..9735966f 100644 --- a/src/utils/src/api-routes.ts +++ b/src/utils/src/api-routes.ts @@ -18,7 +18,6 @@ const PROJECTS_EDIT: string = `${PROJECTS}-edit`; /**************** Work Packages Endpoint ****************/ const WORK_PACKAGES: string = `/work-packages`; const WORK_PACKAGES_BY_WBS: string = `${WORK_PACKAGES}/:wbsNum`; -const WORK_PACKAGES_UPCOMING_DEADLINES: string = `${WORK_PACKAGES}/upcoming-deadlines`; const WORK_PACKAGES_CREATE: string = `${WORK_PACKAGES}-create`; const WORK_PACKAGES_EDIT: string = `${WORK_PACKAGES}-edit`; @@ -39,7 +38,6 @@ export const apiRoutes = { WORK_PACKAGES, WORK_PACKAGES_BY_WBS, - WORK_PACKAGES_UPCOMING_DEADLINES, WORK_PACKAGES_CREATE, WORK_PACKAGES_EDIT, From deee24d8f96e20deedbc40c8b005a79d58731437 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 07:27:39 -0400 Subject: [PATCH 07/15] #729 - make work packages url function fully flexible and thoroughly test it --- src/shared/tests/urls.test.tsx | 64 ++++++++++++++++++++++++++++++++++ src/shared/urls.ts | 12 +++---- 2 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 src/shared/tests/urls.test.tsx diff --git a/src/shared/tests/urls.test.tsx b/src/shared/tests/urls.test.tsx new file mode 100644 index 00000000..6422aa78 --- /dev/null +++ b/src/shared/tests/urls.test.tsx @@ -0,0 +1,64 @@ +/* + * This file is part of NER's PM Dashboard and licensed under GNU AGPLv3. + * See the LICENSE file in the repository root folder for details. + */ + +import { apiUrls } from '../urls'; + +describe('API URLs Tests', () => { + describe('all work packages urls', () => { + it('should return the correct url for all work packages base', () => { + expect(apiUrls.workPackages()).toEqual('/.netlify/functions/work-packages'); + }); + + it('should return the correct url for all work packages filtered by status', () => { + expect(apiUrls.workPackages({ status: 'ACTIVE' })).toEqual( + '/.netlify/functions/work-packages?status=ACTIVE' + ); + }); + + it('should return the correct url for all work packages filtered by timelineStatus', () => { + expect(apiUrls.workPackages({ timelineStatus: 'BEHIND' })).toEqual( + '/.netlify/functions/work-packages?timelineStatus=BEHIND' + ); + }); + + it('should return the correct url for all work packages filtered by daysUntilDeadline', () => { + expect(apiUrls.workPackages({ daysUntilDeadline: '14' })).toEqual( + '/.netlify/functions/work-packages?daysUntilDeadline=14' + ); + }); + + it('should return the correct url for all work packages filtered by status and timelineStatus', () => { + expect(apiUrls.workPackages({ status: 'ACTIVE', timelineStatus: 'AHEAD' })).toEqual( + '/.netlify/functions/work-packages?status=ACTIVE&timelineStatus=AHEAD' + ); + }); + + it('should return the correct url for all work packages filtered by status and daysUntilDeadline', () => { + expect(apiUrls.workPackages({ status: 'COMPLETE', daysUntilDeadline: '12' })).toEqual( + '/.netlify/functions/work-packages?status=COMPLETE&daysUntilDeadline=12' + ); + }); + + it('should return the correct url for all work packages filtered by timelineStatus and daysUntilDeadline', () => { + expect( + apiUrls.workPackages({ timelineStatus: 'VERY_BEHIND', daysUntilDeadline: '10' }) + ).toEqual( + '/.netlify/functions/work-packages?timelineStatus=VERY_BEHIND&daysUntilDeadline=10' + ); + }); + + it('should return the correct url for all work packages filtered by status, timelineStatus, and daysUntilDeadline', () => { + expect( + apiUrls.workPackages({ + status: 'INACTIVE', + timelineStatus: 'ON_TRACK', + daysUntilDeadline: '7' + }) + ).toEqual( + '/.netlify/functions/work-packages?status=INACTIVE&timelineStatus=ON_TRACK&daysUntilDeadline=7' + ); + }); + }); +}); diff --git a/src/shared/urls.ts b/src/shared/urls.ts index 80940dd4..d0403aa7 100644 --- a/src/shared/urls.ts +++ b/src/shared/urls.ts @@ -21,12 +21,12 @@ const projectsCreate = () => `${projects()}-new`; const projectsEdit = () => `${projects()}-edit`; /**************** Work Packages Endpoint ****************/ -const workPackages = (status?: string, timelineStatus?: string, daysUntilDeadline?: string) => { - let url = `${API_URL}/work-packages`; - if (status) url += `?status=${status}&`; - if (timelineStatus) url += `timelineStatus=${timelineStatus}&`; - if (daysUntilDeadline) url += `daysUntilDeadline=${daysUntilDeadline}`; - return url; +const workPackages = (queryParams?: { [field: string]: string }) => { + const url = `${API_URL}/work-packages`; + if (!queryParams) return url; + return `${url}?${Object.keys(queryParams) + .map((param) => `${param}=${queryParams[param]}`) + .join('&')}`; }; const workPackagesByWbsNum = (wbsNum: string) => `${workPackages()}/${wbsNum}`; const workPackagesCreate = () => `${workPackages()}-create`; From 6dfbcc6fe139220d3bd11bcf745f83076f171ea5 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 07:30:35 -0400 Subject: [PATCH 08/15] #729 - update work package services to fit flexible query parameters --- .../upcoming-deadlines/upcoming-deadlines.tsx | 5 +++- .../work-packages-by-timeline-status.tsx | 2 +- src/services/work-packages.api.ts | 24 ++++------------- src/services/work-packages.hooks.ts | 26 +++++-------------- 4 files changed, 16 insertions(+), 41 deletions(-) diff --git a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx index 583636ed..c2e520a3 100644 --- a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx +++ b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx @@ -17,7 +17,10 @@ import styles from './upcoming-deadlines.module.css'; const UpcomingDeadlines: React.FC = () => { const theme = useTheme(); - const workPackages = useAllWorkPackages(WbsElementStatus.Active, undefined, 14); + const workPackages = useAllWorkPackages({ + status: WbsElementStatus.Active, + daysUntilDeadline: '14' + }); if (workPackages.isError) { return ; diff --git a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx index 180f9609..c76285df 100644 --- a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx +++ b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx @@ -19,7 +19,7 @@ import styles from './work-packages-by-timeline-status.module.css'; const WorkPackagesByTimelineStatus: React.FC = () => { const [timelineStatus, setTimelineStatus] = useState(TimelineStatus.VeryBehind); const theme = useTheme(); - const workPackages = useAllWorkPackages(WbsElementStatus.Active, timelineStatus); + const workPackages = useAllWorkPackages({ status: WbsElementStatus.Active, timelineStatus }); useEffect(() => { workPackages.refetch(); diff --git a/src/services/work-packages.api.ts b/src/services/work-packages.api.ts index 9a58dd2f..1341f193 100644 --- a/src/services/work-packages.api.ts +++ b/src/services/work-packages.api.ts @@ -4,14 +4,7 @@ */ import axios from 'axios'; -import { - CreateWorkPackagePayload, - EditWorkPackagePayload, - TimelineStatus, - WbsElementStatus, - WbsNumber, - WorkPackage -} from 'utils'; +import { CreateWorkPackagePayload, EditWorkPackagePayload, WbsNumber, WorkPackage } from 'utils'; import { wbsPipe } from '../shared/pipes'; import { apiUrls } from '../shared/urls'; import { workPackageTransformer } from './transformers/work-packages.transformers'; @@ -19,17 +12,10 @@ import { workPackageTransformer } from './transformers/work-packages.transformer /** * Fetch all work packages. */ -export const getAllWorkPackages = ( - status?: WbsElementStatus, - timelineStatus?: TimelineStatus, - daysUntilDeadline?: number -) => { - return axios.get( - apiUrls.workPackages(status, timelineStatus, daysUntilDeadline?.toString()), - { - transformResponse: (data) => JSON.parse(data).map(workPackageTransformer) - } - ); +export const getAllWorkPackages = (queryParams?: { [field: string]: string }) => { + return axios.get(apiUrls.workPackages(queryParams), { + transformResponse: (data) => JSON.parse(data).map(workPackageTransformer) + }); }; /** diff --git a/src/services/work-packages.hooks.ts b/src/services/work-packages.hooks.ts index ebe770c0..e65170c5 100644 --- a/src/services/work-packages.hooks.ts +++ b/src/services/work-packages.hooks.ts @@ -4,14 +4,7 @@ */ import { useMutation, useQuery } from 'react-query'; -import { - WorkPackage, - WbsNumber, - CreateWorkPackagePayload, - EditWorkPackagePayload, - WbsElementStatus, - TimelineStatus -} from 'utils'; +import { WorkPackage, WbsNumber, CreateWorkPackagePayload, EditWorkPackagePayload } from 'utils'; import { createSingleWorkPackage, editWorkPackage, @@ -22,18 +15,11 @@ import { /** * Custom React Hook to supply all work packages. */ -export const useAllWorkPackages = ( - status?: WbsElementStatus, - timelineStatus?: TimelineStatus, - daysUntilDeadline?: number -) => { - return useQuery( - ['work packages', status, timelineStatus, daysUntilDeadline], - async () => { - const { data } = await getAllWorkPackages(status, timelineStatus, daysUntilDeadline); - return data; - } - ); +export const useAllWorkPackages = (queryParams?: { [field: string]: string }) => { + return useQuery(['work packages', queryParams], async () => { + const { data } = await getAllWorkPackages(queryParams); + return data; + }); }; /** From ff28db6f74637496454aeffdf4bb64f81cba6b32 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 07:35:51 -0400 Subject: [PATCH 09/15] #729 - switch to input group for timeline status dropdown --- .../work-packages-by-timeline-status.test.tsx | 2 +- .../work-packages-by-timeline-status.tsx | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.test.tsx b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.test.tsx index 208349e6..5bfaa87b 100644 --- a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.test.tsx +++ b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.test.tsx @@ -80,7 +80,7 @@ describe('upcoming deadlines component', () => { it('renders timeline status selector', () => { mockHook(false, false, exampleAllWorkPackages); renderComponent(); - expect(screen.getByText('Status:')).toBeInTheDocument(); + expect(screen.getByText('Timeline Status')).toBeInTheDocument(); expect(screen.getByText('VERY_BEHIND')).toBeInTheDocument(); }); }); diff --git a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx index c76285df..3496f842 100644 --- a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx +++ b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx @@ -4,7 +4,7 @@ */ import { useState, useEffect } from 'react'; -import { Card, Container, Form, Row } from 'react-bootstrap'; +import { Card, Container, Form, InputGroup, Row } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import { TimelineStatus, WbsElementStatus } from 'utils'; import { useTheme } from '../../../../services/theme.hooks'; @@ -66,10 +66,13 @@ const WorkPackagesByTimelineStatus: React.FC = () => { -
Status:
+ + + Timeline Status + setTimelineStatus(e.target.value as TimelineStatus)} custom > @@ -84,7 +87,7 @@ const WorkPackagesByTimelineStatus: React.FC = () => { ))} - + } body={ {workPackages.isLoading ? : fullDisplay} From 700d768990b37569aebbecc8163d6fc93cb98469 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 08:09:07 -0400 Subject: [PATCH 10/15] #729 - enable selecting time period for upcoming deadlines --- .../upcoming-deadlines/upcoming-deadlines.tsx | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx index c2e520a3..2a1ec587 100644 --- a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx +++ b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx @@ -3,7 +3,8 @@ * See the LICENSE file in the repository root folder for details. */ -import { Card, Container, Row } from 'react-bootstrap'; +import { useState } from 'react'; +import { Card, Container, Form, InputGroup, Row } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import { WbsElementStatus } from 'utils'; import { useTheme } from '../../../../services/theme.hooks'; @@ -16,11 +17,9 @@ import ErrorPage from '../../ErrorPage/error-page'; import styles from './upcoming-deadlines.module.css'; const UpcomingDeadlines: React.FC = () => { + const [daysUntilDeadline, setDaysUntilDeadline] = useState('14'); const theme = useTheme(); - const workPackages = useAllWorkPackages({ - status: WbsElementStatus.Active, - daysUntilDeadline: '14' - }); + const workPackages = useAllWorkPackages({ status: WbsElementStatus.Active, daysUntilDeadline }); if (workPackages.isError) { return ; @@ -65,7 +64,28 @@ const UpcomingDeadlines: React.FC = () => { return ( } + headerRight={ + + + Next + + setDaysUntilDeadline(e.target.value)} + > + {['1', '2', '5', '7', '14', '21', '30'].map((days) => ( + + ))} + + + Days + + + } body={ {workPackages.isLoading ? : fullDisplay} } From 602f2866ef34e7d0d08afd30145eb145fb6befed Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 08:14:43 -0400 Subject: [PATCH 11/15] #729 - clean up dropdowns and tests --- .../upcoming-deadlines.test.tsx | 8 ++++++++ .../upcoming-deadlines/upcoming-deadlines.tsx | 1 + .../work-packages-by-timeline-status.tsx | 16 ++++++---------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx index c6b646e6..6443698c 100644 --- a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx +++ b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.test.tsx @@ -76,4 +76,12 @@ describe('upcoming deadlines component', () => { renderComponent(); expect(screen.getByText('No upcoming deadlines')).toBeInTheDocument(); }); + + it('renders time period selector', () => { + mockHook(false, false, exampleAllWorkPackages); + renderComponent(); + expect(screen.getByText('Next')).toBeInTheDocument(); + expect(screen.getByText('14')).toBeInTheDocument(); + expect(screen.getByText('Days')).toBeInTheDocument(); + }); }); diff --git a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx index 2a1ec587..3c663123 100644 --- a/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx +++ b/src/frontend/pages/HomePage/upcoming-deadlines/upcoming-deadlines.tsx @@ -31,6 +31,7 @@ const UpcomingDeadlines: React.FC = () => { ? 'No upcoming deadlines' : workPackages.data?.map((wp) => ( { setTimelineStatus(e.target.value as TimelineStatus)} custom > - - {Object.values(TimelineStatus) - .filter((status) => status !== timelineStatus) - .map((status) => ( - - ))} + {Object.values(TimelineStatus).map((status) => ( + + ))} } From 23ff5160838df0344d7a241371ef9a22d37fc430 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 08:16:12 -0400 Subject: [PATCH 12/15] #729 - clean up react list key --- .../work-packages-by-timeline-status.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx index 4a94c25a..e055092c 100644 --- a/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx +++ b/src/frontend/pages/HomePage/work-packages-by-timeline-status/work-packages-by-timeline-status.tsx @@ -35,7 +35,12 @@ const WorkPackagesByTimelineStatus: React.FC = () => { {workPackages.data?.length === 0 ? `No ${timelineStatus} work packages` : workPackages.data?.map((wp) => ( - + From ffa366227fd92f80f9dace0e5ff83300388b42fb Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 08:17:21 -0400 Subject: [PATCH 13/15] #729 - add key to icon link pipe --- src/shared/pipes.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/pipes.tsx b/src/shared/pipes.tsx index 197486ba..0c678d30 100644 --- a/src/shared/pipes.tsx +++ b/src/shared/pipes.tsx @@ -27,7 +27,7 @@ export const linkPipe = (description: string, link: string): ReactElement => { export const iconLinkPipe = (icon: IconProp, description: string, link: string) => { return ( -
+
{linkPipe(description, link)}
From d647e2991d0a78967d057e4ae326de4703ce79c2 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 08:21:05 -0400 Subject: [PATCH 14/15] #729 - add list key and clean up imports --- src/frontend/layouts/nav-top-bar/nav-top-bar.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/frontend/layouts/nav-top-bar/nav-top-bar.tsx b/src/frontend/layouts/nav-top-bar/nav-top-bar.tsx index ee8f04a6..93b61f03 100644 --- a/src/frontend/layouts/nav-top-bar/nav-top-bar.tsx +++ b/src/frontend/layouts/nav-top-bar/nav-top-bar.tsx @@ -6,13 +6,13 @@ import { Dropdown, Nav, Navbar } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import { routes } from '../../../shared/routes'; -import NavUserMenu from './nav-user-menu/nav-user-menu'; -import NavNotificationsMenu from './nav-notifications-menu/nav-notifications-menu'; -import styles from './nav-top-bar.module.css'; import { useAuth } from '../../../services/auth.hooks'; import { fullNamePipe } from '../../../shared/pipes'; import { useTheme } from '../../../services/theme.hooks'; import themes from '../../../shared/themes'; +import NavUserMenu from './nav-user-menu/nav-user-menu'; +import NavNotificationsMenu from './nav-notifications-menu/nav-notifications-menu'; +import styles from './nav-top-bar.module.css'; const NavTopBar: React.FC = () => { const auth = useAuth(); @@ -39,7 +39,9 @@ const NavTopBar: React.FC = () => { {themes .filter((t) => t.name !== theme.name) .map((t) => ( - theme.toggleTheme!(t.name)}>{t.name} + theme.toggleTheme!(t.name)}> + {t.name} + ))} From 388228fe5a2390e79954f54079eaff17ee06f960 Mon Sep 17 00:00:00 2001 From: James C-D <51571627+jamescd18@users.noreply.github.com> Date: Sun, 19 Jun 2022 08:22:29 -0400 Subject: [PATCH 15/15] #729 - remove spare console.log --- src/frontend/pages/LoginPage/login.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/pages/LoginPage/login.tsx b/src/frontend/pages/LoginPage/login.tsx index 3b3ff811..55bcab74 100644 --- a/src/frontend/pages/LoginPage/login.tsx +++ b/src/frontend/pages/LoginPage/login.tsx @@ -28,7 +28,6 @@ const Login: React.FC = ({ postLoginRedirect }) => { if (auth.isLoading) return ; const redirectAfterLogin = () => { - console.log(postLoginRedirect); if (postLoginRedirect.url === routes.LOGIN) { history.push(routes.HOME); } else {