mitgliederverwaltung/lib/mv_web/live/member_live/index/date_presets.ex

70 lines
2.3 KiB
Elixir

defmodule MvWeb.MemberLive.Index.DatePresets do
@moduledoc """
Relative date-range presets for the date value controls (§1.25/§2.8).
Each preset resolves against a reference date "today" into a concrete
`%{from: Date.t(), to: Date.t()}` range. Rolling "last N days/months" presets
end on today; the "this month/quarter/year" presets run period-to-date from
the respective period start up to today. Resolving is pure and clock-free —
the caller passes `today` (defaulting to `Date.utc_today/0`), so the resolved
bounds are testable and reproducible.
The resolved bounds feed the same `jd_*` / `ed_*` / `cdf_*` URL params as an
absolute custom range; presets are purely an input convenience and add no new
persistence dimension.
"""
@type preset ::
:last_7_days
| :last_30_days
| :last_3_months
| :last_12_months
| :this_month
| :this_quarter
| :this_year
@type range :: %{from: Date.t(), to: Date.t()}
@presets [
:last_7_days,
:last_30_days,
:last_3_months,
:last_12_months,
:this_month,
:this_quarter,
:this_year
]
@doc """
Returns every preset key in display order (rolling windows first, then the
period-to-date presets), for rendering the preset radio list.
"""
@spec all() :: [preset()]
def all, do: @presets
@doc """
Whether `key` names a known preset.
"""
@spec preset?(term()) :: boolean()
def preset?(key), do: key in @presets
@doc """
Resolves a preset to a concrete `{from, to}` range relative to `today`
(default `Date.utc_today/0`).
"""
@spec resolve(preset(), Date.t()) :: range()
def resolve(preset, today \\ Date.utc_today())
def resolve(:last_7_days, today), do: %{from: Date.add(today, -6), to: today}
def resolve(:last_30_days, today), do: %{from: Date.add(today, -29), to: today}
def resolve(:last_3_months, today), do: %{from: Date.shift(today, month: -3), to: today}
def resolve(:last_12_months, today), do: %{from: Date.shift(today, month: -12), to: today}
def resolve(:this_month, today), do: %{from: %{today | day: 1}, to: today}
def resolve(:this_quarter, today) do
first_month = div(today.month - 1, 3) * 3 + 1
%{from: Date.new!(today.year, first_month, 1), to: today}
end
def resolve(:this_year, today), do: %{from: Date.new!(today.year, 1, 1), to: today}
end