Fix club admin UI styling and add inline member editing#1257
Fix club admin UI styling and add inline member editing#1257
Conversation
… add edit member
- Replace all variant-* Skeleton UI classes with correct preset-* equivalents
across charges, fees, and stripe admin pages (fixes transparent backgrounds)
- Replace broken modal pattern (separate backdrop + absolute positioning) with
working overlay pattern (fixed inset-0 flex center bg-black/50)
- Add edit member functionality to the members page with PUT /pilots/{id} endpoint
- Remove separate admin/users page; edit buttons shown inline for club admins
- Add UpdatePilotRequest type and update_pilot repo method for pilot qualifications
There was a problem hiding this comment.
Pull request overview
This PR consolidates club member management by adding inline edit functionality to the Members tab, removing the separate admin/users page. It also fixes Skeleton UI styling across club admin pages by migrating from deprecated variant-* classes to preset-* equivalents and replacing a broken custom modal pattern with a consistent fixed inset-0 overlay approach.
Changes:
- Add
PUT /pilots/{id}backend endpoint with club admin authorization, and corresponding inline edit modal on the Members tab - Replace all
variant-*Skeleton UI classes withpreset-*equivalents and replace custom CSS modal pattern with accessible overlay pattern across charges, fees, and stripe pages - Remove the standalone admin/users page and its navigation link, restricting add/edit member actions to club admins only
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/users.rs |
Add UpdatePilotRequest struct with optional fields |
src/users_repo.rs |
Add update_pilot repository method using Diesel |
src/actions/users.rs |
Add update_pilot handler with club admin authorization |
src/web.rs |
Register PUT /pilots/{id} route |
web/src/routes/clubs/[id]/members/+page.svelte |
Add edit modal, restrict add/edit to club admins |
web/src/routes/clubs/[id]/+layout.svelte |
Remove "Users" admin sub-item |
web/src/routes/clubs/[id]/admin/users/+page.svelte |
Delete standalone users page |
web/src/routes/clubs/[id]/admin/users/+page.ts |
Delete standalone users page loader |
web/src/routes/clubs/[id]/admin/charges/+page.svelte |
Fix styling classes and modal pattern |
web/src/routes/clubs/[id]/admin/fees/+page.svelte |
Fix styling classes and modal pattern |
web/src/routes/clubs/[id]/admin/stripe/+page.svelte |
Fix styling classes |
You can also share your feedback on Copilot code review. Take the survey.
| aria-labelledby="create-charge-heading" | ||
| tabindex="-1" | ||
| > | ||
| <h3 class="mb-4 h3">Create Charge</h3> |
| diesel::update(users::table.filter(users::id.eq(user_id))) | ||
| .set(( | ||
| users::first_name.eq(request_clone.first_name.unwrap_or(current.first_name)), | ||
| users::last_name.eq(request_clone.last_name.unwrap_or(current.last_name)), | ||
| users::is_licensed.eq(request_clone.is_licensed.unwrap_or(current.is_licensed)), | ||
| users::is_instructor | ||
| .eq(request_clone.is_instructor.unwrap_or(current.is_instructor)), | ||
| users::is_tow_pilot | ||
| .eq(request_clone.is_tow_pilot.unwrap_or(current.is_tow_pilot)), | ||
| users::is_examiner.eq(request_clone.is_examiner.unwrap_or(current.is_examiner)), | ||
| users::updated_at.eq(now), | ||
| )) | ||
| .execute(&mut conn)?; | ||
|
|
||
| let updated = users::table | ||
| .filter(users::id.eq(user_id)) | ||
| .first::<UserRecord>(&mut conn) | ||
| .optional()?; | ||
| Ok(updated.map(|r| r.into())) |
- Add missing id="create-charge-heading" on the charge modal heading so aria-labelledby resolves correctly for screen readers - Use get_result on the diesel update call in update_pilot to combine UPDATE + SELECT into one round-trip instead of three separate queries
There was a problem hiding this comment.
Pull request overview
This PR updates the club admin experience by fixing Skeleton UI styling issues (variants → presets), standardizing modal overlays, and adding inline member editing on the club Members tab via a new PUT /pilots/{id} endpoint (removing the legacy admin/users page).
Changes:
- Replace broken
variant-*Skeleton classes withpreset-*equivalents across club admin pages. - Replace the legacy backdrop/modal pattern with a fixed full-screen overlay modal pattern for charges/fees (and add an edit modal on members).
- Add backend + frontend support for inline member editing and remove the
/admin/usersroute and nav item.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| web/src/routes/clubs/[id]/members/+page.svelte | Adds inline edit UI + modal and restricts add/edit actions to club admins. |
| web/src/routes/clubs/[id]/admin/users/+page.ts | Removes legacy users admin page load guard. |
| web/src/routes/clubs/[id]/admin/users/+page.svelte | Removes legacy users admin page UI (superseded by inline edit on Members tab). |
| web/src/routes/clubs/[id]/admin/stripe/+page.svelte | Updates styling classes to preset-* variants. |
| web/src/routes/clubs/[id]/admin/fees/+page.svelte | Updates styling classes and replaces modal implementation with overlay pattern. |
| web/src/routes/clubs/[id]/admin/charges/+page.svelte | Updates styling classes and replaces modal implementation with overlay pattern. |
| web/src/routes/clubs/[id]/+layout.svelte | Removes “Users” link from the admin submenu. |
| src/web.rs | Registers PUT /pilots/{id} route. |
| src/users_repo.rs | Adds UsersRepository::update_pilot DB update method. |
| src/users.rs | Adds UpdatePilotRequest payload type. |
| src/actions/users.rs | Adds update_pilot handler with club-admin/site-admin authorization checks. |
You can also share your feedback on Copilot code review. Take the survey.
| let updated = diesel::update(users::table.filter(users::id.eq(user_id))) | ||
| .set(( | ||
| users::first_name.eq(request_clone.first_name.unwrap_or(current.first_name)), | ||
| users::last_name.eq(request_clone.last_name.unwrap_or(current.last_name)), | ||
| users::is_licensed.eq(request_clone.is_licensed.unwrap_or(current.is_licensed)), | ||
| users::is_instructor | ||
| .eq(request_clone.is_instructor.unwrap_or(current.is_instructor)), | ||
| users::is_tow_pilot | ||
| .eq(request_clone.is_tow_pilot.unwrap_or(current.is_tow_pilot)), | ||
| users::is_examiner.eq(request_clone.is_examiner.unwrap_or(current.is_examiner)), | ||
| users::updated_at.eq(now), | ||
| )) | ||
| .get_result::<UserRecord>(&mut conn)?; |
| <button | ||
| onclick={() => openEditModal(member)} | ||
| class="preset-tonal-surface-500 btn btn-sm" | ||
| title="Edit member" |
| onclick={closeEditModal} | ||
| role="button" | ||
| tabindex="0" | ||
| onkeydown={(e) => e.key === 'Escape' && closeEditModal()} |
| <div | ||
| class="m-4 w-full max-w-md card p-6" | ||
| onclick={(e) => e.stopPropagation()} | ||
| onkeydown={(e) => e.stopPropagation()} |
| #[derive(Debug, Clone, Deserialize)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct UpdatePilotRequest { | ||
| pub first_name: Option<String>, | ||
| pub last_name: Option<String>, |
| <button | ||
| onclick={() => openEditModal(member)} | ||
| class="preset-tonal-surface-500 btn btn-sm" | ||
| title="Edit member" |
| <div | ||
| class="m-4 w-full max-w-md space-y-4 card p-6" | ||
| onclick={(e) => e.stopPropagation()} | ||
| onkeydown={(e) => e.stopPropagation()} |
| <div | ||
| class="m-4 w-full max-w-md card p-6" | ||
| onclick={(e) => e.stopPropagation()} | ||
| onkeydown={(e) => e.stopPropagation()} |
| <div | ||
| class="m-4 w-full max-w-md card p-6" | ||
| onclick={(e) => e.stopPropagation()} | ||
| onkeydown={(e) => e.stopPropagation()} |
| <div | ||
| class="m-4 w-full max-w-md card p-6" | ||
| onclick={(e) => e.stopPropagation()} | ||
| onkeydown={(e) => e.stopPropagation()} |
Summary
variant-*Skeleton UI classes with correctpreset-*equivalentsfixed inset-0 flex items-center justify-center bg-black/50overlay patternPUT /pilots/{id}endpoint, removing the need for a separate admin/users pageTest plan