## Description of the implemented changes
The changes were:
- [x] Bugfixing
- [x] New Feature
- [ ] Breaking Change
- [x] Refactoring
This PR standardizes interactive table behavior and improves settings robustness.
It makes the new hover/focus-visible row highlight the default for clickable tables, keeps sticky first-column behavior configurable (and optimized for member selection UX), and tightens SMTP source-of-truth handling so ENV-based and UI-based configuration do not conflict.
## What has been changed?
- Refactored `CoreComponents.table` to expose interaction state via `data-row-interactive` and moved default row hover/focus styling to CSS.
- Made the new row highlight behavior (`hover` + `:has(:focus-visible)`) the default for clickable zebra tables.
- Kept sticky-first-column as an explicit table option and preserved sticky-specific selection accent behavior.
- Updated member overview table usage to the sticky-first-column mode and refined scrolling behavior (table scrollbar within container, not page-coupled).
- Adjusted table-related tests to validate the new interaction contract (attribute/CSS-driven behavior instead of legacy ring classes).
- Improved SMTP config handling:
- clearer ENV-vs-Settings behavior (ENV-only mode when host env is set),
- read-only and warning behavior in global settings UI when required env keys are missing,
- updated related config/tests/docs.
- Updated docs and changelog (`CHANGELOG.md`, `DESIGN_GUIDELINES.md`, `CODE_GUIDELINES.md`, SMTP concept docs).
- Updated gettext catalogs (`default.pot`, `en`, `de`) for new/changed UI strings.
## Definition of Done
### Code Quality
- [x] No new technical depths
- [x] Linting passed
- [x] Documentation is added were 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
- Branch includes 4 commits:
- `fix: make sure smtp can be set either via env or ui`
- `fix: make horizontal scrollbars sticky to bottom`
- `docs: update changelog`
- `feat: make checkbox column in member view sticky`
- Full fast suite passed (`mix test --exclude slow --exclude ui`): 2017 tests, 0 failures (plus expected non-failing warning logs in test output).
- Reviewer focus areas:
1. **Cross-table UX consistency** after moving row interaction styling to component/CSS contract.
2. **Sticky table behavior** (selection accent stripe, zebra background, keyboard focus visibility).
3. **SMTP precedence and UI constraints** in global settings when ENV mode is active.
4. **Regression risk in tests** that previously asserted ring-based row classes.
- No breaking API changes expected; behavior change is primarily visual/interaction-level and intentional.
Reviewed-on: #493
Co-authored-by: Simon <s.thiessen@local-it.org>
Co-committed-by: Simon <s.thiessen@local-it.org>
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.
- Add status column showing last completed or current cycle status
- Add toggle to switch between last/current cycle view
- Add color coding (green/red/gray) for paid/unpaid/suspended
- Add filters for unpaid cycles in last/current cycle
- Efficiently load cycles to avoid N+1 queries
Use URI.encode_www_form() instead of URI.encode() for mailto query parameters.
This is the safer choice for query parameter encoding.
Add comment about mailto URL length limits that vary by email client.
Calculate selected_count, any_selected? and mailto_bcc once in assigns
instead of recalculating Enum.any? and Enum.count multiple times in template.
This improves render performance and makes the template code more readable.
- Add col_click slot attribute to table component that overrides row_click
- Clicking anywhere in the checkbox column now toggles the checkbox
- Clicking other columns still navigates to member details
Closes#223