Merge branch 'account-notes' into 'develop'
Account notes See merge request soapbox-pub/soapbox-fe!1053
This commit is contained in:
@@ -62,6 +62,8 @@ const messages = defineMessages({
|
||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
|
||||
unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
|
||||
createNote: { id: 'account.create_note', defaultMessage: 'Create a note' },
|
||||
editNote: { id: 'account.edit_note', defaultMessage: 'Edit note' },
|
||||
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
|
||||
deactivateUser: { id: 'admin.users.actions.deactivate_user', defaultMessage: 'Deactivate @{name}' },
|
||||
@@ -268,6 +270,14 @@ class Header extends ImmutablePureComponent {
|
||||
});
|
||||
}
|
||||
|
||||
if (features.notes) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(account.getIn(['relationship', 'note']) ? messages.editNote : messages.createNote),
|
||||
action: this.props.onShowNote,
|
||||
icon: require('@tabler/icons/icons/note.svg'),
|
||||
});
|
||||
}
|
||||
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
menu.push({
|
||||
|
||||
@@ -131,6 +131,10 @@ export default class Header extends ImmutablePureComponent {
|
||||
this.props.onUnsuggestUser(this.props.account);
|
||||
}
|
||||
|
||||
handleShowNote = () => {
|
||||
this.props.onShowNote(this.props.account);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { account, identity_proofs } = this.props;
|
||||
const moved = (account) ? account.get('moved') : false;
|
||||
@@ -165,6 +169,7 @@ export default class Header extends ImmutablePureComponent {
|
||||
onDemoteToUser={this.handleDemoteToUser}
|
||||
onSuggestUser={this.handleSuggestUser}
|
||||
onUnsuggestUser={this.handleUnsuggestUser}
|
||||
onShowNote={this.handleShowNote}
|
||||
username={this.props.username}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -3,21 +3,7 @@ import React from 'react';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import {
|
||||
verifyUser,
|
||||
unverifyUser,
|
||||
promoteToAdmin,
|
||||
promoteToModerator,
|
||||
demoteToUser,
|
||||
suggestUsers,
|
||||
unsuggestUsers,
|
||||
} from 'soapbox/actions/admin';
|
||||
import { launchChat } from 'soapbox/actions/chats';
|
||||
import { deactivateUserModal, deleteUserModal } from 'soapbox/actions/moderation';
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { isAdmin } from 'soapbox/utils/accounts';
|
||||
|
||||
import { initAccountNoteModal } from 'soapbox/actions/account_notes';
|
||||
import {
|
||||
followAccount,
|
||||
unfollowAccount,
|
||||
@@ -28,16 +14,31 @@ import {
|
||||
unpinAccount,
|
||||
subscribeAccount,
|
||||
unsubscribeAccount,
|
||||
} from '../../../actions/accounts';
|
||||
} from 'soapbox/actions/accounts';
|
||||
import {
|
||||
verifyUser,
|
||||
unverifyUser,
|
||||
promoteToAdmin,
|
||||
promoteToModerator,
|
||||
demoteToUser,
|
||||
suggestUsers,
|
||||
unsuggestUsers,
|
||||
} from 'soapbox/actions/admin';
|
||||
import { launchChat } from 'soapbox/actions/chats';
|
||||
import {
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
} from '../../../actions/compose';
|
||||
import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
|
||||
import { openModal } from '../../../actions/modals';
|
||||
import { initMuteModal } from '../../../actions/mutes';
|
||||
import { initReport } from '../../../actions/reports';
|
||||
import { makeGetAccount } from '../../../selectors';
|
||||
} from 'soapbox/actions/compose';
|
||||
import { blockDomain, unblockDomain } from 'soapbox/actions/domain_blocks';
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import { deactivateUserModal, deleteUserModal } from 'soapbox/actions/moderation';
|
||||
import { initMuteModal } from 'soapbox/actions/mutes';
|
||||
import { initReport } from 'soapbox/actions/reports';
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
import { isAdmin } from 'soapbox/utils/accounts';
|
||||
|
||||
import Header from '../components/header';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -246,6 +247,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
.then(() => dispatch(snackbar.success(message)))
|
||||
.catch(() => {});
|
||||
},
|
||||
|
||||
onShowNote(account) {
|
||||
dispatch(initAccountNoteModal(account));
|
||||
},
|
||||
});
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header));
|
||||
|
||||
109
app/soapbox/features/ui/components/account_note_modal.js
Normal file
109
app/soapbox/features/ui/components/account_note_modal.js
Normal file
@@ -0,0 +1,109 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { changeAccountNoteComment, submitAccountNote } from 'soapbox/actions/account_notes';
|
||||
import { closeModal } from 'soapbox/actions/modals';
|
||||
import Button from 'soapbox/components/button';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
placeholder: { id: 'account_note.placeholder', defaultMessage: 'No comment provided' },
|
||||
save: { id: 'account_note.save', defaultMessage: 'Save' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
isSubmitting: state.getIn(['account_notes', 'edit', 'isSubmitting']),
|
||||
account: getAccount(state, state.getIn(['account_notes', 'edit', 'account_id'])),
|
||||
comment: state.getIn(['account_notes', 'edit', 'comment']),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
onConfirm() {
|
||||
dispatch(submitAccountNote());
|
||||
},
|
||||
|
||||
onClose() {
|
||||
dispatch(closeModal());
|
||||
},
|
||||
|
||||
onCommentChange(comment) {
|
||||
dispatch(changeAccountNoteComment(comment));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default @connect(makeMapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class AccountNoteModal extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
isSubmitting: PropTypes.bool,
|
||||
account: PropTypes.object.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onCommentChange: PropTypes.func.isRequired,
|
||||
comment: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleCommentChange = e => {
|
||||
this.props.onCommentChange(e.target.value);
|
||||
}
|
||||
|
||||
handleSubmit = () => {
|
||||
this.props.onConfirm();
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
|
||||
this.handleSubmit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { account, isSubmitting, comment, onClose, intl } = this.props;
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal account-note-modal'>
|
||||
<div className='account-note-modal__header'>
|
||||
<Icon src={require('@tabler/icons/icons/note.svg')} />
|
||||
<FormattedMessage id='account_note.target' defaultMessage='Note for @{target}' values={{ target: account.get('acct') }} />
|
||||
</div>
|
||||
|
||||
<div className='account-note-modal__container'>
|
||||
<p><FormattedMessage id='account_note.hint' defaultMessage='You can keep notes about this user for yourself (this will not be shared with them):' /></p>
|
||||
|
||||
<textarea
|
||||
className='setting-text light'
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
value={comment}
|
||||
onChange={this.handleCommentChange}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
disabled={isSubmitting}
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<div className='account-note-modal__action-bar'>
|
||||
<Button onClick={onClose} className='account-note-modal__cancel-button'>
|
||||
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
|
||||
</Button>
|
||||
<Button text={intl.formatMessage(messages.save)} onClick={this.handleSubmit} disabled={isSubmitting} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
ReblogsModal,
|
||||
MentionsModal,
|
||||
BirthdaysModal,
|
||||
AccountNoteModal,
|
||||
} from '../../../features/ui/util/async-components';
|
||||
import BundleContainer from '../containers/bundle_container';
|
||||
|
||||
@@ -59,6 +60,7 @@ const MODAL_COMPONENTS = {
|
||||
'REACTIONS': ReactionsModal,
|
||||
'MENTIONS': MentionsModal,
|
||||
'BIRTHDAYS': BirthdaysModal,
|
||||
'ACCOUNT_NOTE': AccountNoteModal,
|
||||
};
|
||||
|
||||
export default class ModalRoot extends React.PureComponent {
|
||||
|
||||
@@ -9,6 +9,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { initAccountNoteModal } from 'soapbox/actions/account_notes';
|
||||
import Badge from 'soapbox/components/badge';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import VerificationBadge from 'soapbox/components/verification_badge';
|
||||
@@ -48,6 +49,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
||||
intl: PropTypes.object.isRequired,
|
||||
username: PropTypes.string,
|
||||
displayFqn: PropTypes.bool,
|
||||
onShowNote: PropTypes.func,
|
||||
};
|
||||
|
||||
getStaffBadge = () => {
|
||||
@@ -115,6 +117,13 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
handleShowNote = e => {
|
||||
const { account, onShowNote } = this.props;
|
||||
|
||||
e.preventDefault();
|
||||
onShowNote(account);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { account, displayFqn, intl, identity_proofs, username } = this.props;
|
||||
|
||||
@@ -187,6 +196,13 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
||||
|
||||
{this.getBirthday()}
|
||||
|
||||
{!!account.getIn(['relationship', 'note']) && (
|
||||
<a href='#' className='profile-info-panel-content__note' onClick={this.handleShowNote}>
|
||||
<Icon src={require('@tabler/icons/icons/note.svg')} />
|
||||
<FormattedMessage id='account.show_note' defaultMessage='Show note' />
|
||||
</a>
|
||||
)}
|
||||
|
||||
<ProfileStats
|
||||
className='profile-info-panel-content__stats'
|
||||
account={account}
|
||||
@@ -250,8 +266,14 @@ const mapStateToProps = (state, { account }) => {
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onShowNote(account) {
|
||||
dispatch(initAccountNoteModal(account));
|
||||
},
|
||||
});
|
||||
|
||||
export default injectIntl(
|
||||
connect(mapStateToProps, null, null, {
|
||||
connect(mapStateToProps, mapDispatchToProps, null, {
|
||||
forwardRef: true,
|
||||
},
|
||||
)(ProfileInfoPanel));
|
||||
|
||||
@@ -218,6 +218,10 @@ export function BirthdaysModal() {
|
||||
return import(/* webpackChunkName: "features/ui" */'../components/birthdays_modal');
|
||||
}
|
||||
|
||||
export function AccountNoteModal() {
|
||||
return import(/* webpackChunkName: "features/ui" */'../components/account_note_modal');
|
||||
}
|
||||
|
||||
export function ListEditor() {
|
||||
return import(/* webpackChunkName: "features/list_editor" */'../../list_editor');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user