Skip to content
Open
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
267 changes: 135 additions & 132 deletions src/frontend/src/pages/GanttPage/ProjectGanttChart/GanttChartFilters.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this is actually filtering by division? When I try to filter by division none of the projects are showing, despite some of them being in that division

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gotcha I didn't bother to check filtering was actually working, sorry about that. I'll look into that and get back to you!

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';
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';

const FilterChipButton = ({
buttonText,
onChange,
defaultChecked,
checked
const FilterCheckboxes = ({
handlers
}: {
buttonText: string;
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
defaultChecked: boolean;
checked: boolean;
}) => {
const theme = useTheme();

return (
<Checkbox
onChange={onChange}
sx={{
'&:hover': {
backgroundColor: 'transparent'
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,101 +94,89 @@ 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>
);
};

export default GanttChartFilters;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ChangeEvent, useState } from 'react';
import { IconButton, Popover } from '@mui/material';
import GanttChartFilters from './GanttChartFilters';
import { Tune } from '@mui/icons-material';
import { useTheme } from '@mui/material';

interface GanttChartFiltersButtonProps {
carHandlers: { filterLabel: string; handler: (event: ChangeEvent<HTMLInputElement>) => void; defaultChecked: boolean }[];
Expand All @@ -11,31 +12,16 @@ interface GanttChartFiltersButtonProps {
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;
}

const GanttChartFiltersButton = ({
carHandlers,
teamTypeHandlers,
teamHandlers,
overdueHandler,
hideTasksHandler,
resetHandler,
collapseHandler,
expandHandler
resetHandler
}: GanttChartFiltersButtonProps) => {
const theme = useTheme();
const [anchorFilterEl, setAnchorFilterEl] = useState<HTMLButtonElement | null>(null);
const handleFilterClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorFilterEl(event.currentTarget);
Expand Down Expand Up @@ -64,16 +50,21 @@ const GanttChartFiltersButton = ({
horizontal: 'right'
}}
sx={{ maxWidth: '100rem' }}
slotProps={{
paper: {
sx: {
backgroundColor: theme.palette.background.paper,
borderRadius: 2
}
}
}}
>
<GanttChartFilters
carHandlers={carHandlers}
teamTypeHandlers={teamTypeHandlers}
teamHandlers={teamHandlers}
overdueHandler={overdueHandler}
hideTasksHandler={hideTasksHandler}
resetHandler={resetHandler}
collapseHandler={collapseHandler}
expandHandler={expandHandler}
onClose={handleFilterClose}
/>
</Popover>
</>
Expand Down
Loading
Loading