From 71362a922af1296cb6498b02f0b44067e57cc8b9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 4 Jun 2022 15:30:15 -0500 Subject: [PATCH 1/5] QuotedStatus: convert to FC --- .../status/components/quoted_status.tsx | 134 ++++++++---------- 1 file changed, 59 insertions(+), 75 deletions(-) diff --git a/app/soapbox/features/status/components/quoted_status.tsx b/app/soapbox/features/status/components/quoted_status.tsx index 1b8f25c02..bf8069aa8 100644 --- a/app/soapbox/features/status/components/quoted_status.tsx +++ b/app/soapbox/features/status/components/quoted_status.tsx @@ -1,9 +1,7 @@ import classNames from 'classnames'; -import { History } from 'history'; import React from 'react'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl, FormattedMessage, IntlShape, FormattedList } from 'react-intl'; -import { withRouter } from 'react-router-dom'; +import { defineMessages, useIntl, FormattedMessage, FormattedList } from 'react-intl'; +import { useHistory } from 'react-router-dom'; import StatusMedia from 'soapbox/components/status-media'; import { Stack, Text } from 'soapbox/components/ui'; @@ -16,49 +14,42 @@ const messages = defineMessages({ }); interface IQuotedStatus { + /** The quoted status entity. */ status?: StatusEntity, + /** Callback when cancelled (during compose). */ onCancel?: Function, - intl: IntlShape, + /** Whether the status is shown in the post composer. */ compose?: boolean, - history: History, } -class QuotedStatus extends ImmutablePureComponent { - - handleExpandClick = (e: React.MouseEvent) => { - const { compose, status } = this.props; +/** Status embedded in a quote post. */ +const QuotedStatus: React.FC = ({ status, onCancel, compose }) => { + const intl = useIntl(); + const history = useHistory(); + const handleExpandClick = (e: React.MouseEvent) => { if (!status) return; - const account = status.account as AccountEntity; if (!compose && e.button === 0) { - if (!this.props.history) { - return; - } - - this.props.history.push(`/@${account.acct}/posts/${status.id}`); - + history.push(`/@${account.acct}/posts/${status.id}`); e.stopPropagation(); e.preventDefault(); } - } + }; - handleClose = () => { - if (this.props.onCancel) { - this.props.onCancel(); + const handleClose = () => { + if (onCancel) { + onCancel(); } - } - - renderReplyMentions = () => { - const { status } = this.props; + }; + const renderReplyMentions = () => { if (!status?.in_reply_to_id) { return null; } const account = status.account as AccountEntity; - const to = status.mentions || []; if (to.size === 0) { @@ -102,58 +93,51 @@ class QuotedStatus extends ImmutablePureComponent { /> ); + }; + + if (!status) { + return null; } - render() { - const { status, onCancel, intl, compose } = this.props; + const account = status.account as AccountEntity; - if (!status) { - return null; - } - - const account = status.account as AccountEntity; - - let actions = {}; - if (onCancel) { - actions = { - onActionClick: this.handleClose, - actionIcon: require('@tabler/icons/icons/x.svg'), - actionAlignment: 'top', - actionTitle: intl.formatMessage(messages.cancel), - }; - } - - const quotedStatus = ( - - - - {this.renderReplyMentions()} - - - - - - ); - - return quotedStatus; + let actions = {}; + if (onCancel) { + actions = { + onActionClick: handleClose, + actionIcon: require('@tabler/icons/icons/x.svg'), + actionAlignment: 'top', + actionTitle: intl.formatMessage(messages.cancel), + }; } -} + return ( + + -export default withRouter(injectIntl(QuotedStatus) as any); + {renderReplyMentions()} + + + + + + ); +}; + +export default QuotedStatus; From 4c87573972f7c2646e5b35add6c617013259bf0f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 4 Jun 2022 15:31:24 -0500 Subject: [PATCH 2/5] HomeTimeline: remove suggestions --- app/soapbox/features/home_timeline/index.js | 38 ++++++--------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/app/soapbox/features/home_timeline/index.js b/app/soapbox/features/home_timeline/index.js index 01276be6d..f93887713 100644 --- a/app/soapbox/features/home_timeline/index.js +++ b/app/soapbox/features/home_timeline/index.js @@ -5,17 +5,12 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; -import BundleContainer from 'soapbox/features/ui/containers/bundle_container'; import { getFeatures } from 'soapbox/utils/features'; import { expandHomeTimeline } from '../../actions/timelines'; import { Column } from '../../components/ui'; import Timeline from '../ui/components/timeline'; -function FollowRecommendationsContainer() { - return import(/* webpackChunkName: "features/follow_recommendations" */'soapbox/features/follow_recommendations/components/follow_recommendations_container'); -} - const messages = defineMessages({ title: { id: 'column.home', defaultMessage: 'Home' }, }); @@ -92,37 +87,24 @@ class HomeTimeline extends React.PureComponent { } } - handleDone = e => { - this.props.dispatch(expandHomeTimeline()); - this.setState({ done: true }); - } - handleRefresh = () => { const { dispatch } = this.props; return dispatch(expandHomeTimeline()); } render() { - const { intl, siteTitle, isLoading, loadingFailed, isEmpty, features } = this.props; - const { done } = this.state; - const showSuggestions = features.suggestions && isEmpty && !isLoading && !loadingFailed && !done; + const { intl, siteTitle } = this.props; return ( - - {showSuggestions ? ( - - {Component => } - - ) : ( - }} />} - /> - )} + + }} />} + /> ); } From 131fcef7d63493940a43b1cdc68eba1388f1eda9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 4 Jun 2022 15:51:59 -0500 Subject: [PATCH 3/5] HomeTimeline: convert to TSX --- app/soapbox/features/home_timeline/index.js | 112 ------------------- app/soapbox/features/home_timeline/index.tsx | 71 ++++++++++++ 2 files changed, 71 insertions(+), 112 deletions(-) delete mode 100644 app/soapbox/features/home_timeline/index.js create mode 100644 app/soapbox/features/home_timeline/index.tsx diff --git a/app/soapbox/features/home_timeline/index.js b/app/soapbox/features/home_timeline/index.js deleted file mode 100644 index f93887713..000000000 --- a/app/soapbox/features/home_timeline/index.js +++ /dev/null @@ -1,112 +0,0 @@ -import { OrderedSet as ImmutableOrderedSet } from 'immutable'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; -import { Link } from 'react-router-dom'; - -import { getFeatures } from 'soapbox/utils/features'; - -import { expandHomeTimeline } from '../../actions/timelines'; -import { Column } from '../../components/ui'; -import Timeline from '../ui/components/timeline'; - -const messages = defineMessages({ - title: { id: 'column.home', defaultMessage: 'Home' }, -}); - -const mapStateToProps = state => { - const instance = state.get('instance'); - const features = getFeatures(instance); - - return { - hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0, - isPartial: state.getIn(['timelines', 'home', 'isPartial']), - siteTitle: state.getIn(['instance', 'title']), - isLoading: state.getIn(['timelines', 'home', 'isLoading'], true), - loadingFailed: state.getIn(['timelines', 'home', 'loadingFailed'], false), - isEmpty: state.getIn(['timelines', 'home', 'items'], ImmutableOrderedSet()).isEmpty(), - features, - }; -}; - -export default @connect(mapStateToProps) -@injectIntl -class HomeTimeline extends React.PureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - hasUnread: PropTypes.bool, - isPartial: PropTypes.bool, - siteTitle: PropTypes.string, - isLoading: PropTypes.bool, - loadingFailed: PropTypes.bool, - isEmpty: PropTypes.bool, - features: PropTypes.object.isRequired, - }; - - state = { - done: false, - } - - handleLoadMore = maxId => { - this.props.dispatch(expandHomeTimeline({ maxId })); - } - - componentDidMount() { - this._checkIfReloadNeeded(false, this.props.isPartial); - } - - componentDidUpdate(prevProps) { - this._checkIfReloadNeeded(prevProps.isPartial, this.props.isPartial); - } - - componentWillUnmount() { - this._stopPolling(); - } - - _checkIfReloadNeeded(wasPartial, isPartial) { - const { dispatch } = this.props; - - if (wasPartial === isPartial) { - return; - } else if (!wasPartial && isPartial) { - this.polling = setInterval(() => { - dispatch(expandHomeTimeline()); - }, 3000); - } else if (wasPartial && !isPartial) { - this._stopPolling(); - } - } - - _stopPolling() { - if (this.polling) { - clearInterval(this.polling); - this.polling = null; - } - } - - handleRefresh = () => { - const { dispatch } = this.props; - return dispatch(expandHomeTimeline()); - } - - render() { - const { intl, siteTitle } = this.props; - - return ( - - }} />} - /> - - ); - } - -} diff --git a/app/soapbox/features/home_timeline/index.tsx b/app/soapbox/features/home_timeline/index.tsx new file mode 100644 index 000000000..79cca2b9d --- /dev/null +++ b/app/soapbox/features/home_timeline/index.tsx @@ -0,0 +1,71 @@ +import React, { useEffect, useRef } from 'react'; +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; +import { Link } from 'react-router-dom'; + +import { expandHomeTimeline } from 'soapbox/actions/timelines'; +import { Column } from 'soapbox/components/ui'; +import Timeline from 'soapbox/features/ui/components/timeline'; +import { useAppSelector, useAppDispatch } from 'soapbox/hooks'; + +const messages = defineMessages({ + title: { id: 'column.home', defaultMessage: 'Home' }, +}); + +const HomeTimeline: React.FC = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const polling = useRef(null); + + const isPartial = useAppSelector(state => state.timelines.getIn(['home', 'isPartial']) === true); + const siteTitle = useAppSelector(state => state.instance.title); + + const handleLoadMore = (maxId: string) => { + dispatch(expandHomeTimeline({ maxId })); + }; + + useEffect(() => { + checkIfReloadNeeded(); + + return () => { + stopPolling(); + }; + }, [isPartial]); + + // Mastodon generates the feed in Redis, and can return a partial timeline + // (HTTP 206) for new users. Poll until we get a full page of results. + const checkIfReloadNeeded = () => { + if (isPartial) { + polling.current = setInterval(() => { + dispatch(expandHomeTimeline()); + }, 3000); + } else { + stopPolling(); + } + }; + + const stopPolling = () => { + if (polling.current) { + clearInterval(polling.current); + polling.current = null; + } + }; + + const handleRefresh = () => { + return dispatch(expandHomeTimeline()); + }; + + return ( + + }} />} + /> + + ); +}; + +export default HomeTimeline; From 54b6df719c187170687493b8b467d4cfe1ea78a3 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 4 Jun 2022 15:58:41 -0500 Subject: [PATCH 4/5] Layout: fix compose block spacing --- app/soapbox/components/ui/layout/layout.tsx | 2 +- app/soapbox/pages/home_page.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/soapbox/components/ui/layout/layout.tsx b/app/soapbox/components/ui/layout/layout.tsx index d01abbc1f..59e860406 100644 --- a/app/soapbox/components/ui/layout/layout.tsx +++ b/app/soapbox/components/ui/layout/layout.tsx @@ -30,7 +30,7 @@ const Sidebar: React.FC = ({ children }) => ( const Main: React.FC> = ({ children, className }) => (
{children} diff --git a/app/soapbox/pages/home_page.tsx b/app/soapbox/pages/home_page.tsx index c1e0b433e..20f13817d 100644 --- a/app/soapbox/pages/home_page.tsx +++ b/app/soapbox/pages/home_page.tsx @@ -36,7 +36,7 @@ const HomePage: React.FC = ({ children }) => { return ( <> - + {me && ( From e54d666b90196ce037f903b3863ca525feb023cc Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 6 Jun 2022 13:43:38 -0500 Subject: [PATCH 5/5] HomeTimeline: move useEffect above return --- app/soapbox/features/home_timeline/index.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/soapbox/features/home_timeline/index.tsx b/app/soapbox/features/home_timeline/index.tsx index 79cca2b9d..99ed0d569 100644 --- a/app/soapbox/features/home_timeline/index.tsx +++ b/app/soapbox/features/home_timeline/index.tsx @@ -23,14 +23,6 @@ const HomeTimeline: React.FC = () => { dispatch(expandHomeTimeline({ maxId })); }; - useEffect(() => { - checkIfReloadNeeded(); - - return () => { - stopPolling(); - }; - }, [isPartial]); - // Mastodon generates the feed in Redis, and can return a partial timeline // (HTTP 206) for new users. Poll until we get a full page of results. const checkIfReloadNeeded = () => { @@ -54,6 +46,14 @@ const HomeTimeline: React.FC = () => { return dispatch(expandHomeTimeline()); }; + useEffect(() => { + checkIfReloadNeeded(); + + return () => { + stopPolling(); + }; + }, [isPartial]); + return (