Dashboard
This commit is contained in:
@@ -25,8 +25,8 @@ public class GoalMetricPeriodTotalDAO extends AbstractDAO<GoalMetricPeriodTotal>
|
||||
final long athleteId,
|
||||
final GoalMetricEnum metric,
|
||||
final GoalPeriodEnum period,
|
||||
final int periodYear,
|
||||
final int periodIndex) {
|
||||
final int year,
|
||||
final int calendarWeek) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<GoalMetricPeriodTotal> cq = cb.createQuery(GoalMetricPeriodTotal.class);
|
||||
final Root<GoalMetricPeriodTotal> root = cq.from(GoalMetricPeriodTotal.class);
|
||||
@@ -34,8 +34,8 @@ public class GoalMetricPeriodTotalDAO extends AbstractDAO<GoalMetricPeriodTotal>
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.athleteId), athleteId),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.metric), metric),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.period), period),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.periodYear), periodYear),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.periodIndex), periodIndex)
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.year), year),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.calendarWeek), calendarWeek)
|
||||
);
|
||||
return em.createQuery(cq).getResultStream().findFirst().orElse(null);
|
||||
}
|
||||
@@ -51,41 +51,23 @@ public class GoalMetricPeriodTotalDAO extends AbstractDAO<GoalMetricPeriodTotal>
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.metric), GoalMetricEnum.DISTANCE)
|
||||
)
|
||||
.orderBy(
|
||||
cb.desc(root.get(GoalMetricPeriodTotal_.periodYear)),
|
||||
cb.desc(root.get(GoalMetricPeriodTotal_.periodIndex))
|
||||
cb.desc(root.get(GoalMetricPeriodTotal_.year)),
|
||||
cb.desc(root.get(GoalMetricPeriodTotal_.calendarWeek))
|
||||
);
|
||||
return em.createQuery(cq).setMaxResults(1).getResultStream().findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public List<GoalMetricPeriodTotal> findByAthleteForDashboard(
|
||||
final long athleteId,
|
||||
final int weekYear,
|
||||
final int weekIndex,
|
||||
final int monthYear,
|
||||
final int monthIndex,
|
||||
final int calendarYear) {
|
||||
final int year,
|
||||
final int calendarWeek) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<GoalMetricPeriodTotal> cq = cb.createQuery(GoalMetricPeriodTotal.class);
|
||||
final Root<GoalMetricPeriodTotal> root = cq.from(GoalMetricPeriodTotal.class);
|
||||
cq.select(root).where(
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.athleteId), athleteId),
|
||||
cb.or(
|
||||
cb.and(
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.period), GoalPeriodEnum.WEEKLY),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.periodYear), weekYear),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.periodIndex), weekIndex)
|
||||
),
|
||||
cb.and(
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.period), GoalPeriodEnum.MONTHLY),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.periodYear), monthYear),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.periodIndex), monthIndex)
|
||||
),
|
||||
cb.and(
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.period), GoalPeriodEnum.YEARLY),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.periodYear), calendarYear),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.periodIndex), 1)
|
||||
)
|
||||
)
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.year), year),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.calendarWeek), calendarWeek)
|
||||
);
|
||||
return em.createQuery(cq).getResultList();
|
||||
}
|
||||
@@ -104,8 +86,8 @@ public class GoalMetricPeriodTotalDAO extends AbstractDAO<GoalMetricPeriodTotal>
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.period), period)
|
||||
)
|
||||
.orderBy(
|
||||
cb.asc(root.get(GoalMetricPeriodTotal_.periodYear)),
|
||||
cb.asc(root.get(GoalMetricPeriodTotal_.periodIndex))
|
||||
cb.asc(root.get(GoalMetricPeriodTotal_.year)),
|
||||
cb.asc(root.get(GoalMetricPeriodTotal_.calendarWeek))
|
||||
);
|
||||
return em.createQuery(cq).getResultList();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import lombok.EqualsAndHashCode;
|
||||
|
||||
@Entity
|
||||
@Table(name = "goal_metric_period_total", uniqueConstraints = @UniqueConstraint(
|
||||
columnNames = {"athlete_id", "metric", "period", "period_year", "period_index"}))
|
||||
columnNames = {"athlete_id", "metric", "period", "year", "calendar_week"}))
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GoalMetricPeriodTotal extends AbstractTimestampedEntity {
|
||||
@@ -24,11 +24,11 @@ public class GoalMetricPeriodTotal extends AbstractTimestampedEntity {
|
||||
@Column(nullable = false)
|
||||
private GoalPeriodEnum period;
|
||||
|
||||
@Column(name = "period_year", nullable = false)
|
||||
private int periodYear;
|
||||
@Column(name = "year", nullable = false)
|
||||
private int year;
|
||||
|
||||
@Column(name = "period_index", nullable = false)
|
||||
private int periodIndex;
|
||||
@Column(name = "calendar_week", nullable = false)
|
||||
private int calendarWeek;
|
||||
|
||||
@Column(nullable = false)
|
||||
private double aggregatedValue;
|
||||
|
||||
@@ -4,8 +4,8 @@ import com.peakup.activity.model.IntervalsActivity;
|
||||
import com.peakup.activity.service.IntervalsActivityService;
|
||||
import com.peakup.common.service.AbstractService;
|
||||
import com.peakup.goal.dao.GoalMetricPeriodTotalDAO;
|
||||
import com.peakup.goal.model.GoalMetricPeriodTotal;
|
||||
import com.peakup.goal.model.GoalMetricEnum;
|
||||
import com.peakup.goal.model.GoalMetricPeriodTotal;
|
||||
import com.peakup.goal.model.GoalPeriodEnum;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
@@ -30,6 +30,14 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
IntervalsActivityService intervalsActivityService;
|
||||
|
||||
private static double snapshotValue(final @Nullable GoalMetricPeriodTotal snapshot) {
|
||||
return snapshot != null ? snapshot.getAggregatedValue() : 0.0;
|
||||
}
|
||||
|
||||
private static boolean sameMonth(final LocalDate a, final LocalDate b) {
|
||||
return a.getYear() == b.getYear() && a.getMonthValue() == b.getMonthValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GoalMetricPeriodTotalDAO getDAO() {
|
||||
return goalMetricAggregateDAO;
|
||||
@@ -39,14 +47,14 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
public void recalculateForAthlete(final long athleteId, final int year, final int calendarWeek) {
|
||||
final List<IntervalsActivity> weekActivities = fetchWeekActivities(athleteId, year, calendarWeek);
|
||||
for (final GoalMetricEnum metric : GoalMetricEnum.values()) {
|
||||
recalculateMetricForWeek(athleteId, metric, weekActivities);
|
||||
recalculateMetricForWeek(athleteId, metric, weekActivities, year, calendarWeek);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void recalculateForAthlete(final long athleteId, final GoalMetricEnum metric, final int year, final int calendarWeek) {
|
||||
final List<IntervalsActivity> weekActivities = fetchWeekActivities(athleteId, year, calendarWeek);
|
||||
recalculateMetricForWeek(athleteId, metric, weekActivities);
|
||||
recalculateMetricForWeek(athleteId, metric, weekActivities, year, calendarWeek);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -54,9 +62,9 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
final long athleteId,
|
||||
final GoalMetricEnum metric,
|
||||
final GoalPeriodEnum period,
|
||||
final int periodYear,
|
||||
final int periodIndex) {
|
||||
return goalMetricAggregateDAO.findByKey(athleteId, metric, period, periodYear, periodIndex);
|
||||
final int year,
|
||||
final int calendarWeek) {
|
||||
return goalMetricAggregateDAO.findByKey(athleteId, metric, period, year, calendarWeek);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -69,15 +77,7 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
|
||||
@Transactional
|
||||
public List<GoalMetricPeriodTotal> getByAthleteAndWeek(final long athleteId, final int year, final int calendarWeek) {
|
||||
final LocalDate monday = LocalDate.of(year, 1, 4)
|
||||
.with(WeekFields.ISO.weekOfWeekBasedYear(), calendarWeek)
|
||||
.with(WeekFields.ISO.dayOfWeek(), 1);
|
||||
return goalMetricAggregateDAO.findByAthleteForDashboard(
|
||||
athleteId,
|
||||
year, calendarWeek,
|
||||
monday.getYear(), monday.getMonthValue(),
|
||||
monday.getYear()
|
||||
);
|
||||
return goalMetricAggregateDAO.findByAthleteForDashboard(athleteId, year, calendarWeek);
|
||||
}
|
||||
|
||||
private List<IntervalsActivity> fetchWeekActivities(final long athleteId, final int year, final int calendarWeek) {
|
||||
@@ -104,11 +104,12 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Nullable LocalDate resolveStartDate(final long athleteId) {
|
||||
@Nullable
|
||||
LocalDate resolveStartDate(final long athleteId) {
|
||||
final GoalMetricPeriodTotal lastWeekly = goalMetricAggregateDAO.findLastWeeklyByAthlete(athleteId);
|
||||
if (lastWeekly != null) {
|
||||
return LocalDate.of(lastWeekly.getPeriodYear(), 1, 4)
|
||||
.with(WeekFields.ISO.weekOfWeekBasedYear(), lastWeekly.getPeriodIndex())
|
||||
return LocalDate.of(lastWeekly.getYear(), 1, 4)
|
||||
.with(WeekFields.ISO.weekOfWeekBasedYear(), lastWeekly.getCalendarWeek())
|
||||
.with(WeekFields.ISO.dayOfWeek(), 1);
|
||||
}
|
||||
final IntervalsActivity earliestActivity = intervalsActivityService.getEarliestActivity(athleteId);
|
||||
@@ -122,7 +123,9 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
private void recalculateMetricForWeek(
|
||||
final long athleteId,
|
||||
final GoalMetricEnum metric,
|
||||
final List<IntervalsActivity> weekActivities) {
|
||||
final List<IntervalsActivity> weekActivities,
|
||||
final int targetYear,
|
||||
final int targetCalendarWeek) {
|
||||
// WEEKLY: recompute fresh from activities; apply delta to MONTHLY/YEARLY to keep them idempotent.
|
||||
// MONTHLY/YEARLY are attributed to the week's Monday — a slight simplification at month boundaries.
|
||||
final Map<PeriodKey, Double> weeklySums = new HashMap<>();
|
||||
@@ -133,29 +136,59 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
GoalPeriodEnum.WEEKLY.getPeriodIndex(date));
|
||||
weeklySums.merge(key, metric.extractValue(activity), Double::sum);
|
||||
}
|
||||
for (final Map.Entry<PeriodKey, Double> entry : weeklySums.entrySet()) {
|
||||
final int weekYear = entry.getKey().year();
|
||||
final int weekIndex = entry.getKey().index();
|
||||
final double newWeeklyValue = entry.getValue();
|
||||
|
||||
final GoalMetricPeriodTotal previousWeekly = goalMetricAggregateDAO.findByKey(
|
||||
athleteId, metric, GoalPeriodEnum.WEEKLY, weekYear, weekIndex);
|
||||
final double previousWeeklyValue = previousWeekly != null ? previousWeekly.getAggregatedValue() : 0.0;
|
||||
final double weeklyDelta = newWeeklyValue - previousWeeklyValue;
|
||||
|
||||
upsertAggregate(athleteId, metric, GoalPeriodEnum.WEEKLY, weekYear, weekIndex, newWeeklyValue);
|
||||
|
||||
if (weeklyDelta != 0.0) {
|
||||
final LocalDate weekStartDate = LocalDate.of(weekYear, 1, 4)
|
||||
.with(WeekFields.ISO.weekOfWeekBasedYear(), weekIndex)
|
||||
if (weeklySums.isEmpty()) {
|
||||
final boolean weeklyExists = goalMetricAggregateDAO.findByKey(
|
||||
athleteId, metric, GoalPeriodEnum.WEEKLY, targetYear, targetCalendarWeek) != null;
|
||||
if (!weeklyExists) {
|
||||
final LocalDate weekStartDate = LocalDate.of(targetYear, 1, 4)
|
||||
.with(WeekFields.ISO.weekOfWeekBasedYear(), targetCalendarWeek)
|
||||
.with(WeekFields.ISO.dayOfWeek(), 1);
|
||||
for (final GoalPeriodEnum period : List.of(GoalPeriodEnum.MONTHLY, GoalPeriodEnum.YEARLY)) {
|
||||
final int periodYear = period.getPeriodYear(weekStartDate);
|
||||
final int periodIndex = period.getPeriodIndex(weekStartDate);
|
||||
final GoalMetricPeriodTotal existing = goalMetricAggregateDAO.findByKey(
|
||||
athleteId, metric, period, periodYear, periodIndex);
|
||||
final double baseValue = existing != null ? existing.getAggregatedValue() : 0.0;
|
||||
upsertAggregate(athleteId, metric, period, periodYear, periodIndex, baseValue + weeklyDelta);
|
||||
final LocalDate prevMonday = weekStartDate.minusWeeks(1);
|
||||
final int prevYear = prevMonday.get(WeekFields.ISO.weekBasedYear());
|
||||
final int prevCalendarWeek = prevMonday.get(WeekFields.ISO.weekOfWeekBasedYear());
|
||||
|
||||
upsertAggregate(athleteId, metric, GoalPeriodEnum.WEEKLY, targetYear, targetCalendarWeek, 0.0);
|
||||
|
||||
final double monthlyBase = sameMonth(prevMonday, weekStartDate)
|
||||
? snapshotValue(goalMetricAggregateDAO.findByKey(athleteId, metric, GoalPeriodEnum.MONTHLY, prevYear, prevCalendarWeek))
|
||||
: 0.0;
|
||||
upsertAggregate(athleteId, metric, GoalPeriodEnum.MONTHLY, targetYear, targetCalendarWeek, monthlyBase);
|
||||
|
||||
final double yearlyBase = prevMonday.getYear() == weekStartDate.getYear()
|
||||
? snapshotValue(goalMetricAggregateDAO.findByKey(athleteId, metric, GoalPeriodEnum.YEARLY, prevYear, prevCalendarWeek))
|
||||
: 0.0;
|
||||
upsertAggregate(athleteId, metric, GoalPeriodEnum.YEARLY, targetYear, targetCalendarWeek, yearlyBase);
|
||||
}
|
||||
} else {
|
||||
for (final Map.Entry<PeriodKey, Double> entry : weeklySums.entrySet()) {
|
||||
final int weekYear = entry.getKey().year();
|
||||
final int weekIndex = entry.getKey().calendarWeek();
|
||||
final double newWeeklyValue = entry.getValue();
|
||||
|
||||
final GoalMetricPeriodTotal previousWeekly = goalMetricAggregateDAO.findByKey(
|
||||
athleteId, metric, GoalPeriodEnum.WEEKLY, weekYear, weekIndex);
|
||||
final double previousWeeklyValue = previousWeekly != null ? previousWeekly.getAggregatedValue() : 0.0;
|
||||
final double weeklyDelta = newWeeklyValue - previousWeeklyValue;
|
||||
|
||||
upsertAggregate(athleteId, metric, GoalPeriodEnum.WEEKLY, weekYear, weekIndex, newWeeklyValue);
|
||||
|
||||
if (weeklyDelta != 0.0) {
|
||||
final LocalDate weekStartDate = LocalDate.of(weekYear, 1, 4)
|
||||
.with(WeekFields.ISO.weekOfWeekBasedYear(), weekIndex)
|
||||
.with(WeekFields.ISO.dayOfWeek(), 1);
|
||||
final LocalDate prevMonday = weekStartDate.minusWeeks(1);
|
||||
final int prevYear = prevMonday.get(WeekFields.ISO.weekBasedYear());
|
||||
final int prevCalendarWeek = prevMonday.get(WeekFields.ISO.weekOfWeekBasedYear());
|
||||
|
||||
final double monthlyBase = sameMonth(prevMonday, weekStartDate)
|
||||
? snapshotValue(goalMetricAggregateDAO.findByKey(athleteId, metric, GoalPeriodEnum.MONTHLY, prevYear, prevCalendarWeek))
|
||||
: 0.0;
|
||||
upsertAggregate(athleteId, metric, GoalPeriodEnum.MONTHLY, weekYear, weekIndex, monthlyBase + weeklyDelta);
|
||||
|
||||
final double yearlyBase = prevMonday.getYear() == weekStartDate.getYear()
|
||||
? snapshotValue(goalMetricAggregateDAO.findByKey(athleteId, metric, GoalPeriodEnum.YEARLY, prevYear, prevCalendarWeek))
|
||||
: 0.0;
|
||||
upsertAggregate(athleteId, metric, GoalPeriodEnum.YEARLY, weekYear, weekIndex, yearlyBase + weeklyDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,10 +198,10 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
final long athleteId,
|
||||
final GoalMetricEnum metric,
|
||||
final GoalPeriodEnum period,
|
||||
final int periodYear,
|
||||
final int periodIndex,
|
||||
final int year,
|
||||
final int calendarWeek,
|
||||
final double value) {
|
||||
final GoalMetricPeriodTotal existing = goalMetricAggregateDAO.findByKey(athleteId, metric, period, periodYear, periodIndex);
|
||||
final GoalMetricPeriodTotal existing = goalMetricAggregateDAO.findByKey(athleteId, metric, period, year, calendarWeek);
|
||||
if (existing != null) {
|
||||
existing.setAggregatedValue(value);
|
||||
} else {
|
||||
@@ -176,13 +209,13 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
aggregate.setAthleteId(athleteId);
|
||||
aggregate.setMetric(metric);
|
||||
aggregate.setPeriod(period);
|
||||
aggregate.setPeriodYear(periodYear);
|
||||
aggregate.setPeriodIndex(periodIndex);
|
||||
aggregate.setYear(year);
|
||||
aggregate.setCalendarWeek(calendarWeek);
|
||||
aggregate.setAggregatedValue(value);
|
||||
insert(aggregate);
|
||||
}
|
||||
}
|
||||
|
||||
private record PeriodKey(int year, int index) {
|
||||
private record PeriodKey(int year, int calendarWeek) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
-- V41: Rename period_year/period_index to year/calendar_week.
|
||||
-- Both columns now always represent the ISO snapshot calendar week, regardless of period type.
|
||||
-- Existing rows have mismatched semantics (period_index was month number / 1 for YEARLY),
|
||||
-- so the table is truncated; recalculation will rebuild it from activities.
|
||||
|
||||
ALTER TABLE goal_metric_period_total RENAME COLUMN period_year TO year;
|
||||
ALTER TABLE goal_metric_period_total RENAME COLUMN period_index TO calendar_week;
|
||||
|
||||
ALTER TABLE goal_metric_period_total
|
||||
RENAME CONSTRAINT uq_goal_metric_period_total TO uq_goal_metric_period_total_snapshot;
|
||||
|
||||
TRUNCATE TABLE goal_metric_period_total;
|
||||
@@ -53,12 +53,12 @@ class GoalMetricPeriodTotalServiceTest extends AbstractPeakUpTest {
|
||||
assertEquals(1000.0, weekly.getAggregatedValue());
|
||||
|
||||
final GoalMetricPeriodTotal monthly = goalMetricPeriodTotalService.getAggregate(
|
||||
ATHLETE_ID, GoalMetricEnum.DISTANCE, GoalPeriodEnum.MONTHLY, today.getYear(), today.getMonthValue());
|
||||
ATHLETE_ID, GoalMetricEnum.DISTANCE, GoalPeriodEnum.MONTHLY, weekYear, weekIndex);
|
||||
assertNotNull(monthly);
|
||||
assertEquals(1000.0, monthly.getAggregatedValue());
|
||||
|
||||
final GoalMetricPeriodTotal yearly = goalMetricPeriodTotalService.getAggregate(
|
||||
ATHLETE_ID, GoalMetricEnum.DISTANCE, GoalPeriodEnum.YEARLY, today.getYear(), 1);
|
||||
ATHLETE_ID, GoalMetricEnum.DISTANCE, GoalPeriodEnum.YEARLY, weekYear, weekIndex);
|
||||
assertNotNull(yearly);
|
||||
assertEquals(1000.0, yearly.getAggregatedValue());
|
||||
}
|
||||
|
||||
@@ -105,11 +105,11 @@ function formatGoalValue(metric: Metric, value: number): string {
|
||||
function buildActualsFromTotals(
|
||||
totals: GoalMetricPeriodTotalDo[],
|
||||
period: GoalPeriodEnum,
|
||||
periodYear: number,
|
||||
periodIndex: number,
|
||||
year: number,
|
||||
calendarWeek: number,
|
||||
): Actuals {
|
||||
const relevant = totals.filter(
|
||||
(t) => t.period === period && t.periodYear === periodYear && t.periodIndex === periodIndex,
|
||||
(t) => t.period === period && t.year === year && t.calendarWeek === calendarWeek,
|
||||
)
|
||||
const result: Actuals = {DISTANCE: 0, TSS: 0, ELEVATION: 0, TIME: 0}
|
||||
for (const t of relevant) {
|
||||
@@ -360,8 +360,8 @@ export function Dashboard({athleteId}: { athleteId: number }) {
|
||||
// ── Actuals ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const weekActuals = buildActualsFromTotals(goalMetricPeriodTotals, 'WEEKLY', year, week)
|
||||
const monthActuals = buildActualsFromTotals(goalMetricPeriodTotals, 'MONTHLY', wStart.getFullYear(), wStart.getMonth() + 1)
|
||||
const yearActuals = buildActualsFromTotals(goalMetricPeriodTotals, 'YEARLY', wStart.getFullYear(), 1)
|
||||
const monthActuals = buildActualsFromTotals(goalMetricPeriodTotals, 'MONTHLY', year, week)
|
||||
const yearActuals = buildActualsFromTotals(goalMetricPeriodTotals, 'YEARLY', year, week)
|
||||
|
||||
const weeklyGoals = goals.filter((g) => g.period === 'WEEKLY')
|
||||
const monthlyGoals = goals.filter((g) => g.period === 'MONTHLY')
|
||||
|
||||
@@ -8,7 +8,7 @@ export interface GoalMetricPeriodTotalDo extends AbstractTimestampedEntityDo {
|
||||
athleteId: number;
|
||||
metric: GoalMetricEnum;
|
||||
period: GoalPeriodEnum;
|
||||
periodYear: number;
|
||||
periodIndex: number;
|
||||
year: number;
|
||||
calendarWeek: number;
|
||||
aggregatedValue: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user