Skip to content

Commit

Permalink
Merge pull request #1751 from Northeastern-Electric-Racing/feature/Ch…
Browse files Browse the repository at this point in the history
…ange-Request-Redesign

Feature/change request redesign
  • Loading branch information
RChandler234 authored Dec 23, 2023
2 parents 5a79d94 + 6291cc0 commit 7c9dacd
Show file tree
Hide file tree
Showing 29 changed files with 840 additions and 579 deletions.
180 changes: 69 additions & 111 deletions src/frontend/src/components/ChangeRequestDetailCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,96 +3,62 @@
* See the LICENSE file in the repository root folder for details.
*/

import { Card, CardContent, Grid, Typography } from '@mui/material';
import Chip from '@mui/material/Chip';
import { green, blue, red, grey, orange } from '@mui/material/colors';
import { Card, CardContent, Grid, Typography, useTheme } from '@mui/material';
import { Box, Stack } from '@mui/system';
import { Link } from '@mui/material';
import {
ActivationChangeRequest,
ChangeRequest,
ChangeRequestStatus,
ChangeRequestType,
StageGateChangeRequest,
StandardChangeRequest,
wbsPipe
} from 'shared';
import { routes } from '../utils/routes';
import { Link as RouterLink } from 'react-router-dom';
import { datePipe, fullNamePipe } from '../utils/pipes';
import { Cancel, Construction, DateRange, Description, DoneAll, Person, Start, Work } from '@mui/icons-material';
import { ChangeRequestTypeTextPipe } from '../utils/enum-pipes';
import { fullNamePipe } from '../utils/pipes';
import ChangeRequestTypePill from './ChangeRequestTypePill';
import ChangeRequestStatusPill from './ChangeRequestStatusPill';

const determineChangeRequestTypeView = (cr: ChangeRequest) => {
switch (cr.type) {
case 'STAGE_GATE':
return <StageGateCardDetails cr={cr as StageGateChangeRequest} />;
case 'ACTIVATION':
return <ActivationCardDetails cr={cr as ActivationChangeRequest} />;
default:
return <StandardCardDetails cr={cr as StandardChangeRequest} />;
}
};

const determineChangeRequestPillColor = (type: ChangeRequestType) => {
switch (type) {
case 'STAGE_GATE':
return orange[900];
case 'ACTIVATION':
return green[600];
case 'DEFINITION_CHANGE':
return blue[600];
case 'ISSUE':
return red[400];
default:
return grey[500];
}
};

const StandardCardDetails = ({ cr }: { cr: StandardChangeRequest }) => {
return (
<Grid container mt={1} ml={'2px'}>
<Grid item>
<Description sx={{ ml: '-4px' }} display={'inline'} />
</Grid>
<Grid item xs>
<Typography ml={'4px'} display={'inline'}>
{cr.what}
</Typography>
</Grid>
</Grid>
);
};

const StageGateCardDetails = ({ cr }: { cr: StageGateChangeRequest }) => {
const CRCardDescription = ({ cr }: { cr: ChangeRequest }) => {
const theme = useTheme();
const isAccepted = cr.status === ChangeRequestStatus.Implemented || cr.status === ChangeRequestStatus.Accepted;
const isStageGate = cr.type === ChangeRequestType.StageGate;
const isActivation = cr.type === ChangeRequestType.Activation;
return (
<Box ml={-1}>
{cr.confirmDone ? (
<Chip icon={<DoneAll />} label={'Done'} sx={{ backgroundColor: 'transparent' }} />
) : (
<Chip icon={<Cancel />} label={'Not Done'} sx={{ backgroundColor: 'transparent' }} />
)}
</Box>
);
};

const ActivationCardDetails = ({ cr }: { cr: ActivationChangeRequest }) => {
return (
<Box>
<Stack direction="row">
<Chip
icon={<Construction />}
label={fullNamePipe(cr.projectLead)}
sx={{ backgroundColor: 'transparent', mr: 2, ml: -1, maxWidth: '150' }}
/>
<Chip
icon={<Work />}
label={fullNamePipe(cr.projectManager)}
sx={{ backgroundColor: 'transparent', maxWidth: '150' }}
/>
</Stack>
<Stack direction="row" justifyContent={'space-between'}>
<Chip icon={<Start />} label={datePipe(cr.startDate)} sx={{ backgroundColor: 'transparent', ml: -1 }} />
</Stack>
<Box
sx={{
backgroundColor: theme.palette.divider,
width: '100%',
height: 75,
borderRadius: 1,
padding: 1,
overflow: 'hidden',
textOverflow: 'ellipsis'
}}
>
<Typography variant="body1" fontSize={14}>
{isAccepted ? (
cr.reviewNotes ? (
'Review Notes: ' + cr.reviewNotes
) : (
'No review notes'
)
) : isActivation ? (
<div>
<Typography variant="body1" fontSize={14}>
Lead: {fullNamePipe((cr as ActivationChangeRequest).projectLead)}
</Typography>
<Typography variant="body1" fontSize={14}>
Manager: {fullNamePipe((cr as ActivationChangeRequest).projectManager)}
</Typography>
</div>
) : isStageGate ? (
'Stage Gate ' + wbsPipe(cr.wbsNum) + ' - ' + cr.wbsName
) : (
(cr as StandardChangeRequest).what
)}
</Typography>
</Box>
);
};
Expand All @@ -101,49 +67,41 @@ interface ChangeRequestDetailCardProps {
changeRequest: ChangeRequest;
}

// Convert work package stage into badge for display
const ChangeRequestDetailCard: React.FC<ChangeRequestDetailCardProps> = ({ changeRequest }) => {
const ChangeRequestTypeView = () => determineChangeRequestTypeView(changeRequest);
const pillColor = determineChangeRequestPillColor(changeRequest.type);
return (
<Card sx={{ width: 300, mr: 1, mb: 1, borderRadius: 5 }}>
<Card sx={{ minWidth: 325, maxWidth: 325, mr: 2, borderRadius: 3, mb: 2 }}>
<CardContent>
<Grid container justifyContent="space-between" alignItems="center">
<Grid item>
<Link component={RouterLink} to={`${routes.CHANGE_REQUESTS}/${changeRequest.crId}`} noWrap>
<Grid container justifyContent="space-between" alignItems="flex-start">
<Grid item xs mb={1} mt={-1.5}>
<Link
underline={'none'}
color={'inherit'}
component={RouterLink}
to={`${routes.CHANGE_REQUESTS}/${changeRequest.crId}`}
>
<Typography variant="h6" sx={{ mb: 0.5 }}>
{'CR #' + changeRequest.crId}
{'Change Request #' + changeRequest.crId}
</Typography>
</Link>
<Stack direction={'column'} maxWidth={'195px'}>
<Typography variant="body1" sx={{ mr: 2, fontWeight: 'bold', fontSize: 13 }}>
From: {fullNamePipe(changeRequest.submitter)}
</Typography>
<Typography fontWeight={'bold'} fontSize={12} noWrap>
<Link component={RouterLink} to={`${routes.PROJECTS}/${wbsPipe(changeRequest.wbsNum)}`}>
{wbsPipe(changeRequest.wbsNum)} {changeRequest.wbsName}
</Link>
</Typography>
</Stack>
</Grid>
<Grid item display="flex" justifyContent="flex-end">
<Chip
size="small"
label={ChangeRequestTypeTextPipe(changeRequest.type)}
variant="outlined"
sx={{
fontSize: 12,
color: pillColor,
borderColor: pillColor,
mb: 0.5
}}
/>
<Grid item xs="auto" mb={1}>
<Stack direction={'column'} spacing={1}>
<ChangeRequestTypePill type={changeRequest.type} />
<ChangeRequestStatusPill status={changeRequest.status} />
</Stack>
</Grid>
</Grid>
<Stack direction="row">
<Chip
icon={<Person />}
label={fullNamePipe(changeRequest.submitter)}
sx={{ mr: 2, ml: -1, backgroundColor: 'transparent', maxWidth: '150' }}
/>
<Chip icon={<DateRange />} label={datePipe(changeRequest.dateSubmitted)} sx={{ backgroundColor: 'transparent' }} />
</Stack>
<Typography fontWeight={'regular'} variant="h6" fontSize={16} noWrap>
<Link component={RouterLink} to={`${routes.PROJECTS}/${wbsPipe(changeRequest.wbsNum)}`}>
{wbsPipe(changeRequest.wbsNum)} - {changeRequest.wbsName}
</Link>
</Typography>
<ChangeRequestTypeView />
<CRCardDescription cr={changeRequest} />
</CardContent>
</Card>
);
Expand Down
43 changes: 43 additions & 0 deletions src/frontend/src/components/ChangeRequestStatusPill.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of NER's FinishLine and licensed under GNU AGPLv3.
* See the LICENSE file in the repository root folder for details.
*/

import Chip from '@mui/material/Chip';
import { green, blue, red, grey, purple } from '@mui/material/colors';
import { ChangeRequestStatus } from 'shared';
import { ChangeRequestStatusTextPipe } from '../utils/enum-pipes';

const determineChangeRequestStatusPillColor = (status: ChangeRequestStatus) => {
switch (status) {
case ChangeRequestStatus.Implemented:
return blue[600];
case ChangeRequestStatus.Accepted:
return green[600];
case ChangeRequestStatus.Denied:
return red[400];
case ChangeRequestStatus.Open:
return purple[400];
default:
return grey[500];
}
};

const ChangeRequestStatusPill = ({ status }: { status: ChangeRequestStatus }) => {
const statusPillColor = determineChangeRequestStatusPillColor(status);
return (
<Chip
size="small"
label={ChangeRequestStatusTextPipe(status)}
variant="filled"
sx={{
fontSize: 12,
color: 'white',
backgroundColor: statusPillColor,
width: 100
}}
/>
);
};

export default ChangeRequestStatusPill;
22 changes: 22 additions & 0 deletions src/frontend/src/components/ChangeRequestTypePill.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Chip } from '@mui/material';
import { ChangeRequestType } from 'shared';
import { ChangeRequestTypeTextPipe } from '../utils/enum-pipes';
import { red } from '@mui/material/colors';

const ChangeRequestTypePill = ({ type }: { type: ChangeRequestType }) => {
return (
<Chip
size="small"
label={ChangeRequestTypeTextPipe(type)}
variant="filled"
sx={{
fontSize: 12,
color: 'white',
backgroundColor: red[600],
width: 100
}}
/>
);
};

export default ChangeRequestTypePill;
34 changes: 34 additions & 0 deletions src/frontend/src/components/InfoBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* This file is part of NER's FinishLine and licensed under GNU AGPLv3.
* See the LICENSE file in the repository root folder for details.
*/

import Typography from '@mui/material/Typography';
import { Grid } from '@mui/material';
import { ReactNode } from 'react';

interface InfoBlockProps {
title: string;
icon?: ReactNode;
}

/**
* Custom component for a consistent page-building block.
* @param title The title of the block on the page
* @param children The children of the block
*/
const InfoBlock: React.FC<InfoBlockProps> = ({ title, icon, children }) => {
return (
<Grid container spacing={1}>
<Grid item xs={12} display="flex" gap="5px" alignItems="center">
<Typography sx={{ fontWeight: 'bold', fontSize: '19px' }}>{title}</Typography>
{icon}
</Grid>
<Grid item xs={12}>
{children}
</Grid>
</Grid>
);
};

export default InfoBlock;
2 changes: 1 addition & 1 deletion src/frontend/src/components/NERButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Button, styled } from '@mui/material';
export const NERButton = styled(Button)({
textTransform: 'none',
fontSize: 16,
borderColor: '#0062cc',
borderColor: '#ef4345',
boxShadow: 'none',
'&:hover': {
backgroundColor: '#ff0000'
Expand Down
6 changes: 5 additions & 1 deletion src/frontend/src/components/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Box } from '@mui/system';

interface PageLayoutProps {
title?: string;
chips?: ReactNode;
hidePageTitle?: boolean;
previousPages?: LinkItem[];
headerRight?: ReactNode;
Expand All @@ -21,6 +22,7 @@ interface PageLayoutProps {
const PageLayout: React.FC<PageLayoutProps> = ({
children,
title,
chips,
hidePageTitle = false,
previousPages = [],
headerRight,
Expand All @@ -33,7 +35,9 @@ const PageLayout: React.FC<PageLayoutProps> = ({
<title>{`FinishLine ${title && `| ${title}`}`}</title>
<meta name="description" content="FinishLine Project Management Dashboard" />
</Helmet>
{!hidePageTitle && title && <PageTitle sticky={stickyHeader} {...{ title, previousPages, headerRight, tabs }} />}
{!hidePageTitle && title && (
<PageTitle sticky={stickyHeader} {...{ title, chips, previousPages, headerRight, tabs }} />
)}
{children}
</Box>
);
Expand Down
8 changes: 2 additions & 6 deletions src/frontend/src/components/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,10 @@ const NERTabs = ({ setTab, tabsLabels, baseUrl, defaultTab, id }: TabProps) => {
};

return (
<Tabs
sx={{ borderBottom: 1, borderColor: 'divider' }}
value={tabValue}
onChange={handleTabChange}
aria-label={`${id}-tabs`}
>
<Tabs value={tabValue} onChange={handleTabChange} aria-label={`${id}-tabs`}>
{tabsLabels.map((tab, idx) => (
<Tab
sx={{ borderBottom: 1, borderColor: 'divider' }}
label={tab.tabName}
aria-label={tab.tabUrlValue}
value={idx}
Expand Down
Loading

0 comments on commit 7c9dacd

Please sign in to comment.