First of all, I would separate the code from the actual tracker and the testing code.
Your code would also benefit from avoiding the use of
"Magic Numbers".
I would also just save the date of action for every time a user is
making an action.
You should note that I haven't tested the code, and wrote it to make an example of
how I would create the basic logic. It probably won't work without modifying it to suit your needs.
First, let's create some objects that may represent our DB and basic insert logic:
const usersDB = [
{
uid: "uid_1",
username: "Chris",
email: "[email protected]"
}
];
const actionsDB = [
{
actionName: "clickButton",
uid: "uid_1",
counts: [
{
date: "1/1/2022",
count: 7,
},
{
date: "1/2/2022",
count: 7,
},
{
date: "1/3/2022",
count: 7,
},
]
}
];
const insertAction = (uid, actionName, date) => {
const userActionRecord = actionsDB.find(action => action.actionName === actionName && action.uid === uid);
const userDailyCount = userActionRecord.counts.find(dailyCount => dailyCount.date === date);
if (userDailyCount) {
userDailyCount.count += 1;
} else {
userActionRecord.counts.push({date: date, count: 1})
}
}
This way, we can populate the object with whichever data we want to test our logic.
Now, let's create the streak counting function and the tracking of making an action function:
const DAILY_GOAL_COUNT = 10;
const STREAK_COUNT = 7;
const ONE_DAY = <object that represents a day in your context>
const getStreaks = (daysWithGoals) => {
if (daysWithGoals < STREAK_COUNT) {
return;
}
streaks = [[daysWithGoals[0].date]];
currStreakIndex = 0;
for (let i = 1; i < daysWithGoals.Length; i++) {
if (daysWithGoals[i].date - daysWithGoals[i - 1] === ONE_DAY) {
streaks[currStreakIndex].push(daysWithGoals[i]);
} else {
streaks.push([daysWithGoals[i].date])
currStreakIndex++;
}
}
return streaks
.filter(streak => streak.Length >= STREAK_COUNT)
.map((streak) => {
return {start: streak[0], end: streak[streak.Length - 1]}
})
}
const makeActionAndTrack = (uid, actionName) => {
insertAction(uid, actionName, Date());
const daysWithGoals = actionsDB
.filter(action => action.uid === uid && action.actionName === actionName)
.map(action => action.counts.filter(dailyCount => dailyCount.count >= DAILY_GOAL_COUNT))
const streaks = getStreaks(daysWithGoals);
if (streaks) {
streaks.forEach(streak => console.log(streak.start, streak.end))
}
}
This way we made our functions more atomic (probably could be improved a lot by separating to even smaller functions, and maybe creating a util to help with the dates like you did :) )