175 lines
4.1 KiB
JavaScript
175 lines
4.1 KiB
JavaScript
import PropTypes from 'prop-types';
|
|
import { PureComponent } from 'react';
|
|
|
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
|
|
import { is } from 'immutable';
|
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
|
|
import Textarea from 'react-textarea-autosize';
|
|
|
|
const messages = defineMessages({
|
|
placeholder: { id: 'account_note.placeholder', defaultMessage: 'Click to add a note' },
|
|
});
|
|
|
|
class InlineAlert extends PureComponent {
|
|
|
|
static propTypes = {
|
|
show: PropTypes.bool,
|
|
};
|
|
|
|
state = {
|
|
mountMessage: false,
|
|
};
|
|
|
|
static TRANSITION_DELAY = 200;
|
|
|
|
UNSAFE_componentWillReceiveProps (nextProps) {
|
|
if (!this.props.show && nextProps.show) {
|
|
this.setState({ mountMessage: true });
|
|
} else if (this.props.show && !nextProps.show) {
|
|
setTimeout(() => this.setState({ mountMessage: false }), InlineAlert.TRANSITION_DELAY);
|
|
}
|
|
}
|
|
|
|
render () {
|
|
const { show } = this.props;
|
|
const { mountMessage } = this.state;
|
|
|
|
return (
|
|
<span aria-live='polite' role='status' className='inline-alert' style={{ opacity: show ? 1 : 0 }}>
|
|
{mountMessage && <FormattedMessage id='generic.saved' defaultMessage='Saved' />}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
class AccountNote extends ImmutablePureComponent {
|
|
|
|
static propTypes = {
|
|
account: ImmutablePropTypes.record.isRequired,
|
|
value: PropTypes.string,
|
|
onSave: PropTypes.func.isRequired,
|
|
intl: PropTypes.object.isRequired,
|
|
};
|
|
|
|
state = {
|
|
value: null,
|
|
saving: false,
|
|
saved: false,
|
|
};
|
|
|
|
UNSAFE_componentWillMount () {
|
|
this._reset();
|
|
}
|
|
|
|
UNSAFE_componentWillReceiveProps (nextProps) {
|
|
const accountWillChange = !is(this.props.account, nextProps.account);
|
|
const newState = {};
|
|
|
|
if (accountWillChange && this._isDirty()) {
|
|
this._save(false);
|
|
}
|
|
|
|
if (accountWillChange || nextProps.value === this.state.value) {
|
|
newState.saving = false;
|
|
}
|
|
|
|
if (this.props.value !== nextProps.value) {
|
|
newState.value = nextProps.value;
|
|
}
|
|
|
|
this.setState(newState);
|
|
}
|
|
|
|
componentWillUnmount () {
|
|
if (this._isDirty()) {
|
|
this._save(false);
|
|
}
|
|
}
|
|
|
|
setTextareaRef = c => {
|
|
this.textarea = c;
|
|
};
|
|
|
|
handleChange = e => {
|
|
this.setState({ value: e.target.value, saving: false });
|
|
};
|
|
|
|
handleKeyDown = e => {
|
|
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
|
|
e.preventDefault();
|
|
|
|
this._save();
|
|
|
|
if (this.textarea) {
|
|
this.textarea.blur();
|
|
}
|
|
} else if (e.keyCode === 27) {
|
|
e.preventDefault();
|
|
|
|
this._reset(() => {
|
|
if (this.textarea) {
|
|
this.textarea.blur();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
handleBlur = () => {
|
|
if (this._isDirty()) {
|
|
this._save();
|
|
}
|
|
};
|
|
|
|
_save (showMessage = true) {
|
|
this.setState({ saving: true }, () => this.props.onSave(this.state.value));
|
|
|
|
if (showMessage) {
|
|
this.setState({ saved: true }, () => setTimeout(() => this.setState({ saved: false }), 2000));
|
|
}
|
|
}
|
|
|
|
_reset (callback) {
|
|
this.setState({ value: this.props.value }, callback);
|
|
}
|
|
|
|
_isDirty () {
|
|
return !this.state.saving && this.props.value !== null && this.state.value !== null && this.state.value !== this.props.value;
|
|
}
|
|
|
|
render () {
|
|
const { account, intl } = this.props;
|
|
const { value, saved } = this.state;
|
|
|
|
if (!account) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className='account__header__account-note'>
|
|
<label htmlFor={`account-note-${account.get('id')}`}>
|
|
<FormattedMessage id='account.account_note_header' defaultMessage='Note' /> <InlineAlert show={saved} />
|
|
</label>
|
|
|
|
<Textarea
|
|
id={`account-note-${account.get('id')}`}
|
|
className='account__header__account-note__content'
|
|
disabled={this.props.value === null || value === null}
|
|
placeholder={intl.formatMessage(messages.placeholder)}
|
|
value={value || ''}
|
|
onChange={this.handleChange}
|
|
onKeyDown={this.handleKeyDown}
|
|
onBlur={this.handleBlur}
|
|
ref={this.setTextareaRef}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
export default injectIntl(AccountNote);
|