Skip to content

Commit 5ca1266

Browse files
committed
refactor: isolate expand button logic into component
1 parent e49153d commit 5ca1266

File tree

6 files changed

+139
-62
lines changed

6 files changed

+139
-62
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { styled } from '@mui/material/styles';
2+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
3+
import { IconButton } from '@mui/material';
4+
5+
const ExpandMore = styled(props => {
6+
const { expand, ...other } = props;
7+
return (
8+
<IconButton {...other}>
9+
{props.children ? props.children : <ExpandMoreIcon />}
10+
</IconButton>
11+
);
12+
})(({ theme, expand }) => ({
13+
transform: !expand ? 'rotate(0deg)' : 'rotate(180deg)',
14+
marginLeft: 'auto',
15+
transition: theme.transitions.create('transform', {
16+
duration: theme.transitions.duration.shortest
17+
})
18+
}));
19+
20+
export default ExpandMore;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react';
2+
import ExpandMore from './ExpandMore';
3+
4+
export default {
5+
title: 'Check Ins/ExpandMore',
6+
component: ExpandMore
7+
};
8+
const Template = args => <ExpandMore {...args} />;
9+
10+
export const DefaultExpandMore = Template.bind({});
11+
DefaultExpandMore.args = {};
12+
13+
// Expanded
14+
export const ExpandedExpandMore = Template.bind({});
15+
ExpandedExpandMore.args = {
16+
expand: true
17+
};
18+
19+
// Collapsed
20+
export const CollapsedExpandMore = Template.bind({});
21+
CollapsedExpandMore.args = {
22+
expand: false
23+
};
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { render, screen } from '@testing-library/react';
2+
import ExpandMore from './ExpandMore';
3+
4+
describe.only('ExpandMore', () => {
5+
it('should render the component', () => {
6+
render(<ExpandMore />);
7+
8+
const button = screen.getByRole('button');
9+
expect(button).toBeInTheDocument();
10+
11+
// is collapsed by default
12+
expect(button).toHaveStyle('transform: rotate(0deg)');
13+
});
14+
15+
it('should rotate the icon when expanded', () => {
16+
render(<ExpandMore expand />);
17+
18+
const button = screen.getByRole('button');
19+
expect(button).toHaveStyle('transform: rotate(180deg)');
20+
});
21+
22+
it('should rotate the icon when collapsed', () => {
23+
render(<ExpandMore expand={false} />);
24+
25+
const button = screen.getByRole('button');
26+
expect(button).toHaveStyle('transform: rotate(0deg)');
27+
});
28+
29+
it('spreads its props to the button', () => {
30+
render(<ExpandMore data-testid="expand-more" />);
31+
32+
const button = screen.getByTestId('expand-more');
33+
expect(button).toBeInTheDocument();
34+
});
35+
36+
it('spread props include aria-label and aria-expanded', () => {
37+
render(<ExpandMore aria-label="expand" aria-expanded={false} />);
38+
39+
const button = screen.getByRole('button');
40+
expect(button).toHaveAttribute('aria-label', 'expand');
41+
expect(button).toHaveAttribute('aria-expanded', 'false');
42+
});
43+
44+
it('spread props include id and className', () => {
45+
render(<ExpandMore id="expand-more" className="expand-more" />);
46+
47+
const button = screen.getByRole('button');
48+
expect(button).toHaveAttribute('id', 'expand-more');
49+
expect(button).toHaveClass('expand-more');
50+
});
51+
52+
it('displays the expand more icon when no children are provided', () => {
53+
render(<ExpandMore />);
54+
55+
const button = screen.getByRole('button');
56+
const icon = button.querySelector('svg');
57+
expect(icon).toHaveAttribute('data-testid', 'ExpandMoreIcon');
58+
});
59+
60+
it('displays the children when provided', () => {
61+
render(<ExpandMore>Test</ExpandMore>);
62+
63+
const button = screen.getByRole('button');
64+
expect(button).toHaveTextContent('Test');
65+
});
66+
});

web-ui/src/components/feedback_request_card/FeedbackRequestCard.jsx

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import { Avatar, Typography } from '@mui/material';
66
import CardContent from '@mui/material/CardContent';
77
import CardActions from '@mui/material/CardActions';
88
import Collapse from '@mui/material/Collapse';
9-
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
10-
import IconButton from '@mui/material/IconButton';
119
import Grid from '@mui/material/Grid';
1210
import { useHistory } from 'react-router-dom';
1311
import PropTypes from 'prop-types';
@@ -19,6 +17,8 @@ import Divider from '@mui/material/Divider';
1917
import Button from '@mui/material/Button';
2018
import queryString from 'query-string';
2119

20+
import ExpandMore from '../expand-more/ExpandMore';
21+
2222
const PREFIX = 'FeedbackRequestCard';
2323
const classes = {
2424
root: `${PREFIX}-root`,
@@ -36,16 +36,6 @@ const StyledCard = styled(Card)({
3636
maxWidth: '100%'
3737
}
3838
},
39-
[`& .${classes.expandClose}`]: {
40-
transform: 'rotate(0deg)',
41-
marginLeft: 'auto',
42-
transition: 'transform 0.1s linear'
43-
},
44-
[`& .${classes.expandOpen}`]: {
45-
transform: 'rotate(180deg)',
46-
transition: 'transform 0.1s linear',
47-
marginLeft: 'auto'
48-
},
4939
'& .MuiCardContent-root': {
5040
paddingBottom: 0,
5141
paddingTop: 0,
@@ -107,12 +97,10 @@ const FeedbackRequestCard = ({
10797
const requesteeProfile = selectProfile(state, requesteeId);
10898
const avatarURL = getAvatarURL(requesteeProfile?.workEmail);
10999
const history = useHistory();
110-
const [expanded, setExpanded] = React.useState(false);
100+
const [expanded, setExpanded] = useState(false);
111101
const [sortedResponses, setSortedResponses] = useState(responses);
112102

113-
const handleExpandClick = () => {
114-
setExpanded(!expanded);
115-
};
103+
const handleExpandClick = () => setExpanded(!expanded);
116104

117105
const withinDateRange = useCallback(
118106
requestDate => {
@@ -271,15 +259,13 @@ const FeedbackRequestCard = ({
271259
</CardContent>
272260
</div>
273261
<CardActions disableSpacing>
274-
<IconButton
262+
<ExpandMore
263+
expand={expanded}
275264
onClick={handleExpandClick}
276265
aria-expanded={expanded}
277266
aria-label="show more"
278-
className={expanded ? classes.expandOpen : classes.expandClose}
279267
size="large"
280-
>
281-
<ExpandMoreIcon />
282-
</IconButton>
268+
/>
283269
</CardActions>
284270
<Collapse in={expanded} timeout="auto" unmountOnExit>
285271
<CardContent style={{ padding: 0 }}>

web-ui/src/components/member_selector/MemberSelector.jsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,11 @@ import {
1919
} from '@mui/material';
2020
import AddIcon from '@mui/icons-material/Add';
2121
import RemoveIcon from '@mui/icons-material/Remove';
22-
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
23-
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
2422
import HighlightOffIcon from '@mui/icons-material/HighlightOff';
2523
import MoreVertIcon from '@mui/icons-material/MoreVert';
2624
import { getAvatarURL } from '../../api/api';
2725

26+
import ExpandMore from '../expand-more/ExpandMore.jsx';
2827
import MemberSelectorDialog, {
2928
FilterType
3029
} from './member_selector_dialog/MemberSelectorDialog';
@@ -100,6 +99,8 @@ const MemberSelector = ({
10099
const roleFilter = filters.find(filter => filter.type === FilterType.ROLE);
101100
const memberDescriptor = isFilteredByRole ? roleFilter.value : 'members';
102101

102+
const handleExpandClick = () => setExpanded(!expanded);
103+
103104
// When the selected members change, fire the onChange event
104105
useEffect(() => {
105106
if (onChange) {
@@ -176,9 +177,12 @@ const MemberSelector = ({
176177
>
177178
<CardHeader
178179
avatar={
179-
<IconButton onClick={() => setExpanded(!expanded)}>
180-
{expanded ? <ExpandLessIcon /> : <ExpandMoreIcon />}
181-
</IconButton>
180+
<ExpandMore
181+
expand={expanded}
182+
onClick={handleExpandClick}
183+
aria-expanded={expanded}
184+
aria-label="show more"
185+
/>
182186
}
183187
title={
184188
<div className="member-selector-card-title-container">

web-ui/src/pages/ReceivedRequestsPage.jsx

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import TextField from '@mui/material/TextField';
1111
import MenuItem from '@mui/material/MenuItem';
1212
import Typography from '@mui/material/Typography';
1313
import { Search as SearchIcon } from '@mui/icons-material';
14-
import { Collapse, IconButton, InputAdornment } from '@mui/material';
14+
import { Collapse, InputAdornment } from '@mui/material';
1515
import ReceivedRequestCard from '../components/received_request_card/ReceivedRequestCard';
1616
import { getFeedbackRequestsByRecipient } from '../api/feedback';
1717
import './ReceivedRequestsPage.css';
1818
import { UPDATE_TOAST } from '../context/actions';
1919
import Divider from '@mui/material/Divider';
20-
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
20+
import ExpandMore from '../components/expand-more/ExpandMore';
2121
import SkeletonLoader from '../components/skeleton_loader/SkeletonLoader';
2222

2323
const PREFIX = 'ReceivedRequestsPage';
@@ -61,16 +61,6 @@ const Root = styled('div')({
6161
color: 'gray',
6262
marginTop: '4em',
6363
textAlign: 'center'
64-
},
65-
[`& .${classes.expandClose}`]: {
66-
transform: 'rotate(0deg)',
67-
marginLeft: 'auto',
68-
transition: 'transform 0.1s linear'
69-
},
70-
[`& .${classes.expandOpen}`]: {
71-
transform: 'rotate(180deg)',
72-
transition: 'transform 0.1s linear',
73-
marginLeft: 'auto'
7464
}
7565
});
7666

@@ -264,16 +254,12 @@ const ReceivedRequestsPage = () => {
264254
</div>
265255
<div className="request-section-header">
266256
<Typography variant="h5">Received Requests</Typography>
267-
<IconButton
257+
<ExpandMore
258+
expand={receivedRequestsExpanded}
268259
onClick={() => setReceivedRequestsExpanded(!receivedRequestsExpanded)}
260+
aria-expanded={receivedRequestsExpanded}
269261
aria-label="show more"
270-
className={
271-
receivedRequestsExpanded ? classes.expandOpen : classes.expandClose
272-
}
273-
size="large"
274-
>
275-
<ExpandMoreIcon />
276-
</IconButton>
262+
/>
277263
</div>
278264
<Divider />
279265
<Collapse in={!receivedRequestsExpanded} timeout="auto" unmountOnExit>
@@ -309,18 +295,14 @@ const ReceivedRequestsPage = () => {
309295
</Collapse>
310296
<div className="request-section-header">
311297
<Typography variant="h5">Submitted Requests</Typography>
312-
<IconButton
298+
<ExpandMore
299+
expand={submittedRequestsExpanded}
313300
onClick={() =>
314301
setSubmittedRequestsExpanded(!submittedRequestsExpanded)
315302
}
303+
aria-expanded={submittedRequestsExpanded}
316304
aria-label="show more"
317-
className={
318-
submittedRequestsExpanded ? classes.expandOpen : classes.expandClose
319-
}
320-
size="large"
321-
>
322-
<ExpandMoreIcon />
323-
</IconButton>
305+
/>
324306
</div>
325307
<Divider />
326308
<Collapse in={!submittedRequestsExpanded} timeout="auto" unmountOnExit>
@@ -366,16 +348,12 @@ const ReceivedRequestsPage = () => {
366348
</Collapse>
367349
<div className="request-section-header">
368350
<Typography variant="h5">Canceled Requests</Typography>
369-
<IconButton
351+
<ExpandMore
352+
expand={canceledRequestsExpanded}
370353
onClick={() => setCanceledRequestsExpanded(!canceledRequestsExpanded)}
354+
aria-expanded={canceledRequestsExpanded}
371355
aria-label="show more"
372-
className={
373-
canceledRequestsExpanded ? classes.expandOpen : classes.expandClose
374-
}
375-
size="large"
376-
>
377-
<ExpandMoreIcon />
378-
</IconButton>
356+
/>
379357
</div>
380358
<Divider />
381359
<Collapse in={!canceledRequestsExpanded} timeout="auto" unmountOnExit>

0 commit comments

Comments
 (0)