security-checklist/components/ChecklistItem/index.js

150 lines
4.1 KiB
JavaScript
Raw Permalink Normal View History

2019-01-13 07:00:23 +00:00
// @flow
import React from 'react';
import type { ChecklistResource } from '../../types';
import { getCheckedStatusById, setCheckedStatusById } from './utils';
import Card from '../Card';
import LoadingChecklistItem from '../LoadingChecklistItem';
import { Heading } from './Heading';
import { Apps } from './Apps';
import { Resources } from './Resources';
import {
Container,
CheckboxContainer,
CardContent,
ResourceContent,
2019-01-13 07:36:51 +00:00
Divider,
Description,
Content,
2019-01-13 07:00:23 +00:00
} from './style';
type Props = {
resource: ChecklistResource,
};
type State = {
isChecked: boolean,
isLoading: boolean,
2019-01-13 23:55:19 +00:00
isCollapsed: boolean,
contentHeight: number,
2019-01-13 07:00:23 +00:00
};
class ChecklistItem extends React.Component<Props, State> {
state = { isChecked: false, isLoading: true, isCollapsed: true, contentHeight: 2000, };
2019-02-06 18:27:36 +00:00
contentContainer: { current: null | HTMLDivElement }
2019-02-06 18:27:36 +00:00
constructor(props: Props) {
super(props);
this.contentContainer = React.createRef();
}
2019-01-13 07:00:23 +00:00
componentDidMount() {
const { resource } = this.props;
const isChecked = getCheckedStatusById(resource.id);
2019-01-13 23:55:19 +00:00
return this.setState({
isChecked,
isLoading: false,
isCollapsed: isChecked,
});
2019-01-13 07:00:23 +00:00
}
2019-02-06 18:27:36 +00:00
componentDidUpdate(prevProps: Props, prevState: State) {
if (prevState.isLoading && !this.state.isLoading && this.contentContainer.current) {
return this.setState({
contentHeight: this.contentContainer.current.scrollHeight,
})
}
}
2019-01-13 07:00:23 +00:00
handleSetChecked = () => {
2019-01-14 00:05:01 +00:00
const { isChecked } = this.state;
2019-01-13 07:00:23 +00:00
const { resource } = this.props;
setCheckedStatusById(resource.id, !isChecked);
2019-01-14 00:02:22 +00:00
return this.setState({ isChecked: !isChecked, isCollapsed: !isChecked });
2019-01-13 07:00:23 +00:00
};
uncollapse = () => {
this.setState(state => ({ isCollapsed: !state.isCollapsed }));
2019-02-06 18:27:36 +00:00
this.contentContainer.current && this.contentContainer.current.focus();
};
2019-02-06 18:27:36 +00:00
handleAppsExpand = (appsContainerHeight: number) => {
return this.contentContainer.current && this.setState({
contentHeight: this.contentContainer.current.scrollHeight + appsContainerHeight,
})
}
2019-01-14 00:02:22 +00:00
2019-01-13 07:00:23 +00:00
render() {
const { isChecked, isLoading, isCollapsed, contentHeight } = this.state;
2019-01-13 07:00:23 +00:00
const { resource } = this.props;
if (isLoading) return <LoadingChecklistItem />;
return (
<Container>
<Card isChecked={isChecked}>
2019-01-14 00:16:03 +00:00
<CardContent isCollapsed={isCollapsed}>
2019-02-03 17:37:05 +00:00
<CheckboxContainer>
<input
aria-expanded={!isCollapsed}
2019-02-03 17:37:05 +00:00
type="checkbox"
checked={isChecked}
id={`checkbox_${resource.id}`}
onChange={this.handleSetChecked}
2019-02-03 17:44:22 +00:00
aria-controls={`content_${resource.id}`}
2019-02-03 17:37:05 +00:00
/>
<label htmlFor={`checkbox_${resource.id}`}>
2019-02-03 17:37:05 +00:00
{resource.title}
</label>
2019-01-13 07:00:23 +00:00
</CheckboxContainer>
2019-02-03 17:44:22 +00:00
<ResourceContent
isChecked={isChecked}
isCollapsed={isCollapsed}
>
2019-01-14 00:02:22 +00:00
<Heading
resource={resource}
isCollapsed={isCollapsed}
handleCollapse={this.uncollapse}
/>
2019-01-13 23:50:07 +00:00
<Content
aria-hidden={isCollapsed}
id={`content_${resource.id}`}
role="region"
tabindex="-1"
ref={this.contentContainer}
style={{ '--maxHeight': `${contentHeight}px` }}
>
<Description source={resource.description} />
{resource.apps && (
<React.Fragment>
<Divider />
<Apps
resource={resource}
handleAppsExpand={this.handleAppsExpand}
/>
</React.Fragment>
)}
{resource.resources && (
<React.Fragment>
<Divider />
<Resources resource={resource} />
</React.Fragment>
)}
</Content>
2019-01-13 07:00:23 +00:00
</ResourceContent>
</CardContent>
</Card>
</Container>
);
}
}
export default ChecklistItem;