feat(#12): дневная цель — soft cap reps/день, после которого упражнение умолкает

This commit is contained in:
AnRil
2026-05-22 13:45:37 +07:00
parent 9e59be9cba
commit a6ae931461
6 changed files with 121 additions and 11 deletions

View File

@@ -92,6 +92,16 @@ export function validateExerciseInput(
const icon = safeStr(raw.icon, 64) ?? 'Activity'
const enabled = bool(raw.enabled) ?? true
const category = oneOf(raw.category, VALID_CATEGORIES) // undefined OK = default
const dailyGoal =
raw.dailyGoal === undefined || raw.dailyGoal === null
? undefined
: intInRange(raw.dailyGoal, 1, 100_000)
// dailyGoal: undefined = не задан (нет soft-cap'a), null от UI приводим к
// undefined; иначе — должен пройти int-range, иначе reject (нельзя
// отправить из renderer'а NaN/негатив и тихо обнулить).
if (raw.dailyGoal !== undefined && raw.dailyGoal !== null && dailyGoal === undefined) {
return null
}
if (
name === undefined ||
reps === undefined ||
@@ -107,6 +117,7 @@ export function validateExerciseInput(
enabled
}
if (category !== undefined) out.category = category
if (dailyGoal !== undefined) out.dailyGoal = dailyGoal
return out
}
@@ -145,6 +156,16 @@ export function validateExercisePatch(
if (v === undefined) return null
out.category = v
}
if ('dailyGoal' in raw) {
// Допустим null/undefined как «снять goal».
if (raw.dailyGoal === null || raw.dailyGoal === undefined) {
out.dailyGoal = undefined
} else {
const v = intInRange(raw.dailyGoal, 1, 100_000)
if (v === undefined) return null
out.dailyGoal = v
}
}
// Allow scheduler-controlled fields to be patched (used by store.markDone
// through this same boundary), but range-check them.
if ('nextFireAt' in raw) {