* wip * Right aligned the comment subscription panel. * Cleaned up the comment area on the article page so it uses crayon margin classes. * Updated tests * Removed old UI for comment subscriptions. * Made Discussion text bigger and bolder. * Fixed some layout issues as per PR comments. * Fixed some layout issues as per PR comments. * Updated Storybook stories, tests and snapshots * wip * Everything works now, just need to integrate snackbar. * Removed setTimeout I was debugging with. * Using the new utilities/http/request utility now. * Added the <SnackbarPoller /> * Now when unsubscribed, the subscription type resets to all comments. * Removed overflow hidden from .home CSS class so comment subscription component displays properly. * Now unsuccessful subscribes/unsubscribes error properly. * Changed button text from Done to Subscribe * Merged the <SnackbarPoller /> component into the <Snackbar /> component. * Fixed a propType issue. * Fixed a test. * Removed snackbar tests for now. Need to figure out polling in tests. * Now comment subscription component is only loaded for logged on users. * Added a comment. * Updated some storybook stories. * Fixed a small formatting issue. * Reduced snackbar item lifespans to 3 seconds. * Extracted <CogIcon /> to it's own file because other features are going to need it. * Added some Storybook stories and tests for the <CogIcon /> component. * Revert "Extracted <CogIcon /> to it's own file because other features are going to need it." This reverts commit b30406a50e491c53c3dce5be03bcdf8112b043df. * Put back <CogIcon /> component. * Added some error handling if the component doesn't load. * Moving some things around. * Rename the article pack file. * Changed wording from "article" to "post". * Fixed false negative CSS issue. It was a dangling div tag. * Add the option to add an optional close button to snackbar items. * Fixed z-index of subscription type options panel so it is always visible on mobile. * Reworked the comment subsciption utilities a bit. * Added test for comment subscription utilities. * Fixed a broken test from a refactor. * Added more tests for comment subscription utiltities. * Fixed comments footer bottom padding. * Fixed issue with stale find in comment subscription test. * Update app/javascript/packs/articlePage.jsx Co-authored-by: ludwiczakpawel <ludwiczakpawel@gmail.com> * Update app/assets/stylesheets/article-show.scss Co-authored-by: ludwiczakpawel <ludwiczakpawel@gmail.com> * Changed close button wording to Dismiss. * Fixed padding to use utility variable instead. * Added missing import for SASS file. Co-authored-by: ludwiczakpawel <ludwiczakpawel@gmail.com>
236 lines
7.1 KiB
JavaScript
236 lines
7.1 KiB
JavaScript
import { h, Component } from 'preact';
|
||
import PropTypes from 'prop-types';
|
||
import {
|
||
Button,
|
||
ButtonGroup,
|
||
Dropdown,
|
||
FormField,
|
||
RadioButton,
|
||
} from '@crayons';
|
||
|
||
export const COMMENT_SUBSCRIPTION_TYPE = Object.freeze({
|
||
ALL: 'all_comments',
|
||
TOP: 'top_level_comments',
|
||
AUTHOR: 'only_author_comments',
|
||
NOT_SUBSCRIBED: 'not_subscribed',
|
||
});
|
||
|
||
export class CommentSubscription extends Component {
|
||
constructor(props) {
|
||
const { subscriptionType } = props;
|
||
super(props);
|
||
|
||
const subscribed =
|
||
subscriptionType &&
|
||
(subscriptionType.length > 0 && subscriptionType) !==
|
||
COMMENT_SUBSCRIPTION_TYPE.NOT_SUBSCRIBED;
|
||
|
||
const initialState = {
|
||
subscriptionType: subscribed
|
||
? subscriptionType
|
||
: COMMENT_SUBSCRIPTION_TYPE.ALL,
|
||
subscribed,
|
||
showOptions: false,
|
||
};
|
||
|
||
this.state = initialState;
|
||
}
|
||
|
||
componentDidUpdate() {
|
||
const { showOptions } = this.state;
|
||
|
||
if (showOptions) {
|
||
window.addEventListener('scroll', this.dropdownPlacementHandler);
|
||
this.dropdownPlacementHandler();
|
||
} else {
|
||
window.removeEventListener('scroll', 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({
|
||
subscriptionType: event.target.value,
|
||
});
|
||
};
|
||
|
||
render() {
|
||
const { showOptions, subscriptionType, subscribed } = this.state;
|
||
const {
|
||
onSubscribe,
|
||
onUnsubscribe,
|
||
positionType = 'relative',
|
||
} = 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={positionType}>
|
||
<ButtonGroup
|
||
ref={(element) => {
|
||
this.buttonGroupElement = element;
|
||
}}
|
||
>
|
||
<Button
|
||
variant="outlined"
|
||
onClick={(_event) => {
|
||
if (subscribed) {
|
||
onUnsubscribe(COMMENT_SUBSCRIPTION_TYPE.NOT_SUBSCRIBED);
|
||
this.setState({
|
||
subscriptionType: COMMENT_SUBSCRIPTION_TYPE.ALL,
|
||
});
|
||
} else {
|
||
onSubscribe(subscriptionType);
|
||
}
|
||
|
||
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 z-30 right-4 left-4 s:right-0 s:left-auto${
|
||
positionType === 'relative' ? ' 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={COMMENT_SUBSCRIPTION_TYPE.ALL}
|
||
checked={subscriptionType === 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={COMMENT_SUBSCRIPTION_TYPE.TOP}
|
||
onClick={this.commentSubscriptionClick}
|
||
checked={subscriptionType === 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={COMMENT_SUBSCRIPTION_TYPE.AUTHOR}
|
||
onClick={this.commentSubscriptionClick}
|
||
checked={
|
||
subscriptionType === 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.subscriptionType);
|
||
|
||
return { ...prevState, showOptions: false };
|
||
});
|
||
}}
|
||
>
|
||
Done
|
||
</Button>
|
||
</Dropdown>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
}
|
||
|
||
CommentSubscription.displayName = 'CommentSubscription';
|
||
|
||
CommentSubscription.propTypes = {
|
||
positionType: PropTypes.oneOf(['absolute', 'relative', 'static']).isRequired,
|
||
onSubscribe: PropTypes.func.isRequired,
|
||
onUnsubscribe: PropTypes.func.isRequired,
|
||
subscriptionType: PropTypes.oneOf(
|
||
Object.entries(COMMENT_SUBSCRIPTION_TYPE).map(([, value]) => value),
|
||
).isRequired,
|
||
};
|