Home Reference Source

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