Add RSVP support and Open Graph meta tags

People can now RSVP without claiming a slot. OG tags show
event title, date/time/location, and headcount in link previews.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-15 10:18:36 -04:00
parent 2b08f81c8d
commit d51e7fe867
9 changed files with 238 additions and 5 deletions
+8
View File
@@ -27,6 +27,14 @@ type Event struct {
CreatedAt time.Time
}
type Rsvp struct {
ID int64
EventID int64
Name string
Note string
CreatedAt time.Time
}
type Slot struct {
ID int64
EventID int64
+14
View File
@@ -51,3 +51,17 @@ DELETE FROM claims WHERE id = ?;
-- name: CountClaimsBySlot :one
SELECT COUNT(*) FROM claims WHERE slot_id = ?;
-- name: ListRsvps :many
SELECT * FROM rsvps WHERE event_id = ? ORDER BY created_at;
-- name: CreateRsvp :one
INSERT INTO rsvps (event_id, name, note)
VALUES (?, ?, ?)
RETURNING *;
-- name: DeleteRsvp :exec
DELETE FROM rsvps WHERE id = ?;
-- name: CountRsvps :one
SELECT COUNT(*) FROM rsvps WHERE event_id = ?;
+78
View File
@@ -20,6 +20,17 @@ func (q *Queries) CountClaimsBySlot(ctx context.Context, slotID int64) (int64, e
return count, err
}
const countRsvps = `-- name: CountRsvps :one
SELECT COUNT(*) FROM rsvps WHERE event_id = ?
`
func (q *Queries) CountRsvps(ctx context.Context, eventID int64) (int64, error) {
row := q.db.QueryRowContext(ctx, countRsvps, eventID)
var count int64
err := row.Scan(&count)
return count, err
}
const createClaim = `-- name: CreateClaim :one
INSERT INTO claims (slot_id, name, note)
VALUES (?, ?, ?)
@@ -83,6 +94,31 @@ func (q *Queries) CreateEvent(ctx context.Context, arg CreateEventParams) (Event
return i, err
}
const createRsvp = `-- name: CreateRsvp :one
INSERT INTO rsvps (event_id, name, note)
VALUES (?, ?, ?)
RETURNING id, event_id, name, note, created_at
`
type CreateRsvpParams struct {
EventID int64
Name string
Note string
}
func (q *Queries) CreateRsvp(ctx context.Context, arg CreateRsvpParams) (Rsvp, error) {
row := q.db.QueryRowContext(ctx, createRsvp, arg.EventID, arg.Name, arg.Note)
var i Rsvp
err := row.Scan(
&i.ID,
&i.EventID,
&i.Name,
&i.Note,
&i.CreatedAt,
)
return i, err
}
const createSlot = `-- name: CreateSlot :one
INSERT INTO slots (event_id, name, emoji, max_claims, sort_order)
VALUES (?, ?, ?, ?, ?)
@@ -135,6 +171,15 @@ func (q *Queries) DeleteEvent(ctx context.Context, id int64) error {
return err
}
const deleteRsvp = `-- name: DeleteRsvp :exec
DELETE FROM rsvps WHERE id = ?
`
func (q *Queries) DeleteRsvp(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, deleteRsvp, id)
return err
}
const deleteSlot = `-- name: DeleteSlot :exec
DELETE FROM slots WHERE id = ?
`
@@ -271,6 +316,39 @@ func (q *Queries) ListClaimsBySlot(ctx context.Context, slotID int64) ([]Claim,
return items, nil
}
const listRsvps = `-- name: ListRsvps :many
SELECT id, event_id, name, note, created_at FROM rsvps WHERE event_id = ? ORDER BY created_at
`
func (q *Queries) ListRsvps(ctx context.Context, eventID int64) ([]Rsvp, error) {
rows, err := q.db.QueryContext(ctx, listRsvps, eventID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Rsvp
for rows.Next() {
var i Rsvp
if err := rows.Scan(
&i.ID,
&i.EventID,
&i.Name,
&i.Note,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listSlots = `-- name: ListSlots :many
SELECT id, event_id, name, emoji, max_claims, sort_order FROM slots WHERE event_id = ? ORDER BY sort_order, id
`