components/Dialogs/Dialogs.jsx

/**
 * Окно диалогов пользователя
 * @module Dialogs
 * @author Ihor Bielchenko
 * @requires react
 * @requires react#Component
 * @requires redux#bindActionCreators
 * @requires react-redux#connect
 * @requires actions/StateNoticesAction.js
 * @requires actions/StateConfigAction.js
 */

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import jQuery from 'jquery';
import './emojionearea/dist/emojionearea.js';
import './emojionearea/dist/emojionearea.css';
import Link from '../Common/Link.jsx';
import Message from '../../img/title-message.png';
import Cancel from '../../img/title-cancel.png';
import Contact from '../../img/choose-contact-icon.png';
import More from '../../img/more.png';
import Clip from '../../img/clip.png';
import ArrowB from '../../img/arrow-bottom.png';
import Attach from '../../img/attach.png';
import Send from '../../img/send-message.png';
import * as StateNoticesAction from '../../actions/StateNoticesAction.js';
import * as StateConfigAction from '../../actions/StateConfigAction.js';

/**
 * Окно диалогов пользователя
 * @extends Component
 */
class Dialogs extends Component {

	/**
	 * Invoked immediately after a component is mounted
	 * @fires componentDidMount
	 */
	componentDidMount() {
		jQuery('#chat-textarea').emojioneArea();
		jQuery('body').css('overflow', 'hidden');
		jQuery('#js_messages-block').scrollTop(jQuery('#js_messages-block')[0].scrollHeight);

		this.readMessages();
	}

	/**
	 * Invoked immediately before a component is unmounted
	 * @fires componentDidMount
	 */
	componentWillUnmount() {
		jQuery('body').css('overflow', 'auto');
	}

	/**
	 * Сделать все сообщения в текущем диалоге прочитанными
	 */
	readMessages() {
		var i,
			current;

		for(i = 0; i < this.props.notices.items.length; i++) {
			if(this.props.notices.items[i].id === this.props.notices.current_dialog) {
				current = this.props.notices.items[i];
				break;
			}
		}

		for(i = 0; i < current.messages.length; i++) {
			current.messages[i].readed = 1;
		}
		this.props.StateNoticesAction.update(this.props.notices);
	}

	/**
	 * Отпрвка сообщения
	 * @fires submit
	 * @param {Object} e
	 */
	sendMessage(e) {
		e.preventDefault();
		let el = jQuery('#chat-textarea');
		let value = el.val();

		if(this.props.notices.current_dialog !== 0 && value !== '' && typeof value !== 'undefined') {
			this.props.StateNoticesAction.sendMessage(this.props.notices, value, this.props.user.id, () => {
				el.val('');
				jQuery('.emojionearea-editor').html('');
				jQuery('#js_messages-block').scrollTop(jQuery('#js_messages-block')[0].scrollHeight);
			});
		}
	}

	/**
	 * Открыть диалог
	 * @fires click
	 * @param {Number} dialogID id диалога, который нужно открвыть
	 * @param {Object} e
	 */
	open(dialogID, e) {
		this.props.notices.current_dialog = dialogID;
		this.props.StateNoticesAction.update(this.props.notices, () => {
			this.readMessages();
		});
	}

	/**
	 * Render component
	 * @return {Object} jsx object
	 */
	render() {
		let lang = this.props.lang;
		var contacts = [],
			messages = [],
			i, last, length,
			current,
			currentIndex = 0;

		for(i = 0; i < this.props.notices.items.length; i++) {
			length = this.props.notices.items[i].messages.length;
			last = this.props.notices.items[i].messages[length - 1];

			if(this.props.notices.items[i].id === this.props.notices.current_dialog) {
				current = this.props.notices.items[i];
				currentIndex = i;
			}

			contacts.push(<div key={i}
							className={this.props.notices.items[i].id === this.props.notices.current_dialog	?
								'item dialog-item active' :
								'item dialog-item'}
							onClick={this.open.bind(this, this.props.notices.items[i].id)}>
								<div className="avatar">
									<img src={this.props.notices.items[i].avatar_62x62} alt="avatar" />
								</div>
								
								<div className="right-info">
									<div className="name">
										<span>{this.props.notices.items[i].username}</span>
										<Link>
											<img className="more" src={More} alt="more" />
										</Link>
									</div>
									<div className="text">
										<span>{last.introtext} [...]</span>
										<Link>
											<img src={Clip} alt="clip" />
										</Link>
									</div>
								</div>
						</div>);
		}

		for(i = 0; i < this.props.notices.items[currentIndex].messages.length; i++) {
			if(this.props.notices.items[currentIndex].messages[i].user_id === this.props.user.id) {
				messages.push(<div className="message-template my-message-template" key={i}>
								<div className="right-block">
									<span className="message-text">
										{this.props.notices.items[currentIndex].messages[i].content}
									</span>
								</div>
								<div className="avatar-left">
									<div className="avatar-block">
										<img src={this.props.user.avatar_32x32} alt="avatar" />
									</div>
									<span className="time">{this.props.notices.items[currentIndex].messages[i].time}</span>
								</div>
							</div>);
			}

			else {
				messages.push(<div className="message-template" key={i}>
								<div className="avatar-left">
									<div className="avatar-block">
										<img src="http://placeimg.com/200/200/people" alt="avatar" />
									</div>
									<span className="time">{this.props.notices.items[currentIndex].messages[i].time}</span>
								</div>
								<div className="right-block">
									<span className="message-text">
										{this.props.notices.items[currentIndex].messages[i].content}
									</span>
								</div>
							</div>);
			}
		}

		return <div className="modal fade popup-chat show" 
					id="popup23" 
					tabIndex="-1" 
					role="dialog">
				
				<div className="modal-dialog" role="document">
					<div className="modal-content">
						<div className="title">
							<img src={Message} alt="message" />
							<span>{lang.dialogs_title}</span>
							<Link
								data-dismiss="modal" 
								className="dismiss"
								onClick={() => {
									this.props.StateConfigAction.showElement(this.props.config, 'dialogs');
								}}>
									<img src={Cancel} alt="cancel" />
							</Link>
						</div>
						
						<div className="block">
							<div className="left-block">
								<div className="title-block">
									<img src={Contact} alt="contact" />
									<span>{lang.select_contact_title}</span>
								</div>

								<div className="contact-list">
									{contacts}
								</div>

								<div className="open">
									<img src={ArrowB} alt="arrow button" />
								</div>
							</div>
							
							<div className="right-block">
								<div className="title-block">{lang.dialog_width_title} {current.username}</div>
								<div className="messages-block js_messages-block"
									id="js_messages-block">
										{messages}
								</div>

								<form onSubmit={this.sendMessage.bind(this)}>
									<div className="textarea-block">

										<Link href="">
											<img src={Attach} alt="attach" />
										</Link>
										<textarea id="chat-textarea"
												className="chat-textarea" 
												placeholder={lang.write_your_msg_title}></textarea>

										<button type="submit" 
											className="submit">
												<img src={Send} alt="send" />
										</button>
									</div>
								</form>
							</div>
						</div>
					</div>
				</div>
			</div>
	}
}

/**
 * Init redux states
 * @param {Object} state
 * @return {Object}
 */
function mapStateToProps(state) {
	return {
		lang: state.lang,
		user: state.user,
		config: state.config,
		notices: state.notices
	}
}

/**
 * Init redux actions
 * @param {Function} dispatch
 * @return {Object}
 */
function mapDispatchToProps(dispatch) {
	return {
		StateNoticesAction: bindActionCreators(StateNoticesAction, dispatch),
		StateConfigAction: bindActionCreators(StateConfigAction, dispatch),
	}
}

export default connect(mapStateToProps, mapDispatchToProps)(Dialogs);