You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
3.5 KiB

  1. import React from 'react';
  2. import { Provider } from 'react-redux';
  3. import PropTypes from 'prop-types';
  4. import configureStore from '../store/configureStore';
  5. import {
  6. updateTimeline,
  7. deleteFromTimelines,
  8. refreshHomeTimeline,
  9. connectTimeline,
  10. disconnectTimeline,
  11. } from '../actions/timelines';
  12. import { showOnboardingOnce } from '../actions/onboarding';
  13. import { updateNotifications, refreshNotifications } from '../actions/notifications';
  14. import BrowserRouter from 'react-router-dom/BrowserRouter';
  15. import Route from 'react-router-dom/Route';
  16. import ScrollContext from 'react-router-scroll/lib/ScrollBehaviorContext';
  17. import UI from '../features/ui';
  18. import { hydrateStore } from '../actions/store';
  19. import createStream from '../stream';
  20. import { IntlProvider, addLocaleData } from 'react-intl';
  21. import { getLocale } from '../locales';
  22. const { localeData, messages } = getLocale();
  23. addLocaleData(localeData);
  24. const store = configureStore();
  25. const initialState = JSON.parse(document.getElementById('initial-state').textContent);
  26. store.dispatch(hydrateStore(initialState));
  27. export default class Mastodon extends React.PureComponent {
  28. static propTypes = {
  29. locale: PropTypes.string.isRequired,
  30. };
  31. componentDidMount() {
  32. const { locale } = this.props;
  33. const streamingAPIBaseURL = store.getState().getIn(['meta', 'streaming_api_base_url']);
  34. const accessToken = store.getState().getIn(['meta', 'access_token']);
  35. const setupPolling = () => {
  36. this.polling = setInterval(() => {
  37. store.dispatch(refreshHomeTimeline());
  38. store.dispatch(refreshNotifications());
  39. }, 20000);
  40. };
  41. const clearPolling = () => {
  42. clearInterval(this.polling);
  43. this.polling = undefined;
  44. };
  45. this.subscription = createStream(streamingAPIBaseURL, accessToken, 'user', {
  46. connected () {
  47. clearPolling();
  48. store.dispatch(connectTimeline('home'));
  49. },
  50. disconnected () {
  51. setupPolling();
  52. store.dispatch(disconnectTimeline('home'));
  53. },
  54. received (data) {
  55. switch(data.event) {
  56. case 'update':
  57. store.dispatch(updateTimeline('home', JSON.parse(data.payload)));
  58. break;
  59. case 'delete':
  60. store.dispatch(deleteFromTimelines(data.payload));
  61. break;
  62. case 'notification':
  63. store.dispatch(updateNotifications(JSON.parse(data.payload), messages, locale));
  64. break;
  65. }
  66. },
  67. reconnected () {
  68. clearPolling();
  69. store.dispatch(connectTimeline('home'));
  70. store.dispatch(refreshHomeTimeline());
  71. store.dispatch(refreshNotifications());
  72. },
  73. });
  74. // Desktop notifications
  75. if (typeof window.Notification !== 'undefined' && Notification.permission === 'default') {
  76. Notification.requestPermission();
  77. }
  78. store.dispatch(showOnboardingOnce());
  79. }
  80. componentWillUnmount () {
  81. if (typeof this.subscription !== 'undefined') {
  82. this.subscription.close();
  83. this.subscription = null;
  84. }
  85. if (typeof this.polling !== 'undefined') {
  86. clearInterval(this.polling);
  87. this.polling = null;
  88. }
  89. }
  90. render () {
  91. const { locale } = this.props;
  92. return (
  93. <IntlProvider locale={locale} messages={messages}>
  94. <Provider store={store}>
  95. <BrowserRouter basename='/web'>
  96. <ScrollContext>
  97. <Route path='/' component={UI} />
  98. </ScrollContext>
  99. </BrowserRouter>
  100. </Provider>
  101. </IntlProvider>
  102. );
  103. }
  104. }