From fb3b88b80b617d002fa918cc85cf371e3167def6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 10 Apr 2022 10:20:12 +0200 Subject: [PATCH 1/6] reply mentions modalto tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../containers/reply_mentions_container.js | 2 +- .../features/ui/components/reactions_modal.js | 130 ------------------ .../ui/components/reactions_modal.tsx | 110 +++++++++++++++ .../ui/components/reply_mentions_modal.js | 85 ------------ .../ui/components/reply_mentions_modal.tsx | 40 ++++++ app/soapbox/reducers/compose.js | 2 +- 6 files changed, 152 insertions(+), 217 deletions(-) delete mode 100644 app/soapbox/features/ui/components/reactions_modal.js create mode 100644 app/soapbox/features/ui/components/reactions_modal.tsx delete mode 100644 app/soapbox/features/ui/components/reply_mentions_modal.js create mode 100644 app/soapbox/features/ui/components/reply_mentions_modal.tsx diff --git a/app/soapbox/features/compose/containers/reply_mentions_container.js b/app/soapbox/features/compose/containers/reply_mentions_container.js index ced480967..c888ae48a 100644 --- a/app/soapbox/features/compose/containers/reply_mentions_container.js +++ b/app/soapbox/features/compose/containers/reply_mentions_container.js @@ -32,7 +32,7 @@ const makeMapStateToProps = () => { const me = state.get('me'); const account = state.getIn(['accounts', me]); - const parentTo = statusToMentionsAccountIdsArray(state, status, account); + const parentTo = statusToMentionsAccountIdsArray(status, account); return { to, diff --git a/app/soapbox/features/ui/components/reactions_modal.js b/app/soapbox/features/ui/components/reactions_modal.js deleted file mode 100644 index 36f79ea66..000000000 --- a/app/soapbox/features/ui/components/reactions_modal.js +++ /dev/null @@ -1,130 +0,0 @@ -import { List as ImmutableList } from 'immutable'; -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { injectIntl, FormattedMessage, defineMessages } from 'react-intl'; -import { connect } from 'react-redux'; - -import { fetchFavourites, fetchReactions } from 'soapbox/actions/interactions'; -import FilterBar from 'soapbox/components/filter_bar'; -import ScrollableList from 'soapbox/components/scrollable_list'; -import { Modal, Spinner } from 'soapbox/components/ui'; -import AccountContainer from 'soapbox/containers/account_container'; - -const messages = defineMessages({ - close: { id: 'lightbox.close', defaultMessage: 'Close' }, - all: { id: 'reactions.all', defaultMessage: 'All' }, -}); - -const mapStateToProps = (state, props) => { - - const favourites = state.getIn(['user_lists', 'favourited_by', props.statusId]); - const reactions = state.getIn(['user_lists', 'reactions', props.statusId]); - const allReactions = favourites && reactions && ImmutableList(favourites ? [{ accounts: favourites, count: favourites.size, name: '👍' }] : []).concat(reactions || []); - - return { - reactions: allReactions, - }; -}; - -export default @connect(mapStateToProps) -@injectIntl -class ReactionsModal extends React.PureComponent { - - static propTypes = { - onClose: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - statusId: PropTypes.string.isRequired, - username: PropTypes.string.isRequired, - reaction: PropTypes.string, - dispatch: PropTypes.func.isRequired, - reactions: ImmutablePropTypes.list, - }; - - state = { - reaction: this.props.reaction, - } - - fetchData = () => { - const { dispatch, statusId } = this.props; - - dispatch(fetchFavourites(statusId)); - dispatch(fetchReactions(statusId)); - } - - componentDidMount() { - this.fetchData(); - } - - onClickClose = () => { - this.props.onClose('REACTIONS'); - }; - - handleFilterChange = (reaction) => () => { - this.setState({ reaction }); - }; - - renderFilterBar() { - const { intl, reactions } = this.props; - const { reaction } = this.state; - - const items = [ - { - text: intl.formatMessage(messages.all), - action: this.handleFilterChange(''), - name: 'all', - }, - ]; - - reactions.forEach(reaction => items.push( - { - text: `${reaction.name} ${reaction.count}`, - action: this.handleFilterChange(reaction.name), - name: reaction.name, - }, - )); - - return ; - } - - render() { - const { reactions } = this.props; - const { reaction } = this.state; - - const accounts = reactions && (reaction - ? reactions.find(reaction => reaction.name === this.state.reaction)?.accounts.map(account => ({ id: account, reaction: this.state.reaction })) - : reactions.map(reaction => reaction?.accounts.map(account => ({ id: account, reaction: reaction.name }))).flatten()); - - let body; - - if (!accounts) { - body = ; - } else { - const emptyMessage = ; - - body = (<> - {reactions.size > 0 && this.renderFilterBar()} - - {accounts.map((account) => - , - )} - - ); - } - - - return ( - } - onClose={this.onClickClose} - > - {body} - - ); - } - -} diff --git a/app/soapbox/features/ui/components/reactions_modal.tsx b/app/soapbox/features/ui/components/reactions_modal.tsx new file mode 100644 index 000000000..72f5eddc9 --- /dev/null +++ b/app/soapbox/features/ui/components/reactions_modal.tsx @@ -0,0 +1,110 @@ +import { List as ImmutableList } from 'immutable'; +import React from 'react'; +import { useEffect } from 'react'; +import { useState } from 'react'; +import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; +import { useDispatch } from 'react-redux'; + +import { fetchFavourites, fetchReactions } from 'soapbox/actions/interactions'; +import FilterBar from 'soapbox/components/filter_bar'; +import ScrollableList from 'soapbox/components/scrollable_list'; +import { Modal, Spinner } from 'soapbox/components/ui'; +import AccountContainer from 'soapbox/containers/account_container'; +import { useAppSelector } from 'soapbox/hooks'; + +const messages = defineMessages({ + close: { id: 'lightbox.close', defaultMessage: 'Close' }, + all: { id: 'reactions.all', defaultMessage: 'All' }, +}); + +interface IReactionsModal { + onClose: (string: string) => void, + statusId: string, + username: string, + reaction?: string, +} + +const ReactionsModal: React.FC = ({ onClose, statusId, ...props }) => { + const dispatch = useDispatch(); + const intl = useIntl(); + const [reaction, setReaction] = useState(props.reaction); + const reactions = useAppSelector, + count: number, + name: string, + }>>((state) => { + const favourites = state.user_lists.getIn(['favourited_by', statusId]); + const reactions = state.user_lists.getIn(['reactions', statusId]); + return favourites && reactions && ImmutableList(favourites ? [{ accounts: favourites, count: favourites.size, name: '👍' }] : []).concat(reactions || []); + }); + + const fetchData = () => { + dispatch(fetchFavourites(statusId)); + dispatch(fetchReactions(statusId)); + }; + + const onClickClose = () => { + onClose('REACTIONS'); + }; + + const renderFilterBar = () => { + const items = [ + { + text: intl.formatMessage(messages.all), + action: () => setReaction(''), + name: 'all', + }, + ]; + + reactions.forEach(reaction => items.push( + { + text: `${reaction.name} ${reaction.count}`, + action: () => setReaction(reaction.name), + name: reaction.name, + }, + )); + + return ; + }; + + useEffect(() => { + fetchData(); + }, []); + + const accounts = reactions && (reaction + ? reactions.find(({ name }) => name === reaction)?.accounts.map(account => ({ id: account, reaction: reaction })) + : reactions.map(({ accounts, name }) => accounts.map(account => ({ id: account, reaction: name }))).flat()); + + let body; + + if (!accounts) { + body = ; + } else { + const emptyMessage = ; + + body = (<> + {reactions.length > 0 && renderFilterBar()} + + {accounts.map((account) => + , + )} + + ); + } + + + return ( + } + onClose={onClickClose} + > + {body} + + ); +}; + +export default ReactionsModal; diff --git a/app/soapbox/features/ui/components/reply_mentions_modal.js b/app/soapbox/features/ui/components/reply_mentions_modal.js deleted file mode 100644 index 3685b0a51..000000000 --- a/app/soapbox/features/ui/components/reply_mentions_modal.js +++ /dev/null @@ -1,85 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; - -import IconButton from 'soapbox/components/icon_button'; -import { statusToMentionsAccountIdsArray } from 'soapbox/reducers/compose'; -import { makeGetStatus } from 'soapbox/selectors'; - -import Account from '../../reply_mentions/account'; - -const messages = defineMessages({ - close: { id: 'lightbox.close', defaultMessage: 'Close' }, - confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, -}); - -const makeMapStateToProps = () => { - const getStatus = makeGetStatus(); - - return state => { - const status = getStatus(state, { id: state.getIn(['compose', 'in_reply_to']) }); - - if (!status) { - return { - isReply: false, - }; - } - - const me = state.get('me'); - const account = state.getIn(['accounts', me]); - - const mentions = statusToMentionsAccountIdsArray(state, status, account); - - return { - mentions, - author: status.getIn(['account', 'id']), - isReply: true, - }; - }; -}; - -class ReplyMentionsModal extends ImmutablePureComponent { - - static propTypes = { - mentions: ImmutablePropTypes.OrderedSet, - author: PropTypes.string, - intl: PropTypes.object.isRequired, - onClose: PropTypes.func.isRequired, - dispatch: PropTypes.func.isRequired, - }; - - onClickClose = () => { - const { onClose } = this.props; - onClose('REPLY_MENTIONS'); - }; - - render() { - const { intl, mentions, author } = this.props; - - return ( -
-
- -

- -

-
-
- {mentions.map(accountId => )} -
-
- ); - } - -} - -export default injectIntl(connect(makeMapStateToProps)(ReplyMentionsModal)); diff --git a/app/soapbox/features/ui/components/reply_mentions_modal.tsx b/app/soapbox/features/ui/components/reply_mentions_modal.tsx new file mode 100644 index 000000000..996aeee15 --- /dev/null +++ b/app/soapbox/features/ui/components/reply_mentions_modal.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { Modal } from 'soapbox/components/ui'; +import { useAppSelector } from 'soapbox/hooks'; +import { statusToMentionsAccountIdsArray } from 'soapbox/reducers/compose'; +import { makeGetStatus } from 'soapbox/selectors'; + +import Account from '../../reply_mentions/account'; + +import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities'; + +interface IReplyMentionsModal { + onClose: (string: string) => void, +} + +const ReplyMentionsModal: React.FC = ({ onClose }) => { + const status = useAppSelector(state => makeGetStatus()(state, { id: state.compose.get('in_reply_to') })); + const account = useAppSelector((state) => state.accounts.get(state.me)); + + const mentions = statusToMentionsAccountIdsArray(status, account); + const author = (status?.account as AccountEntity).id; + + const onClickClose = () => { + onClose('REPLY_MENTIONS'); + }; + + return ( + } + onClose={onClickClose} + > +
+ {mentions.map(accountId => )} +
+
+ ); +}; + +export default ReplyMentionsModal; diff --git a/app/soapbox/reducers/compose.js b/app/soapbox/reducers/compose.js index c5e03f54e..010a59f08 100644 --- a/app/soapbox/reducers/compose.js +++ b/app/soapbox/reducers/compose.js @@ -113,7 +113,7 @@ export const statusToMentionsArray = (status, account) => { .delete(account.get('acct')); }; -export const statusToMentionsAccountIdsArray = (state, status, account) => { +export const statusToMentionsAccountIdsArray = (status, account) => { const author = status.getIn(['account', 'id']); const mentions = status.get('mentions', []).map(m => m.get('id')); From 7d2a62b1817b579d9de940caee043d877dc59e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 10 Apr 2022 10:48:56 +0200 Subject: [PATCH 2/6] ReplyMentions component to ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/media_gallery.js | 2 +- app/soapbox/components/status.tsx | 2 +- .../compose/components/reply_mentions.js | 56 ---------------- .../compose/components/reply_mentions.tsx | 64 +++++++++++++++++++ 4 files changed, 66 insertions(+), 58 deletions(-) delete mode 100644 app/soapbox/features/compose/components/reply_mentions.js create mode 100644 app/soapbox/features/compose/components/reply_mentions.tsx diff --git a/app/soapbox/components/media_gallery.js b/app/soapbox/components/media_gallery.js index 42feafa02..af2a35797 100644 --- a/app/soapbox/components/media_gallery.js +++ b/app/soapbox/components/media_gallery.js @@ -602,7 +602,7 @@ class MediaGallery extends React.PureComponent { /> ) : (