Merge branch 'account-notes' into 'develop'

Account notes

See merge request soapbox-pub/soapbox-fe!1053
This commit is contained in:
Alex Gleason
2022-02-26 21:30:05 +00:00
14 changed files with 367 additions and 59 deletions

View 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>
);
}
}

View File

@@ -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 {

View File

@@ -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));