209 lines
6.1 KiB
JavaScript
209 lines
6.1 KiB
JavaScript
import { h, Component } from 'preact';
|
||
import PropTypes from 'prop-types';
|
||
import {
|
||
Button,
|
||
ButtonGroup,
|
||
Dropdown,
|
||
FormField,
|
||
RadioButton,
|
||
} from '@crayons';
|
||
|
||
const COMMENT_SUBSCRIPTION_TYPE = {
|
||
ALL: 'all_comments',
|
||
TOP: 'top_level_comments',
|
||
AUTHOR: 'only_author_comments',
|
||
};
|
||
|
||
export class CommentSubscription extends Component {
|
||
state = {
|
||
showOptions: false,
|
||
commentSubscriptionType: COMMENT_SUBSCRIPTION_TYPE.ALL,
|
||
subscribed: false,
|
||
};
|
||
|
||
componentDidMount() {
|
||
window.addEventListener('scroll', this.dropdownPlacementHandler);
|
||
}
|
||
|
||
componentDidUpdate() {
|
||
const { showOptions } = this.state;
|
||
|
||
if (showOptions) {
|
||
this.dropdownPlacementHandler();
|
||
}
|
||
}
|
||
|
||
componentWillUnmount() {
|
||
window.removeEventListener('scroll', this.dropdownPlacementHandler);
|
||
}
|
||
|
||
dropdownPlacementHandler = () => {
|
||
const { base: element } = this.dropdownElement;
|
||
|
||
// Reset the top before doing any calculations
|
||
element.style.bottom = '';
|
||
|
||
const { bottom: dropDownBottom } = element.getBoundingClientRect();
|
||
const { height } = this.buttonGroupElement.base.getBoundingClientRect();
|
||
|
||
if (
|
||
Math.sign(dropDownBottom) === -1 ||
|
||
dropDownBottom > window.innerHeight
|
||
) {
|
||
// The 4 pixels is the box shadow from the drop down.
|
||
element.style.bottom = `${height + 4}px`;
|
||
}
|
||
};
|
||
|
||
commentSubscriptionClick = (event) => {
|
||
this.setState({
|
||
commentSubscriptionType: event.target.value,
|
||
});
|
||
};
|
||
|
||
render() {
|
||
const { showOptions, commentSubscriptionType, subscribed } = this.state;
|
||
const { onSubscribe, onUnsubscribe } = this.props;
|
||
|
||
const CogIcon = () => (
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
width="24"
|
||
height="24"
|
||
role="img"
|
||
aria-labelledby="ai2ols8ka2ohfp0z568lj68ic2du21s"
|
||
className="crayons-icon"
|
||
>
|
||
<title id="ai2ols8ka2ohfp0z568lj68ic2du21s">Preferences</title>
|
||
<path d="M12 1l9.5 5.5v11L12 23l-9.5-5.5v-11L12 1zm0 2.311L4.5 7.653v8.694l7.5 4.342 7.5-4.342V7.653L12 3.311zM12 16a4 4 0 110-8 4 4 0 010 8zm0-2a2 2 0 100-4 2 2 0 000 4z" />
|
||
</svg>
|
||
);
|
||
|
||
return (
|
||
<div className="relative">
|
||
<ButtonGroup
|
||
ref={(element) => {
|
||
this.buttonGroupElement = element;
|
||
}}
|
||
>
|
||
<Button
|
||
variant="outlined"
|
||
onClick={(_event) => {
|
||
if (subscribed) {
|
||
onUnsubscribe();
|
||
} else {
|
||
onSubscribe(commentSubscriptionType);
|
||
}
|
||
|
||
this.setState({ subscribed: !subscribed });
|
||
}}
|
||
>
|
||
{subscribed ? 'Unsubscribe' : 'Subscribe'}
|
||
</Button>
|
||
{subscribed && (
|
||
<Button
|
||
variant="outlined"
|
||
icon={CogIcon}
|
||
contentType="icon"
|
||
onClick={(_event) => {
|
||
this.setState({ showOptions: !showOptions });
|
||
}}
|
||
/>
|
||
)}
|
||
</ButtonGroup>
|
||
{subscribed && (
|
||
<Dropdown
|
||
className={showOptions ? 'inline-block w-full' : null}
|
||
ref={(element) => {
|
||
this.dropdownElement = element;
|
||
}}
|
||
>
|
||
<div className="crayons-fields mb-5">
|
||
<FormField variant="radio">
|
||
<RadioButton
|
||
id="subscribe-all"
|
||
name="subscribe_comments"
|
||
value="all_comments"
|
||
checked={
|
||
commentSubscriptionType === COMMENT_SUBSCRIPTION_TYPE.ALL
|
||
}
|
||
onClick={this.commentSubscriptionClick}
|
||
/>
|
||
<label htmlFor="subscribe-all" className="crayons-field__label">
|
||
All comments
|
||
<p className="crayons-field__description">
|
||
You’ll receive notifications for all new comments.
|
||
</p>
|
||
</label>
|
||
</FormField>
|
||
|
||
<FormField variant="radio">
|
||
<RadioButton
|
||
id="subscribe-toplevel"
|
||
name="subscribe_comments"
|
||
value="top_level_comments"
|
||
onClick={this.commentSubscriptionClick}
|
||
checked={
|
||
commentSubscriptionType === COMMENT_SUBSCRIPTION_TYPE.TOP
|
||
}
|
||
/>
|
||
<label
|
||
htmlFor="subscribe-toplevel"
|
||
className="crayons-field__label"
|
||
>
|
||
Top-level comments
|
||
<p className="crayons-field__description">
|
||
You’ll receive notifications only for all new top-level
|
||
comments.
|
||
</p>
|
||
</label>
|
||
</FormField>
|
||
|
||
<FormField variant="radio">
|
||
<RadioButton
|
||
id="subscribe-author"
|
||
name="subscribe_comments"
|
||
value="only_author_comments"
|
||
onClick={this.commentSubscriptionClick}
|
||
checked={
|
||
commentSubscriptionType === COMMENT_SUBSCRIPTION_TYPE.AUTHOR
|
||
}
|
||
/>
|
||
<label
|
||
htmlFor="subscribe-author"
|
||
className="crayons-field__label"
|
||
>
|
||
Post author comments
|
||
<p className="crayons-field__description">
|
||
You’ll receive notifications only if post author sends a new
|
||
comment.
|
||
</p>
|
||
</label>
|
||
</FormField>
|
||
</div>
|
||
|
||
<Button
|
||
className="w-100"
|
||
onClick={(_event) => {
|
||
this.setState((prevState) => {
|
||
onSubscribe(prevState.commentSubscriptionType);
|
||
|
||
return { ...prevState, showOptions: false };
|
||
});
|
||
}}
|
||
>
|
||
Done
|
||
</Button>
|
||
</Dropdown>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
}
|
||
|
||
CommentSubscription.displayName = 'CommentSubscription';
|
||
|
||
CommentSubscription.propTypes = {
|
||
onSubscribe: PropTypes.func.isRequired,
|
||
onUnsubscribe: PropTypes.func.isRequired,
|
||
};
|