@ -3,99 +3,166 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types' ;
import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
import ImmutablePureComponent from 'react-immutable-pure-component' ;
import Icon from 'mastodon/components/icon' ;
import Textarea from 'react-textarea-autosize' ;
import { is } from 'immutable' ;
const messages = defineMessages ( {
placeholder : { id : 'account_note.placeholder' , defaultMessage : 'No comment provided ' } ,
placeholder : { id : 'account_note.placeholder' , defaultMessage : 'Click to add a note ' } ,
} ) ;
class InlineAlert extends React . PureComponent {
static propTypes = {
show : PropTypes . bool ,
} ;
state = {
mountMessage : false ,
} ;
static TRANSITION_DELAY = 200 ;
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' / > }
< / s p a n >
) ;
}
}
export default @ injectIntl
class Header extends ImmutablePureComponent {
class AccountNote extends ImmutablePureComponent {
static propTypes = {
account : ImmutablePropTypes . map . isRequired ,
isEditing : PropTypes . bool ,
isSubmitting : PropTypes . bool ,
accountNote : PropTypes . string ,
onEditAccountNote : PropTypes . func . isRequired ,
onCancelAccountNote : PropTypes . func . isRequired ,
onSaveAccountNote : PropTypes . func . isRequired ,
onChangeAccountNote : PropTypes . func . isRequired ,
value : PropTypes . string ,
onSave : PropTypes . func . isRequired ,
intl : PropTypes . object . isRequired ,
} ;
handleChangeAccountNote = ( e ) => {
this . props . onChangeAccountNote ( e . target . value ) ;
state = {
value : null ,
saving : false ,
saved : false ,
} ;
componentWillMount ( ) {
this . _reset ( ) ;
}
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 . props . isEditing ) {
this . props . onCancelAccountNote ( ) ;
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 ) ) {
this . props . onSaveAccountNote ( ) ;
e . preventDefault ( ) ;
this . _save ( ) ;
if ( this . textarea ) {
this . textarea . blur ( ) ;
}
} else if ( e . keyCode === 27 ) {
this . props . onCancelAccountNote ( ) ;
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 , accountNote , isEditing , isSubmitting , intl } = this . props ;
const { account , intl } = this . props ;
const { value , saved } = this . state ;
if ( ! account || ( ! accountNote && ! isEditing ) ) {
if ( ! account ) {
return null ;
}
let action_buttons = null ;
if ( isEditing ) {
action_buttons = (
< div className = 'account__header__account-note__buttons' >
< button className = 'text-btn' tabIndex = '0' onClick = { this . props . onCancelAccountNote } disabled = { isSubmitting } >
< Icon id = 'times' size = { 15 } / > < FormattedMessage id = 'account_note.cancel' defaultMessage = 'Cancel' / >
< / b u t t o n >
< div className = 'flex-spacer' / >
< button className = 'text-btn' tabIndex = '0' onClick = { this . props . onSaveAccountNote } disabled = { isSubmitting } >
< Icon id = 'check' size = { 15 } / > < FormattedMessage id = 'account_note.save' defaultMessage = 'Save' / >
< / b u t t o n >
< / d i v >
) ;
}
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 } / >
< / l a b e l >
let note_container = null ;
if ( isEditing ) {
note_container = (
< Textarea
id = { ` account-note- ${ account . get ( 'id' ) } ` }
className = 'account__header__account-note__content'
disabled = { isSubmitting }
disabled = { this . props . value === null || value === null }
placeholder = { intl . formatMessage ( messages . placeholder ) }
value = { accountNote }
onChange = { this . handleChangeAccountNote }
value = { value || '' }
onChange = { this . handleChange }
onKeyDown = { this . handleKeyDown }
autoFocus
onBlur = { this . handleBlur }
ref = { this . setTextareaRef }
/ >
) ;
} else {
note_container = ( < div className = 'account__header__account-note__content' > { accountNote } < / d i v > ) ;
}
return (
< div className = 'account__header__account-note' >
< div className = 'account__header__account-note__header' >
< strong > < FormattedMessage id = 'account.account_note_header' defaultMessage = 'Your note for @{name}' values = { { name : account . get ( 'username' ) } } / > < / s t r o n g >
{ ! isEditing && (
< div >
< button className = 'text-btn' tabIndex = '0' onClick = { this . props . onEditAccountNote } disabled = { isSubmitting } >
< Icon id = 'pencil' size = { 15 } / > < FormattedMessage id = 'account_note.edit' defaultMessage = 'Edit' / >
< / b u t t o n >
< / d i v >
) }
< / d i v >
{ note_container }
{ action_buttons }
< / d i v >
) ;
}