I want to implement this in a SQL database schema, but am doing it in JavaScript first to make sure I have the logic right. Basically, I would like to track "actions" a user performs. If they perform a certain amount of actions within a period (a day for now), then they hit the goal for that day. Then if they do this for multiple days in a row, they get a streak. If they skip a day, they lose the streak.
Do I have this implemented correctly? It appears to be working as expected, but I am not 100% sure this is how this type of thing should be implemented. Any suggestions on how to improve the implementation?
const { shiftTimeBy } = require('time-fast-forward')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
// 20 days ago
shiftTimeBy(-1 * 20 * 24 * 60 * 60 * 1000);
let startOfDay = dayjs.utc().startOf('day').toDate()
let startOfPreviousDay = dayjs.utc().startOf('day').subtract(1, 'day').toDate()
const actionTrackers = {}
// do action 22 times in a day, but daily goal is only 10
let i = 0
while (i < 22) {
trackAction({ actionId: 'vote', userId: 'bar' })
i++
}
// jump ahead to the next day
shiftTimeBy((1 * 24 * 60 * 60 * 1000) + 220);
startOfDay = dayjs.utc().startOf('day').toDate()
startOfPreviousDay = dayjs.utc().startOf('day').subtract(1, 'day').toDate()
// do action 22 times in a day again, but daily goal is only 10
i = 0
while (i < 22) {
trackAction({ actionId: 'vote', userId: 'bar' })
i++
}
// jump ahead 3 days
shiftTimeBy((3 * 24 * 60 * 60 * 1000) + 220);
startOfDay = dayjs.utc().startOf('day').toDate()
startOfPreviousDay = dayjs.utc().startOf('day').subtract(1, 'day').toDate()
// do action 22 times in a day again, but daily goal is only 10
i = 0
while (i < 22) {
trackAction({ actionId: 'vote', userId: 'bar' })
i++
}
function trackAction({ actionId, userId, dailyGoal = 10 }) {
const actionUsersTracker = actionTrackers[actionId] = actionTrackers[actionId] ?? {}
const actionUserTracker = actionUsersTracker[userId] = actionUsersTracker[userId] ?? {}
if (!actionUserTracker.lastDate) {
actionUserTracker.lastDate = new Date
actionUserTracker.actionCount = 1
actionUserTracker.streakCount = 0
} else {
if (actionUserTracker.lastDate < startOfDay) {
if (actionUserTracker.lastDate < startOfPreviousDay) {
actionUserTracker.streakCount = 0
}
actionUserTracker.lastDate = new Date
actionUserTracker.actionCount = 1
} else {
// within same day
actionUserTracker.actionCount++
if (actionUserTracker.actionCount === dailyGoal) {
actionUserTracker.streakCount++
}
}
}
console.log(actionUserTracker)
}
The time manipulation library is there to simulate a test where time passes and we perform the action at different points in time.