<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {withStyles} from 'material-ui/styles';
import List, {ListItem, ListItemText} from 'material-ui/List';
import Avatar from 'material-ui/Avatar';
import {getChatMessages} from '../selectors/chatSelectors';

const styles = (theme) => ({
    root: {
        width: '100%',
        flex: 'auto',
        overflowY: 'auto',
        height: 0,
        background: theme.palette.background.paper,
        marginBottom: theme.spacing.unit * 2,
    },
    avatar: {
        width: 32,
        height: 32,
    }
});

const mapStateToProps = (state) => ({
    messages: getChatMessages(state),
});

class ChatListContainer extends Component {
    static propTypes = {
        classes: PropTypes.object.isRequired,
        messages: PropTypes.arrayOf(
            PropTypes.shape({
                message: PropTypes.string,
            })
        ),
    };

    render() {
        const {classes, messages} = this.props;

        return (
            <div className={classes.root}>
                <List>
                    {messages.map((msg, key) => (
                        <ListItem key={key} dense>
                            <Avatar className={classes.avatar}>
                                {key.toString()}
                            </Avatar>
                            <ListItemText primary={msg.message}/>
                        </ListItem>
                    ))}
                </List>
            </div>
        );
    }
}

export default withStyles(styles)(connect(mapStateToProps)(ChatListContainer));<commit_msg>scroll chat to bottom<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {withStyles} from 'material-ui/styles';
import List, {ListItem, ListItemText} from 'material-ui/List';
import Avatar from 'material-ui/Avatar';
import {getChatMessages} from '../selectors/chatSelectors';

const calculationError = 1;

const styles = (theme) => ({
    root: {
        width: '100%',
        flex: 'auto',
        overflowY: 'auto',
        height: 0,
        background: theme.palette.background.paper,
        marginBottom: theme.spacing.unit * 2,
    },
    avatar: {
        width: 32,
        height: 32,
    },
});

const mapStateToProps = (state) => ({
    messages: getChatMessages(state),
});

class ChatListContainer extends Component {
    static propTypes = {
        classes: PropTypes.object.isRequired,
        messages: PropTypes.arrayOf(
            PropTypes.shape({
                message: PropTypes.string,
            })
        ),
    };

    refScrollArea = null;

    wasUserScroll = false;

    setRefScrollArea = (ref) => {
        this.refScrollArea = ref;
    };

    componentDidMount() {
        this.scrollToBottom();
    }

    componentDidUpdate(prevProps) {
        if (!this.wasUserScroll && this.props.messages.length !== prevProps.messages.length) {
            this.scrollToBottom();
        }
    }

    onScroll = () => {
        const scrollBottom = this.refScrollArea.scrollTop + this.refScrollArea.offsetHeight;

        // if scroll area is scrolled to the bottom
        // set wasUserScroll to false
        this.wasUserScroll = scrollBottom + calculationError < this.refScrollArea.scrollHeight;
    };

    scrollToBottom() {
        this.refScrollArea.scrollTop = this.refScrollArea.scrollHeight;
    }

    render() {
        const {classes, messages} = this.props;

        return (
            <div className={classes.root} ref={this.setRefScrollArea} onScroll={this.onScroll}>
                <List>
                    {messages.map((msg, key) => (
                        <ListItem key={key} dense>
                            <Avatar className={classes.avatar}>
                                {key.toString()}
                            </Avatar>
                            <ListItemText primary={msg.message}/>
                        </ListItem>
                    ))}
                </List>
            </div>
        );
    }
}

export default withStyles(styles)(connect(mapStateToProps)(ChatListContainer));
{'fraction_non_alphanumeric': 0.12184673964778676, 'fraction_numerical': 0.004521656354117087, 'mean_word_length': 1.8611300204220558, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 29, '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': '4217152', 'n_tokens_mistral': 1160, 'n_tokens_neox': 1128, 'n_words': 241}