Make cycle button match PaymentFilterComponent and Columns button style.
Show 'Current Cycle Payment Status' or 'Last Cycle Payment Status'
based on active state. Button shows active state when current cycle
is selected.
Replace paid_filter with cycle_status_filter that filters based on
membership fee cycle status (last or current cycle). Update
PaymentFilterComponent to use new filter with options All, Paid, Unpaid.
Remove membership fee status filter dropdown. Extend
filter_members_by_cycle_status/3 to support both paid and unpaid filtering.
Update toggle_cycle_view to preserve filter state in URL.
Remove paid field from Member resource, database migration,
tests, seeds, and UI. This field is no longer needed as payment
status is now tracked via membership fee cycles.
- Fix get_last_completed_cycle to find most recent completed cycle
- Fix create_cycle helpers to delete auto-generated cycles first
- Fix Ash.destroy return value handling
- Fix form selectors to use specific IDs
- Fix URL parameter names for filters
- Fix Ash.read_one return value expectations in tests
- Set join_date in past to ensure cycles can be generated
- Check for flash message to verify action completion
- More reliable test that works with cycle generation logic
- Add tab switching to membership fees tab in all tests
- Update button selectors to use correct phx-value attributes
- Fix cycle display test to check for formatted dates
- All membership fees tests now pass
- Normalize checkbox 'on' value to boolean true in settings
- Change Payment Data layout to flex-nowrap for horizontal display
- Replace membership fee type dropdown with display-only view
- Fix tests to use correct button selectors and switch to membership fees tab
- Replace Enum.map |> Enum.join with Enum.map_join for efficiency
- Extract helper functions to reduce nesting depth from 4 to 2
- Rename is_current_cycle? to current_cycle? following Elixir conventions
- Implemented regenerate_cycles_on_type_change helper in Member resource
- Cycles that haven't ended yet (cycle_end >= today) are deleted and regenerated
- Paid and suspended cycles remain unchanged (not deleted)
- CycleGenerator reloads member with new membership_fee_type_id
- Adjusted tests to work with current cycles only (no future cycles)
- All integration tests passing
Phase 4 completed: Cycle regeneration on type change
- Remove Process.sleep calls from integration tests (tests run synchronously in SQL sandbox)
- Improve error handling: membership_fee_type_not_found now returns changeset error instead of just logging
- Clarify partial_failure documentation: successful_cycles are not persisted on rollback
- Update documentation: joined_at → join_date, left_at → exit_date
- Document PostgreSQL advisory locks per member (not whole table lock)
- Document gap handling: explicitly deleted cycles are not recreated
- Add create_member_with_cycles helper that uses fixed 'today' date
- Update tests to use explicit 'today:' option instead of Date.utc_today()
- Prevents test failures when current date changes (e.g., in 2026+)
- Tests now explicitly delete and regenerate cycles with fixed dates
- Ensures consistent test behavior regardless of execution date
- Change algorithm to start from last existing cycle instead of start_date
- Deleted cycles (gaps) are no longer automatically filled
- Add test to verify gaps remain unfilled
- Update documentation to clarify gap handling behavior
- Replace weak assertions (>= 0, if length > 0) with concrete expectations
- Remove unnecessary Process.sleep calls (tests run synchronously)
- Add get_member_cycles helper for direct cycle verification
- Tests now validate actual generated cycles instead of relying on async behavior
- Remove exit_date filter from generate_cycles_for_all_members query
- Inactive members now get cycles generated up to their exit_date
- Add tests for inactive member processing and exit_date boundary
- Document exit_date == cycle_start behavior (cycle still generated)
Add tests to verify that copy and open-email buttons are disabled
when no members are selected and enabled after selection.
Also verify that the counter shows the correct count.