logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe

direct_conversation_service.js (4245B)


      1 import { uniqueId } from 'lodash'
      2 
      3 const empty = () => {
      4   return {
      5     ids: new Set(),
      6     prevIds: new Set(),
      7     collection: [],
      8     markedForDeletion: {},
      9     latestTimestamp: 0,
     10     newMessagesCount: 0,
     11     conversationId: undefined
     12   }
     13 }
     14 
     15 const clear = (storage) => {
     16   storage.ids.clear()
     17   storage.prevIds.clear()
     18   storage.collection.splice(0, storage.collection.length)
     19   storage.markedForDeletion = {}
     20   storage.latestTimestamp = 0
     21   storage.newMessagesCount = 0
     22   storage.conversationId = undefined
     23 }
     24 
     25 const remove = (storage, id) => {
     26   storage.ids.delete(id)
     27   storage.collection = storage.collection.filter(c => c.id !== id)
     28   delete storage.markedForDeletion[status.id]
     29 }
     30 
     31 const setConversationId = (storage, conversationId) => {
     32   storage.conversationId = conversationId
     33 }
     34 
     35 const add = (storage, { statuses: newStatuses, check = false, isFirstFetch = false }) => {
     36   for (let i = 0; i < newStatuses.length; i++) {
     37     let status = newStatuses[i]
     38     // sanity check
     39     if (status.direct_conversation_id !== storage.conversationId) { return }
     40     if (check && storage.markedForDeletion[status.id]) {
     41       delete storage.markedForDeletion[status.id]
     42     }
     43 
     44     if (!storage.ids.has(status.id)) {
     45       if (storage.latestTimestamp < status.created_at) {
     46         storage.newMessagesCount++
     47         storage.latestTimestamp = status.created_at
     48       }
     49       storage.collection.push(status)
     50       storage.ids.add(status.id)
     51     }
     52   }
     53 
     54   // Mark for deletion first to avoid race conditions with streaming and regular fetch (used as a fallback)
     55   if (check && !isFirstFetch) {
     56     storage.ids.forEach(id => {
     57       if (!storage.prevIds.has(id)) {
     58         if (storage.markedForDeletion[id] && storage.markedForDeletion[id] > 2) {
     59           remove(storage, id)
     60         } else {
     61           if (storage.markedForDeletion[id]) {
     62             storage.markedForDeletion[id]++
     63           } else {
     64             storage.markedForDeletion[id] = 1
     65           }
     66         }
     67       }
     68     })
     69   }
     70 
     71   if (check) {
     72     storage.prevIds = new Set(newStatuses.map(s => s.id))
     73   }
     74 }
     75 
     76 const resetNewMessageCount = (storage) => {
     77   storage.newMessagesCount = 0
     78 }
     79 
     80 const sortById = (a, b) => {
     81   const seqA = Number(a.id)
     82   const seqB = Number(b.id)
     83   const isSeqA = !Number.isNaN(seqA)
     84   const isSeqB = !Number.isNaN(seqB)
     85   if (isSeqA && isSeqB) {
     86     return seqA > seqB ? 1 : -1
     87   } else if (isSeqA && !isSeqB) {
     88     return -1
     89   } else if (!isSeqA && isSeqB) {
     90     return 1
     91   } else {
     92     return a.id > b.id ? 1 : -1
     93   }
     94 }
     95 
     96 // Inserts date separators and marks the head and tail if it's the sequence of messages made by the same user
     97 const getView = (storage) => {
     98   let { collection } = storage
     99 
    100   let coll = collection.sort(sortById)
    101   let res = []
    102 
    103   let prev = coll[coll.length - 1]
    104   let currentSequenceId
    105 
    106   let firstStatus = coll[0]
    107   if (firstStatus) {
    108     let date = new Date(firstStatus.created_at)
    109     date.setHours(0, 0, 0, 0)
    110     res.push({ type: 'date', date: date, id: date.getTime().toString() })
    111   }
    112 
    113   let afterDate = false
    114 
    115   for (let i = 0; i < coll.length; i++) {
    116     let status = coll[i]
    117     let nextStatus = coll[i + 1]
    118 
    119     let date = new Date(status.created_at)
    120     date.setHours(0, 0, 0, 0)
    121 
    122     // insert date separator and start a new sequence
    123     if (prev && prev.date < date) {
    124       res.push({ type: 'date', date: date, id: date.getTime().toString() })
    125       prev['isTail'] = true
    126       currentSequenceId = undefined
    127       afterDate = true
    128     }
    129 
    130     let object = { type: 'status', data: status, date: date, id: status.id, sequenceId: currentSequenceId }
    131     // end a message sequence
    132     if ((nextStatus && nextStatus.user.id) !== status.user.id) {
    133       object['isTail'] = true
    134       currentSequenceId = undefined
    135     }
    136     // start a new message sequence
    137     if ((prev && prev.data && prev.data.user && prev.data.user.id) !== status.user.id || afterDate) {
    138       currentSequenceId = uniqueId()
    139       object['isHead'] = true
    140       object['sequenceId'] = currentSequenceId
    141     }
    142     res.push(object)
    143     prev = object
    144     afterDate = false
    145   }
    146 
    147   return res
    148 }
    149 
    150 const DirectConversationStatuses = {
    151   add,
    152   empty,
    153   remove,
    154   resetNewMessageCount,
    155   getView,
    156   clear,
    157   setConversationId
    158 }
    159 
    160 export default DirectConversationStatuses