Skip to content

Commit 9c260ed

Browse files
authored
Merge pull request #2220 from Northeastern-Electric-Racing/#2062-single-design-review-hook
#2062 created hook for single design review
2 parents c70c875 + 80d2870 commit 9c260ed

8 files changed

Lines changed: 69 additions & 13 deletions

File tree

src/frontend/src/apis/design-reviews.api.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,14 @@ export const getAllDesignReviews = () => {
1414
transformResponse: (data) => JSON.parse(data).map(designReviewTransformer)
1515
});
1616
};
17+
18+
/**
19+
* Gets a single design review
20+
* @param id the ID of the design review to return
21+
* @returns the request design review
22+
*/
23+
export const getSingleDesignReview = async (id: string) => {
24+
return axios.get(apiUrls.designReviewById(id), {
25+
transformResponse: (data) => designReviewTransformer(JSON.parse(data))
26+
});
27+
};

src/frontend/src/hooks/design-reviews.hooks.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* See the LICENSE file in the repository root folder for details.
44
*/
55
import { useQuery } from 'react-query';
6-
import { getAllDesignReviews } from '../apis/design-reviews.api';
6+
import { getAllDesignReviews, getSingleDesignReview } from '../apis/design-reviews.api';
77
import { DesignReview } from 'shared';
88

99
/**
@@ -17,3 +17,15 @@ export const useAllDesignReviews = () => {
1717
return data;
1818
});
1919
};
20+
21+
/**
22+
* Custom react hook to get a single design review
23+
*
24+
* @returns a single design review
25+
*/
26+
export const useSingleDesignReview = (id: string) => {
27+
return useQuery<DesignReview, Error>(['design-reviews', id], async () => {
28+
const { data } = await getSingleDesignReview(id);
29+
return data;
30+
});
31+
};

src/frontend/src/pages/CalendarPage/Calendar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
import { Route, Switch } from 'react-router-dom';
66
import { routes } from '../../utils/routes';
77
import CalendarPage from './CalendarPage';
8-
import DesignReviewDetailPage from './DesignReviewDetailPage/DesignReviewDetailPage';
8+
import DesignReviewDetails from './DesignReviewDetailPage/DesignReviewDetails';
99

1010
const Calendar: React.FC = () => {
1111
return (
1212
<Switch>
13-
<Route path={routes.DESIGN_REVIEW_BY_ID} component={DesignReviewDetailPage} />
13+
<Route path={routes.DESIGN_REVIEW_BY_ID} component={DesignReviewDetails} />
1414
<Route path={routes.CALENDAR} component={CalendarPage} />
1515
</Switch>
1616
);

src/frontend/src/pages/CalendarPage/DesignReviewDetailPage/DesignReviewDetailPage.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,20 @@ import { useState } from 'react';
1010
import CheckBoxIcon from '@mui/icons-material/CheckBox';
1111
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
1212
import { routes } from '../../../utils/routes';
13+
import { DesignReview, wbsPipe } from 'shared';
1314

1415
interface DesignReviewDetailPageProps {
15-
name: string;
16+
designReview: DesignReview;
1617
}
1718

18-
const DesignReviewDetailPage: React.FC<DesignReviewDetailPageProps> = ({ name }) => {
19+
const DesignReviewDetailPage: React.FC<DesignReviewDetailPageProps> = ({ designReview, designReview: { teamType } }) => {
1920
const theme = useTheme();
2021
const { isLoading: allUsersIsLoading, isError: allUsersIsError, error: allUsersError, data: allUsers } = useAllUsers();
2122
const [requiredUsers, setRequiredUsers] = useState([].map(userToAutocompleteOption));
2223
const [optionalUsers, setOptionalUsers] = useState([].map(userToAutocompleteOption));
2324
if (allUsersIsError) return <ErrorPage message={allUsersError?.message} />;
2425
if (allUsersIsLoading || !allUsers) return <LoadingIndicator />;
25-
26+
const designReviewName = `${wbsPipe(designReview.wbsNum)} - ${designReview.wbsName}`;
2627
const users = allUsers.map(userToAutocompleteOption);
2728

2829
return (
@@ -52,7 +53,7 @@ const DesignReviewDetailPage: React.FC<DesignReviewDetailPageProps> = ({ name })
5253
</Grid>
5354
<Grid item xs={3}>
5455
<Box sx={{ padding: 1.5, fontSize: '1.2em', backgroundColor: 'grey', borderRadius: 3, textAlign: 'center' }}>
55-
{name}
56+
{designReviewName}
5657
</Box>
5758
</Grid>
5859
<Grid item xs={1}>
@@ -74,7 +75,7 @@ const DesignReviewDetailPage: React.FC<DesignReviewDetailPageProps> = ({ name })
7475
<Grid item xs={3}>
7576
<Box sx={{ padding: 1, backgroundColor: 'grey', borderRadius: 3, textAlign: 'center' }}>
7677
<Autocomplete
77-
isOptionEqualToValue={(option, value) => option.id === value.id} // What is this for
78+
isOptionEqualToValue={(option, value) => option.id === value.id}
7879
multiple
7980
disableCloseOnSelect
8081
limitTags={1}
@@ -120,7 +121,7 @@ const DesignReviewDetailPage: React.FC<DesignReviewDetailPageProps> = ({ name })
120121
<Grid item xs={3}>
121122
<Box sx={{ padding: 1, backgroundColor: 'grey', borderRadius: 3, textAlign: 'center' }}>
122123
<Autocomplete
123-
isOptionEqualToValue={(option, value) => option.id === value.id} // What is this for
124+
isOptionEqualToValue={(option, value) => option.id === value.id}
124125
multiple
125126
disableCloseOnSelect
126127
limitTags={1}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* This file is part of NER's FinishLine and licensed under GNU AGPLv3.
3+
* See the LICENSE file in the repository root folder for details.
4+
*/
5+
import LoadingIndicator from '../../../components/LoadingIndicator';
6+
import { useParams } from 'react-router-dom';
7+
import ErrorPage from '../../ErrorPage';
8+
import DesignReviewDetailPage from './DesignReviewDetailPage';
9+
import { useSingleDesignReview } from '../../../hooks/design-reviews.hooks';
10+
11+
const DesignReviewDetails: React.FC = () => {
12+
const { id } = useParams<{ id: string }>();
13+
const { data: designReview, isError, error, isLoading } = useSingleDesignReview(id);
14+
15+
if (isError) return <ErrorPage error={error} />;
16+
if (!designReview || isLoading) return <LoadingIndicator />;
17+
18+
return <DesignReviewDetailPage designReview={designReview} />;
19+
};
20+
21+
export default DesignReviewDetails;

src/frontend/src/pages/CalendarPage/SummaryComponents/DesignReviewSummaryModalButtons.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ const DesignReviewSummaryModalButtons: React.FC<DesignReviewSummaryModalButtonsP
7474
textDecoration: 'none'
7575
}}
7676
component={RouterLink}
77-
to={`${routes.CALENDAR}/1`}
77+
to={`${routes.CALENDAR}/${designReview.designReviewId}`}
7878
>
7979
<NERFailButton
8080
sx={{

src/frontend/src/tests/hooks/DesignReviews.hooks.test.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import { AxiosResponse } from 'axios';
88
import { DesignReview } from 'shared';
99
import wrapper from '../../app/AppContextQuery';
1010
import { mockPromiseAxiosResponse } from '../test-support/test-data/test-utils.stub';
11-
import { exampleAllDesignReviews } from '../test-support/test-data/design-reviews.stub';
12-
import { getAllDesignReviews } from '../../apis/design-reviews.api';
13-
import { useAllDesignReviews } from '../../hooks/design-reviews.hooks';
11+
import { exampleAllDesignReviews, exampleDesignReview1 } from '../test-support/test-data/design-reviews.stub';
12+
import { getAllDesignReviews, getSingleDesignReview } from '../../apis/design-reviews.api';
13+
import { useAllDesignReviews, useSingleDesignReview } from '../../hooks/design-reviews.hooks';
1414

1515
vi.mock('../../apis/design-reviews.api');
1616

@@ -23,4 +23,13 @@ describe('design review hooks', () => {
2323
await waitFor(() => result.current.isSuccess);
2424
expect(result.current.data).toEqual(exampleAllDesignReviews);
2525
});
26+
27+
it('handles getting a single design review', async () => {
28+
const mockedGetSingleDesignReview = getSingleDesignReview as jest.Mock<Promise<AxiosResponse<DesignReview>>>;
29+
mockedGetSingleDesignReview.mockReturnValue(mockPromiseAxiosResponse<DesignReview>(exampleDesignReview1));
30+
31+
const { result, waitFor } = renderHook(() => useSingleDesignReview('1'), { wrapper });
32+
await waitFor(() => result.current.isSuccess);
33+
expect(result.current.data).toEqual(exampleDesignReview1);
34+
});
2635
});

src/frontend/src/utils/urls.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ const bomCreateUnit = () => `${bomEndpoints()}/units/create`;
133133

134134
/**************** Design Reviews Endpoints ****************/
135135
const designReviews = () => `${API_URL}/design-reviews`;
136+
const designReviewById = (id: string) => `${designReviews()}/${id}`;
136137

137138
/**************** Other Endpoints ****************/
138139
const version = () => `https://api.github.com/repos/Northeastern-Electric-Racing/FinishLine/releases/latest`;
@@ -189,6 +190,7 @@ export const apiUrls = {
189190
changeRequestRequestReviewer,
190191

191192
designReviews,
193+
designReviewById,
192194

193195
teams,
194196
teamsById,

0 commit comments

Comments
 (0)