Refactored volunteer check_in as ready status.

This commit is contained in:
Pen Anderson 2026-03-05 17:34:50 -06:00
parent e722ef055e
commit 40ebaf07bf
7 changed files with 48 additions and 28 deletions

46
db.go
View file

@ -93,8 +93,8 @@ func migrate(db *sql.DB) error {
phone TEXT NOT NULL DEFAULT '',
department_id INTEGER REFERENCES departments(id) ON DELETE SET NULL,
is_lead INTEGER NOT NULL DEFAULT 0,
checked_in INTEGER NOT NULL DEFAULT 0,
checked_in_at TEXT,
ready INTEGER NOT NULL DEFAULT 0,
ready_at TEXT,
note TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
@ -177,6 +177,8 @@ func migrateV2(db *sql.DB) error {
addColumnIfMissing(db, "volunteers", "confirmed INTEGER NOT NULL DEFAULT 0")
addColumnIfMissing(db, "volunteers", "confirmed_at TEXT")
addColumnIfMissing(db, "volunteers", "kiosk_code TEXT")
renameColumnIfExists(db, "volunteers", "checked_in", "ready")
renameColumnIfExists(db, "volunteers", "checked_in_at", "ready_at")
db.Exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_volunteers_kiosk_code ON volunteers(kiosk_code) WHERE kiosk_code IS NOT NULL`)
// Migrate kiosk codes from tickets to volunteers (idempotent).
db.Exec(`
@ -340,6 +342,24 @@ func addColumnIfMissing(db *sql.DB, table, colDef string) {
db.Exec(`ALTER TABLE "` + table + `" ADD COLUMN ` + colDef)
}
func renameColumnIfExists(db *sql.DB, table, oldName, newName string) {
rows, err := db.Query(`PRAGMA table_info("` + table + `")`)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
var cid, notNull, pk int
var name, typ string
var dflt sql.NullString
rows.Scan(&cid, &name, &typ, &notNull, &dflt, &pk)
if name == oldName {
db.Exec(`ALTER TABLE "` + table + `" RENAME COLUMN "` + oldName + `" TO "` + newName + `"`)
return
}
}
}
// --- Types ---
const attendeeCols = `id, name, email, phone, ticket_id, ticket_type, volunteer_token,
@ -407,8 +427,8 @@ type Volunteer struct {
Pronouns string `json:"pronouns"`
DepartmentID *int `json:"department_id,omitempty"`
IsLead bool `json:"is_lead"`
CheckedIn bool `json:"checked_in"`
CheckedInAt *string `json:"checked_in_at,omitempty"`
Ready bool `json:"ready"`
ReadyAt *string `json:"ready_at,omitempty"`
Confirmed bool `json:"confirmed"`
ConfirmedAt *string `json:"confirmed_at,omitempty"`
EmailConfirmed bool `json:"email_confirmed"`
@ -1203,14 +1223,14 @@ const volunteerSelect = `v.id, v.participant_id, v.attendee_id,
COALESCE(NULLIF(p.email,''), v.email),
COALESCE(NULLIF(p.phone,''), v.phone),
COALESCE(NULLIF(p.pronouns,''), v.pronouns),
v.department_id, v.is_lead, v.checked_in, v.checked_in_at,
v.department_id, v.is_lead, v.ready, v.ready_at,
v.confirmed, v.confirmed_at,
v.email_confirmed, v.confirmation_token, v.kiosk_code, v.note,
v.created_at, v.updated_at, v.deleted_at`
const volunteerFrom = `FROM volunteers v LEFT JOIN participants p ON p.id = v.participant_id`
// volunteerCols is kept for backward-compat references that expect unqualified column names.
const volunteerCols = `id, attendee_id, name, preferred_name, email, phone, pronouns, department_id, is_lead, checked_in, checked_in_at, email_confirmed, confirmation_token, note, created_at, updated_at, deleted_at`
const volunteerCols = `id, attendee_id, name, preferred_name, email, phone, pronouns, department_id, is_lead, ready, ready_at, email_confirmed, confirmation_token, note, created_at, updated_at, deleted_at`
func (app *App) listVolunteers(search string, deptID *int, since string) ([]Volunteer, error) {
q := `SELECT ` + volunteerSelect + ` ` + volunteerFrom + ` WHERE 1=1`
@ -1292,13 +1312,13 @@ func (app *App) deleteVolunteer(id int) error {
return err
}
// checkInVolunteer marks the volunteer as checked in and, if linked to an attendee,
// markVolunteerReady marks the volunteer as ready and, if linked to an attendee,
// also increments the attendee's checked_in_count.
func (app *App) checkInVolunteer(id, userID int) (*Volunteer, error) {
func (app *App) markVolunteerReady(id, userID int) (*Volunteer, error) {
t := now()
_, err := app.db.Exec(
`UPDATE volunteers SET checked_in=1, checked_in_at=?, updated_at=?
WHERE id=? AND deleted_at IS NULL AND checked_in=0`,
`UPDATE volunteers SET ready=1, ready_at=?, updated_at=?
WHERE id=? AND deleted_at IS NULL AND ready=0`,
t, t, id,
)
if err != nil {
@ -1337,12 +1357,12 @@ func queryVolunteers(db *sql.DB, q string, args ...any) ([]Volunteer, error) {
for rows.Next() {
var v Volunteer
var participantID, attendeeID, deptID sql.NullInt64
var isLead, checkedIn, confirmed, emailConfirmed int
var isLead, ready, confirmed, emailConfirmed int
var confirmationToken, confirmedAt, kioskCode sql.NullString
if err := rows.Scan(
&v.ID, &participantID, &attendeeID, &v.Name, &v.PreferredName,
&v.Email, &v.Phone, &v.Pronouns, &deptID,
&isLead, &checkedIn, &v.CheckedInAt,
&isLead, &ready, &v.ReadyAt,
&confirmed, &confirmedAt,
&emailConfirmed, &confirmationToken, &kioskCode, &v.Note,
&v.CreatedAt, &v.UpdatedAt, &v.DeletedAt,
@ -1371,7 +1391,7 @@ func queryVolunteers(db *sql.DB, q string, args ...any) ([]Volunteer, error) {
v.KioskCode = &kioskCode.String
}
v.IsLead = isLead == 1
v.CheckedIn = checkedIn == 1
v.Ready = ready == 1
v.Confirmed = confirmed == 1
v.EmailConfirmed = emailConfirmed == 1
result = append(result, v)