<commit_before>import React from 'react';
import { connect } from 'react-redux';
import _ from 'underscore';
import $ from 'jquery';
import moment from 'moment';

import * as actions from './actions';
import Avatar from './Avatar.jsx';
import News from './SiteComponents/News.jsx';
import AlertPanel from './SiteComponents/AlertPanel.jsx';
import Typeahead from './FormComponents/Typeahead.jsx';

class InnerLobby extends React.Component {
    constructor() {
        super();

        this.onChange = this.onChange.bind(this);
        this.onKeyPress = this.onKeyPress.bind(this);
        this.onSendClick = this.onSendClick.bind(this);
        this.onScroll = this.onScroll.bind(this);

        this.state = {
            canScroll: true,
            message: '',
            showUsers: false
        };
    }

    componentDidMount() {
        this.props.loadNews({ limit: 3 });
    }

    componentDidUpdate() {
        if(this.state.canScroll) {
            $(this.refs.messages).scrollTop(999999);
        }
    }

    sendMessage() {
        if(this.state.message === '') {
            return;
        }

        this.props.socket.emit('lobbychat', this.state.message);

        this.setState({ message: '' });
    }

    onKeyPress(event) {
        if(event.key === 'Enter') {
            this.sendMessage();

            this.refs.message.clear();

            event.preventDefault();
        }
    }

    onSendClick(event) {
        event.preventDefault();

        this.sendMessage();
    }

    onChange(value) {
        this.setState({ message: value });
    }

    onScroll() {
        let messages = this.refs.messages;

        setTimeout(() => {
            if(messages.scrollTop >= messages.scrollHeight - messages.offsetHeight - 20) {
                this.setState({ canScroll: true });
            } else {
                this.setState({ canScroll: false });
            }
        }, 500);
    }

    onBurgerClick() {
        this.setState({ showUsers: !this.state.showUsers });
    }

    render() {
        let index = 0;
        let groupedMessages = _.groupBy(this.props.messages, message => message.user && message.user.username + moment(message.time).format('YYYYMMDDHHmm'));
        let today = moment();
        let yesterday = moment().add(-1, 'days');

        let messages = _.map(groupedMessages, messages => {
            let timestamp = '';
            let firstMessage = _.first(messages);

            if(!firstMessage.user) {
                return;
            }

            if(today.isSame(firstMessage.time, 'd')) {
                timestamp = moment(firstMessage.time).format('H:mm');
            } else if(yesterday.isSame(firstMessage.time, 'd')) {
                timestamp = 'yesterday ' + moment(firstMessage.time).format('H:mm');
            } else {
                timestamp = moment(firstMessage.time).format('MMM Do H:mm');
            }

            let renderedMessages = _.map(messages, message => {
                if(!message.user) {
                    return;
                }
                return (<div className='lobby-message'>{ message.message }</div>);
            });

            return (
                <div key={ timestamp + firstMessage.user.username + (index++).toString() }>
                    <Avatar emailHash={ firstMessage.user.emailHash } float forceDefault={ firstMessage.user.noAvatar } />
                    <span className='username'>{ firstMessage.user.username }</span><span>{ timestamp }</span>
                    { renderedMessages }
                </div>
            );
        });

        let userList = _.map(this.props.users, user => {
            return (
                <div className='user-row' key={ user.name }>
                    <Avatar emailHash={ user.emailHash } forceDefault={ user.noAvatar } />
                    <span>{ user.name }</span><commit_msg>Fix message grouping so that it doesnt bounce back and make messages go out of order<commit_after>import React from 'react';
import { connect } from 'react-redux';
import _ from 'underscore';
import $ from 'jquery';
import moment from 'moment';

import * as actions from './actions';
import Avatar from './Avatar.jsx';
import News from './SiteComponents/News.jsx';
import AlertPanel from './SiteComponents/AlertPanel.jsx';
import Typeahead from './FormComponents/Typeahead.jsx';

class InnerLobby extends React.Component {
    constructor() {
        super();

        this.onChange = this.onChange.bind(this);
        this.onKeyPress = this.onKeyPress.bind(this);
        this.onSendClick = this.onSendClick.bind(this);
        this.onScroll = this.onScroll.bind(this);

        this.state = {
            canScroll: true,
            message: '',
            showUsers: false
        };
    }

    componentDidMount() {
        this.props.loadNews({ limit: 3 });
    }

    componentDidUpdate() {
        if(this.state.canScroll) {
            $(this.refs.messages).scrollTop(999999);
        }
    }

    sendMessage() {
        if(this.state.message === '') {
            return;
        }

        this.props.socket.emit('lobbychat', this.state.message);

        this.setState({ message: '' });
    }

    onKeyPress(event) {
        if(event.key === 'Enter') {
            this.sendMessage();

            this.refs.message.clear();

            event.preventDefault();
        }
    }

    onSendClick(event) {
        event.preventDefault();

        this.sendMessage();
    }

    onChange(value) {
        this.setState({ message: value });
    }

    onScroll() {
        let messages = this.refs.messages;

        setTimeout(() => {
            if(messages.scrollTop >= messages.scrollHeight - messages.offsetHeight - 20) {
                this.setState({ canScroll: true });
            } else {
                this.setState({ canScroll: false });
            }
        }, 500);
    }

    onBurgerClick() {
        this.setState({ showUsers: !this.state.showUsers });
    }

    getMessages() {
        let groupedMessages = {};
        let index = 0;
        let today = moment();
        let yesterday = moment().add(-1, 'days');
        let lastUser;
        let currentGroup = 0;

        _.each(this.props.messages, message => {
            if(!message.user) {
                return;
            }

            let formattedTime = moment(message.time).format('YYYYMMDDHHmm');
            if(lastUser && message.user && lastUser !== message.user.username) {
                currentGroup++;
            }

            let key = message.user.username + formattedTime + currentGroup;

            console.info(key);

            if(!groupedMessages[key]) {
                groupedMessages[key] = [];
            }

            groupedMessages[key].push(message);

            lastUser = message.user.username;
        });

        return _.map(groupedMessages, messages => {
            let timestamp = '';
            let firstMessage = _.first(messages);

            if(!firstMessage.user) {
                return;
            }

            if(today.isSame(firstMessage.time, 'd')) {
                timestamp = moment(firstMessage.time).format('H:mm');
            } else if(yesterday.isSame(firstMessage.time, 'd')) {
                timestamp = 'yesterday ' + moment(firstMessage.time).format('H:mm');
            } else {
                timestamp = moment(firstMessage.time).format('MMM Do H:mm');
            }

            let renderedMessages = _.map(messages, message => {
                if(!message.user) {
                    return;
                }
                return (<div className='lobby-message'>{ message.message }</div>);
            });

            return (
                <div key={ timestamp + firstMessage.user.username + (index++).toString() }>
                    <Avatar emailHash={ firstMessage.user.emailHash } float forceDefault={ firstMessage.user.noAvatar } />
                    <span className='username'>{ firstMessage.user.username }</span><span>{ timestamp }</span>
                    { renderedMessages }
                </div>
            );
        });
    }

    render() {
        let messages = this.getMessages();

        let userList = _.map(this.props.users, user => {
            return (
                <div className='user-row' key={ user.name }>
                    <Avatar emailHash={ user.emailHash } forceDefault={ user.noAvatar } />
                    <span>{ user.name }</span>
{'fraction_non_alphanumeric': 0.13574392412566685, 'fraction_numerical': 0.0034380557202133965, 'mean_word_length': 1.771353482260184, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3692526', 'n_tokens_mistral': 2352, 'n_tokens_neox': 2222, 'n_words': 438}