Skip to content

Commit

Permalink
handle possibility of new incoming messages when browsing history paging
Browse files Browse the repository at this point in the history
  • Loading branch information
franklevasseur committed May 24, 2019
1 parent b89e1d3 commit f814990
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 31 deletions.
30 changes: 22 additions & 8 deletions modules/history/src/backend/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,30 @@ export default async (bp: typeof sdk, db: Database) => {

router.get('/messages/:convId', async (req, res) => {
const convId = req.params.convId
const offset = req.query.offset ? req.query.offset : 0

const { messages, messageCount } = await db.getMessagesOfConversation(convId, N_MESSAGE_GROUPS_READ, offset)
const messageGroupsArray = await prepareMessagesRessource(db, convId, 0)
const messageCount = await db.getConversationMessageCount(convId)
const messageGroupCount = await db.getConversationMessageGroupCount(convId)
res.send({ messageGroupsArray, messageCount, messageGroupCount })
})

const messageGroupKeyBuild = (msg: sdk.IO.Event) =>
msg.direction === 'incoming' ? msg.id : (msg as sdk.IO.OutgoingEvent).incomingEventId
const messageGroups = _.groupBy(messages, messageGroupKeyBuild)
router.get('/more-messages/:convId', async (req, res) => {
const convId = req.params.convId
const { offset, clientCount } = req.query

const messageGroupsArray = _.sortBy(_.values(messageGroups), mg => moment(mg[0].createdOn).unix()).reverse()
const actualCount = await db.getConversationMessageGroupCount(convId)
const unsyncOffset = Number(offset) + Math.max(actualCount - clientCount, 0)

res.send({ messageGroupsArray, messageCount })
const messageGroupsArray = await prepareMessagesRessource(db, convId, unsyncOffset)
res.send(messageGroupsArray)
})
}

async function prepareMessagesRessource(db, convId, offset) {
const messages = await db.getMessagesOfConversation(convId, N_MESSAGE_GROUPS_READ, offset)

const messageGroupKeyBuild = (msg: sdk.IO.Event) =>
msg.direction === 'incoming' ? msg.id : (msg as sdk.IO.OutgoingEvent).incomingEventId
const messageGroups = _.groupBy(messages, messageGroupKeyBuild)

return _.sortBy(_.values(messageGroups), mg => moment(mg[0].createdOn).unix()).reverse()
}
16 changes: 11 additions & 5 deletions modules/history/src/backend/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default class HistoryDb {
const queryResults = await query
const uniqueConversations: string[] = queryResults.map(x => x.sessionId)

const buildConversationInfo = async c => ({ id: c, count: await this._getConversationCount(c) })
const buildConversationInfo = async c => ({ id: c, count: await this.getConversationMessageCount(c) })
return Promise.all(uniqueConversations.map(buildConversationInfo))
}

Expand All @@ -48,16 +48,22 @@ export default class HistoryDb {
.whereIn('incomingEventId', incomingMessages.map(x => x.id))
.then(rows => rows.map(r => this.knex.json.get(r.event)))

const messageCount = await this._getConversationCount(sessionId)
return messages
}

getConversationMessageCount = async (sessionId: string) => {
return this._getMessageCountWhere({ sessionId })
}

return { messages, messageCount }
getConversationMessageGroupCount = async (sessionId: string) => {
return this._getMessageCountWhere({ sessionId, direction: 'incoming' })
}

private _getConversationCount = async (sessionId: string) => {
private async _getMessageCountWhere(whereParams) {
const messageCountObject = await this.knex
.from('events')
.count()
.where({ sessionId })
.where(whereParams)

return messageCountObject.pop()['count(*)']
}
Expand Down
4 changes: 2 additions & 2 deletions modules/history/src/views/full/MessageViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ class MessagesHeader extends React.Component {
constructor(props) {
super(props)

const flattenMessages = props.messageGroups.flatMap(d => d)
const flattenMessages = props.messageGroups.flat()
const content = JSON.stringify(flattenMessages)
let blob = new Blob([content], { type: 'application/json' })
this.fileURL = window.URL.createObjectURL(blob)
}

getLastMessageDate = messageGroups => {
const messages = messageGroups.flatMap(m => m)
const messages = messageGroups.flat()
const maxDateMessage = _.maxBy(messages, m => m.createdOn)
return new Date(maxDateMessage.createdOn)
}
Expand Down
37 changes: 21 additions & 16 deletions modules/history/src/views/full/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default class FullView extends React.Component {
.subtract(30, 'days'),
currentConversation: null,
currentConversationMessageGroupsOffset: 0,
isThereStillMessagesLeft: false
currentConversationMessageGroupsCount: 0
}

componentDidMount() {
Expand All @@ -37,31 +37,35 @@ export default class FullView extends React.Component {
}

selectConversation = async sessionId => {
if (sessionId == this.state.currentConversation) {
return
}
const url = new URL(window.location.href)
url.searchParams.set(CONV_PARAM_NAME, sessionId)
window.history.pushState(window.history.state, '', url.toString())

await this.getMessagesOfConversation(sessionId)
}

hasConversationChanged(sessionId, currentConversation, receivedData) {
return sessionId !== this.state.currentConversation || currentConversation.count !== receivedData.messageCount
}

getMessagesOfConversation = async sessionId => {
const { data } = await this.props.bp.axios.get(`/mod/history/messages/${sessionId}`)

const conversationsInfoCopy = [...this.state.conversationsInfo]
const desiredConvInfo = conversationsInfoCopy.find(c => c.id === sessionId)
if (desiredConvInfo) {
desiredConvInfo.count = data.messageCount

if (!desiredConvInfo || !this.hasConversationChanged(sessionId, desiredConvInfo, data)) {
return
}

desiredConvInfo.count = data.messageCount

this.setState({
currentConversation: sessionId,
messageGroups: data.messageGroupsArray,
conversationsInfo: this.state.conversationsInfo,
conversationsInfo: conversationsInfoCopy,
currentConversationMessageGroupsOffset: data.messageGroupsArray.length,
isThereStillMessagesLeft: data.messageGroupsArray.flatMap(mg => mg).length !== data.messageCount
currentConversationMessageGroupsCount: data.messageGroupCount
})
}

Expand All @@ -77,27 +81,28 @@ export default class FullView extends React.Component {
this.getConversations(this.state.from, moment_day)
}

fetchNewMessages = async () => {
fetchMoreMessages = async () => {
const { data } = await this.props.bp.axios.get(
`/mod/history/messages/${this.state.currentConversation}?offset=${
`/mod/history/more-messages/${this.state.currentConversation}?offset=${
this.state.currentConversationMessageGroupsOffset
}`
}&clientCount=${this.state.currentConversationMessageGroupsCount}`
)

let messageGroupsCopy = [...this.state.messageGroups]
messageGroupsCopy = messageGroupsCopy.concat(data.messageGroupsArray)
messageGroupsCopy = messageGroupsCopy.concat(data)

this.setState({
messageGroups: messageGroupsCopy,
currentConversationMessageGroupsOffset: messageGroupsCopy.length,
isThereStillMessagesLeft: messageGroupsCopy.flatMap(mg => mg).length !== data.messageCount
currentConversationMessageGroupsOffset: messageGroupsCopy.length
})
}

render() {
if (!this.state.conversationsInfo) {
return null
}
const isThereStillMessagesLeftToFetch =
this.state.currentConversationMessageGroupsOffset !== this.state.currentConversationMessageGroupsCount
return (
<div className={style['history-component']}>
<ConversationPicker
Expand All @@ -110,8 +115,8 @@ export default class FullView extends React.Component {
refresh={() => this.getConversations(this.state.from, this.state.to)}
/>
<MessageViewer
isThereStillMessagesLeft={this.state.isThereStillMessagesLeft}
fetchNewMessages={() => this.fetchNewMessages()}
isThereStillMessagesLeft={isThereStillMessagesLeftToFetch}
fetchNewMessages={() => this.fetchMoreMessages()}
conversation={this.state.currentConversation}
messageGroups={this.state.messageGroups}
/>
Expand Down

0 comments on commit f814990

Please sign in to comment.