chat-pane.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import React, { useEffect } from 'react'
  2. import PropTypes from 'prop-types'
  3. import MessageList from './message-list'
  4. import MessageInput from './message-input'
  5. import InfiniteScroll from './infinite-scroll'
  6. import Icon from '../../../shared/components/icon'
  7. import { useTranslation } from 'react-i18next'
  8. import { useChatStore } from '../store/chat-store-effect'
  9. import withErrorBoundary from '../../../infrastructure/error-boundary'
  10. function ChatPane({ resetUnreadMessages }) {
  11. const { t } = useTranslation()
  12. const {
  13. atEnd,
  14. loading,
  15. loadMoreMessages,
  16. messages,
  17. sendMessage,
  18. userId
  19. } = useChatStore()
  20. useEffect(() => {
  21. loadMoreMessages()
  22. // eslint-disable-next-line react-hooks/exhaustive-deps
  23. }, [])
  24. const shouldDisplayPlaceholder = !loading && messages.length === 0
  25. const messageContentCount = messages.reduce(
  26. (acc, { contents }) => acc + contents.length,
  27. 0
  28. )
  29. return (
  30. <aside className="chat">
  31. <InfiniteScroll
  32. atEnd={atEnd}
  33. className="messages"
  34. fetchData={loadMoreMessages}
  35. isLoading={loading}
  36. itemCount={messageContentCount}
  37. >
  38. <div>
  39. <h2 className="sr-only">{t('chat')}</h2>
  40. {loading && <LoadingSpinner />}
  41. {shouldDisplayPlaceholder && <Placeholder />}
  42. <MessageList
  43. messages={messages}
  44. userId={userId}
  45. resetUnreadMessages={resetUnreadMessages}
  46. />
  47. </div>
  48. </InfiniteScroll>
  49. <MessageInput
  50. resetUnreadMessages={resetUnreadMessages}
  51. sendMessage={sendMessage}
  52. />
  53. </aside>
  54. )
  55. }
  56. function LoadingSpinner() {
  57. const { t } = useTranslation()
  58. return (
  59. <div className="loading">
  60. <Icon type="fw" modifier="refresh" spin />
  61. {` ${t('loading')}…`}
  62. </div>
  63. )
  64. }
  65. function Placeholder() {
  66. const { t } = useTranslation()
  67. return (
  68. <>
  69. <div className="no-messages text-center small">{t('no_messages')}</div>
  70. <div className="first-message text-center">
  71. {t('send_first_message')}
  72. <br />
  73. <Icon type="arrow-down" />
  74. </div>
  75. </>
  76. )
  77. }
  78. ChatPane.propTypes = {
  79. resetUnreadMessages: PropTypes.func.isRequired
  80. }
  81. export default withErrorBoundary(ChatPane)