Home Reference Source

application/components/custom-content/channel.js

import React from 'react';
import {connect} from 'react-redux';
import Immutable from 'immutable';
import uuid from 'uuid';

import Paper from 'material-ui/Paper';
import Subheader from 'material-ui/Subheader';
import Divider from 'material-ui/Divider';
import FlatButton from 'material-ui/FlatButton';
import RaisedButton from 'material-ui/RaisedButton';
import IconButton from 'material-ui/IconButton';
import FontIcon from 'material-ui/FontIcon';
import TextField from 'material-ui/TextField';
import CheckBox from 'material-ui/Checkbox';
import DeleteButton from './../common/delete-button';

import {browserHistory, Link} from 'react-router';

import {Row, Col} from './../flexbox';
import Config from './../../config';
import CurrentUser from './../../current-user';

import EntryField from './field';

import {sluggify} from './../../util/strings';

import {
    channelsFetchOne,
    channelCreate,
    channelUpdate,
    channelsRemove
} from './../../redux/actions/channel-actions';

import {
    snackbarShowMessage
} from './../../redux/actions/snackbar-actions';

class CustomContentChannel extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            'channel': Immutable.fromJS({
                'channelMeta': []
            }),
            'isReady': false,
            'newFields': Immutable.fromJS([]),
            'newFieldElements': []
        };
    }

    getRouter() {
        return this.props.router;
    }

    /**
     * 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;
    }

    isNew() {
        if (!this.getUuid() || this.getUuid() === 'new') {
            return true;
        }

        return false;
    }

    componentWillMount() {
        const {dispatch} = this.props;

        if (!this.isNew()) {
            dispatch(channelsFetchOne(this.getUuid()))
                .then(() => {
                    const channel = this.props.channels.items.find((item) => item.get('uuid') == this.getUuid());
                    this.setState({
                        channel: channel,
                        isReady: true
                    });
                });
        } else {
            this.setState({
                channel: Immutable.fromJS({
                    channelMeta: []
                }),
                isReady: true
            });
        }
    }

    componentDidMount() {
    }

    handleSave(e) {
        let data = {
            'title':    this.state.channel.get('title'),
            'slug':     this.state.channel.get('slug'),
            'is_routable': this.state.channel.get('is_routable') ? 1 : 0,
            'channelMeta':   []
        };

        // process the existing fields
        this.state.channel.get('channelMeta').map((item) => {
            let fieldData = {
                'uuid': item.get('uuid'),
                'type': item.get('type'),
                'label': item.get('label'),
                'description': item.get('description')
            };

            data.channelMeta.push(fieldData);
        });

        const {dispatch} = this.props;

        if (!this.isNew()) {
            dispatch(channelUpdate(this.getUuid(), data))
                .then(() => {
                    dispatch(snackbarShowMessage('Channel saved'));
                    browserHistory.push('/ceo/redirect?next=custom/channel/' + this.getUuid());
                });
        } else {
            dispatch(channelCreate(data))
                .then((resp) => {
                    dispatch(snackbarShowMessage('Channel created'));
                    const uuid = resp.payload.channel.get('uuid');
                    browserHistory.push('/ceo/redirect?next=custom/channel/' + uuid);
                });
        }
    }

    handleDelete() {
        const {dispatch} = this.props;
        dispatch(channelsRemove(this.getUuid()))
            .then(() => {
                browserHistory.push('/ceo/custom');
                dispatch(snackbarShowMessage('Channel removed'));
            });
    }

    handleTextChange(e) {
        const key = e.target.name;
        let channel = this.state.channel.asMutable();

        switch(key) {
            case 'slug':
                channel.set(key, sluggify(e.target.value, true));
                break;
            case 'title':
                channel.set('slug', sluggify(e.target.value, true));
                channel.set(key, e.target.value);
                break;
            default:
                channel.set(key, e.target.value);
                break;
        }

        this.setState({'channel': channel.asImmutable()});
    }

    handleUpdateRoutable(e, checked) {
        let channel = this.state.channel.asMutable();
        channel.set('is_routable', checked ? 1 : 0);

        this.setState({'channel': channel.asImmutable()});
    }


    handleAddField(e) {
        const field = {
            'uuid': uuid.v4(),
            'type': null,
            'label': null,
            'description': null,
            'isNew': true
        };
        const newFieldData = Immutable.fromJS(field);

        this.setState({
            channel: this.state.channel.set(
                'channelMeta', this.state.channel.get('channelMeta').push(newFieldData)
            )
        });
    }

    handleFieldsChanged(field) {
        const uuid = field.uuid;
        const index = this.state.channel.get('channelMeta').findIndex((item) => item.get('uuid') == uuid);
        const newFieldData = Immutable.fromJS(field);

        this.setState({
            channel: this.state.channel.set('channelMeta', this.state.channel.get('channelMeta').set(index, newFieldData))
        });
    }

    handleRemoveField(field) {
        const uuid = field.uuid;
        let index = this.state.channel.get('channelMeta').findIndex((item) => item.get('uuid') == uuid);

        if (index == -1) {
            return;
        }

        let channel = this.state.channel;
        const newMeta = channel.get('channelMeta').delete(index);
        const newChannel = channel.set('channelMeta', newMeta);

        this.setState({
            channel: newChannel
        });
    }

    render() {
        return (
            <div className="channel-item-root">
                <Row>
                    <Col xs={8} offsetXs={2}>
                        <Paper className='toolbar' style={{ paddingTop:'10px', paddingBottom:'10px' }}>
                            <Row middle='xs'>
                                <Col xs={1}>
                                    <IconButton
                                        containerElement={<Link to="/ceo/custom" />}
                                        >
                                        <FontIcon className="mui-icons">keyboard_arrow_left</FontIcon>
                                    </IconButton>
                                </Col>
                                <Col xs={6}>
                                    <FlatButton
                                        label="Save Channel"
                                        primary={true}
                                        onClick={this.handleSave.bind(this)}
                                        />
                                </Col>
                                <Col xs={5} end='xs'>
                                    <DeleteButton
                                        disabled={this.isNew()}
                                        onDelete={this.handleDelete.bind(this)}
                                        />
                                </Col>
                            </Row>
                        </Paper>

                        <Row top='xs'>
                            <Col xs={12}>
                                <Paper className='padded clear-bottom'>
                                    <p>Channels are the basic container for custom content. Here you can define the fields for each custom channel type.</p>
                                    <p>A publicly routable channel is one that can be accessed using its slug as the URL on your site.</p>
                                    <TextField
                                        name='title'
                                        fullWidth={true}
                                        floatingLabelText='Channel Title'
                                        value={this.state.channel.get('title')}
                                        onChange={this.handleTextChange.bind(this)}
                                        />

                                    <TextField
                                        name='slug'
                                        fullWidth={true}
                                        floatingLabelText='Slug'
                                        value={this.state.channel.get('slug')}
                                        onChange={this.handleTextChange.bind(this)}
                                        />

                                    <CheckBox
                                        name='is_routable'
                                        label='Channel is publicly routable'
                                        checked={parseInt(this.state.channel.get('is_routable')) ? true : false}
                                        onCheck={this.handleUpdateRoutable.bind(this)}
                                        />
                                </Paper>

                                {this.state.channel.get('channelMeta').map((item) => {
                                    return <Paper className="padded clear-bottom"><EntryField field={item} onRemove={this.handleRemoveField.bind(this)} onChange={this.handleFieldsChanged.bind(this)} /></Paper>
                                })}

                                <RaisedButton
                                    secondary={true}
                                    label="Add Field"
                                    onClick={this.handleAddField.bind(this)}
                                    />

                            </Col>
                        </Row>
                    </Col>
                </Row>
            </div>
        );
    }
}

const mapStateToProps = state => {
    return {
        channels: state.channels
    };
}

export default connect(mapStateToProps)(CustomContentChannel);