@benshi.ai/js-sdk
Version:
Benshi SDK
118 lines (96 loc) • 4.16 kB
text/typescript
import { CTAType, INudgesRepository, Nudge } from './repositories/nudges/typings'
import { EventEmitter } from 'events';
import { NotificationAction, NotificationDispatcher } from '../drivers/notifications/typings'
import { IStorage } from '../drivers/storage/typings'
import { DateTime } from 'luxon'
import { INudgeManager, NudgeManagerAction } from './BsNudgeManager.typings';
interface IndexedNudge {
[key: string]: Nudge
}
export default class NudgeManager extends EventEmitter implements INudgeManager {
private timersId = []
private notificationDispatcher
private nudgesRepository
private refreshInterval = 5 * 60 * 1000
private indexedNudges: IndexedNudge = {}
public constructor(
userId: string,
notificationDispacher: NotificationDispatcher,
nudgesRepository: INudgesRepository,
refreshInterval = 5 * 60 * 1000
) {
super()
this.notificationDispatcher = notificationDispacher
this.nudgesRepository = nudgesRepository
this.refreshInterval = refreshInterval
/*
- nudges are retrieved periodically, each 5min.
- in the future this timeout will be configurable
- dispatched_at will be:
- current time less 1 hour the first time
- time of last shown nudge, if exists, or current time next times
*/
this.notificationDispatcher.on(NotificationAction.Open, (id) => {
this.emit(NudgeManagerAction.Open, id, this.indexedNudges[id])
const hasActions = () => {
return (this.indexedNudges[id].action.call_to_action.type !== CTAType.None &&
this.indexedNudges[id].action.call_to_action.cta_resource.id !== "")
}
if (!this.indexedNudges[id]) {
return
}
if (!hasActions()) {
return
}
this.emit(
NudgeManagerAction.Action,
this.indexedNudges[id].action.call_to_action)
})
this.notificationDispatcher.on(NotificationAction.Discard, id => {
this.emit(NudgeManagerAction.Discard, id, this.indexedNudges[id])
})
this.notificationDispatcher.on(NotificationAction.Block, id => {
this.emit(NudgeManagerAction.Block, id, this.indexedNudges[id])
})
const oneHourAgo = new Date()
oneHourAgo.setHours(oneHourAgo.getHours() - 1)
// get storaged item:
this.fetchNudges(userId)
setInterval(() => {
this.fetchNudges(userId)
}, this.refreshInterval)
}
private async fetchNudges(userId: string) {
let nudges;
try {
nudges = await this.nudgesRepository.getNudges(userId)
} catch (e) {
console.error('Error fetching nudges: ', e)
return
}
const nudgeExpiryDate = DateTime.local().plus({ seconds: 3600 }).toJSDate().toISOString()
nudges
.filter(({ id }) => {
const alreadyShown = this.nudgesRepository.haveBeenAlreadyShown(id)
return !alreadyShown
})
.forEach(nudge => {
const { action: { definition: { title, body } }, id, dispatched_at, expire_at } = nudge
this.indexedNudges[id] = nudge
this.processNudge(id, dispatched_at, expire_at, title, body)
})
}
private processNudge(id: string, dispatched_at: string, expire_at: string, title: string, body: string) {
const dispatched_at_date = new Date(dispatched_at)
const expirationNotDefined = expire_at === "0001-01-01T00:00:00Z"
const notExpired = expire_at > new Date().toISOString()
if (notExpired || expirationNotDefined) {
const timeout = dispatched_at_date.getTime() - Date.now()
const timeoutId = setTimeout(() => {
this.nudgesRepository.markNudgeAsShown(id)
this.notificationDispatcher.show(title, body, id)
}, timeout)
this.timersId.push(timeoutId)
}
}
}