Progress
This commit is contained in:
@@ -1,55 +1,30 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import { fetchAccount, fetchAccountByUsername } from '../../actions/accounts';
|
||||
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
|
||||
import { fetchAccountIdentityProofs } from '../../actions/identity_proofs';
|
||||
import { me } from '../../initial_state';
|
||||
import StatusList from '../../components/status_list/status_list';
|
||||
import ColumnIndicator from '../../components/column_indicator';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { List as ImmutableList } from 'immutable'
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines'
|
||||
import { fetchAccountIdentityProofs } from '../../actions/identity_proofs'
|
||||
import StatusList from '../../components/status_list/status_list'
|
||||
|
||||
const messages = defineMessages({
|
||||
posts: { id: 'account.posts', defaultMessage: 'Gabs' },
|
||||
postsWithReplies: { id: 'account.posts_with_replies', defaultMessage: 'Gabs and replies' },
|
||||
media: { id: 'account.media', defaultMessage: 'Media' },
|
||||
error: { id: 'empty_column.account_unavailable', defaultMessage: 'Profile unavailable' },
|
||||
});
|
||||
empty: { id: 'empty_column.account_timeline', defaultMessage: 'No gabs here!' },
|
||||
})
|
||||
|
||||
const emptyList = ImmutableList();
|
||||
const emptyList = ImmutableList()
|
||||
|
||||
const mapStateToProps = (state, { params: { username }, withReplies = false }) => {
|
||||
const accounts = state.getIn(['accounts']);
|
||||
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() == username.toLowerCase());
|
||||
const mapStateToProps = (state, { account, withReplies = false }) => {
|
||||
const accountId = !!account ? account.getIn(['id'], null) : -1
|
||||
|
||||
let accountId = -1;
|
||||
let accountUsername = username;
|
||||
if (accountFetchError) {
|
||||
accountId = null;
|
||||
} else {
|
||||
let account = accounts.find(acct => username.toLowerCase() == acct.getIn(['acct'], '').toLowerCase());
|
||||
accountId = account ? account.getIn(['id'], null) : -1;
|
||||
accountUsername = account ? account.getIn(['acct'], '') : '';
|
||||
}
|
||||
|
||||
const path = withReplies ? `${accountId}:with_replies` : accountId;
|
||||
|
||||
const isBlocked = state.getIn(['relationships', accountId, 'blocked_by'], false);
|
||||
const isLocked = state.getIn(['accounts', accountId, 'locked'], false);
|
||||
const isFollowing = state.getIn(['relationships', accountId, 'following'], false);
|
||||
const unavailable = (me == accountId) ? false : (isBlocked || (isLocked && !isFollowing));
|
||||
const path = withReplies ? `${accountId}:with_replies` : accountId
|
||||
|
||||
return {
|
||||
accountId,
|
||||
unavailable,
|
||||
accountUsername,
|
||||
isAccount: !!state.getIn(['accounts', accountId]),
|
||||
statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),
|
||||
featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], emptyList),
|
||||
isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
|
||||
hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']),
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps)
|
||||
@@ -64,57 +39,56 @@ class AccountTimeline extends ImmutablePureComponent {
|
||||
isLoading: PropTypes.bool,
|
||||
hasMore: PropTypes.bool,
|
||||
withReplies: PropTypes.bool,
|
||||
isAccount: PropTypes.bool,
|
||||
unavailable: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const { params: { username }, accountId, withReplies } = this.props;
|
||||
const { accountId, withReplies } = this.props
|
||||
|
||||
if (accountId && accountId !== -1) {
|
||||
this.props.dispatch(fetchAccount(accountId));
|
||||
this.props.dispatch(fetchAccountIdentityProofs(accountId));
|
||||
this.props.dispatch(fetchAccountIdentityProofs(accountId))
|
||||
|
||||
if (!withReplies) {
|
||||
this.props.dispatch(expandAccountFeaturedTimeline(accountId));
|
||||
this.props.dispatch(expandAccountFeaturedTimeline(accountId))
|
||||
}
|
||||
|
||||
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
|
||||
} else {
|
||||
this.props.dispatch(fetchAccountByUsername(username));
|
||||
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }))
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.accountId && nextProps.accountId !== -1 && (nextProps.accountId !== this.props.accountId && nextProps.accountId) || nextProps.withReplies !== this.props.withReplies) {
|
||||
this.props.dispatch(fetchAccount(nextProps.accountId));
|
||||
this.props.dispatch(fetchAccountIdentityProofs(nextProps.accountId));
|
||||
this.props.dispatch(fetchAccountIdentityProofs(nextProps.accountId))
|
||||
|
||||
if (!nextProps.withReplies) {
|
||||
this.props.dispatch(expandAccountFeaturedTimeline(nextProps.accountId));
|
||||
this.props.dispatch(expandAccountFeaturedTimeline(nextProps.accountId))
|
||||
}
|
||||
|
||||
this.props.dispatch(expandAccountTimeline(nextProps.accountId, { withReplies: nextProps.withReplies }));
|
||||
this.props.dispatch(expandAccountTimeline(nextProps.accountId, { withReplies: nextProps.withReplies }))
|
||||
}
|
||||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
if (this.props.accountId && this.props.accountId !== -1) {
|
||||
this.props.dispatch(expandAccountTimeline(this.props.accountId, { maxId, withReplies: this.props.withReplies }));
|
||||
this.props.dispatch(expandAccountTimeline(this.props.accountId, {
|
||||
maxId,
|
||||
withReplies: this.props.withReplies
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { statusIds, featuredStatusIds, isLoading, hasMore, isAccount, accountId, unavailable, accountUsername, intl } = this.props;
|
||||
const {
|
||||
account,
|
||||
statusIds,
|
||||
featuredStatusIds,
|
||||
isLoading,
|
||||
hasMore,
|
||||
intl
|
||||
} = this.props
|
||||
|
||||
if (!account) return null
|
||||
|
||||
if (!isAccount && accountId !== -1) {
|
||||
return <ColumnIndicator type='missing' />
|
||||
} else if (accountId === -1 || (!statusIds && isLoading)) {
|
||||
return <ColumnIndicator type='loading' />
|
||||
} else if (unavailable) {
|
||||
return <ColumnIndicator type='error' message={intl.formatMessage(messages.error)} />
|
||||
}
|
||||
return (
|
||||
<StatusList
|
||||
scrollKey='account_timeline'
|
||||
@@ -123,9 +97,9 @@ class AccountTimeline extends ImmutablePureComponent {
|
||||
isLoading={isLoading}
|
||||
hasMore={hasMore}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.account_timeline' defaultMessage='No gabs here!' />}
|
||||
emptyMessage={intl.formatMessage(messages.empty)}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export default class Header extends ImmutablePureComponent {
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
onReblogToggle: PropTypes.func.isRequired,
|
||||
onRepostToggle: PropTypes.func.isRequired,
|
||||
onReport: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func.isRequired,
|
||||
onBlockDomain: PropTypes.func.isRequired,
|
||||
@@ -47,8 +47,8 @@ export default class Header extends ImmutablePureComponent {
|
||||
this.props.onReport(this.props.account);
|
||||
}
|
||||
|
||||
handleReblogToggle = () => {
|
||||
this.props.onReblogToggle(this.props.account);
|
||||
handleRepostToggle = () => {
|
||||
this.props.onRepostToggle(this.props.account);
|
||||
}
|
||||
|
||||
handleMute = () => {
|
||||
@@ -94,7 +94,7 @@ export default class Header extends ImmutablePureComponent {
|
||||
onBlock={this.handleBlock}
|
||||
onMention={this.handleMention}
|
||||
onDirect={this.handleDirect}
|
||||
onReblogToggle={this.handleReblogToggle}
|
||||
onRepostToggle={this.handleRepostToggle}
|
||||
onReport={this.handleReport}
|
||||
onMute={this.handleMute}
|
||||
onBlockDomain={this.handleBlockDomain}
|
||||
|
||||
@@ -114,9 +114,9 @@ class Header extends ImmutablePureComponent {
|
||||
} else {
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
menu.push({ text: intl.formatMessage(messages.hideReblogs, { name: account.get('username') }), action: this.props.onReblogToggle });
|
||||
menu.push({ text: intl.formatMessage(messages.hideReblogs, { name: account.get('username') }), action: this.props.onRepostToggle });
|
||||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.showReblogs, { name: account.get('username') }), action: this.props.onReblogToggle });
|
||||
menu.push({ text: intl.formatMessage(messages.showReblogs, { name: account.get('username') }), action: this.props.onRepostToggle });
|
||||
}
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), action: this.props.onAddToList });
|
||||
@@ -279,7 +279,7 @@ class Header extends ImmutablePureComponent {
|
||||
<NavLink exact activeClassName='active' to={`/${account.get('acct')}/favorites`} title={intl.formatNumber(account.get('favourite_count'))}>
|
||||
{ /* : TODO : shortNumberFormat(account.get('favourite_count')) */ }
|
||||
<span>•</span>
|
||||
<FormattedMessage id='navigation_bar.favourites' defaultMessage='Favorites' />
|
||||
<FormattedMessage id='navigation_bar.favorites' defaultMessage='Favorites' />
|
||||
</NavLink>
|
||||
<NavLink exact activeClassName='active' to={`/${account.get('acct')}/pins`} title={intl.formatNumber(account.get('pinned_count'))}>
|
||||
{ /* : TODO : shortNumberFormat(account.get('pinned_count')) */ }
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './profile_info_panel'
|
||||
@@ -1,135 +0,0 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import Icon from '../../../../components/icon';
|
||||
import VerifiedIcon from '../../../../components/verified_icon';
|
||||
import Badge from '../../../../components/badge';
|
||||
|
||||
const messages = defineMessages({
|
||||
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
|
||||
account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },
|
||||
bot: { id: 'account.badges.bot', defaultMessage: 'Bot' },
|
||||
memberSince: { id: 'account.member_since', defaultMessage:'Member since {date}'},
|
||||
});
|
||||
|
||||
const dateFormatOptions = {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, { account }) => {
|
||||
const identity_proofs = account ? state.getIn(['identity_proofs', account.get('id')], ImmutableList()) : ImmutableList();
|
||||
return {
|
||||
identity_proofs,
|
||||
domain: state.getIn(['meta', 'domain']),
|
||||
};
|
||||
};
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class ProfileInfoPanel extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
identity_proofs: ImmutablePropTypes.list,
|
||||
intl: PropTypes.object.isRequired,
|
||||
username: PropTypes.string,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account, intl, identity_proofs, username } = this.props;
|
||||
|
||||
if (!account) {
|
||||
return (
|
||||
<div className='profile-info-panel'>
|
||||
<div className='profile-info-panel__content'>
|
||||
<div className='profile-info-panel-content__name'>
|
||||
<h1>
|
||||
<span/>
|
||||
<small>@{username}</small>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const lockedIcon = account.get('locked') ? (<Icon id='lock' title={intl.formatMessage(messages.account_locked)} />) : '';
|
||||
const badge = account.get('bot') ? (<div className='account-role bot'>{intl.formatMessage(messages.bot)}</div>) : null;
|
||||
const content = { __html: account.get('note_emojified') };
|
||||
const fields = account.get('fields');
|
||||
const acct = account.get('acct');
|
||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
||||
const memberSinceDate = intl.formatDate(account.get('created_at'), { month: 'long', year: 'numeric' });
|
||||
|
||||
return (
|
||||
<div className='profile-info-panel'>
|
||||
<div className='profile-info-panel__content'>
|
||||
|
||||
<div className='profile-info-panel-content__name'>
|
||||
<h1>
|
||||
<span dangerouslySetInnerHTML={displayNameHtml} />
|
||||
{account.get('is_verified') && <VerifiedIcon />}
|
||||
{badge}
|
||||
<small>@{acct} {lockedIcon}</small>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className='profile-info-panel-content__badges'>
|
||||
{account.get('is_pro') && <Badge type='pro' />}
|
||||
{account.get('is_donor') && <Badge type='donor' />}
|
||||
{account.get('is_investor') && <Badge type='investor' />}
|
||||
<div className='profile-info-panel-content__badges__join-date'>
|
||||
<Icon id="calendar"/>
|
||||
{intl.formatMessage(messages.memberSince, {
|
||||
date: memberSinceDate
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
(account.get('note').length > 0 && account.get('note') !== '<p></p>') &&
|
||||
<div className='profile-info-panel-content__bio' dangerouslySetInnerHTML={content} />
|
||||
}
|
||||
|
||||
{(fields.size > 0 || identity_proofs.size > 0) && (
|
||||
<div className='profile-info-panel-content__fields'>
|
||||
{identity_proofs.map((proof, i) => (
|
||||
<dl className='test' key={i}>
|
||||
<dt dangerouslySetInnerHTML={{ __html: proof.get('provider') }} />
|
||||
|
||||
<dd className='verified'>
|
||||
<a href={proof.get('proof_url')} target='_blank' rel='noopener'>
|
||||
<span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(proof.get('updated_at'), dateFormatOptions) })}>
|
||||
<Icon id='check' className='verified__mark' />
|
||||
</span>
|
||||
</a>
|
||||
<a href={proof.get('profile_url')} target='_blank' rel='noopener'>
|
||||
<span dangerouslySetInnerHTML={{ __html: ' ' + proof.get('provider_username') }} />
|
||||
</a>
|
||||
</dd>
|
||||
</dl>
|
||||
))}
|
||||
|
||||
{fields.map((pair, i) => (
|
||||
<dl className='profile-info-panel-content__fields__item' key={i}>
|
||||
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
|
||||
|
||||
<dd className={pair.get('verified_at') && 'verified'} title={pair.get('value_plain')}>
|
||||
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
|
||||
</dd>
|
||||
</dl>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
.profile-info-panel {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1;
|
||||
|
||||
@media (min-width:895px) {
|
||||
padding-top: 60px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.profile-info-panel-content {
|
||||
display: flex;
|
||||
|
||||
&__badges {
|
||||
display: flex;
|
||||
margin: 5px 0;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&__join-date {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
|
||||
.fa {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: $primary-text-color;
|
||||
|
||||
@include text-sizing(15px, 400, 1.25);
|
||||
|
||||
body.theme-gabsocial-light & {
|
||||
color: $gab-default-text-light;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__name {
|
||||
display: block;
|
||||
|
||||
.account-role {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.emojione {
|
||||
@include size(22px);
|
||||
}
|
||||
|
||||
h1 {
|
||||
span:first-of-type {
|
||||
color: #ffffff;
|
||||
|
||||
@include text-overflow(nowrap);
|
||||
@include text-sizing(20px, 600, 1.25);
|
||||
|
||||
body.theme-gabsocial-light & {
|
||||
color: $gab-default-text-light;
|
||||
}
|
||||
}
|
||||
|
||||
small {
|
||||
display: block;
|
||||
color: $secondary-text-color;
|
||||
|
||||
@include text-sizing(16px, 400, 1.5);
|
||||
@include text-overflow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__bio {
|
||||
display: block;
|
||||
flex: 1 1;
|
||||
color: $primary-text-color;
|
||||
margin: 15px 0;
|
||||
|
||||
@include text-sizing(15px, 400, 1.25);
|
||||
|
||||
a {
|
||||
color: lighten($ui-highlight-color, 8%);
|
||||
}
|
||||
}
|
||||
|
||||
&__fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-top: 1px solid lighten($ui-base-color, 12%);
|
||||
padding: 10px 0;
|
||||
margin: 5px 0;
|
||||
|
||||
@media screen and (max-width:895px) {
|
||||
border-bottom: 1px solid lighten($ui-base-color, 12%);
|
||||
}
|
||||
|
||||
a {
|
||||
color: lighten($ui-highlight-color, 8%);
|
||||
}
|
||||
|
||||
dl:first-child .verified {
|
||||
border-radius: 0 4px 0 0;
|
||||
}
|
||||
|
||||
.verified a {
|
||||
color: $valid-value-color;
|
||||
}
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
padding: 2px 0;
|
||||
margin: 2px 0;
|
||||
flex: 1 1;
|
||||
|
||||
* {
|
||||
@include text-sizing(15px, 400, 24px);
|
||||
}
|
||||
|
||||
dt {
|
||||
min-width: 26px;
|
||||
}
|
||||
|
||||
dd {
|
||||
padding-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
dispatch(directCompose(account, router));
|
||||
},
|
||||
|
||||
onReblogToggle (account) {
|
||||
onRepostToggle (account) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
dispatch(followAccount(account.get('id'), false));
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user