Skip to main content
added 339 characters in body
Source Link
Roei
  • 71
  • 4

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 :) ).
I would also separate the insert and the tracking (in my example I just
wanted to make an example of a trigger to the tracking function - an
insertion of an action, but it could be a scheduled event or any event).
and so we'd be able to implement @kemicofa ghost answer without modifying
the code too much.

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 :) )

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 :) ).
I would also separate the insert and the tracking (in my example I just
wanted to make an example of a trigger to the tracking function - an
insertion of an action, but it could be a scheduled event or any event).
and so we'd be able to implement @kemicofa ghost answer without modifying
the code too much.

Source Link
Roei
  • 71
  • 4

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 :) )