2020-09-28 20:29:43 +09:00
import PropTypes from 'prop-types' ;
2023-05-24 00:15:17 +09:00
2020-09-28 20:29:43 +09:00
import { defineMessages , injectIntl } from 'react-intl' ;
2023-05-24 00:15:17 +09:00
import classNames from 'classnames' ;
2023-10-20 02:44:55 +09:00
import { withRouter } from 'react-router-dom' ;
2023-05-24 00:15:17 +09:00
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import ImmutablePureComponent from 'react-immutable-pure-component' ;
import { connect } from 'react-redux' ;
2024-01-16 19:27:26 +09:00
import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react' ;
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react' ;
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react' ;
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react' ;
import StarIcon from '@/material-icons/400-24px/star.svg?react' ;
2020-09-28 20:29:43 +09:00
import { replyCompose } from 'mastodon/actions/compose' ;
import { reblog , favourite , unreblog , unfavourite } from 'mastodon/actions/interactions' ;
import { openModal } from 'mastodon/actions/modal' ;
2023-05-24 00:15:17 +09:00
import { IconButton } from 'mastodon/components/icon_button' ;
2024-05-20 02:07:32 +09:00
import { identityContextPropShape , withIdentity } from 'mastodon/identity_context' ;
2023-05-24 00:15:17 +09:00
import { me , boostModal } from 'mastodon/initial_state' ;
import { makeGetStatus } from 'mastodon/selectors' ;
2023-10-20 02:44:55 +09:00
import { WithRouterPropTypes } from 'mastodon/utils/react_router' ;
2020-09-28 20:29:43 +09:00
const messages = defineMessages ( {
reply : { id : 'status.reply' , defaultMessage : 'Reply' } ,
replyAll : { id : 'status.replyAll' , defaultMessage : 'Reply to thread' } ,
reblog : { id : 'status.reblog' , defaultMessage : 'Boost' } ,
reblog _private : { id : 'status.reblog_private' , defaultMessage : 'Boost with original visibility' } ,
cancel _reblog _private : { id : 'status.cancel_reblog_private' , defaultMessage : 'Unboost' } ,
cannot _reblog : { id : 'status.cannot_reblog' , defaultMessage : 'This post cannot be boosted' } ,
2023-07-22 02:09:13 +09:00
favourite : { id : 'status.favourite' , defaultMessage : 'Favorite' } ,
2020-09-28 20:29:43 +09:00
replyConfirm : { id : 'confirmations.reply.confirm' , defaultMessage : 'Reply' } ,
replyMessage : { id : 'confirmations.reply.message' , defaultMessage : 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' } ,
2020-11-27 11:24:11 +09:00
open : { id : 'status.open' , defaultMessage : 'Expand this status' } ,
2020-09-28 20:29:43 +09:00
} ) ;
const makeMapStateToProps = ( ) => {
const getStatus = makeGetStatus ( ) ;
const mapStateToProps = ( state , { statusId } ) => ( {
status : getStatus ( state , { id : statusId } ) ,
askReplyConfirmation : state . getIn ( [ 'compose' , 'text' ] ) . trim ( ) . length !== 0 ,
} ) ;
return mapStateToProps ;
} ;
class Footer extends ImmutablePureComponent {
static propTypes = {
2024-05-20 02:07:32 +09:00
identity : identityContextPropShape ,
2020-09-28 20:29:43 +09:00
statusId : PropTypes . string . isRequired ,
status : ImmutablePropTypes . map . isRequired ,
intl : PropTypes . object . isRequired ,
dispatch : PropTypes . func . isRequired ,
askReplyConfirmation : PropTypes . bool ,
2020-11-27 11:24:11 +09:00
withOpenButton : PropTypes . bool ,
onClose : PropTypes . func ,
2023-10-20 02:44:55 +09:00
... WithRouterPropTypes ,
2020-09-28 20:29:43 +09:00
} ;
_performReply = ( ) => {
2023-10-20 02:44:55 +09:00
const { dispatch , status , onClose , history } = this . props ;
2020-11-27 11:24:11 +09:00
if ( onClose ) {
2022-02-25 08:51:01 +09:00
onClose ( true ) ;
2020-11-27 11:24:11 +09:00
}
2023-10-20 02:44:55 +09:00
dispatch ( replyCompose ( status , history ) ) ;
2020-09-28 20:29:43 +09:00
} ;
handleReplyClick = ( ) => {
2022-10-07 17:14:31 +09:00
const { dispatch , askReplyConfirmation , status , intl } = this . props ;
2024-05-20 02:07:32 +09:00
const { signedIn } = this . props . identity ;
2022-10-07 17:14:31 +09:00
if ( signedIn ) {
if ( askReplyConfirmation ) {
2023-05-25 22:42:37 +09:00
dispatch ( openModal ( {
modalType : 'CONFIRM' ,
modalProps : {
message : intl . formatMessage ( messages . replyMessage ) ,
confirm : intl . formatMessage ( messages . replyConfirm ) ,
onConfirm : this . _performReply ,
} ,
2022-10-07 17:14:31 +09:00
} ) ) ;
} else {
this . _performReply ( ) ;
}
2020-09-28 20:29:43 +09:00
} else {
2023-05-25 22:42:37 +09:00
dispatch ( openModal ( {
modalType : 'INTERACTION' ,
modalProps : {
type : 'reply' ,
accountId : status . getIn ( [ 'account' , 'id' ] ) ,
2023-07-27 23:11:17 +09:00
url : status . get ( 'uri' ) ,
2023-05-25 22:42:37 +09:00
} ,
2022-10-07 17:14:31 +09:00
} ) ) ;
2020-09-28 20:29:43 +09:00
}
} ;
handleFavouriteClick = ( ) => {
const { dispatch , status } = this . props ;
2024-05-20 02:07:32 +09:00
const { signedIn } = this . props . identity ;
2022-10-07 17:14:31 +09:00
if ( signedIn ) {
if ( status . get ( 'favourited' ) ) {
dispatch ( unfavourite ( status ) ) ;
} else {
dispatch ( favourite ( status ) ) ;
}
2020-09-28 20:29:43 +09:00
} else {
2023-05-25 22:42:37 +09:00
dispatch ( openModal ( {
modalType : 'INTERACTION' ,
modalProps : {
type : 'favourite' ,
accountId : status . getIn ( [ 'account' , 'id' ] ) ,
2023-07-27 23:11:17 +09:00
url : status . get ( 'uri' ) ,
2023-05-25 22:42:37 +09:00
} ,
2022-10-07 17:14:31 +09:00
} ) ) ;
2020-09-28 20:29:43 +09:00
}
} ;
2021-02-11 08:53:12 +09:00
_performReblog = ( status , privacy ) => {
const { dispatch } = this . props ;
2024-05-23 18:50:13 +09:00
dispatch ( reblog ( status . id , privacy ) ) ;
2023-01-30 09:45:35 +09:00
} ;
2020-09-28 20:29:43 +09:00
handleReblogClick = e => {
const { dispatch , status } = this . props ;
2024-05-20 02:07:32 +09:00
const { signedIn } = this . props . identity ;
2022-10-07 17:14:31 +09:00
if ( signedIn ) {
if ( status . get ( 'reblogged' ) ) {
2024-05-23 18:50:13 +09:00
dispatch ( unreblog ( status . id ) ) ;
2022-10-07 17:14:31 +09:00
} else if ( ( e && e . shiftKey ) || ! boostModal ) {
this . _performReblog ( status ) ;
} else {
2024-03-29 00:33:15 +09:00
dispatch ( openModal ( { modalType : 'BOOST' , modalProps : { status , onReblog : this . _performReblog } } ) ) ;
2022-10-07 17:14:31 +09:00
}
2020-09-28 20:29:43 +09:00
} else {
2023-05-25 22:42:37 +09:00
dispatch ( openModal ( {
modalType : 'INTERACTION' ,
modalProps : {
type : 'reblog' ,
accountId : status . getIn ( [ 'account' , 'id' ] ) ,
2023-07-27 23:11:17 +09:00
url : status . get ( 'uri' ) ,
2023-05-25 22:42:37 +09:00
} ,
2022-10-07 17:14:31 +09:00
} ) ) ;
2020-09-28 20:29:43 +09:00
}
} ;
2020-11-27 11:24:11 +09:00
handleOpenClick = e => {
2023-10-20 02:44:55 +09:00
if ( e . button !== 0 || ! history ) {
2020-11-27 11:24:11 +09:00
return ;
}
2021-07-25 08:13:46 +09:00
const { status , onClose } = this . props ;
if ( onClose ) {
onClose ( ) ;
}
2020-11-27 11:24:11 +09:00
2023-11-15 18:29:10 +09:00
this . props . history . push ( ` /@ ${ status . getIn ( [ 'account' , 'acct' ] ) } / ${ status . get ( 'id' ) } ` ) ;
2023-01-30 09:45:35 +09:00
} ;
2020-11-27 11:24:11 +09:00
2020-09-28 20:29:43 +09:00
render ( ) {
2020-11-27 11:24:11 +09:00
const { status , intl , withOpenButton } = this . props ;
2020-09-28 20:29:43 +09:00
const publicStatus = [ 'public' , 'unlisted' ] . includes ( status . get ( 'visibility' ) ) ;
const reblogPrivate = status . getIn ( [ 'account' , 'id' ] ) === me && status . get ( 'visibility' ) === 'private' ;
2023-10-25 02:45:08 +09:00
let replyIcon , replyIconComponent , replyTitle ;
2020-09-28 20:29:43 +09:00
if ( status . get ( 'in_reply_to_id' , null ) === null ) {
replyIcon = 'reply' ;
2023-12-29 18:48:27 +09:00
replyIconComponent = ReplyIcon ;
2020-09-28 20:29:43 +09:00
replyTitle = intl . formatMessage ( messages . reply ) ;
} else {
replyIcon = 'reply-all' ;
2023-10-25 02:45:08 +09:00
replyIconComponent = ReplyAllIcon ;
2020-09-28 20:29:43 +09:00
replyTitle = intl . formatMessage ( messages . replyAll ) ;
}
let reblogTitle = '' ;
if ( status . get ( 'reblogged' ) ) {
reblogTitle = intl . formatMessage ( messages . cancel _reblog _private ) ;
} else if ( publicStatus ) {
reblogTitle = intl . formatMessage ( messages . reblog ) ;
} else if ( reblogPrivate ) {
reblogTitle = intl . formatMessage ( messages . reblog _private ) ;
} else {
reblogTitle = intl . formatMessage ( messages . cannot _reblog ) ;
}
return (
< div className = 'picture-in-picture__footer' >
2023-10-25 02:45:08 +09:00
< IconButton className = 'status__action-bar-button' title = { replyTitle } icon = { status . get ( 'in_reply_to_account_id' ) === status . getIn ( [ 'account' , 'id' ] ) ? 'reply' : replyIcon } iconComponent = { status . get ( 'in_reply_to_account_id' ) === status . getIn ( [ 'account' , 'id' ] ) ? ReplyIcon : replyIconComponent } onClick = { this . handleReplyClick } counter = { status . get ( 'replies_count' ) } / >
< IconButton className = { classNames ( 'status__action-bar-button' , { reblogPrivate } ) } disabled = { ! publicStatus && ! reblogPrivate } active = { status . get ( 'reblogged' ) } title = { reblogTitle } icon = 'retweet' iconComponent = { RepeatIcon } onClick = { this . handleReblogClick } counter = { status . get ( 'reblogs_count' ) } / >
< IconButton className = 'status__action-bar-button star-icon' animate active = { status . get ( 'favourited' ) } title = { intl . formatMessage ( messages . favourite ) } icon = 'star' iconComponent = { StarIcon } onClick = { this . handleFavouriteClick } counter = { status . get ( 'favourites_count' ) } / >
{ withOpenButton && < IconButton className = 'status__action-bar-button' title = { intl . formatMessage ( messages . open ) } icon = 'external-link' iconComponent = { OpenInNewIcon } onClick = { this . handleOpenClick } href = { ` /@ ${ status . getIn ( [ 'account' , 'acct' ] ) } / ${ status . get ( 'id' ) } ` } / > }
2020-09-28 20:29:43 +09:00
< / div >
) ;
}
}
2023-03-24 11:17:53 +09:00
2024-05-20 02:07:32 +09:00
export default connect ( makeMapStateToProps ) ( withIdentity ( withRouter ( injectIntl ( Footer ) ) ) ) ;