@ -1,53 +1,75 @@
import PropTypes from 'prop-types' ;
import { PureComponent } from 'react' ;
import { useCallback, useEffect , useRef } from 'react' ;
import { injectIntl , defineMessages , FormattedMessage } from 'react-intl' ;
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' ;
import Toggle from 'react-toggle' ;
import { fetchAccount } from 'mastodon/actions/accounts' ;
import Button from 'mastodon/components/button' ;
import { useAppDispatch , useAppSelector } from 'mastodon/store' ;
const messages = defineMessages ( {
placeholder : { id : 'report.placeholder' , defaultMessage : 'Type or paste additional comments' } ,
} ) ;
class Comment extends PureComponent {
const selectRepliedToAccountIds = createSelector (
[
( state ) => state . get ( 'statuses' ) ,
( _ , statusIds ) => statusIds ,
] ,
( statusesMap , statusIds ) => statusIds . map ( ( statusId ) => statusesMap . getIn ( [ statusId , 'in_reply_to_account_id' ] ) ) ,
{
resultEqualityCheck : shallowEqual ,
}
) ;
static propTypes = {
onSubmit : PropTypes . func . isRequired ,
comment : PropTypes . string . isRequired ,
onChangeComment : PropTypes . func . isRequired ,
intl : PropTypes . object . isRequired ,
isSubmitting : PropTypes . bool ,
forward : PropTypes . bool ,
isRemote : PropTypes . bool ,
domain : PropTypes . string ,
onChangeForward : PropTypes . func . isRequired ,
} ;
const Comment = ( { comment , domain , statusIds , isRemote , isSubmitting , selectedDomains , onSubmit , onChangeComment , onToggleDomain } ) => {
const intl = useIntl ( ) ;
handleClick = ( ) => {
const { onSubmit } = this . props ;
onSubmit ( ) ;
} ;
const dispatch = useAppDispatch ( ) ;
const loadedRef = useRef ( false ) ;
handleChange = e => {
const { onChangeComment } = this . props ;
onChangeComment ( e . target . value ) ;
} ;
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 ] ) ;
handleKeyDown = e => {
const handleKeyDown = useCallback ( ( e ) => {
if ( e . keyCode === 13 && ( e . ctrlKey || e . metaKey ) ) {
this . handleClick ( ) ;
handleClick ( ) ;
}
} ;
} , [ handleClick ] ) ;
handleForwardChange = e => {
const { onChangeForward } = this . props ;
onChangeForward ( e . target . checked ) ;
} ;
/ / M e m o i z e a c c o u n t I d s s i n c e w e d o n ' t w a n t i t t o t r i g g e r ` u s e E f f e c t ` o n e a c h r e n d e r
const accountIds = useAppSelector ( ( state ) => domain ? selectRepliedToAccountIds ( state , statusIds ) : ImmutableList ( ) ) ;
/ / W h i l e w e c o u l d m e m o i z e ` a v a i l a b l e D o m a i n s ` , i t i s p r e t t y i n e x p e n s i v e t o r e c o m p u t e
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 ( ) ;
render ( ) {
const { comment , isRemote , forward , domain , isSubmitting , intl } = this . props ;
useEffect ( ( ) => {
if ( loadedRef . current ) {
return ;
}
loadedRef . current = true ;
/ / F i r s t , p r e - s e l e c t k n o w n d o m a i n s
availableDomains . forEach ( ( domain ) => {
onToggleDomain ( domain , true ) ;
} ) ;
/ / T h e n , f e t c h m i s s i n g r e p l i e d - t o a c c o u n t s
const unknownAccounts = OrderedSet ( accountIds . filter ( accountId => accountId && ! accountsMap . has ( accountId ) ) ) ;
unknownAccounts . forEach ( ( accountId ) => {
dispatch ( fetchAccount ( accountId ) ) ;
} ) ;
} ) ;
return (
< >
@ -57,8 +79,8 @@ class Comment extends PureComponent {
className = 'report-dialog-modal__textarea'
placeholder = { intl . formatMessage ( messages . placeholder ) }
value = { comment }
onChange = { this . handleChange }
onKeyDown = { this . handleKeyDown }
onChange = { handleChange }
onKeyDown = { handleKeyDown }
disabled = { isSubmitting }
/ >
@ -66,22 +88,34 @@ class Comment extends PureComponent {
< >
< 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 >
< label className = 'report-dialog-modal__toggle' >
< Toggle checked = { forward } disabled = { isSubmitting } onChange = { this . handleForwardChange } / >
{ availableDomains . map ( ( domain ) => (
< label className = 'report-dialog-modal__toggle' key = { ` toggle- ${ domain } ` } >
< Toggle checked = { selectedDomains . includes ( domain ) } disabled = { isSubmitting } onChange = { handleToggleDomain } value = { domain } / >
< FormattedMessage id = 'report.forward' defaultMessage = 'Forward to {target}' values = { { target : domain } } / >
< / label >
) ) }
< / >
) }
< div className = 'flex-spacer' / >
< div className = 'report-dialog-modal__actions' >
< Button onClick = { this . handleClick } disabled = { isSubmitting } > < FormattedMessage id = 'report.submit' defaultMessage = 'Submit report' / > < / Button >
< Button onClick = { handleClick } disabled = { isSubmitting } > < FormattedMessage id = 'report.submit' defaultMessage = 'Submit report' / > < / Button >
< / div >
< / >
) ;
}
}
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 injectIntl ( Comment ) ;
export default Comment;