feat(overview): replace filter panel with add-filter builder and aging column
Swaps the unbounded vertical filter panel for a Polaris-style add-filter builder (searchable grouped field picker, type-aware value control, applied chips) and colour-codes the fees column with each member's period-scoped unpaid-cycle count.
This commit is contained in:
parent
7d1a71b1fd
commit
c547ca19af
35 changed files with 2817 additions and 3149 deletions
72
test/mv_web/member_live/index_payment_wiring_test.exs
Normal file
72
test/mv_web/member_live/index_payment_wiring_test.exs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
defmodule MvWeb.MemberLive.IndexPaymentWiringTest do
|
||||
@moduledoc """
|
||||
§1.16 / §1.17 — the member overview LiveView honours the period-scoped
|
||||
payment-count filter and payment-period URL contract (`pay_filter`,
|
||||
`pay_from`, `pay_to`), driving the same DB result set the OverviewQuery unit
|
||||
tests pin, but through `handle_params` and the query wiring.
|
||||
"""
|
||||
use MvWeb.ConnCase, async: false
|
||||
|
||||
import Phoenix.LiveViewTest
|
||||
import Mv.Fixtures, only: [create_fee_type: 2, member_fixture_with_actor: 2, create_cycle: 4]
|
||||
|
||||
setup %{conn: conn} do
|
||||
actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
ft = create_fee_type(%{interval: :monthly}, actor)
|
||||
|
||||
# Deterministic id set: drop the seeded members.
|
||||
Mv.Membership.Member
|
||||
|> Ash.read!(actor: actor)
|
||||
|> Enum.each(&Ash.destroy!(&1, actor: actor))
|
||||
|
||||
%{conn: conn_with_oidc_user(conn), actor: actor, ft: ft}
|
||||
end
|
||||
|
||||
defp member_with_unpaid(n, actor, ft) do
|
||||
member = member_fixture_with_actor(%{}, actor)
|
||||
|
||||
Enum.each(1..max(n, 0)//1, fn i ->
|
||||
create_cycle(member, ft, %{cycle_start: Date.new!(2024, i, 1), status: :unpaid}, actor)
|
||||
end)
|
||||
|
||||
member
|
||||
end
|
||||
|
||||
test "has-unpaid >= 2 shows only members with at least two in-period unpaid cycles", ctx do
|
||||
one = member_with_unpaid(1, ctx.actor, ctx.ft)
|
||||
two = member_with_unpaid(2, ctx.actor, ctx.ft)
|
||||
|
||||
{:ok, view, _html} =
|
||||
live(ctx.conn, "/members?pay_filter=unpaid_2&pay_from=2024-01-01&pay_to=2024-12-31")
|
||||
|
||||
assert has_element?(view, "#row-#{two.id}")
|
||||
refute has_element?(view, "#row-#{one.id}")
|
||||
end
|
||||
|
||||
test "fully_paid shows only members with zero in-period unpaid cycles", ctx do
|
||||
paid = member_with_unpaid(0, ctx.actor, ctx.ft)
|
||||
create_cycle(paid, ctx.ft, %{cycle_start: ~D[2024-05-01], status: :paid}, ctx.actor)
|
||||
unpaid = member_with_unpaid(1, ctx.actor, ctx.ft)
|
||||
|
||||
{:ok, view, _html} =
|
||||
live(ctx.conn, "/members?pay_filter=fully_paid&pay_from=2024-01-01&pay_to=2024-12-31")
|
||||
|
||||
assert has_element?(view, "#row-#{paid.id}")
|
||||
refute has_element?(view, "#row-#{unpaid.id}")
|
||||
end
|
||||
|
||||
test "the active period scopes the filter: a cycle outside the period does not count", ctx do
|
||||
# One unpaid cycle in 2023, none in 2024. With a 2024 period, has-unpaid>=1
|
||||
# must not select this member; with the all-outstanding default it must.
|
||||
member = member_fixture_with_actor(%{}, ctx.actor)
|
||||
create_cycle(member, ctx.ft, %{cycle_start: ~D[2023-03-01], status: :unpaid}, ctx.actor)
|
||||
|
||||
{:ok, scoped, _} =
|
||||
live(ctx.conn, "/members?pay_filter=unpaid_1&pay_from=2024-01-01&pay_to=2024-12-31")
|
||||
|
||||
refute has_element?(scoped, "#row-#{member.id}")
|
||||
|
||||
{:ok, all_time, _} = live(ctx.conn, "/members?pay_filter=unpaid_1")
|
||||
assert has_element?(all_time, "#row-#{member.id}")
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue