|
import firebase from 'firebase' |
|
|
|
export function defaultDirectKey(users) { |
|
return users.sort().join('-') |
|
} |
|
|
|
class Firechat { |
|
constructor(firebaseRef, options = {}) { |
|
this.directKey = options.directKey || defaultDirectKey |
|
this.maximumMessagesFetch = options.maximumMessagesFetch || 100 |
|
|
|
this.firebaseRef = firebaseRef |
|
|
|
this.directMessagesRef = firebaseRef.child('direct-messages') |
|
this.groupMessagesRef = firebaseRef.child('group-messages') |
|
this.groupMetadataRef = firebaseRef.child('group-metadata') |
|
this.usersRef = firebaseRef.child('users') |
|
} |
|
|
|
get uid() { |
|
return (firebase.auth().currentUser || {}).uid |
|
} |
|
|
|
get timestamp() { |
|
return firebase.database.ServerValue.TIMESTAMP |
|
} |
|
|
|
async gotoDirectMessage(otherUsers) { |
|
const users = [...otherUsers, this.uid] |
|
const directKey = this.directKey(users) |
|
const snapshotGroup = await this.directMessagesRef.child(directKey).once('value') |
|
let groupId = snapshotGroup.val() |
|
if (!groupId) { |
|
groupId = await this.createGroup('DirectMessage', 'direct', users) |
|
const { snapshot } = await this.directMessagesRef |
|
.child(directKey) |
|
.transaction((currentData) => { |
|
if (currentData === null) { |
|
return groupId |
|
} |
|
return undefined |
|
}) |
|
|
|
if (groupId !== snapshot.val()) { |
|
// NOTE(giautm): Có direct messages group khác đã được tạo trước đó. |
|
await this.deleteGroup(groupId) |
|
groupId = snapshot.val() |
|
} |
|
} |
|
|
|
return this.fetchGroupMetadata(groupId) |
|
} |
|
|
|
async fetchGroupMetadata(groupId) { |
|
const snapshot = await this.groupMetadataRef |
|
.child(groupId) |
|
.once('value') |
|
|
|
return snapshot.val() |
|
} |
|
|
|
async createGroup(name, type, users) { |
|
const groupRef = this.groupMetadataRef.push() |
|
await groupRef.set({ |
|
createdAt: this.timestamp, |
|
createdByUserId: this.uid, |
|
id: groupRef.key, |
|
name, |
|
type, |
|
users: users.reduce((u, k) => ({ |
|
...u, |
|
[k]: true, |
|
}), {}), |
|
}) |
|
|
|
// NOTE(giautm): This should happen on server-side or cloud function. |
|
await Promise.all(users.map(uid => this.usersRef.child( |
|
`${uid}/groups/${groupRef.key}`, |
|
).set(true))) |
|
|
|
return groupRef.key |
|
} |
|
|
|
async deleteGroup(groupId) { |
|
const groupRef = this.groupMetadataRef.child(groupId) |
|
|
|
// NOTE(giautm): This should happen on server-side or cloud function. |
|
const snapshot = await groupRef.child('users').once('value') |
|
const users = snapshot.val() |
|
await users.map(uid => this.usersRef.child( |
|
`${uid}/groups/${groupId}`, |
|
).remove()) |
|
|
|
return groupRef.remove() |
|
} |
|
|
|
sendMessage(groupId, message) { |
|
const messageRef = this.groupMessagesRef.child(groupId).push() |
|
return messageRef.set({ |
|
...message, |
|
createdAt: this.timestamp, |
|
user: this.uid, |
|
}) |
|
} |
|
|
|
sendMessages(groupId, messages) { |
|
return Promise.all(messages.map(m => this.sendMessage(groupId, m))) |
|
} |
|
|
|
onMessage = (groupId, callback) => this.groupMessagesRef.child(groupId) |
|
.limitToLast(this.maximumMessagesFetch) |
|
.on('child_added', snapshot => callback(this.parseMessage(snapshot))); |
|
|
|
onGroupAdded = callback => this.usersRef.child(`${this.uid}/groups`) |
|
.on('child_added', snapshot => this.parseGroup(snapshot.key).then(callback)) |
|
|
|
onGroupRemoved = callback => this.usersRef.child(`${this.uid}/groups`) |
|
.on('child_removed', snapshot => this.parseGroup(snapshot.key).then(callback)) |
|
|
|
parseGroup = async (groupId) => { |
|
const snapshot = await this.groupMetadataRef.child(groupId).once('value') |
|
const { createdAt, ...rest } = snapshot.val() |
|
return ({ |
|
...rest, |
|
createdAt: new Date(createdAt), |
|
}) |
|
}; |
|
|
|
parseMessage = (snapshot) => { |
|
const { createdAt, text, user } = snapshot.val() |
|
const { key: _id } = snapshot |
|
return ({ |
|
_id, |
|
createdAt: new Date(createdAt), |
|
text, |
|
user, |
|
}) |
|
}; |
|
} |
|
|
|
export default Firechat |