@ -1,6 +1,44 @@ | |||||
import api from '../api'; | |||||
import api from '../api'; | |||||
import axios from 'axios'; | |||||
export const STATUS_FETCH = 'STATUS_FETCH'; | export const STATUS_FETCH = 'STATUS_FETCH'; | ||||
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; | export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; | ||||
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'; | export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'; | ||||
export const STATUS_FETCH_FAIL = 'STATUS_FETCH_FAIL'; | export const STATUS_FETCH_FAIL = 'STATUS_FETCH_FAIL'; | ||||
export function fetchStatusRequest(id) { | |||||
return { | |||||
type: STATUS_FETCH_REQUEST, | |||||
id: id | |||||
}; | |||||
}; | |||||
export function fetchStatus(id) { | |||||
return (dispatch, getState) => { | |||||
const boundApi = api(getState); | |||||
dispatch(fetchStatusRequest(id)); | |||||
axios.all([boundApi.get(`/api/statuses/${id}`), boundApi.get(`/api/statuses/${id}/context`)]).then(values => { | |||||
dispatch(fetchStatusSuccess(values[0].data, values[1].data)); | |||||
}).catch(error => { | |||||
dispatch(fetchStatusFail(id, error)); | |||||
}); | |||||
}; | |||||
}; | |||||
export function fetchStatusSuccess(status, context) { | |||||
return { | |||||
type: STATUS_FETCH_SUCCESS, | |||||
status: status, | |||||
context: context | |||||
}; | |||||
}; | |||||
export function fetchStatusFail(id, error) { | |||||
return { | |||||
type: STATUS_FETCH_FAIL, | |||||
id: id, | |||||
error: error | |||||
}; | |||||
}; |
@ -0,0 +1,79 @@ | |||||
import { connect } from 'react-redux'; | |||||
import PureRenderMixin from 'react-addons-pure-render-mixin'; | |||||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||||
import { fetchAccount, followAccount, unfollowAccount } from '../../actions/accounts'; | |||||
import Button from '../../components/button'; | |||||
function selectAccount(state, id) { | |||||
return state.getIn(['timelines', 'accounts', id], null); | |||||
} | |||||
const mapStateToProps = (state, props) => ({ | |||||
account: selectAccount(state, Number(props.params.accountId)) | |||||
}); | |||||
const Account = React.createClass({ | |||||
propTypes: { | |||||
params: React.PropTypes.object.isRequired, | |||||
dispatch: React.PropTypes.func.isRequired, | |||||
account: ImmutablePropTypes.map | |||||
}, | |||||
mixins: [PureRenderMixin], | |||||
componentWillMount () { | |||||
this.props.dispatch(fetchAccount(this.props.params.accountId)); | |||||
}, | |||||
componentWillReceiveProps(nextProps) { | |||||
if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { | |||||
this.props.dispatch(fetchAccount(nextProps.params.accountId)); | |||||
} | |||||
}, | |||||
handleFollowClick () { | |||||
this.props.dispatch(followAccount(this.props.account.get('id'))); | |||||
}, | |||||
handleUnfollowClick () { | |||||
this.props.dispatch(unfollowAccount(this.props.account.get('id'))); | |||||
}, | |||||
render () { | |||||
const { account } = this.props; | |||||
let action; | |||||
if (account === null) { | |||||
return <div>Loading {this.props.params.accountId}...</div>; | |||||
} | |||||
if (account.get('following')) { | |||||
action = <Button text='Unfollow' onClick={this.handleUnfollowClick} />; | |||||
} else { | |||||
action = <Button text='Follow' onClick={this.handleFollowClick} /> | |||||
} | |||||
return ( | |||||
<div> | |||||
<p> | |||||
{account.get('display_name')} | |||||
{account.get('acct')} | |||||
</p> | |||||
{account.get('url')} | |||||
<p>{account.get('note')}</p> | |||||
{account.get('followers_count')} followers<br /> | |||||
{account.get('following_count')} following<br /> | |||||
{account.get('statuses_count')} posts | |||||
<p>{action}</p> | |||||
</div> | |||||
); | |||||
} | |||||
}); | |||||
export default connect(mapStateToProps)(Account); |
@ -0,0 +1,28 @@ | |||||
import { connect } from 'react-redux'; | |||||
import PureRenderMixin from 'react-addons-pure-render-mixin'; | |||||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||||
const mapStateToProps = (state, props) => ({ | |||||
}); | |||||
const Settings = React.createClass({ | |||||
propTypes: { | |||||
params: React.PropTypes.object.isRequired, | |||||
dispatch: React.PropTypes.func.isRequired | |||||
}, | |||||
mixins: [PureRenderMixin], | |||||
componentWillMount () { | |||||
// | |||||
}, | |||||
render () { | |||||
return <div>Settings</div>; | |||||
} | |||||
}); | |||||
export default connect(mapStateToProps)(Settings); |
@ -0,0 +1,74 @@ | |||||
import { connect } from 'react-redux'; | |||||
import PureRenderMixin from 'react-addons-pure-render-mixin'; | |||||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||||
import { fetchStatus } from '../../actions/statuses'; | |||||
import Immutable from 'immutable'; | |||||
import EmbeddedStatus from '../../components/status'; | |||||
function selectStatus(state, id) { | |||||
let status = state.getIn(['timelines', 'statuses', id]); | |||||
status = status.set('account', state.getIn(['timelines', 'accounts', status.get('account')])); | |||||
if (status.get('reblog') !== null) { | |||||
status = status.set('reblog', selectStatus(state, status.get('reblog'))); | |||||
} | |||||
return status; | |||||
}; | |||||
function selectStatuses(state, ids) { | |||||
return ids.map(id => selectStatus(state, id)); | |||||
}; | |||||
const mapStateToProps = (state, props) => ({ | |||||
status: selectStatus(state, Number(props.params.statusId)), | |||||
ancestors: selectStatuses(state, state.getIn(['timelines', 'ancestors', Number(props.params.statusId)], Immutable.List())), | |||||
descendants: selectStatuses(state, state.getIn(['timelines', 'descendants', Number(props.params.statusId)], Immutable.List())) | |||||
}); | |||||
const Status = React.createClass({ | |||||
propTypes: { | |||||
params: React.PropTypes.object.isRequired, | |||||
dispatch: React.PropTypes.func.isRequired, | |||||
status: ImmutablePropTypes.map, | |||||
ancestors: ImmutablePropTypes.list.isRequired, | |||||
descendants: ImmutablePropTypes.list.isRequired | |||||
}, | |||||
mixins: [PureRenderMixin], | |||||
componentWillMount () { | |||||
this.props.dispatch(fetchStatus(this.props.params.statusId)); | |||||
}, | |||||
componentWillReceiveProps (nextProps) { | |||||
if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { | |||||
this.props.dispatch(fetchStatus(nextProps.params.statusId)); | |||||
} | |||||
}, | |||||
renderChildren (list) { | |||||
return list.map(s => <EmbeddedStatus status={s} key={s.get('id')} />); | |||||
}, | |||||
render () { | |||||
const { status, ancestors, descendants } = this.props; | |||||
if (status === null) { | |||||
return <div>Loading {this.props.params.statusId}...</div>; | |||||
} | |||||
return ( | |||||
<div> | |||||
{this.renderChildren(ancestors)} | |||||
<EmbeddedStatus status={status} /> | |||||
{this.renderChildren(descendants)} | |||||
</div> | |||||
); | |||||
} | |||||
}); | |||||
export default connect(mapStateToProps)(Status); |
@ -0,0 +1,28 @@ | |||||
import { connect } from 'react-redux'; | |||||
import PureRenderMixin from 'react-addons-pure-render-mixin'; | |||||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||||
const mapStateToProps = (state, props) => ({ | |||||
}); | |||||
const Subscriptions = React.createClass({ | |||||
propTypes: { | |||||
params: React.PropTypes.object.isRequired, | |||||
dispatch: React.PropTypes.func.isRequired | |||||
}, | |||||
mixins: [PureRenderMixin], | |||||
componentWillMount () { | |||||
// | |||||
}, | |||||
render () { | |||||
return <div>Subscriptions</div>; | |||||
} | |||||
}); | |||||
export default connect(mapStateToProps)(Subscriptions); |
@ -0,0 +1,13 @@ | |||||
object false | |||||
node :ancestors do | |||||
@ancestors.map do |status| | |||||
partial('api/statuses/show', object: status) | |||||
end | |||||
end | |||||
node :descendants do | |||||
@descendants.map do |status| | |||||
partial('api/statuses/show', object: status) | |||||
end | |||||
end |