Skip to content

Commit 34bb3c0

Browse files
committed
#4025 guest change requests page
1 parent 6cad68e commit 34bb3c0

8 files changed

Lines changed: 182 additions & 10 deletions

File tree

src/backend/src/prisma-query-args/change-requests.query-args.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,28 @@ export const getManyChangeRequestQueryArgs = (organizationId: string) =>
5050
Prisma.validator<Prisma.Change_RequestDefaultArgs>()({
5151
include: {
5252
submitter: getUserQueryArgs(organizationId),
53-
wbsElement: true,
53+
wbsElement: {
54+
include: {
55+
project: {
56+
include: {
57+
teams: {
58+
include: { teamType: true }
59+
}
60+
}
61+
},
62+
workPackage: {
63+
include: {
64+
project: {
65+
include: {
66+
teams: {
67+
include: { teamType: true }
68+
}
69+
}
70+
}
71+
}
72+
}
73+
}
74+
},
5475
category: getReimbursementProductOtherReasonQueryArgs(organizationId),
5576
accountCode: getAccountCodeQueryArgs(organizationId),
5677
reviewer: getUserQueryArgs(organizationId),
@@ -77,7 +98,9 @@ export const getChangeRequestWithProjectAndWorkPackageQueryArgs = (organizationI
7798
workPackage: getWorkPackageQueryArgs(organizationId),
7899
project: {
79100
include: {
80-
teams: true
101+
teams: {
102+
include: { teamType: true }
103+
}
81104
}
82105
},
83106
descriptionBullets: { where: { dateDeleted: null } },

src/backend/src/transformers/change-requests.transformer.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,14 @@ export const changeRequestManyTransformer = (
133133
confirmDone: changeRequest.stageGateChangeRequest?.confirmDone ?? undefined,
134134
requestedReviewers: changeRequest.requestedReviewers.map(userTransformer) ?? [],
135135
//budget cr fields
136-
proposedBudget: changeRequest.budgetChangeRequest?.proposedBudget ?? undefined
136+
proposedBudget: changeRequest.budgetChangeRequest?.proposedBudget ?? undefined,
137+
teamTypeNames: [
138+
...new Set(
139+
(changeRequest.wbsElement?.project ?? changeRequest.wbsElement?.workPackage?.project)?.teams
140+
.map((t) => t.teamType?.name)
141+
.filter((name): name is string => name != null) ?? []
142+
)
143+
]
137144
};
138145
};
139146

@@ -224,7 +231,14 @@ const changeRequestTransformer = (
224231
confirmDone: changeRequest.stageGateChangeRequest?.confirmDone ?? undefined,
225232
requestedReviewers: changeRequest.requestedReviewers.map(userTransformer) ?? [],
226233
//budget cr fields
227-
proposedBudget: changeRequest.budgetChangeRequest?.proposedBudget ?? undefined
234+
proposedBudget: changeRequest.budgetChangeRequest?.proposedBudget ?? undefined,
235+
teamTypeNames: [
236+
...new Set(
237+
(changeRequest.wbsElement?.project ?? changeRequest.wbsElement?.workPackage?.project)?.teams
238+
.map((t) => t.teamType?.name)
239+
.filter((name): name is string => name != null) ?? []
240+
)
241+
]
228242
};
229243
};
230244

src/backend/tests/test-data/change-requests.test-data.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,6 @@ export const sharedChangeRequest: SharedChangeRequest = {
5959
type: ChangeRequestType.Redefinition,
6060
status: ChangeRequestStatus.Open,
6161
requestedReviewers: [],
62-
identifier: 1
62+
identifier: 1,
63+
teamTypeNames: []
6364
};

src/frontend/src/pages/ChangeRequestsPage/ChangeRequestsView.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ChangeRequestsOverview from './ChangeRequestsOverview';
99
import ChangeRequestsTable from './ChangeRequestsTable';
1010
import PageLayout from '../../components/PageLayout';
1111
import FullPageTabs from '../../components/FullPageTabs';
12+
import GuestChangeRequestsPage from './GuestChangeRequestsPage';
1213

1314
const ChangeRequestsView: React.FC = () => {
1415
const history = useHistory();
@@ -17,6 +18,9 @@ const ChangeRequestsView: React.FC = () => {
1718
// Default to the "overview" tab
1819
const [tabIndex, setTabIndex] = useState<number>(0);
1920

21+
if (isGuest(user.role)) {
22+
return <GuestChangeRequestsPage />;
23+
}
2024
const headerRight = (
2125
<NERButton
2226
variant="contained"
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import LoadingIndicator from '../../components/LoadingIndicator';
2+
import ErrorPage from '../ErrorPage';
3+
import { alpha, Box, useMediaQuery, useTheme } from '@mui/system';
4+
import PageLayout from '../../components/PageLayout';
5+
import { useAllTeamTypes } from '../../hooks/team-types.hooks';
6+
import { Chip, Typography } from '@mui/material';
7+
import { useState } from 'react';
8+
import { useAllChangeRequests } from '../../hooks/change-requests.hooks';
9+
import { ChangeRequest, wbsPipe } from 'shared';
10+
import { ChangeRequestTypeTextPipe, ChangeRequestStatusTextPipe } from '../../utils/enum-pipes';
11+
12+
const CrCard = ({ cr }: { cr: ChangeRequest }) => {
13+
const theme = useTheme();
14+
15+
const submitterName =
16+
cr.submitter?.firstName && cr.submitter?.lastName ? `${cr.submitter.firstName} ${cr.submitter.lastName}` : 'N/A';
17+
const reviewerName =
18+
cr.reviewer?.firstName && cr.reviewer?.lastName ? `${cr.reviewer.firstName} ${cr.reviewer.lastName}` : 'N/A';
19+
20+
return (
21+
<Box
22+
sx={{
23+
display: 'flex',
24+
flexDirection: 'column',
25+
gap: 0.5,
26+
p: 2,
27+
mb: 1,
28+
backgroundColor: theme.palette.background.paper,
29+
width: '100%',
30+
borderRadius: 1
31+
}}
32+
>
33+
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
34+
<Typography fontWeight="bold" fontSize={18}>
35+
CR #{cr.identifier.toLocaleString()}
36+
</Typography>
37+
<Chip
38+
size="small"
39+
variant="filled"
40+
sx={{
41+
fontSize: 12,
42+
bgcolor: alpha(theme.palette.primary.main, 0.45),
43+
color: theme.palette.primary.light
44+
}}
45+
label={ChangeRequestStatusTextPipe(cr.status)}
46+
/>
47+
</Box>
48+
<Typography fontSize={12} color="text.secondary">
49+
Submitter: {submitterName} {' · '} Reviewer: {reviewerName}
50+
</Typography>
51+
<Typography fontSize={12} color="text.secondary">
52+
{cr.wbsNum ? `${wbsPipe(cr.wbsNum)} - ` : ''}
53+
{cr.wbsName ? `${cr.wbsName} · ` : ''}
54+
{ChangeRequestTypeTextPipe(cr.type)}
55+
</Typography>
56+
</Box>
57+
);
58+
};
59+
60+
const GuestChangeRequestsPage: React.FC = () => {
61+
const { data: allCrs, isLoading, isError, error } = useAllChangeRequests();
62+
const [selectedTeamTypes, setSelectedTeamTypes] = useState<string[]>([]);
63+
const isMobilePortrait = useMediaQuery('(max-width:480px)');
64+
const {
65+
isLoading: teamTypesIsLoading,
66+
isError: teamTypesIsError,
67+
data: teamTypes,
68+
error: teamTypesError
69+
} = useAllTeamTypes();
70+
71+
if (isLoading || !allCrs || teamTypesIsLoading || !teamTypes) return <LoadingIndicator />;
72+
if (isError) return <ErrorPage message={error.message} />;
73+
if (teamTypesIsError) return <ErrorPage message={teamTypesError.message} />;
74+
75+
const filteredCrs = allCrs.filter(
76+
(cr) => selectedTeamTypes.length === 0 || cr.teamTypeNames.some((name) => selectedTeamTypes.includes(name))
77+
);
78+
79+
return (
80+
<PageLayout title="Change Requests">
81+
<Box
82+
width={'100%'}
83+
display={'flex'}
84+
justifyContent={'center'}
85+
gap={2}
86+
mb={3}
87+
sx={{
88+
overflowX: 'auto',
89+
pb: 1
90+
}}
91+
>
92+
{teamTypes.map((team) => (
93+
<Chip
94+
key={team.name}
95+
label={team.name}
96+
onClick={() =>
97+
setSelectedTeamTypes((prev) =>
98+
prev?.includes(team.name) ? prev.filter((t: string) => t !== team.name) : [...(prev || []), team.name]
99+
)
100+
}
101+
clickable
102+
color={selectedTeamTypes?.includes(team.name) ? 'primary' : 'default'}
103+
sx={{ flexShrink: 0 }}
104+
/>
105+
))}
106+
</Box>
107+
<Box
108+
sx={{
109+
display: 'grid',
110+
gridTemplateColumns: isMobilePortrait ? '1fr' : 'repeat(3, 1fr)',
111+
gap: isMobilePortrait ? 2 : 3,
112+
width: '100%',
113+
px: isMobilePortrait ? 1 : 0
114+
}}
115+
>
116+
{filteredCrs.map((changeRequest) => (
117+
<CrCard cr={changeRequest} />
118+
))}
119+
</Box>
120+
</PageLayout>
121+
);
122+
};
123+
124+
export default GuestChangeRequestsPage;

src/frontend/src/tests/pages/ChangeRequestDetailPage/ReviewChangeRequest.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ const renderComponent = (modalShow: boolean, route: string) => {
3535
type: 'ISSUE',
3636
wbsName: 'a',
3737
status: ChangeRequestStatus.Open,
38-
requestedReviewers: []
38+
requestedReviewers: [],
39+
teamTypeNames: []
3940
}}
4041
modalShow={modalShow}
4142
handleClose={() => null}

src/frontend/src/tests/test-support/test-data/change-requests.stub.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ export const exampleStandardChangeRequest: StandardChangeRequest = {
6161
budgetImpact: 75,
6262
timelineImpact: 2,
6363
proposedSolutions: [],
64-
requestedReviewers: []
64+
requestedReviewers: [],
65+
teamTypeNames: []
6566
};
6667

6768
export const exampleActivationChangeRequest: ActivationChangeRequest = {
@@ -77,7 +78,8 @@ export const exampleActivationChangeRequest: ActivationChangeRequest = {
7778
startDate: new Date('03/01/21'),
7879
confirmDetails: true,
7980
status: ChangeRequestStatus.Accepted,
80-
requestedReviewers: []
81+
requestedReviewers: [],
82+
teamTypeNames: []
8183
};
8284

8385
export const exampleStageGateChangeRequest: StageGateChangeRequest = {
@@ -91,7 +93,8 @@ export const exampleStageGateChangeRequest: StageGateChangeRequest = {
9193
leftoverBudget: 26,
9294
confirmDone: true,
9395
status: ChangeRequestStatus.Implemented,
94-
requestedReviewers: []
96+
requestedReviewers: [],
97+
teamTypeNames: []
9598
};
9699

97100
export const exampleStandardImplementedChangeRequest: StandardChangeRequest = {
@@ -197,7 +200,8 @@ export const exampleStandardImplementedChangeRequest: StandardChangeRequest = {
197200
}
198201
],
199202
proposedSolutions: [],
200-
requestedReviewers: []
203+
requestedReviewers: [],
204+
teamTypeNames: []
201205
};
202206

203207
export const exampleAllChangeRequests: ChangeRequest[] = [

src/shared/src/types/change-request-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export interface ChangeRequest {
2626
implementedChanges?: ImplementedChange[];
2727
status: ChangeRequestStatus;
2828
requestedReviewers: User[];
29+
teamTypeNames: string[];
2930
}
3031

3132
export const ChangeRequestType = {

0 commit comments

Comments
 (0)