<commit_before>'use strict'

import React, { useCallback, useEffect, useLayoutEffect, useState } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import debounce from 'lodash.debounce'

import MessageRow from './MessageRow'
import MessagesDateSeparator from './MessagesDateSeparator'
import { FirstMessage, LoadingMessages, LoadMore } from './MessageTypes'
import DelayRender from './DelayRender'

import { useVisibility, useRefCallback } from '../utils/hooks'

function MessageList ({
  messages,
  channelName,
  loading,
  hasUnreadMessages,
  entryCount,
  loadMore,
  resetOffset,
  theme,
  ...messageRowProps
}) {
  const [listRef, setListRef] = useRefCallback()

  const [atBottom, setAtBottom] = useState(true)

  const botMargin = 20

  function checkBoundaries () {
    if (!listRef) return

    const el = listRef
    const botVisible = el.scrollTop + el.clientHeight >= el.scrollHeight - botMargin

    setAtBottom(botVisible)
  }

  function stayAtBottom () {
    if (!listRef) return
    if (atBottom) listRef.scrollTop = listRef.scrollHeight
  }

  useEffect(() => () => resetOffset(), [])
  useLayoutEffect(checkBoundaries, [listRef])
  useLayoutEffect(stayAtBottom, [atBottom, listRef, entryCount])

  const checkBoundariesDebounced = useCallback(debounce(checkBoundaries, 40, { leading: true }), [
    listRef
  ])

  const onLoadMore = useCallback(() => {
    if (!listRef) return
    const el = listRef
    const scrollFromBot = el.scrollHeight - el.clientHeight - el.scrollTop
    loadMore()
    el.scrollTop = el.scrollHeight - el.clientHeight - scrollFromBot
  }, [listRef])

  return (
    <>
      <div
        ref={setListRef}
        onScroll={checkBoundariesDebounced}
        className={classNames('MessageList')}
      >
        {loading ? (
          <LoadingMessages />
        ) : messages.length < entryCount ? (
          <LoadMore parentElement={listRef} onActivate={onLoadMore} />
        ) : (
          <FirstMessage channelName={channelName} />
        )}
        {messages.map((m, index) => (
          <MessageListRow
            key={`message-${m.hash}`}
            parentElement={listRef}
            message={m}
            prevMessage={messages[index - 1]}
            {...messageRowProps}
          />
        ))}
      </div>
      {!atBottom && hasUnreadMessages ? <div className='unreadIndicator' style={theme} /> : null}
      <DelayRender visible={loading}>
        <div className='progressBar' style={theme} />
      </DelayRender>
    </>
  )
}

MessageList.propTypes = {
  messages: PropTypes.array.isRequired,<commit_msg>Allow to load more while network is loading<commit_after>'use strict'

import React, { useCallback, useEffect, useLayoutEffect, useState } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import debounce from 'lodash.debounce'

import MessageRow from './MessageRow'
import MessagesDateSeparator from './MessagesDateSeparator'
import { FirstMessage, LoadingMessages, LoadMore } from './MessageTypes'
import DelayRender from './DelayRender'

import { useVisibility, useRefCallback } from '../utils/hooks'

function MessageList ({
  messages,
  channelName,
  loading,
  hasUnreadMessages,
  entryCount,
  loadMore,
  resetOffset,
  theme,
  ...messageRowProps
}) {
  const [listRef, setListRef] = useRefCallback()

  const [atBottom, setAtBottom] = useState(true)

  const botMargin = 20

  function checkBoundaries () {
    if (!listRef) return

    const el = listRef
    const botVisible = el.scrollTop + el.clientHeight >= el.scrollHeight - botMargin

    setAtBottom(botVisible)
  }

  function stayAtBottom () {
    if (!listRef) return
    if (atBottom) listRef.scrollTop = listRef.scrollHeight
  }

  useEffect(() => () => resetOffset(), [])
  useLayoutEffect(checkBoundaries, [listRef])
  useLayoutEffect(stayAtBottom, [listRef, entryCount])

  const checkBoundariesDebounced = useCallback(debounce(checkBoundaries, 40, { leading: true }), [
    listRef
  ])

  const onLoadMore = useCallback(() => {
    if (!listRef) return
    const el = listRef
    const scrollFromBot = el.scrollHeight - el.clientHeight - el.scrollTop
    loadMore()
    el.scrollTop = el.scrollHeight - el.clientHeight - scrollFromBot
  }, [listRef])

  return (
    <>
      <div
        ref={setListRef}
        onScroll={checkBoundariesDebounced}
        className={classNames('MessageList')}
      >
        {messages.length < entryCount ? (
          <LoadMore parentElement={listRef} onActivate={onLoadMore} />
        ) : loading ? (
          <LoadingMessages />
        ) : (
          <FirstMessage channelName={channelName} />
        )}
        {messages.map((m, index) => (
          <MessageListRow
            key={`message-${m.hash}`}
            parentElement={listRef}
            message={m}
            prevMessage={messages[index - 1]}
            {...messageRowProps}
          />
        ))}
      </div>
      {!atBottom && hasUnreadMessages ? <div className='unreadIndicator' style={theme} /> : null}
      <DelayRender visible={loading}>
        <div className='progressBar' style={theme} />
      </DelayRender>
    </>
  )
}

MessageList.propTypes = {
  messages: PropTypes.array.isRequired,
{'fraction_non_alphanumeric': 0.12137957317073171, 'fraction_numerical': 0.0019054878048780487, 'mean_word_length': 3.06584043377227, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 37, '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': '4797636', 'n_tokens_mistral': 1551, 'n_tokens_neox': 1526, 'n_words': 335}