feat: add periodStats to user dashboard endpoint

feat: add periodStats to user dashboard endpoint
This commit is contained in:
Gabriel Menezes 2026-05-22 20:28:28 -04:00 committed by GitHub
commit 607bbef7d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 57 additions and 13 deletions

View file

@ -8,5 +8,7 @@ public record DashboardOutput(
List<DashboardProjectStats> projectStats, List<DashboardProjectStats> projectStats,
List<DashboardCategoryStats> categoryStats, List<DashboardCategoryStats> categoryStats,
List<CreateTaskOutput> yesterdayTasks, List<CreateTaskOutput> yesterdayTasks,
List<CreateTaskOutput> finishedTasksInPeriod List<CreateTaskOutput> finishedTasksInPeriod,
List<DashboardPeriodStats> periodStats,
String groupedBy
) {} ) {}

View file

@ -0,0 +1,9 @@
package net.beetechgroup.beetask.usecase.dashboard;
public record DashboardPeriodStats(
int year,
int month,
int day,
int finishedTasksCount,
long totalMinutesWorked
) {}

View file

@ -1,13 +1,17 @@
package net.beetechgroup.beetask.usecase.dashboard; package net.beetechgroup.beetask.usecase.dashboard;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.TreeMap;
import net.beetechgroup.beetask.entities.Category; import net.beetechgroup.beetask.entities.Category;
import net.beetechgroup.beetask.entities.task.Task; import net.beetechgroup.beetask.entities.task.Task;
@ -45,28 +49,36 @@ public class DashboardUseCase {
long totalMinutes = 0; long totalMinutes = 0;
Map<Long, DashboardProjectStats> projectStatsMap = new HashMap<>(); Map<Long, DashboardProjectStats> projectStatsMap = new HashMap<>();
Map<Long, DashboardCategoryStats> categoryStatsMap = new HashMap<>(); Map<Long, DashboardCategoryStats> categoryStatsMap = new HashMap<>();
// [0] = totalMinutesWorked, [1] = finishedTasksCount grouped by day key
Map<LocalDate, long[]> periodMap = new TreeMap<>();
for (Task task : workedTasks) { for (Task task : workedTasks) {
for (TaskHistoryItem h : task.getHistory()) {
if (!isWithinPeriod(h, input.startDate(), input.endDate())) continue;
long minutes = calculateMinutesInRange(h, input.startDate(), input.endDate());
totalMinutes += minutes;
LocalDate day = h.getStartAt().toLocalDate();
long[] bucket = periodMap.computeIfAbsent(day, k -> new long[]{0L, 0L});
bucket[0] += minutes;
}
if (Objects.nonNull(task.getProject())) {
long taskMinutesInPeriod = task.getHistory().stream() long taskMinutesInPeriod = task.getHistory().stream()
.filter(h -> isWithinPeriod(h, input.startDate(), input.endDate())) .filter(h -> isWithinPeriod(h, input.startDate(), input.endDate()))
.mapToLong(h -> calculateMinutesInRange(h, input.startDate(), input.endDate())) .mapToLong(h -> calculateMinutesInRange(h, input.startDate(), input.endDate()))
.sum(); .sum();
totalMinutes += taskMinutesInPeriod;
if (Objects.nonNull(task.getProject())) {
Long projectId = task.getProject().getId(); Long projectId = task.getProject().getId();
DashboardProjectStats stats = projectStatsMap.getOrDefault(projectId, DashboardProjectStats stats = projectStatsMap.getOrDefault(projectId,
new DashboardProjectStats(projectId, task.getProject().getName(), 0L)); new DashboardProjectStats(projectId, task.getProject().getName(), 0L));
projectStatsMap.put(projectId, new DashboardProjectStats( projectStatsMap.put(projectId, new DashboardProjectStats(
projectId, projectId, stats.projectName(), stats.totalMinutes() + taskMinutesInPeriod));
stats.projectName(),
stats.totalMinutes() + taskMinutesInPeriod
));
} }
if (Objects.nonNull(task.getCategory())) { if (Objects.nonNull(task.getCategory())) {
long taskMinutesInPeriod = task.getHistory().stream()
.filter(h -> isWithinPeriod(h, input.startDate(), input.endDate()))
.mapToLong(h -> calculateMinutesInRange(h, input.startDate(), input.endDate()))
.sum();
Category cat = task.getCategory(); Category cat = task.getCategory();
DashboardCategoryStats existing = categoryStatsMap.getOrDefault(cat.getId(), DashboardCategoryStats existing = categoryStatsMap.getOrDefault(cat.getId(),
new DashboardCategoryStats(cat.getId(), cat.getName(), cat.getColor(), cat.getIcon(), 0L)); new DashboardCategoryStats(cat.getId(), cat.getName(), cat.getColor(), cat.getIcon(), 0L));
@ -76,12 +88,33 @@ public class DashboardUseCase {
} }
} }
for (Task task : finishedTasks) {
if (Objects.isNull(task.getFinishedAt())) continue;
LocalDate day = task.getFinishedAt().toLocalDate();
long[] bucket = periodMap.computeIfAbsent(day, k -> new long[]{0L, 0L});
bucket[1]++;
}
long daySpan = ChronoUnit.DAYS.between(input.startDate().toLocalDate(), input.endDate().toLocalDate());
String groupedBy = daySpan <= 62 ? "DAY" : "MONTH";
List<DashboardPeriodStats> periodStats = periodMap.entrySet().stream()
.map(e -> new DashboardPeriodStats(
e.getKey().getYear(), e.getKey().getMonthValue(), e.getKey().getDayOfMonth(),
(int) e.getValue()[1], e.getValue()[0]))
.sorted(Comparator.comparingInt(DashboardPeriodStats::year)
.thenComparingInt(DashboardPeriodStats::month)
.thenComparingInt(DashboardPeriodStats::day))
.toList();
DashboardOutput output = new DashboardOutput( DashboardOutput output = new DashboardOutput(
totalMinutes, totalMinutes,
new ArrayList<>(projectStatsMap.values()), new ArrayList<>(projectStatsMap.values()),
new ArrayList<>(categoryStatsMap.values()), new ArrayList<>(categoryStatsMap.values()),
yesterdayTasks.stream().map(CreateTaskMapper::toCreateTaskOutput).toList(), yesterdayTasks.stream().map(CreateTaskMapper::toCreateTaskOutput).toList(),
finishedTasks.stream().map(CreateTaskMapper::toCreateTaskOutput).toList() finishedTasks.stream().map(CreateTaskMapper::toCreateTaskOutput).toList(),
periodStats,
groupedBy
); );
LOGGER.infof("Dashboard calculated for user %s with %d worked tasks, %d finished tasks and %d total minutes", LOGGER.infof("Dashboard calculated for user %s with %d worked tasks, %d finished tasks and %d total minutes",
input.userEmail(), workedTasks.size(), finishedTasks.size(), totalMinutes); input.userEmail(), workedTasks.size(), finishedTasks.size(), totalMinutes);