2022-02-23 20:03:46 +01:00
import PropTypes from 'prop-types' ;
2023-07-10 18:26:56 +02:00
import { useCallback , useEffect , useRef } from 'react' ;
2023-05-23 17:15:17 +02:00
2023-07-10 18:26:56 +02:00
import { useIntl , defineMessages , FormattedMessage } from 'react-intl' ;
import { OrderedSet , List as ImmutableList } from 'immutable' ;
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import { shallowEqual } from 'react-redux' ;
import { createSelector } from 'reselect' ;
2023-05-23 17:15:17 +02:00
2022-02-23 20:03:46 +01:00
import Toggle from 'react-toggle' ;
2023-07-10 18:26:56 +02:00
import { fetchAccount } from 'mastodon/actions/accounts' ;
2023-05-23 17:15:17 +02:00
import Button from 'mastodon/components/button' ;
2023-07-10 18:26:56 +02:00
import { useAppDispatch , useAppSelector } from 'mastodon/store' ;
2023-05-23 17:15:17 +02:00
2022-02-23 20:03:46 +01:00
const messages = defineMessages ( {
placeholder : { id : 'report.placeholder' , defaultMessage : 'Type or paste additional comments' } ,
} ) ;
2023-07-10 18:26:56 +02:00
const selectRepliedToAccountIds = createSelector (
[
( state ) => state . get ( 'statuses' ) ,
( _ , statusIds ) => statusIds ,
] ,
( statusesMap , statusIds ) => statusIds . map ( ( statusId ) => statusesMap . getIn ( [ statusId , 'in_reply_to_account_id' ] ) ) ,
{
resultEqualityCheck : shallowEqual ,
}
) ;
const Comment = ( { comment , domain , statusIds , isRemote , isSubmitting , selectedDomains , onSubmit , onChangeComment , onToggleDomain } ) => {
const intl = useIntl ( ) ;
const dispatch = useAppDispatch ( ) ;
const loadedRef = useRef ( false ) ;
const handleClick = useCallback ( ( ) => onSubmit ( ) , [ onSubmit ] ) ;
const handleChange = useCallback ( ( e ) => onChangeComment ( e . target . value ) , [ onChangeComment ] ) ;
const handleToggleDomain = useCallback ( e => onToggleDomain ( e . target . value , e . target . checked ) , [ onToggleDomain ] ) ;
const handleKeyDown = useCallback ( ( e ) => {
2022-02-23 20:03:46 +01:00
if ( e . keyCode === 13 && ( e . ctrlKey || e . metaKey ) ) {
2023-07-10 18:26:56 +02:00
handleClick ( ) ;
2022-02-23 20:03:46 +01:00
}
2023-07-10 18:26:56 +02:00
} , [ handleClick ] ) ;
// Memoize accountIds since we don't want it to trigger `useEffect` on each render
const accountIds = useAppSelector ( ( state ) => domain ? selectRepliedToAccountIds ( state , statusIds ) : ImmutableList ( ) ) ;
// While we could memoize `availableDomains`, it is pretty inexpensive to recompute
const accountsMap = useAppSelector ( ( state ) => state . get ( 'accounts' ) ) ;
const availableDomains = domain ? OrderedSet ( [ domain ] ) . union ( accountIds . map ( ( accountId ) => accountsMap . getIn ( [ accountId , 'acct' ] , '' ) . split ( '@' ) [ 1 ] ) . filter ( domain => ! ! domain ) ) : OrderedSet ( ) ;
useEffect ( ( ) => {
if ( loadedRef . current ) {
return ;
}
loadedRef . current = true ;
// First, pre-select known domains
availableDomains . forEach ( ( domain ) => {
onToggleDomain ( domain , true ) ;
} ) ;
// Then, fetch missing replied-to accounts
const unknownAccounts = OrderedSet ( accountIds . filter ( accountId => accountId && ! accountsMap . has ( accountId ) ) ) ;
unknownAccounts . forEach ( ( accountId ) => {
dispatch ( fetchAccount ( accountId ) ) ;
} ) ;
} ) ;
return (
< >
< h3 className = 'report-dialog-modal__title' > < FormattedMessage id = 'report.comment.title' defaultMessage = 'Is there anything else you think we should know?' / > < / h3 >
< textarea
className = 'report-dialog-modal__textarea'
placeholder = { intl . formatMessage ( messages . placeholder ) }
value = { comment }
onChange = { handleChange }
onKeyDown = { handleKeyDown }
disabled = { isSubmitting }
/ >
{ isRemote && (
< >
< p className = 'report-dialog-modal__lead' > < FormattedMessage id = 'report.forward_hint' defaultMessage = 'The account is from another server. Send an anonymized copy of the report there as well?' / > < / p >
{ availableDomains . map ( ( domain ) => (
< label className = 'report-dialog-modal__toggle' key = { ` toggle- ${ domain } ` } >
< Toggle checked = { selectedDomains . includes ( domain ) } disabled = { isSubmitting } onChange = { handleToggleDomain } value = { domain } / >
2022-02-23 20:03:46 +01:00
< FormattedMessage id = 'report.forward' defaultMessage = 'Forward to {target}' values = { { target : domain } } / >
< / label >
2023-07-10 18:26:56 +02:00
) ) }
< / >
) }
2022-02-23 20:03:46 +01:00
2023-07-10 18:26:56 +02:00
< div className = 'flex-spacer' / >
2022-02-23 20:03:46 +01:00
2023-07-10 18:26:56 +02:00
< div className = 'report-dialog-modal__actions' >
< Button onClick = { handleClick } disabled = { isSubmitting } > < FormattedMessage id = 'report.submit' defaultMessage = 'Submit report' / > < / Button >
< / div >
< / >
) ;
2022-02-23 20:03:46 +01:00
}
2023-03-24 03:17:53 +01:00
2023-07-10 18:26:56 +02:00
Comment . propTypes = {
comment : PropTypes . string . isRequired ,
domain : PropTypes . string ,
statusIds : ImmutablePropTypes . list . isRequired ,
isRemote : PropTypes . bool ,
isSubmitting : PropTypes . bool ,
selectedDomains : ImmutablePropTypes . set . isRequired ,
onSubmit : PropTypes . func . isRequired ,
onChangeComment : PropTypes . func . isRequired ,
onToggleDomain : PropTypes . func . isRequired ,
} ;
export default Comment ;