Skip to content

Admin volunteer hours: read, credit and void - #129

Merged
byteful merged 18 commits into
mainfrom
feat/admin-user-hours
Sep 30, 2026
Merged

byteful merged 18 commits into
mainfrom
feat/admin-user-hours

Conversation

@byteful

@byteful byteful commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

What changed

The admin console's "Hours" tab on a user now works: an operator can see a neighbor's volunteer hours, credit hours for an ended event or as a manual adjustment, and void an entry. Before this, the tab failed to load on staging because the server side was missing. The neighbor sees an operator credit as "credited by CivFix". Admin, plus the neighbor's profile on web and mobile.

Before you start

  • Where: admin.civfix.dev, civfix.dev and the TestFlight build, after merge (staging)
  • Sign in as: an operator on admin.civfix.dev; a normal citizen (not the official @civfix account) on civfix.dev and in the app
  • Data: an ended event with a location in a city, that the citizen has no hours for yet
  • Related PRs: Adopt the released @civfix/shared 0.58.0 civfix-admin#50 moves the console onto the released contract. Also supersedes Adopt @civfix/shared 0.58.0 #121
  • Size: 1912 counted lines, about 1100 of them tests — the read, credit and void endpoints of one screen, which can't ship apart without leaving the tab half-broken

Verify

[Admin]

  1. Open "Users", search for the citizen in "Search name, handle, city…" and click their row
  2. Click the "Hours" tab — Expect: "Total hours", "Entries" and "Voided" tiles and the list, or "No hours yet"; no "Could not load this"
  3. Click "Credit hours", keep "Event credit", search the event in "Search ended events by title or place…" and pick it
  4. Enter "1" in "Hours", type a reason in "Reason", click "Credit hours", then "Credit hours" in the dialog — Expect: a toast " · +1 h"; the entry appears at the top with the event title and "Credited by CivFix · "; "Total hours" rises by 1
  5. Click "Credit hours" again, switch to "Manual adjustment", leave "Date of service" as today, enter "0.5" and a reason, and confirm — Expect: a "Manual adjustment" entry; "Total hours" rises by 0.5
  6. Click "Void" on the manual entry, type a reason under "Reason (required)", click "Void entry" — Expect: a toast " · 0.5 h voided"; the entry stays with a "Voided" tag and your reason; "Total hours" drops by 0.5; "Voided" shows 1
  7. Click "Credit hours", pick the same event again, enter "1" and confirm — Expect: the form shows "That volunteer already holds 1 h for this event; void that entry first."

[Web]

  1. As the citizen, open your profile, then the "Hours" tab — Expect: "Total volunteer hours" rose by 1; under "Service record" the event row reads "credited by CivFix"; no "Adjustment" row for the voided credit
  2. Open notifications — Expect: "Service hours credited" for the event credit and "CivFix credited 0.5 hours to your volunteer record." for the manual one; nothing for the void

[Mobile]

  1. As the citizen, open the "You" tab, then "Hours" — Expect: the same total and "credited by CivFix" row as on web

Regression

Refused credits — [Admin]

  1. Open the official @civfix account (search "civfix"), click "Hours", then "Credit hours", fill it in and confirm — Expect: "You cannot credit hours to the official CivFix account from the console." in the form, and no "Void" buttons on its entries
  2. Click the "Deleted" filter, open any account and click "Hours" — Expect: "Credit hours" is disabled with "Hours can't be credited to a deleted account."

Host view of the event — [Web] [Mobile]

  1. As the event's host, open the event — Expect: the "Volunteer hours" card counts the credited hour; the citizen's row shows their name, or "Credited by CivFix" if they weren't on the attendee list
  2. Tap "Edit" on that card and save without changes — Expect: the citizen's hours stay at 1 and their profile still reads "credited by CivFix"

Transcripts — [Web] [Admin]

  1. As the citizen, on "Hours" tap "Prepare transcript", then "Open PDF" — Expect: the event row is listed
  2. As the operator, void that event entry — Expect: a dialog "Issued transcripts still list this entry" listing the transcript
  3. As the citizen, reload "Hours" — Expect: the row and its hour are gone from the total

Other tabs on the user — [Admin]

  1. Click "Reports", "Events" and "Messages" on the same user — Expect: they load as before

Your data export — [Web]

  1. As the citizen, open Settings, then "Account", then "Request my data" — Expect: the emailed copy lists the hours entries, including the voided one, and none of the operator's reasons

Not covered

  • The 30-per-minute limit on credits and voids isn't practical to hit by hand.
  • The operator audit entries for view, credit and void have no screen in the console yet.
  • The citizen's city leaderboard for the event credit is checkable only if the event's city has other volunteers to rank against.

…in-user-hours

# Conflicts:
#	docs/volunteer-hours-integrity.md
#	services/api/src/services/volunteer-hours-repository.drizzle.ts
#	services/api/src/services/volunteer-hours-repository.memory.ts
#	services/api/src/services/volunteer-hours-rules.ts
#	services/api/src/services/volunteer-hours-service.ts
#	services/api/test/integration/admin-user-hours-pg.test.ts
#	services/api/test/unit/volunteer-hours-operator-ledger.test.ts
@byteful
byteful merged commit 26185d0 into main Sep 30, 2026
3 checks passed
@byteful
byteful deleted the feat/admin-user-hours branch September 30, 2026 03:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant