Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/backend/src/prisma-query-args/teams.query-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const getTeamPreviewQueryArgs = (organizationId: string) =>
include: {
members: getUserQueryArgs(organizationId),
head: getUserQueryArgs(organizationId),
leads: getUserQueryArgs(organizationId)
leads: getUserQueryArgs(organizationId),
teamType: true
}
});
3 changes: 2 additions & 1 deletion src/backend/src/transformers/teams.transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export const teamPreviewTransformer = (team: Prisma.TeamGetPayload<TeamPreviewQu
leads: team.leads.map(userTransformer),
members: team.members.map(userTransformer),
head: userTransformer(team.head),
dateArchived: team.dateArchived ?? undefined
dateArchived: team.dateArchived ?? undefined,
teamType: team.teamType ? teamTypeTransformer(team.teamType) : undefined
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const GanttChartCollectionSection = <E, T>({

const ignoreBool = () => false;

return (
return collection.tasks.length > 0 ? (
<Box sx={collectionSectionBackgroundStyle}>
<Box sx={collectionDescriptionContainerStyle}>
<Typography variant="h6" fontWeight={400}>
Expand Down Expand Up @@ -108,7 +108,7 @@ const GanttChartCollectionSection = <E, T>({
/>
</Box>
</Box>
);
) : null;
};

export default GanttChartCollectionSection;
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
OnMouseOverOptions,
RequestEventChange
} from '../../../utils/gantt.utils';
import { Box, Typography } from '@mui/material';
import { Box } from '@mui/material';
import { useState } from 'react';
import GanttTaskBar from './GanttChartComponents/GanttTaskBar/GanttTaskBar';
import GanttToolTip from './GanttChartComponents/GanttToolTip';
Expand Down Expand Up @@ -64,7 +64,7 @@ const GanttChartSection = <T,>({
setCurrentTooltipOptions(undefined);
};

return tasks.length > 0 ? (
return (
<ArcherContainer strokeColor="#ef4545">
<Box sx={{ width: 'fit-content' }}>
<Box sx={{ mt: '1rem', width: 'fit-content' }}>
Expand Down Expand Up @@ -102,8 +102,6 @@ const GanttChartSection = <T,>({
)}
</Box>
</ArcherContainer>
) : (
<Typography sx={{ marginTop: 5 }}>No Projects to Display</Typography>
);
};

Expand Down
268 changes: 136 additions & 132 deletions src/frontend/src/pages/GanttPage/ProjectGanttChart/GanttChartFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,86 @@
* See the LICENSE file in the repository root folder for details.
*/

import { Box, Checkbox, Chip, IconButton, Typography, useTheme } from '@mui/material';
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
import RestartAltIcon from '@mui/icons-material/RestartAlt';
import { ChangeEvent } from 'react';

const FilterChipButton = ({
buttonText,
onChange,
defaultChecked,
checked
}: {
buttonText: string;
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
defaultChecked: boolean;
checked: boolean;
}) => {
const theme = useTheme();
import {
Box,
Checkbox,
Typography,
useTheme,
Accordion,
AccordionSummary,
AccordionDetails,
FormControlLabel,
IconButton
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import CloseIcon from '@mui/icons-material/Close';
import { ChangeEvent, useState } from 'react';

return (
<Checkbox
onChange={onChange}
sx={{
'&:hover': {
backgroundColor: 'transparent'
const FilterCheckboxes = ({
handlers
}: {
handlers: { filterLabel: string; handler: (event: ChangeEvent<HTMLInputElement>) => void; defaultChecked: boolean }[];
}) => (
<Box display="flex" flexDirection="column">
{handlers.map((handler) => (
<FormControlLabel
key={handler.filterLabel}
slotProps={{ typography: { fontSize: '14px' } }}
control={
<Checkbox
size="small"
onChange={handler.handler}
defaultChecked={handler.defaultChecked}
sx={{ padding: '2px 7px' }}
/>
}
}}
icon={<Chip label={buttonText} sx={{ borderRadius: '20px', paddingX: 1 }} />}
checkedIcon={
<Chip label={buttonText} sx={{ borderRadius: '20px', paddingX: 1, backgroundColor: theme.palette.primary.main }} />
}
defaultChecked={defaultChecked}
checked={checked}
/>
);
};
label={handler.filterLabel}
/>
))}
</Box>
);

const FilterRow = ({
const FilterAccordion = ({
label,
buttons
children,
expanded,
onChange
}: {
label: string;
buttons: { filterLabel: string; handler: (event: ChangeEvent<HTMLInputElement>) => void; defaultChecked: boolean }[];
children: React.ReactNode;
expanded: boolean;
onChange: () => void;
}) => {
const checkedMap: { [filterLabel: string]: boolean } = {};
const theme = useTheme();

buttons.forEach((button) => {
checkedMap[button.filterLabel] = button.defaultChecked;
});
return (
<Box width={label === 'Team' ? '60%' : undefined}>
<Typography variant="h6" component="label" textAlign="right">
{label}
</Typography>
<Box display={'flex'} flexDirection={label === 'Team' ? undefined : 'column'} flexWrap={'wrap'}>
{buttons.map((button) => (
<FilterChipButton
buttonText={button.filterLabel}
onChange={button.handler}
defaultChecked={button.defaultChecked}
checked={checkedMap[button.filterLabel]}
/>
))}
</Box>
</Box>
<Accordion
disableGutters
elevation={0}
expanded={expanded}
onChange={onChange}
sx={{
backgroundColor: 'transparent',
'&:before': { display: 'none' }
}}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon sx={{ color: theme.palette.text.secondary }} />}
sx={{
minHeight: '36px',
px: 0,
flexDirection: 'row-reverse',
gap: 1,
'& .MuiAccordionSummary-expandIconWrapper': { marginRight: 0, marginLeft: 0 },
'& .MuiAccordionSummary-content': { margin: '6px 0' }
}}
>
<Typography variant="h6" fontWeight="normal" color="text.primary">
{label}
</Typography>
</AccordionSummary>
<AccordionDetails sx={{ padding: '0 0 0 36px' }}>{children}</AccordionDetails>
</Accordion>
);
};

Expand All @@ -79,99 +94,88 @@ interface GanttChartFiltersProps {
defaultChecked: boolean;
}[];
teamHandlers: { filterLabel: string; handler: (event: ChangeEvent<HTMLInputElement>) => void; defaultChecked: boolean }[];
overdueHandler: {
filterLabel: string;
handler: (event: ChangeEvent<HTMLInputElement>) => void;
defaultChecked?: boolean;
}[];
hideTasksHandler: {
filterLabel: string;
handler: (event: ChangeEvent<HTMLInputElement>) => void;
defaultChecked?: boolean;
}[];
resetHandler: () => void;
collapseHandler: () => void;
expandHandler: () => void;
onClose: () => void;
}

const GanttChartFilters = ({
carHandlers,
teamTypeHandlers,
teamHandlers,
overdueHandler,
hideTasksHandler,
resetHandler,
collapseHandler,
expandHandler
onClose
}: GanttChartFiltersProps) => {
const FilterButtons = () => {
return (
<Box display={'flex'} flexDirection={'column'} alignItems={'center'} mt={-1} mb={1}>
<IconButton onClick={expandHandler}>
<UnfoldMoreIcon sx={{ color: '#ef4345' }} />
</IconButton>
<Typography fontSize={'10px'} sx={{ color: '#ef4345' }}>
Expand
</Typography>
<IconButton onClick={collapseHandler}>
<UnfoldLessIcon sx={{ color: '#ef4345' }} />
</IconButton>
<Typography fontSize={'10px'} sx={{ color: '#ef4345' }}>
Collapse
const theme = useTheme();

const [expanded, setExpanded] = useState({
car: true,
division: true,
team: true
});

const [resetKey, setResetKey] = useState(0);

const handleReset = () => {
setResetKey((prev) => prev + 1);
resetHandler();
};

const toggle = (section: keyof typeof expanded) => {
setExpanded((prev) => ({ ...prev, [section]: !prev[section] }));
};

return (
<Box
display="flex"
flexDirection="column"
sx={{ padding: 2, width: '20rem', backgroundColor: theme.palette.background.paper, borderRadius: 1 }}
>
<Box display="flex" flexDirection="row" justifyContent="space-between" alignItems="center" sx={{ mb: 0.5 }}>
<Typography variant="h5" fontWeight="normal" color="text.primary">
Filters
</Typography>
<IconButton onClick={resetHandler}>
<RestartAltIcon sx={{ color: '#ef4345' }} />
<IconButton size="small" onClick={onClose}>
<CloseIcon fontSize="small" />
</IconButton>
<Typography fontSize={'10px'} sx={{ color: '#ef4345' }}>
</Box>

<Box display="flex" flexDirection="row" alignItems="center" gap={0.5} sx={{ mb: -0.5 }}>
<Typography
fontSize="14px"
sx={{ color: theme.palette.primary.main, cursor: 'pointer', '&:hover': { textDecoration: 'underline' } }}
onClick={handleReset}
>
Reset
</Typography>
<Checkbox
onChange={overdueHandler[0].handler}
sx={{
'&:hover': {
backgroundColor: 'transparent'
},
color: '#ef4345'
}}
defaultChecked={overdueHandler[0].defaultChecked}
checked={overdueHandler[0].defaultChecked}
/>
<Typography fontSize={'10px'} sx={{ color: '#ef4345' }}>
Overdue
<Typography sx={{ color: theme.palette.text.primary, lineHeight: 2.75, fontSize: '0.5rem' }}>•</Typography>
<Typography
fontSize="13px"
sx={{ color: theme.palette.primary.main, cursor: 'pointer', '&:hover': { textDecoration: 'underline' } }}
onClick={() => setExpanded({ car: true, division: true, team: true })}
>
Expand All
</Typography>
<Checkbox
onChange={hideTasksHandler[0].handler}
sx={{
'&:hover': {
backgroundColor: 'transparent'
},
color: '#ef4345'
}}
defaultChecked={hideTasksHandler[0].defaultChecked}
checked={hideTasksHandler[0].defaultChecked}
/>
<Typography fontSize={'10px'} sx={{ color: '#ef4345' }}>
Hide Tasks
<Typography sx={{ color: theme.palette.text.primary, lineHeight: 2.75, fontSize: '0.5rem' }}>•</Typography>
<Typography
fontSize="13px"
sx={{ color: theme.palette.primary.main, cursor: 'pointer', '&:hover': { textDecoration: 'underline' } }}
onClick={() => setExpanded({ car: false, division: false, team: false })}
>
Collapse All
</Typography>
</Box>
);
};

return (
<Box
display={'flex'}
sx={{
justifyContent: 'start',
alignItems: 'start',
paddingLeft: 2,
paddingTop: 2,
maxWidth: '45rem'
}}
>
<FilterRow label="Car" buttons={carHandlers} />
<FilterRow label="Subteam" buttons={teamTypeHandlers} />
<FilterRow label="Team" buttons={teamHandlers} />
<FilterButtons />
<FilterAccordion label="Car" expanded={expanded.car} onChange={() => toggle('car')}>
<FilterCheckboxes key={`car-${resetKey}`} handlers={carHandlers} />
</FilterAccordion>

<FilterAccordion label="Division" expanded={expanded.division} onChange={() => toggle('division')}>
<FilterCheckboxes key={`division-${resetKey}`} handlers={teamTypeHandlers} />
</FilterAccordion>

<FilterAccordion label="Team" expanded={expanded.team} onChange={() => toggle('team')}>
<FilterCheckboxes key={`team-${resetKey}`} handlers={teamHandlers} />
</FilterAccordion>
</Box>
);
};
Expand Down
Loading
Loading