Port 65506bac3f
to glitch-soc
Signed-off-by: Thibaut Girka <thib@sitedethib.com>
closed-social-glitch-2
@ -0,0 +1,69 @@ | |||
import api from 'flavours/glitch/util/api'; | |||
export const ACCOUNT_NOTE_SUBMIT_REQUEST = 'ACCOUNT_NOTE_SUBMIT_REQUEST'; | |||
export const ACCOUNT_NOTE_SUBMIT_SUCCESS = 'ACCOUNT_NOTE_SUBMIT_SUCCESS'; | |||
export const ACCOUNT_NOTE_SUBMIT_FAIL = 'ACCOUNT_NOTE_SUBMIT_FAIL'; | |||
export const ACCOUNT_NOTE_INIT_EDIT = 'ACCOUNT_NOTE_INIT_EDIT'; | |||
export const ACCOUNT_NOTE_CANCEL = 'ACCOUNT_NOTE_CANCEL'; | |||
export const ACCOUNT_NOTE_CHANGE_COMMENT = 'ACCOUNT_NOTE_CHANGE_COMMENT'; | |||
export function submitAccountNote() { | |||
return (dispatch, getState) => { | |||
dispatch(submitAccountNoteRequest()); | |||
const id = getState().getIn(['account_notes', 'edit', 'account_id']); | |||
api(getState).post(`/api/v1/accounts/${id}/note`, { | |||
comment: getState().getIn(['account_notes', 'edit', 'comment']), | |||
}).then(response => { | |||
dispatch(submitAccountNoteSuccess(response.data)); | |||
}).catch(error => dispatch(submitAccountNoteFail(error))); | |||
}; | |||
}; | |||
export function submitAccountNoteRequest() { | |||
return { | |||
type: ACCOUNT_NOTE_SUBMIT_REQUEST, | |||
}; | |||
}; | |||
export function submitAccountNoteSuccess(relationship) { | |||
return { | |||
type: ACCOUNT_NOTE_SUBMIT_SUCCESS, | |||
relationship, | |||
}; | |||
}; | |||
export function submitAccountNoteFail(error) { | |||
return { | |||
type: ACCOUNT_NOTE_SUBMIT_FAIL, | |||
error, | |||
}; | |||
}; | |||
export function initEditAccountNote(account) { | |||
return (dispatch, getState) => { | |||
const comment = getState().getIn(['relationships', account.get('id'), 'note']); | |||
dispatch({ | |||
type: ACCOUNT_NOTE_INIT_EDIT, | |||
account, | |||
comment, | |||
}); | |||
}; | |||
}; | |||
export function cancelAccountNote() { | |||
return { | |||
type: ACCOUNT_NOTE_CANCEL, | |||
}; | |||
}; | |||
export function changeAccountNoteComment(comment) { | |||
return { | |||
type: ACCOUNT_NOTE_CHANGE_COMMENT, | |||
comment, | |||
}; | |||
}; |
@ -0,0 +1,103 @@ | |||
import React from 'react'; | |||
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 'flavours/glitch/components/icon'; | |||
import Textarea from 'react-textarea-autosize'; | |||
const messages = defineMessages({ | |||
placeholder: { id: 'account_note.placeholder', defaultMessage: 'No comment provided' }, | |||
}); | |||
export default @injectIntl | |||
class Header 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, | |||
intl: PropTypes.object.isRequired, | |||
}; | |||
handleChangeAccountNote = (e) => { | |||
this.props.onChangeAccountNote(e.target.value); | |||
}; | |||
componentWillUnmount () { | |||
if (this.props.isEditing) { | |||
this.props.onCancelAccountNote(); | |||
} | |||
} | |||
handleKeyDown = e => { | |||
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { | |||
this.props.onSaveAccountNote(); | |||
} else if (e.keyCode === 27) { | |||
this.props.onCancelAccountNote(); | |||
} | |||
} | |||
render () { | |||
const { account, accountNote, isEditing, isSubmitting, intl } = this.props; | |||
if (!account || (!accountNote && !isEditing)) { | |||
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' /> | |||
</button> | |||
<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' /> | |||
</button> | |||
</div> | |||
); | |||
} | |||
let note_container = null; | |||
if (isEditing) { | |||
note_container = ( | |||
<Textarea | |||
className='account__header__account-note__content' | |||
disabled={isSubmitting} | |||
placeholder={intl.formatMessage(messages.placeholder)} | |||
value={accountNote} | |||
onChange={this.handleChangeAccountNote} | |||
onKeyDown={this.handleKeyDown} | |||
autoFocus | |||
/> | |||
); | |||
} else { | |||
note_container = (<div className='account__header__account-note__content'>{accountNote}</div>); | |||
} | |||
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') }} /></strong> | |||
{!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' /> | |||
</button> | |||
</div> | |||
)} | |||
</div> | |||
{note_container} | |||
{action_buttons} | |||
</div> | |||
); | |||
} | |||
} |
@ -0,0 +1,34 @@ | |||
import { connect } from 'react-redux'; | |||
import { changeAccountNoteComment, submitAccountNote, initEditAccountNote, cancelAccountNote } from 'flavours/glitch/actions/account_notes'; | |||
import AccountNote from '../components/account_note'; | |||
const mapStateToProps = (state, { account }) => { | |||
const isEditing = state.getIn(['account_notes', 'edit', 'account_id']) === account.get('id'); | |||
return { | |||
isSubmitting: state.getIn(['account_notes', 'edit', 'isSubmitting']), | |||
accountNote: isEditing ? state.getIn(['account_notes', 'edit', 'comment']) : account.getIn(['relationship', 'note']), | |||
isEditing, | |||
}; | |||
}; | |||
const mapDispatchToProps = (dispatch, { account }) => ({ | |||
onEditAccountNote() { | |||
dispatch(initEditAccountNote(account)); | |||
}, | |||
onSaveAccountNote() { | |||
dispatch(submitAccountNote()); | |||
}, | |||
onCancelAccountNote() { | |||
dispatch(cancelAccountNote()); | |||
}, | |||
onChangeAccountNote(comment) { | |||
dispatch(changeAccountNoteComment(comment)); | |||
}, | |||
}); | |||
export default connect(mapStateToProps, mapDispatchToProps)(AccountNote); |
@ -0,0 +1,44 @@ | |||
import { Map as ImmutableMap } from 'immutable'; | |||
import { | |||
ACCOUNT_NOTE_INIT_EDIT, | |||
ACCOUNT_NOTE_CANCEL, | |||
ACCOUNT_NOTE_CHANGE_COMMENT, | |||
ACCOUNT_NOTE_SUBMIT_REQUEST, | |||
ACCOUNT_NOTE_SUBMIT_FAIL, | |||
ACCOUNT_NOTE_SUBMIT_SUCCESS, | |||
} from '../actions/account_notes'; | |||
const initialState = ImmutableMap({ | |||
edit: ImmutableMap({ | |||
isSubmitting: false, | |||
account_id: null, | |||
comment: null, | |||
}), | |||
}); | |||
export default function account_notes(state = initialState, action) { | |||
switch (action.type) { | |||
case ACCOUNT_NOTE_INIT_EDIT: | |||
return state.withMutations((state) => { | |||
state.setIn(['edit', 'isSubmitting'], false); | |||
state.setIn(['edit', 'account_id'], action.account.get('id')); | |||
state.setIn(['edit', 'comment'], action.comment); | |||
}); | |||
case ACCOUNT_NOTE_CHANGE_COMMENT: | |||
return state.setIn(['edit', 'comment'], action.comment); | |||
case ACCOUNT_NOTE_SUBMIT_REQUEST: | |||
return state.setIn(['edit', 'isSubmitting'], true); | |||
case ACCOUNT_NOTE_SUBMIT_FAIL: | |||
return state.setIn(['edit', 'isSubmitting'], false); | |||
case ACCOUNT_NOTE_SUBMIT_SUCCESS: | |||
case ACCOUNT_NOTE_CANCEL: | |||
return state.withMutations((state) => { | |||
state.setIn(['edit', 'isSubmitting'], false); | |||
state.setIn(['edit', 'account_id'], null); | |||
state.setIn(['edit', 'comment'], null); | |||
}); | |||
default: | |||
return state; | |||
} | |||
} |