User endorsements
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
e1475e0ba5
commit
0a160f4422
|
@ -55,6 +55,10 @@ export const ACCOUNT_UNPIN_REQUEST = 'ACCOUNT_UNPIN_REQUEST';
|
|||
export const ACCOUNT_UNPIN_SUCCESS = 'ACCOUNT_UNPIN_SUCCESS';
|
||||
export const ACCOUNT_UNPIN_FAIL = 'ACCOUNT_UNPIN_FAIL';
|
||||
|
||||
export const PINNED_ACCOUNTS_FETCH_REQUEST = 'PINNED_ACCOUNTS_FETCH_REQUEST';
|
||||
export const PINNED_ACCOUNTS_FETCH_SUCCESS = 'PINNED_ACCOUNTS_FETCH_SUCCESS';
|
||||
export const PINNED_ACCOUNTS_FETCH_FAIL = 'PINNED_ACCOUNTS_FETCH_FAIL';
|
||||
|
||||
export const ACCOUNT_SEARCH_REQUEST = 'ACCOUNT_SEARCH_REQUEST';
|
||||
export const ACCOUNT_SEARCH_SUCCESS = 'ACCOUNT_SEARCH_SUCCESS';
|
||||
export const ACCOUNT_SEARCH_FAIL = 'ACCOUNT_SEARCH_FAIL';
|
||||
|
@ -960,6 +964,43 @@ export function unpinAccountFail(error) {
|
|||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedAccounts(id) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchPinnedAccountsRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/pleroma/accounts/${id}/endorsements`).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchPinnedAccountsSuccess(id, response.data, null));
|
||||
}).catch(error => {
|
||||
dispatch(fetchPinnedAccountsFail(id, error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedAccountsRequest(id) {
|
||||
return {
|
||||
type: PINNED_ACCOUNTS_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedAccountsSuccess(id, accounts, next) {
|
||||
return {
|
||||
type: PINNED_ACCOUNTS_FETCH_SUCCESS,
|
||||
id,
|
||||
accounts,
|
||||
next,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedAccountsFail(id, error) {
|
||||
return {
|
||||
type: PINNED_ACCOUNTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function accountSearch(params, cancelToken) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: ACCOUNT_SEARCH_REQUEST, params });
|
||||
|
|
|
@ -280,7 +280,10 @@ class Header extends ImmutablePureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
// menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });
|
||||
if (features.accountEndorsements) {
|
||||
menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });
|
||||
}
|
||||
|
||||
menu.push(null);
|
||||
} else if (features.lists && features.unrestrictedLists) {
|
||||
menu.push({
|
||||
|
|
|
@ -20,7 +20,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
onMute: PropTypes.func.isRequired,
|
||||
onBlockDomain: PropTypes.func.isRequired,
|
||||
onUnblockDomain: PropTypes.func.isRequired,
|
||||
// onEndorseToggle: PropTypes.func.isRequired,
|
||||
onEndorseToggle: PropTypes.func.isRequired,
|
||||
onAddToList: PropTypes.func.isRequired,
|
||||
username: PropTypes.string,
|
||||
};
|
||||
|
@ -81,9 +81,9 @@ export default class Header extends ImmutablePureComponent {
|
|||
this.props.onChat(this.props.account, this.context.router.history);
|
||||
}
|
||||
|
||||
// handleEndorseToggle = () => {
|
||||
// this.props.onEndorseToggle(this.props.account);
|
||||
// }
|
||||
handleEndorseToggle = () => {
|
||||
this.props.onEndorseToggle(this.props.account);
|
||||
}
|
||||
|
||||
handleAddToList = () => {
|
||||
this.props.onAddToList(this.props.account);
|
||||
|
|
|
@ -8,8 +8,8 @@ import {
|
|||
blockAccount,
|
||||
unblockAccount,
|
||||
unmuteAccount,
|
||||
// pinAccount,
|
||||
// unpinAccount,
|
||||
pinAccount,
|
||||
unpinAccount,
|
||||
subscribeAccount,
|
||||
unsubscribeAccount,
|
||||
} from '../../../actions/accounts';
|
||||
|
@ -128,13 +128,13 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
}
|
||||
},
|
||||
|
||||
// onEndorseToggle(account) {
|
||||
// if (account.getIn(['relationship', 'endorsed'])) {
|
||||
// dispatch(unpinAccount(account.get('id')));
|
||||
// } else {
|
||||
// dispatch(pinAccount(account.get('id')));
|
||||
// }
|
||||
// },
|
||||
onEndorseToggle(account) {
|
||||
if (account.getIn(['relationship', 'endorsed'])) {
|
||||
dispatch(unpinAccount(account.get('id')));
|
||||
} else {
|
||||
dispatch(pinAccount(account.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onReport(account) {
|
||||
dispatch(initReport(account));
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import AccountContainer from '../../../containers/account_container';
|
||||
import { fetchPinnedAccounts } from '../../../actions/accounts';
|
||||
|
||||
class PinnedAccountsPanel extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
pinned: ImmutablePropTypes.list.isRequired,
|
||||
fetchPinned: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fetchPinned();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { account } = this.props;
|
||||
const pinned = this.props.pinned.slice(0, this.props.limit);
|
||||
|
||||
if (pinned.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='wtf-panel'>
|
||||
<div className='wtf-panel-header'>
|
||||
<Icon src={require('@tabler/icons/icons/users.svg')} className='wtf-panel-header__icon' />
|
||||
<span className='wtf-panel-header__label'>
|
||||
<FormattedMessage
|
||||
id='pinned_accounts.title'
|
||||
defaultMessage='{name}’s choices'
|
||||
values={{
|
||||
name: account.get('display_name_html'),
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className='wtf-panel__content'>
|
||||
<div className='wtf-panel__list'>
|
||||
{pinned && pinned.map(suggestion => (
|
||||
<AccountContainer
|
||||
key={suggestion}
|
||||
id={suggestion}
|
||||
withRelationship={false}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, { account }) => ({
|
||||
pinned: state.getIn(['user_lists', 'pinned', account.get('id'), 'items'], ImmutableList()),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch, { account }) => {
|
||||
return {
|
||||
fetchPinned: () => dispatch(fetchPinnedAccounts(account.get('id'))),
|
||||
};
|
||||
};
|
||||
|
||||
export default injectIntl(
|
||||
connect(mapStateToProps, mapDispatchToProps, null, {
|
||||
forwardRef: true,
|
||||
},
|
||||
)(PinnedAccountsPanel));
|
|
@ -338,6 +338,10 @@ export function ProfileMediaPanel() {
|
|||
return import(/* webpackChunkName: "features/account_gallery" */'../components/profile_media_panel');
|
||||
}
|
||||
|
||||
export function PinnedAccountsPanel() {
|
||||
return import(/* webpackChunkName: "features/pinned_accounts]" */'../components/pinned_accounts_panel');
|
||||
}
|
||||
|
||||
export function InstanceInfoPanel() {
|
||||
return import(/* webpackChunkName: "features/remote_timeline" */'../components/instance_info_panel');
|
||||
}
|
||||
|
|
|
@ -680,6 +680,7 @@
|
|||
"password_reset.confirmation": "Sprawdź swoją pocztę e-mail, aby potwierdzić.",
|
||||
"password_reset.fields.username_placeholder": "Adres e-mail lub nazwa użytkownika",
|
||||
"password_reset.reset": "Resetuj hasło",
|
||||
"pinned_accounts.title": "Polecani przez {name}",
|
||||
"pinned_statuses.none": "Brak przypięć do pokazania.",
|
||||
"poll.closed": "Zamknięte",
|
||||
"poll.refresh": "Odśwież",
|
||||
|
|
|
@ -12,9 +12,10 @@ import {
|
|||
SignUpPanel,
|
||||
ProfileInfoPanel,
|
||||
ProfileMediaPanel,
|
||||
PinnedAccountsPanel,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
import LinkFooter from '../features/ui/components/link_footer';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import { getAcct, isLocal } from 'soapbox/utils/accounts';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { makeGetAccount } from '../selectors';
|
||||
|
@ -116,7 +117,11 @@ class ProfilePage extends ImmutablePureComponent {
|
|||
{Component => <Component account={account} />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
{features.suggestions && (
|
||||
{account && features.accountEndorsements && isLocal(account) ? (
|
||||
<BundleContainer fetchComponent={PinnedAccountsPanel}>
|
||||
{Component => <Component account={account} />}
|
||||
</BundleContainer>
|
||||
) : features.suggestions && (
|
||||
<BundleContainer fetchComponent={WhoToFollowPanel}>
|
||||
{Component => <Component />}
|
||||
</BundleContainer>
|
||||
|
|
|
@ -14,6 +14,7 @@ describe('user_lists reducer', () => {
|
|||
mutes: ImmutableMap(),
|
||||
groups: ImmutableMap(),
|
||||
groups_removed_accounts: ImmutableMap(),
|
||||
pinned: ImmutableMap(),
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
FOLLOW_REQUESTS_EXPAND_SUCCESS,
|
||||
FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
|
||||
FOLLOW_REQUEST_REJECT_SUCCESS,
|
||||
PINNED_ACCOUNTS_FETCH_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import {
|
||||
REBLOGS_FETCH_SUCCESS,
|
||||
|
@ -52,6 +53,7 @@ const initialState = ImmutableMap({
|
|||
mutes: ImmutableMap(),
|
||||
groups: ImmutableMap(),
|
||||
groups_removed_accounts: ImmutableMap(),
|
||||
pinned: ImmutableMap(),
|
||||
});
|
||||
|
||||
const normalizeList = (state, type, id, accounts, next) => {
|
||||
|
@ -126,6 +128,8 @@ export default function userLists(state = initialState, action) {
|
|||
return appendToList(state, 'groups_removed_accounts', action.id, action.accounts, action.next);
|
||||
case GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS:
|
||||
return state.updateIn(['groups_removed_accounts', action.groupId, 'items'], list => list.filterNot(item => item === action.id));
|
||||
case PINNED_ACCOUNTS_FETCH_SUCCESS:
|
||||
return normalizeList(state, 'pinned', action.id, action.accounts, action.next);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ export const getFeatures = createSelector([
|
|||
]),
|
||||
remoteInteractionsAPI: v.software === PLEROMA && gte(v.version, '2.4.50'),
|
||||
explicitAddressing: v.software === PLEROMA && gte(v.version, '1.0.0'),
|
||||
accountEndorsements: v.software === PLEROMA && gte(v.version, '2.4.50'),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
&.svg-icon {
|
||||
width: 20px;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue