chat-store.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import EventEmitter from '../../../utils/EventEmitter'
  2. import { appendMessage, prependMessages } from './message-list-appender'
  3. import { getJSON, postJSON } from '../../../infrastructure/fetch-json'
  4. import { v4 as uuid } from 'uuid'
  5. export const MESSAGE_LIMIT = 50
  6. export class ChatStore {
  7. constructor(user, projectId) {
  8. this.messages = []
  9. this.loading = false
  10. this.atEnd = false
  11. this._user = user
  12. this._projectId = projectId
  13. this._nextBeforeTimestamp = null
  14. this._justSent = false
  15. this._emitter = new EventEmitter()
  16. this._onNewChatMessage = message => {
  17. const messageIsFromSelf =
  18. message && message.user && message.user.id === this._user.id
  19. if (!messageIsFromSelf || !this._justSent) {
  20. this.messages = appendMessage(this.messages, message)
  21. this._emitter.emit('updated')
  22. this._emitter.emit('message-received', message)
  23. window.dispatchEvent(
  24. new CustomEvent('Chat.MessageReceived', { detail: { message } })
  25. )
  26. }
  27. this._justSent = false
  28. }
  29. window._ide.socket.on('new-chat-message', this._onNewChatMessage)
  30. }
  31. destroy() {
  32. window._ide.socket.removeListener(
  33. 'new-chat-message',
  34. this._onNewChatMessage
  35. )
  36. this._emitter.off() // removes all listeners
  37. }
  38. on(event, fn) {
  39. this._emitter.on(event, fn)
  40. }
  41. off(event, fn) {
  42. this._emitter.off(event, fn)
  43. }
  44. loadMoreMessages() {
  45. if (this.atEnd) {
  46. return
  47. }
  48. this.loading = true
  49. this._emitter.emit('updated')
  50. let url = `/project/${window.project_id}/messages?limit=${MESSAGE_LIMIT}`
  51. if (this._nextBeforeTimestamp) {
  52. url += `&before=${this._nextBeforeTimestamp}`
  53. }
  54. return getJSON(url).then(response => {
  55. const messages = response || []
  56. this.loading = false
  57. if (messages.length < MESSAGE_LIMIT) {
  58. this.atEnd = true
  59. }
  60. messages.reverse()
  61. this.messages = prependMessages(this.messages, messages)
  62. this._nextBeforeTimestamp = this.messages[0]
  63. ? this.messages[0].timestamp
  64. : undefined
  65. this._emitter.emit('updated')
  66. })
  67. }
  68. sendMessage(message) {
  69. if (!message) {
  70. return
  71. }
  72. const body = {
  73. content: message,
  74. _csrf: window.csrfToken
  75. }
  76. this._justSent = true
  77. this.messages = appendMessage(this.messages, {
  78. id: uuid(), // uuid valid for this session, ensures all messages have an identifier
  79. user: this._user,
  80. content: message,
  81. timestamp: Date.now()
  82. })
  83. const url = `/project/${this._projectId}/messages`
  84. this._emitter.emit('updated')
  85. return postJSON(url, { body })
  86. }
  87. }