application/components/author/author-item.js
import React, { Component } from 'react';
import {browserHistory} from 'react-router';
import {connect} from 'react-redux';
import Immutable from 'immutable';
import uuid from 'uuid';
import Paper from 'material-ui/Paper';
import FontIcon from 'material-ui/FontIcon';
import FlatButton from 'material-ui/FlatButton';
import IconButton from 'material-ui/IconButton';
import TextField from 'material-ui/TextField';
import Checkbox from 'material-ui/Checkbox';
import Subheader from 'material-ui/Subheader';
import Divider from 'material-ui/Divider';
import {Row, Col} from './../flexbox';
import RichEditor from './../common/rich-editor';
import LoadingIndicator from './../common/loading-indicator';
import DeleteButton from './../common/delete-button';
import {rawToHtml} from './../../util/rawToHtml';
import {sluggify} from './../../util/strings';
import {
authorCreate,
authorUpdate,
authorsFetchOne,
authorsRemove
} from './../../redux/actions/author-actions';
import {
snackbarShowMessage
} from './../../redux/actions/snackbar-actions';
class AuthorItem extends Component {
constructor(props) {
super(props);
this.getUuid = this.getUuid.bind(this);
this.toHtml = this.toHtml.bind(this);
this.isNew = this.isNew.bind(this);
this.state = {
isReady: false,
editorContent: '',
editorRaw: {},
author: Immutable.fromJS({})
};
}
componentWillMount() {
const {dispatch} = this.props;
if (!this.isNew()) {
dispatch(authorsFetchOne(this.getUuid()))
.then(() => {
const author = this.props.authors.items.find((item) => item.get('uuid') == this.getUuid());
this.setState({
author: author,
isReady: true
});
});
} else {
this.setState({
author: Immutable.fromJS({}),
isReady: true
});
}
}
/**
* Return the requested UID, starts with UUID property,
* then goes to the URL property.
* @return {string}
*/
getUuid() {
if (this.props.uuid) {
return this.props.uuid;
}
if (this.props.params && this.props.params.id) {
return this.props.params.id;
}
return false;
}
toHtml(contentState) {
return rawToHtml(contentState);
}
isNew() {
if (!this.getUuid() || this.getUuid() === 'new') {
return true;
}
return false;
}
handleTextChange(e) {
const key = e.target.name;
let author = this.state.author.asMutable();
switch(key) {
case 'status':
author.set('status', this.state.author.get('status') ? false : true);
break;
case 'slug':
author.set(key, sluggify(e.target.value, true));
break;
case 'name':
author.set('slug', sluggify(e.target.value, true));
author.set(key, e.target.value);
break;
default:
author.set(key, e.target.value);
break;
}
console.log(author);
this.setState({'author': author.asImmutable()});
}
handleCheckChange(e, isChecked) {
const key = e.target.name;
let author = this.state.author.asMutable();
author.set('status', isChecked ? 1 : 0);
this.setState({'author': author.asImmutable()});
}
handleEditorChange(raw, editorState, name) {
this.setState({'editorContent': editorState.getCurrentContent(), 'editorRaw': raw});
}
toHtml(state) {
return rawToHtml(state);
}
handleDelete() {
const {dispatch} = this.props;
dispatch(authorsRemove(this.getUuid()))
.then(() => {
browserHistory.goBack();
dispatch(snackbarShowMessage('Author removed'));
});
}
handleSave() {
let data = {
'name': this.state.author.get('name'),
'email': this.state.author.get('email'),
'tagline': this.state.author.get('tagline'),
'slug': this.state.author.get('slug'),
'status': this.state.author.get('status')
};
if (this.state.editorContent) {
data['description'] = this.toHtml(this.state.editorContent);
data['description_raw'] = this.state.editorRaw;
}
if (this.state.author.get('metadata')) {
const metadata = this.state.author.get('metadata').toArray();
if (metadata.length) {
data['metadata'] = metadata;
}
}
const {dispatch} = this.props;
if (!this.isNew()) {
dispatch(authorUpdate(this.getUuid(), data))
.then(() => {
dispatch(snackbarShowMessage('Author updated'));
})
.then(() => {
browserHistory.goBack();
});
} else {
dispatch(authorCreate(data))
.then(() => {
dispatch(snackbarShowMessage('Author created'));
})
.then(() => {
browserHistory.goBack();
});
}
}
handleMetaLabelChange(id, e) {
if (id == 'new') {
this.setState({'newMetaLabel': e.target.value});
return;
}
let metadata = this.state.author.get('metadata') ? this.state.author.get('metadata') : Immutable.fromJS([]);
const key = metadata.findIndex(item => item.get('id') == id);
let item = metadata.get(key);
const label = e.target.value;
item = item.set('label', label);
metadata = metadata.set(key, item);
this.setState({
author: this.state.author.set('metadata', metadata)
});
}
handleMetaValueChange(id, e) {
if (id == 'new') {
this.setState({'newMetaValue': e.target.value});
return;
}
let metadata = this.state.author.get('metadata') ? this.state.author.get('metadata') : Immutable.fromJS([]);
const key = metadata.findIndex(item => item.get('id') == id);
let item = metadata.get(key);
const value = e.target.value;
item = item.set('value', value);
metadata = metadata.set(key, item);
this.setState({
author: this.state.author.set('metadata', metadata)
});
}
handleMetaAdd(e) {
const id = uuid.v4();
let metadata = this.state.author.get('metadata') ? this.state.author.get('metadata') : Immutable.fromJS([]);
const newSet = Immutable.fromJS({
id: id,
label: this.state.newMetaLabel ? this.state.newMetaLabel : '',
value: this.state.newMetaValue ? this.state.newMetaValue : ''
});
metadata = metadata.push(newSet);
const author = this.state.author.set('metadata', metadata);
this.setState({
author: author,
newMetaLabel: '',
newMetaValue: ''
});
}
handleMetaRemove(id, e) {
const metadata = this.state.author.get('metadata').filter(meta => meta.get('id') != id);
this.setState({
author: this.state.author.set('metadata', metadata)
});
}
handleMetaKeyPress(e) {
if (e.key == 'Enter' || e.key == 'enter') {
this.handleMetaAdd.call(this, e);
}
return;
}
render() {
const metadata = this.state.author.get('metadata') ? this.state.author.get('metadata') : Immutable.fromJS([]);
return (
<div className="author-item-root">
<Row>
<Col xs={8} offsetXs={2}>
<Paper>
<Row middle='xs'>
<Col xs={6}>
<FlatButton
primary={true}
label='Save'
icon={<FontIcon className='mui-icons'>save</FontIcon>}
onClick={this.handleSave.bind(this)}
style={{marginLeft:'20px'}}
/>
</Col>
<Col xs={6} end='xs'>
<DeleteButton
disabled={this.isNew()}
onDelete={this.handleDelete.bind(this)}
/>
</Col>
</Row>
</Paper>
<Paper className='clear-top clear-bottom padded'>
<TextField
name='name'
fullWidth={true}
floatingLabelText='Author Name'
value={this.state.author.get('name')}
onChange={this.handleTextChange.bind(this)}
/>
<TextField
name='slug'
fullWidth={true}
floatingLabelText='Slug'
value={this.state.author.get('slug')}
onChange={this.handleTextChange.bind(this)}
/>
<TextField
name='email'
fullWidth={true}
floatingLabelText='Email'
value={this.state.author.get('email')}
onChange={this.handleTextChange.bind(this)}
/>
<TextField
name='tagline'
fullWidth={true}
floatingLabelText='Tagline'
value={this.state.author.get('tagline')}
onChange={this.handleTextChange.bind(this)}
/>
<div className='clear-top clear-bottom'>
<Checkbox
label='Active author'
name='active'
checked={parseInt(this.state.author.get('status')) || this.isNew() ? true : false}
onCheck={this.handleCheckChange.bind(this)}
/>
</div>
<div className='editor-container'>
<RichEditor
label='Description'
enableComments={false}
defaultValue={this.state.author.get('description_raw') ? this.state.author.get('description_raw') : this.state.author.get('description')}
onChange={this.handleEditorChange.bind(this)}
/>
</div>
<div className="clear-top">
<Subheader>Meta Properties</Subheader>
{metadata.map((meta) => (
<Row key={meta.get('id')} bottom='xs'>
<Col xs={3}>
<TextField
fullWidth={true}
floatingLabelText='Label'
value={meta.get('label')}
onChange={this.handleMetaLabelChange.bind(this, meta.get('id'))}
/>
</Col>
<Col xs={8}>
<TextField
fullWidth={true}
floatingLabelText={'Value'}
value={meta.get('value')}
onChange={this.handleMetaValueChange.bind(this, meta.get('id'))}
/>
</Col>
<Col xs={1} start='xs' bottom='xs'>
<IconButton
className='secondary-button'
onClick={this.handleMetaRemove.bind(this, meta.get('id'))}>
<FontIcon className='mui-icons'>close</FontIcon>
</IconButton>
</Col>
</Row>
))}
<Row bottom='xs'>
<Col xs={3}>
<TextField
fullWidth={true}
floatingLabelText='Label'
value={this.state.newMetaLabel}
onKeyPress={this.handleMetaKeyPress.bind(this)}
onChange={this.handleMetaLabelChange.bind(this, 'new')}
/>
</Col>
<Col xs={8}>
<TextField
fullWidth={true}
floatingLabelText={'Value'}
value={this.state.newMetaValue}
onKeyPress={this.handleMetaKeyPress.bind(this)}
onChange={this.handleMetaValueChange.bind(this, 'new')}
/>
</Col>
<Col xs={1} start='xs' bottom='xs'>
<IconButton
className='secondary-button'
onClick={this.handleMetaAdd.bind(this)}>
<FontIcon className='mui-icons'>add</FontIcon>
</IconButton>
</Col>
</Row>
</div>
</Paper>
</Col>
</Row>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
authors: state.authors
};
}
export default connect(mapStateToProps)(AuthorItem);