# Member list: visible Add Member action and modal creation flow

## Objective
Apply the service-page action/modal pattern to member management. Make “Add new member” unmistakably visible on `admin/member_view.php` and open the complete existing registration form in a polished accessible modal instead of sending normal users to a separate page.

## Scope
Modify:
- `admin/member_view.php`
- create `admin/member_add_modal.php` or another reusable member-form partial
- `admin/member_add.php` as a fallback/deep-link wrapper reusing the same form partial, not duplicated fields
- `admin/process_member_add.php` only as needed for CSRF, safe validation, and redirecting the modal flow back to `member_view`
- `assets/portal/css/admin.css`
- `assets/portal/js/admin.js` only if the existing accessible modal controller needs enhancement

## Permission and behavior
- Page remains `members.view`.
- `$canCreate = appStaffCan($dbh, 'members.create')`.
- “Add new member” appears only for `$canCreate`, as a lemon-green primary action at least 44px tall in the intro/header action area.
- Keep a visible Reports center action for users with `reports.view`; do not link directly to PDF.
- Clicking Add opens `#addMemberModal`; no navigation.
- View-only users never receive modal markup or creation action.
- Modal closes with X, Cancel, Escape, and backdrop; focus trap/restoration uses existing controller.
- The modal must not auto-open normally. If the process redirects back after a validation failure and field preservation is implemented safely, it may reopen with errors; otherwise show a toast and let the user reopen.
- Successful creation redirects to `member_view` and shows toast. Duplicate/validation errors also redirect to `member_view` (not `member_add`) and show toast.
- Standalone `member_add.php` remains a working accessible fallback for bookmarked links, but it must reuse the same fields/partial and point users back to member list.

## Form fields to preserve
First name, last name, gender, date of birth, residence, phone number, optional email, profile image, ministry, member type. Load ministries before rendering; escape IDs/text. Use meaningful IDs/labels, autocomplete attributes, phone input as `type=tel` (not number), sensible maximum lengths, and accept only supported image types.

## Backend safety
- Add `appCsrfField()` to modal and fallback form and verify it in `process_member_add.php` with the shared security helper.
- Require POST and `members.create`.
- Validate required strings, gender allowlist, real DOB not in future, email, ministry integer/existence, member-type allowlist, and phone length/content.
- Preserve duplicate check.
- Profile image: validate upload success, size limit (about 5 MB), MIME allowlist JPEG/PNG/WebP using server inspection, generate a random unique filename/extension, and fail safely if move fails. Do not trust or reuse the original filename. If schema/form policy keeps image required, communicate that clearly.
- Insert transactionally where practical; prevent race/duplicate member IDs. Existing sequential JSOW ID logic should be made concurrency-safe or retried on unique conflict rather than silently colliding.
- Escape or avoid detailed database exception messages in user toasts.
- Preserve existing welcome SMS behavior if available, but a failed external SMS must not roll back or falsely report member creation failure. Do not expose API secrets in UI/log output.
- Redirect all outcomes to `member_view` for the modal-first flow.

## Member list improvement
- Fetch ministries once for modal.
- Add intro copy and visible action grouping matching service setup page.
- Keep searchable responsive records, safe image fallback, View/Archive permissions.
- Provide clear empty state with Add Member action for creators.
- Remove obsolete ordered-list/plain link styling and old cache key.

## Visual direction
Established strong photo overlay, forest glass, lemon accent. Modal is a premium registration sheet: clear title, short reassurance, grouped Personal / Contact / Church profile sections, optional image preview if simple and reliable, sticky or clearly visible footer actions. Avoid cramped generic Bootstrap form.

## Responsive/accessibility
- Modal width around 820–900px desktop, scrolls internally within viewport.
- Two columns desktop, one column phone; actions always reachable above bottom nav.
- 1440, 1024, 768, 430, 375; no overflow.
- Focus management, ARIA label/description, touch targets >=44px, no native alert.

## Verification
- PHP lint all changed PHP.
- Runtime authenticated `member_view` HTTP 200; modal/action present for creator.
- Confirm view-only gating statically.
- Confirm modal form field names exactly match processor.
- Confirm successful/error redirects target `member_view`.
- Do not create a real member during testing unless using a transaction that is safely rolled back; prefer static/backend unit checks.
- Update CSS/JS cache keys.
