Files
HomeAssistantVS/custom_components/maintenance_supporter/frontend-src/helpers/interval.ts
T
2026-07-08 10:43:39 -04:00

42 lines
1.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Unit-aware interval math (issue #59) for the frontend's progress bars and
* calendar projection stepping. Uses an AVERAGE day-span per unit (below), an
* intentional approximation — the backend `helpers/dates.add_interval` is
* calendar-exact (Jan+1mo = 31 days), so display-side spans can differ by a day
* or two. Cosmetic only. Pure functions — unit-tested in interval.test.ts.
*/
/** Approximate (average) days per interval unit — mean Gregorian month / Julian
* year. NOT calendar-exact; see the module note above. */
export const UNIT_DAYS: Record<string, number> = {
days: 1,
weeks: 7,
months: 30.4368,
years: 365.25,
};
/** Approximate length of `intervalDays` of `unit` in days; 0 when no interval. */
export function intervalSpanDays(
intervalDays: number | null | undefined,
unit?: string | null,
): number {
if (!intervalDays || intervalDays <= 0) return 0;
return intervalDays * (UNIT_DAYS[unit || "days"] ?? 1);
}
/**
* Progress through the current cycle, unit-aware.
* Returns a clamped 0100 % plus `overflow` (raw % > 100, i.e. past due).
* Falls back to {0, false} when there is no usable interval/countdown.
*/
export function daysProgress(
intervalDays: number | null | undefined,
daysUntilDue: number | null | undefined,
unit?: string | null,
): { pct: number; overflow: boolean } {
const span = intervalSpanDays(intervalDays, unit);
if (span <= 0 || daysUntilDue == null) return { pct: 0, overflow: false };
const raw = ((span - daysUntilDue) / span) * 100;
return { pct: Math.max(0, Math.min(100, raw)), overflow: raw > 100 };
}