2020-03-27 13:59:38 -07:00
import React from 'react' ;
import { connect } from 'react-redux' ;
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import PropTypes from 'prop-types' ;
import { fetchAccount , fetchAccountByUsername } from '../../actions/accounts' ;
import { expandAccountFeaturedTimeline , expandAccountTimeline } from '../../actions/timelines' ;
2021-08-11 13:49:57 -07:00
import Icon from 'soapbox/components/icon' ;
2020-03-27 13:59:38 -07:00
import StatusList from '../../components/status_list' ;
import LoadingIndicator from '../../components/loading_indicator' ;
import Column from '../ui/components/column' ;
2021-08-11 13:49:57 -07:00
import ColumnSettingsContainer from './containers/column_settings_container' ;
2021-07-08 12:52:07 -07:00
import { OrderedSet as ImmutableOrderedSet } from 'immutable' ;
2020-03-27 13:59:38 -07:00
import ImmutablePureComponent from 'react-immutable-pure-component' ;
import { FormattedMessage } from 'react-intl' ;
import { fetchAccountIdentityProofs } from '../../actions/identity_proofs' ;
2020-05-28 15:52:07 -07:00
import MissingIndicator from 'soapbox/components/missing_indicator' ;
2020-03-27 13:59:38 -07:00
import { NavLink } from 'react-router-dom' ;
2020-07-04 19:25:43 -07:00
import { fetchPatronAccount } from '../../actions/patron' ;
2020-08-23 13:56:18 -07:00
import { getSoapboxConfig } from 'soapbox/actions/soapbox' ;
2021-08-11 14:00:49 -07:00
import { getSettings } from 'soapbox/actions/settings' ;
2021-10-07 12:35:07 -07:00
import { makeGetStatusIds , findAccountByUsername } from 'soapbox/selectors' ;
2021-08-11 13:49:57 -07:00
import classNames from 'classnames' ;
2020-03-27 13:59:38 -07:00
2021-08-11 13:31:46 -07:00
const makeMapStateToProps = ( ) => {
const getStatusIds = makeGetStatusIds ( ) ;
2020-03-27 13:59:38 -07:00
2021-08-11 13:31:46 -07:00
const mapStateToProps = ( state , { params , withReplies = false } ) => {
const username = params . username || '' ;
const me = state . get ( 'me' ) ;
const accountFetchError = ( state . getIn ( [ 'accounts' , - 1 , 'username' ] , '' ) . toLowerCase ( ) === username . toLowerCase ( ) ) ;
const soapboxConfig = getSoapboxConfig ( state ) ;
2020-03-27 13:59:38 -07:00
2021-08-11 13:31:46 -07:00
let accountId = - 1 ;
let accountUsername = username ;
let accountApId = null ;
if ( accountFetchError ) {
accountId = null ;
} else {
2021-10-07 12:35:07 -07:00
const account = findAccountByUsername ( state , username ) ;
2021-08-11 13:31:46 -07:00
accountId = account ? account . getIn ( [ 'id' ] , null ) : - 1 ;
accountUsername = account ? account . getIn ( [ 'acct' ] , '' ) : '' ;
accountApId = account ? account . get ( 'url' ) : '' ;
}
2020-03-27 13:59:38 -07:00
2021-08-11 13:31:46 -07:00
const path = withReplies ? ` ${ accountId } :with_replies ` : accountId ;
2020-03-27 13:59:38 -07:00
2021-08-11 13:31:46 -07:00
const isBlocked = state . getIn ( [ 'relationships' , accountId , 'blocked_by' ] , false ) ;
const unavailable = ( me === accountId ) ? false : isBlocked ;
2021-08-11 14:00:49 -07:00
const showPins = getSettings ( state ) . getIn ( [ 'account_timeline' , 'shows' , 'pinned' ] ) && ! withReplies ;
2021-08-11 13:31:46 -07:00
return {
accountId ,
unavailable ,
accountUsername ,
accountApId ,
2021-09-09 09:53:19 -07:00
isBlocked ,
2021-08-11 13:31:46 -07:00
isAccount : ! ! state . getIn ( [ 'accounts' , accountId ] ) ,
statusIds : getStatusIds ( state , { type : ` account: ${ path } ` , prefix : 'account_timeline' } ) ,
2021-08-11 14:00:49 -07:00
featuredStatusIds : showPins ? getStatusIds ( state , { type : ` account: ${ accountId } :pinned ` , prefix : 'account_timeline' } ) : ImmutableOrderedSet ( ) ,
2021-08-11 13:31:46 -07:00
isLoading : state . getIn ( [ 'timelines' , ` account: ${ path } ` , 'isLoading' ] ) ,
hasMore : state . getIn ( [ 'timelines' , ` account: ${ path } ` , 'hasMore' ] ) ,
me ,
patronEnabled : soapboxConfig . getIn ( [ 'extensions' , 'patron' , 'enabled' ] ) ,
} ;
2020-03-27 13:59:38 -07:00
} ;
2021-08-11 13:31:46 -07:00
return mapStateToProps ;
2020-03-27 13:59:38 -07:00
} ;
2021-08-11 13:31:46 -07:00
export default @ connect ( makeMapStateToProps )
2020-03-27 13:59:38 -07:00
class AccountTimeline extends ImmutablePureComponent {
static propTypes = {
params : PropTypes . object . isRequired ,
dispatch : PropTypes . func . isRequired ,
2021-07-08 12:52:07 -07:00
statusIds : ImmutablePropTypes . orderedSet ,
featuredStatusIds : ImmutablePropTypes . orderedSet ,
2020-03-27 13:59:38 -07:00
isLoading : PropTypes . bool ,
hasMore : PropTypes . bool ,
withReplies : PropTypes . bool ,
isAccount : PropTypes . bool ,
unavailable : PropTypes . bool ,
} ;
2021-08-11 13:49:57 -07:00
state = {
collapsed : true ,
animating : false ,
}
2020-06-17 18:42:30 -07:00
componentDidMount ( ) {
2020-07-04 19:25:43 -07:00
const { params : { username } , accountId , accountApId , withReplies , me , patronEnabled } = this . props ;
2020-03-27 13:59:38 -07:00
if ( accountId && accountId !== - 1 ) {
this . props . dispatch ( fetchAccount ( accountId ) ) ;
2020-04-10 17:49:05 -07:00
if ( me ) this . props . dispatch ( fetchAccountIdentityProofs ( accountId ) ) ;
2020-03-27 13:59:38 -07:00
if ( ! withReplies ) {
this . props . dispatch ( expandAccountFeaturedTimeline ( accountId ) ) ;
}
2020-07-04 19:25:43 -07:00
if ( patronEnabled && accountApId ) {
this . props . dispatch ( fetchPatronAccount ( accountApId ) ) ;
}
2020-03-27 13:59:38 -07:00
this . props . dispatch ( expandAccountTimeline ( accountId , { withReplies } ) ) ;
2020-04-14 11:44:40 -07:00
} else {
2020-03-27 13:59:38 -07:00
this . props . dispatch ( fetchAccountByUsername ( username ) ) ;
}
}
2020-07-04 16:41:41 -07:00
componentDidUpdate ( prevProps ) {
2021-10-02 13:45:14 -07:00
const { params : { username } , me , accountId , withReplies , accountApId , patronEnabled } = this . props ;
if ( accountId && ( accountId !== - 1 ) && ( accountId !== prevProps . accountId ) || withReplies !== prevProps . withReplies ) {
2020-07-04 16:41:41 -07:00
this . props . dispatch ( fetchAccount ( accountId ) ) ;
if ( me ) this . props . dispatch ( fetchAccountIdentityProofs ( accountId ) ) ;
if ( ! withReplies ) {
this . props . dispatch ( expandAccountFeaturedTimeline ( accountId ) ) ;
2020-03-27 13:59:38 -07:00
}
2020-07-04 19:25:43 -07:00
if ( patronEnabled && accountApId ) {
this . props . dispatch ( fetchPatronAccount ( accountApId ) ) ;
}
2020-07-04 16:41:41 -07:00
this . props . dispatch ( expandAccountTimeline ( accountId , { withReplies } ) ) ;
2021-10-02 13:45:14 -07:00
} else if ( username && ( username !== prevProps . params . username ) ) {
this . props . dispatch ( fetchAccountByUsername ( username ) ) ;
2020-03-27 13:59:38 -07:00
}
}
handleLoadMore = maxId => {
if ( this . props . accountId && this . props . accountId !== - 1 ) {
this . props . dispatch ( expandAccountTimeline ( this . props . accountId , { maxId , withReplies : this . props . withReplies } ) ) ;
}
}
2021-08-11 13:49:57 -07:00
handleToggleClick = ( e ) => {
e . stopPropagation ( ) ;
this . setState ( { collapsed : ! this . state . collapsed , animating : true } ) ;
}
handleTransitionEnd = ( ) => {
this . setState ( { animating : false } ) ;
}
2020-04-14 14:47:35 -07:00
render ( ) {
2021-09-09 09:53:19 -07:00
const { statusIds , featuredStatusIds , isLoading , hasMore , isBlocked , isAccount , accountId , unavailable , accountUsername } = this . props ;
2021-08-11 13:49:57 -07:00
const { collapsed , animating } = this . state ;
2020-03-27 13:59:38 -07:00
if ( ! isAccount && accountId !== - 1 ) {
return (
< Column >
< MissingIndicator / >
< / C o l u m n >
) ;
}
2020-04-14 13:45:38 -07:00
if ( accountId === - 1 || ( ! statusIds && isLoading ) ) {
2020-03-27 13:59:38 -07:00
return (
< Column >
< LoadingIndicator / >
< / C o l u m n >
) ;
}
if ( unavailable ) {
return (
< Column >
< div className = 'empty-column-indicator' >
2020-11-02 07:25:21 -08:00
{ isBlocked ? < FormattedMessage id = 'empty_column.account_blocked' defaultMessage = 'You are blocked by @{accountUsername}.' values = { { accountUsername : accountUsername } } / >
: < FormattedMessage id = 'empty_column.account_unavailable' defaultMessage = 'Profile unavailable' / > }
2020-03-27 13:59:38 -07:00
< / d i v >
< / C o l u m n >
) ;
}
return (
2021-10-06 13:57:24 -07:00
< Column transparent >
2020-03-27 13:59:38 -07:00
< div className = 'account__section-headline' >
2020-11-10 19:38:18 -08:00
< NavLink exact to = { ` /@ ${ accountUsername } ` } >
< FormattedMessage id = 'account.posts' defaultMessage = 'Posts' / >
< / N a v L i n k >
< NavLink exact to = { ` /@ ${ accountUsername } /with_replies ` } >
< FormattedMessage id = 'account.posts_with_replies' defaultMessage = 'Posts and replies' / >
< / N a v L i n k >
< NavLink exact to = { ` /@ ${ accountUsername } /media ` } >
< FormattedMessage id = 'account.media' defaultMessage = 'Media' / >
< / N a v L i n k >
2021-08-11 13:49:57 -07:00
< div className = 'column-header__buttons' >
< button onClick = { this . handleToggleClick } >
< Icon id = 'sliders' / >
< / b u t t o n >
< / d i v >
< / d i v >
< div className = { classNames ( 'column-header__collapsible' , { collapsed , animating } ) } onTransitionEnd = { this . handleTransitionEnd } >
< div className = 'column-header__collapsible-inner' >
2021-09-14 04:55:52 -07:00
{ ( ! collapsed || animating ) && < ColumnSettingsContainer / > }
2020-03-27 13:59:38 -07:00
< / d i v >
< / d i v >
< StatusList
scrollKey = 'account_timeline'
statusIds = { statusIds }
featuredStatusIds = { featuredStatusIds }
isLoading = { isLoading }
hasMore = { hasMore }
onLoadMore = { this . handleLoadMore }
emptyMessage = { < FormattedMessage id = 'empty_column.account_timeline' defaultMessage = 'No posts here!' / > }
/ >
< / C o l u m n >
) ;
}
}