* 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>
178 lines
4.2 KiB
JavaScript
178 lines
4.2 KiB
JavaScript
import { h, Component } from 'preact';
|
|
import PropTypes from 'prop-types';
|
|
import { SnackbarItem } from './SnackbarItem';
|
|
|
|
let snackbarItems = [];
|
|
|
|
export function addSnackbarItem(snackbarItem) {
|
|
if (!Array.isArray(snackbarItem.actions)) {
|
|
snackbarItem.actions = []; // eslint-disable-line no-param-reassign
|
|
}
|
|
|
|
snackbarItems.push(snackbarItem);
|
|
}
|
|
|
|
export class Snackbar extends Component {
|
|
state = {
|
|
snacks: [],
|
|
};
|
|
|
|
pollingId;
|
|
|
|
paused = false;
|
|
|
|
pauseLifespan;
|
|
|
|
resumeLifespan;
|
|
|
|
componentDidMount() {
|
|
this.initializePolling();
|
|
}
|
|
|
|
componentDidUpdate() {
|
|
if (!this.pauseLifespan) {
|
|
this.pauseLifespan = (_event) => {
|
|
this.paused = true;
|
|
};
|
|
|
|
this.resumeLifespan = (event) => {
|
|
event.stopPropagation();
|
|
this.paused = false;
|
|
};
|
|
|
|
this.element.addEventListener('mouseover', this.pauseLifespan);
|
|
this.element.addEventListener('mouseout', this.resumeLifespan, true);
|
|
}
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
if (this.element) {
|
|
this.element.removeEventListener('mouseover', this.pauseLifespan);
|
|
this.element.addEventListener('mouseout', this.resumeLifespan);
|
|
}
|
|
}
|
|
|
|
initializePolling() {
|
|
const { pollingTime, lifespan } = this.props;
|
|
|
|
this.pollingId = setInterval(() => {
|
|
if (snackbarItems.length > 0) {
|
|
// Need to add the lifespan to snackbar items because each second that goes by, we
|
|
// decrease the lifespan until it is no more.
|
|
const newSnacks = snackbarItems.map((snackbarItem) => ({
|
|
...snackbarItem,
|
|
lifespan,
|
|
}));
|
|
|
|
snackbarItems = [];
|
|
|
|
this.updateSnackbarItems(newSnacks);
|
|
|
|
// Start the lifespan countdowns for each new snackbar item.
|
|
newSnacks.forEach((snack) => {
|
|
// eslint-disable-next-line no-param-reassign
|
|
snack.lifespanTimeoutId = setTimeout(() => {
|
|
this.decreaseLifespan(snack);
|
|
}, 1000);
|
|
|
|
if (snack.addCloseButton) {
|
|
// Adds an optional close button if addDefaultACtion is true.
|
|
snack.actions.push({
|
|
text: 'Dismiss',
|
|
handler: () => {
|
|
this.setState((prevState) => {
|
|
return {
|
|
prevState,
|
|
snacks: prevState.snacks.filter(
|
|
(potentialSnackToFilterOut) =>
|
|
potentialSnackToFilterOut !== snack,
|
|
),
|
|
};
|
|
});
|
|
},
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}, pollingTime);
|
|
}
|
|
|
|
updateSnackbarItems(newSnacks) {
|
|
this.setState((prevState) => {
|
|
let updatedSnacks = [...prevState.snacks, ...newSnacks];
|
|
|
|
if (updatedSnacks.length > 3) {
|
|
const snacksToBeDiscarded = updatedSnacks.slice(
|
|
0,
|
|
updatedSnacks.length - 3,
|
|
);
|
|
|
|
snacksToBeDiscarded.forEach(({ lifespanTimeoutId }) => {
|
|
clearTimeout(lifespanTimeoutId);
|
|
});
|
|
|
|
updatedSnacks = updatedSnacks.slice(updatedSnacks.length - 3);
|
|
}
|
|
|
|
return { ...prevState, snacks: updatedSnacks };
|
|
});
|
|
}
|
|
|
|
decreaseLifespan(snack) {
|
|
/* eslint-disable no-param-reassign */
|
|
if (!this.paused && snack.lifespan === 0) {
|
|
clearTimeout(snack.lifespanTimeoutId);
|
|
|
|
this.setState((prevState) => {
|
|
const snacks = prevState.snacks.filter(
|
|
(currentSnack) => currentSnack !== snack,
|
|
);
|
|
|
|
return {
|
|
...prevState,
|
|
snacks,
|
|
};
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (!this.paused) {
|
|
snack.lifespan -= 1;
|
|
}
|
|
|
|
snack.lifespanTimeoutId = setTimeout(() => {
|
|
this.decreaseLifespan(snack);
|
|
}, 1000);
|
|
/* eslint-enable no-param-reassign */
|
|
}
|
|
|
|
render() {
|
|
const { snacks } = this.state;
|
|
|
|
return (
|
|
<div
|
|
className={snacks.length > 0 ? 'crayons-snackbar' : 'hidden'}
|
|
ref={(element) => {
|
|
this.element = element;
|
|
}}
|
|
>
|
|
{snacks.map(({ message, actions = [] }) => (
|
|
<SnackbarItem message={message} actions={actions} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
Snackbar.defaultProps = {
|
|
lifespan: 5,
|
|
pollingTime: 300,
|
|
};
|
|
|
|
Snackbar.displayName = 'SnackbarPoller';
|
|
|
|
Snackbar.propTypes = {
|
|
lifespan: PropTypes.number,
|
|
pollingTime: PropTypes.number,
|
|
};
|