Member Fee Type in overview and exports, fix column visibility from URL #442

Merged
moritz merged 11 commits from feat/show_memberfeetype into main 2026-02-24 09:50:50 +01:00
Owner

Description of the implemented changes

The changes were:

  • Bugfixing
  • New Feature
  • Breaking Change
  • Refactoring

Member Fee Type is shown as a selectable/sortable column in the member overview and included in CSV and PDF exports. Column visibility is correctly restored from the URL on full page reload or direct link.


What has been changed?

New feature: Fee Type in member overview and exports

  • Overview: Added “Fee Type” (Beitragsart) as a pseudo field in the member index: optional column, show/hide via “Show/Hide Columns”, sortable.
  • Field visibility: FieldVisibility and FieldSelection support the new pseudo field; translations (EN/DE) for the column label.
  • CSV export: Fee Type column in CSV export; controller allowlist and MembersCSV updated.
  • PDF export: Fee Type and groups in PDF export: MemberExport allowlist and insert_fee_type_and_computed_fields_like_table, Build (load/sort/cell_value for membership_fee_type), MemberPdfExportController allowlist for membership_fee_type and groups.
  • Tests: Tests for fee type column visibility, CSV export (fee type column), export controller (membership_fee_type), and FieldVisibility pseudo fields.

Bugfix: Column visibility from URL on reload

  • Problem: With ?fields=first_name,email in the URL, a full reload or opening the link again showed all columns instead of only the chosen ones.
  • Cause: On first load, conn.params has no query string (Phoenix runs fetch_query_params after render). In addition, when the URL had fields, the result was merged with global settings so all other columns became visible again.
  • Fix:
    • Read the fields parameter from the request URI in handle_params (via merge_fields_param_from_uri), with fallback to request_url_from_socket(socket) when the URL argument is nil (e.g. static render).
    • When ?fields=... is present, use FieldVisibility.selection_from_url_only/2 so only the listed columns are visible (no merge with global settings).
    • If the URL contains only invalid field names, fall back to session + global settings so behaviour matches “no valid URL selection”.
  • Files: lib/mv_web/live/member_live/index.ex (handle_params, merge_fields_param_from_uri, request_url_from_socket, compute_final_field_selection), lib/mv_web/live/member_live/index/field_visibility.ex (selection_from_url_only).

Definition of Done

Code Quality

  • No new technical depths
  • Linting passed
  • Documentation is added where needed

Accessibility

  • New elements are properly defined with html-tags
  • Colour contrast follows WCAG criteria
  • Aria labels are added when needed
  • Everything is accessible by keyboard
  • Tab-Order is comprehensible
  • All interactive elements have a visible focus

Testing

  • Tests for new code are written
  • All tests pass
  • axe-core dev tools show no critical or major issues

Additional Notes

  • Fee Type column uses the same patterns as existing optional columns (e.g. groups, membership_fee_status) and the existing “Show/Hide Columns” UI.
  • Column visibility fix only affects the fields URL parameter (Spaltenauswahl); other query params (e.g. filters, sort) are unchanged.
  • Credo refactors in MemberExport and MemberExport.Build (e.g. maybe_sort, insert_fee_type_and_computed_fields_like_table) were done to keep complexity and nesting within limits.
## Description of the implemented changes The changes were: - [x] Bugfixing - [x] New Feature - [ ] Breaking Change - [ ] Refactoring **Member Fee Type** is shown as a selectable/sortable column in the member overview and included in CSV and PDF exports. **Column visibility** is correctly restored from the URL on full page reload or direct link. --- ## What has been changed? ### New feature: Fee Type in member overview and exports - **Overview:** Added “Fee Type” (Beitragsart) as a pseudo field in the member index: optional column, show/hide via “Show/Hide Columns”, sortable. - **Field visibility:** `FieldVisibility` and `FieldSelection` support the new pseudo field; translations (EN/DE) for the column label. - **CSV export:** Fee Type column in CSV export; controller allowlist and `MembersCSV` updated. - **PDF export:** Fee Type and groups in PDF export: `MemberExport` allowlist and `insert_fee_type_and_computed_fields_like_table`, `Build` (load/sort/cell_value for `membership_fee_type`), `MemberPdfExportController` allowlist for `membership_fee_type` and `groups`. - **Tests:** Tests for fee type column visibility, CSV export (fee type column), export controller (membership_fee_type), and `FieldVisibility` pseudo fields. ### Bugfix: Column visibility from URL on reload - **Problem:** With `?fields=first_name,email` in the URL, a full reload or opening the link again showed all columns instead of only the chosen ones. - **Cause:** On first load, `conn.params` has no query string (Phoenix runs `fetch_query_params` after render). In addition, when the URL had `fields`, the result was merged with global settings so all other columns became visible again. - **Fix:** - Read the `fields` parameter from the request URI in `handle_params` (via `merge_fields_param_from_uri`), with fallback to `request_url_from_socket(socket)` when the URL argument is nil (e.g. static render). - When `?fields=...` is present, use `FieldVisibility.selection_from_url_only/2` so only the listed columns are visible (no merge with global settings). - If the URL contains only invalid field names, fall back to session + global settings so behaviour matches “no valid URL selection”. - **Files:** `lib/mv_web/live/member_live/index.ex` (handle_params, merge_fields_param_from_uri, request_url_from_socket, compute_final_field_selection), `lib/mv_web/live/member_live/index/field_visibility.ex` (selection_from_url_only). --- ## Definition of Done ### Code Quality - [x] No new technical depths - [x] Linting passed - [x] Documentation is added where needed ### Accessibility - [x] New elements are properly defined with html-tags - [x] Colour contrast follows WCAG criteria - [x] Aria labels are added when needed - [x] Everything is accessible by keyboard - [x] Tab-Order is comprehensible - [x] All interactive elements have a visible focus ### Testing - [x] Tests for new code are written - [x] All tests pass - [ ] axe-core dev tools show no critical or major issues --- ## Additional Notes - Fee Type column uses the same patterns as existing optional columns (e.g. groups, membership_fee_status) and the existing “Show/Hide Columns” UI. - Column visibility fix only affects the `fields` URL parameter (Spaltenauswahl); other query params (e.g. filters, sort) are unchanged. - Credo refactors in `MemberExport` and `MemberExport.Build` (e.g. `maybe_sort`, `insert_fee_type_and_computed_fields_like_table`) were done to keep complexity and nesting within limits.
moritz added 7 commits 2026-02-24 01:10:06 +01:00
Allow Fee Type as selectable column in member overview dropdown.
MemberFields.label(:membership_fee_type), DE: Beitragsart.
Load membership_fee_type when column visible; sort by membership_fee_type_id;
add table column with SortHeader and fee type name.
Payload and column_order when visible; allowlist, load, sort;
MembersCSV cell for :membership_fee_type.
FieldVisibility pseudo fields and visible selection; MembersCSV fee type
column; export accepts membership_fee_type and returns Fee Type column.
MemberExport allowlist and insert_fee_type; Build load/sort/cell_value;
MemberPdfExportController allow membership_fee_type and groups.
fix(members): restore column visibility from URL on reload
All checks were successful
continuous-integration/drone/push Build is passing
d41d13d122
Read 'fields' from URI when conn.params has no query (e.g. full page load).
When ?fields=... is present use URL-only selection so columns are not
merged with global settings. Fall back to session+global when URL has
only invalid field names.
moritz added 3 commits 2026-02-24 09:29:46 +01:00
Use Ash related-field sort (membership_fee_type.name) instead of
membership_fee_type_id so column order is alphabetical. Load
membership_fee_type when sorting by it even if column is hidden.
In-memory re-sort (Build) uses loaded fee type name.

Co-authored-by: Cursor <cursoragent@cursor.com>
Append membership_fee_type to column list when it is visible but
membership_fee_start_date was not in the selection (MemberExport,
export_column_order, build_export_member_fields_list).

Co-authored-by: Cursor <cursoragent@cursor.com>
test: export and PDF regression for Fee Type without start_date
Some checks reported errors
continuous-integration/drone/push Build was killed
f211f45cb2
Add test for CSV export with only first_name and membership_fee_type.
Add test for PDF export with same field set (status and content-type).

Co-authored-by: Cursor <cursoragent@cursor.com>
moritz force-pushed feat/show_memberfeetype from f211f45cb2 to d5df2338a7 2026-02-24 09:30:30 +01:00 Compare
moritz added 1 commit 2026-02-24 09:42:39 +01:00
fix: treat URL with only custom fields as valid in ?fields= mode
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is passing
10ad32eb6f
Consider visible custom fields in compute_final_field_selection so that
a link with only custom_field_X is not wrongly treated as invalid and
reverted to session/global. Add test for URL containing only custom field.
moritz changed title from WIP: Member Fee Type in overview and exports, fix column visibility from URL to Member Fee Type in overview and exports, fix column visibility from URL 2026-02-24 09:43:32 +01:00
moritz merged commit c9d4254152 into main 2026-02-24 09:50:50 +01:00
moritz deleted branch feat/show_memberfeetype 2026-02-24 09:50:51 +01:00
moritz self-assigned this 2026-02-24 09:52:02 +01:00
moritz added this to the Sprint 13: 19.02-26.02 project 2026-02-24 09:52:08 +01:00
Sign in to join this conversation.
No description provided.