waypoint.js 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. /* jshint ignore:start */
  2. import React from 'react';
  3. import * as post from 'misago/reducers/post';
  4. import * as thread from 'misago/reducers/thread';
  5. import ajax from 'misago/services/ajax';
  6. import snackbar from 'misago/services/snackbar';
  7. import store from 'misago/services/store';
  8. export default class extends React.Component {
  9. /*
  10. Super naive and de-facto placeholder implementation for reading posts on scroll
  11. */
  12. componentDidMount() {
  13. if(this.props.post.is_read) return; // don't register read tracker
  14. $(this.documentNode).waypoint({
  15. handler: (direction) => {
  16. if (direction !== 'down' || this.props.post.is_read) return;
  17. // after 1500ms run flag post as read logic
  18. window.setTimeout(() => {
  19. // check if post's bottom edge is still in viewport
  20. const boundingClientRect = this.documentNode.getBoundingClientRect();
  21. const offsetBottom = boundingClientRect.height + boundingClientRect.top;
  22. const clientHeight = document.documentElement.clientHeight;
  23. if (offsetBottom < 5) return; // scrolled past the post
  24. if (offsetBottom > clientHeight) return; // scrolled back up
  25. // mark post as read
  26. store.dispatch(post.patch(this.props.post, {
  27. is_read: true
  28. }));
  29. // call API to let it know we have unread post
  30. ajax.post(this.props.post.api.read).then(
  31. (data) => {
  32. store.dispatch(thread.update(this.props.thread, {
  33. is_read: data.thread_is_read
  34. }));
  35. },
  36. (rejection) => {
  37. snackbar.apiError(rejection);
  38. }
  39. );
  40. }, 1000);
  41. },
  42. offset: 'bottom-in-view'
  43. });
  44. }
  45. render() {
  46. return (
  47. <div className={this.props.className} ref={(node) => { this.documentNode = node; }}>
  48. {this.props.children}
  49. </div>
  50. );
  51. }
  52. }