Membership Fee 6 - UI Components & LiveViews closes #280 #304

Merged
moritz merged 79 commits from feature/280_membership_fee_ui into main 2025-12-26 23:14:50 +01:00
Showing only changes of commit ee6589c4fa - Show all commits

View file

@ -15,13 +15,14 @@ defmodule MvWeb.MemberLive.Index.MembershipFeeStatus do
Loads membership fee cycles for members efficiently.
Preloads cycles with membership_fee_type relationship to avoid N+1 queries.
Only loads the relevant cycle per member (last completed or current, depending on show_current).
Note: This loads all cycles for each member. The filtering to get the relevant
cycle (current or last completed) happens in `get_cycle_status_for_member/2`.
## Parameters
- `query` - Ash query for members
- `show_current` - If true, load current cycle; if false, load last completed cycle
- `today` - Optional date to use as reference (defaults to today)
- `show_current` - If true, get current cycle status; if false, get last completed cycle status (currently unused, kept for API compatibility)
- `today` - Optional date to use as reference (currently unused, kept for API compatibility)
## Returns
@ -30,11 +31,11 @@ defmodule MvWeb.MemberLive.Index.MembershipFeeStatus do
## Performance
Uses Ash.Query.load to efficiently preload cycles in a single query.
Filters cycles at database level to only load the relevant cycle per member.
All cycles are loaded; filtering happens in memory in `get_cycle_status_for_member/2`.
"""
@spec load_cycles_for_members(Ash.Query.t(), boolean(), Date.t() | nil) :: Ash.Query.t()
def load_cycles_for_members(query, _show_current \\ false, _today \\ nil) do
# Load membership_fee_type and cycles with efficient filtering
# Load membership_fee_type and cycles
query
|> Ash.Query.load([:membership_fee_type, membership_fee_cycles: [:membership_fee_type]])
end
@ -65,13 +66,14 @@ defmodule MvWeb.MemberLive.Index.MembershipFeeStatus do
iex> MvWeb.MemberLive.Index.MembershipFeeStatus.get_cycle_status_for_member(member, true)
:unpaid
"""
@spec get_cycle_status_for_member(Member.t(), boolean()) :: :paid | :unpaid | :suspended | nil
def get_cycle_status_for_member(member, show_current \\ false) do
@spec get_cycle_status_for_member(Member.t(), boolean(), Date.t() | nil) ::
:paid | :unpaid | :suspended | nil
def get_cycle_status_for_member(member, show_current \\ false, today \\ nil) do
cycle =
if show_current do
MembershipFeeHelpers.get_current_cycle(member)
MembershipFeeHelpers.get_current_cycle(member, today)
else
MembershipFeeHelpers.get_last_completed_cycle(member)
MembershipFeeHelpers.get_last_completed_cycle(member, today)
end
case cycle do