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:
+65
@@ -96,6 +96,7 @@ type SlotView struct {
|
||||
type EventPageData struct {
|
||||
Event db.Event
|
||||
Slots []SlotView
|
||||
Rsvps []db.Rsvp
|
||||
TotalGoing int64
|
||||
IsAdmin bool
|
||||
}
|
||||
@@ -143,9 +144,16 @@ func (s *Server) loadEventPage(r *http.Request, slug string, isAdmin bool) (*Eve
|
||||
})
|
||||
}
|
||||
|
||||
rsvps, err := s.q.ListRsvps(r.Context(), event.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalGoing += int64(len(rsvps))
|
||||
|
||||
return &EventPageData{
|
||||
Event: event,
|
||||
Slots: slotViews,
|
||||
Rsvps: rsvps,
|
||||
TotalGoing: totalGoing,
|
||||
IsAdmin: isAdmin,
|
||||
}, nil
|
||||
@@ -262,6 +270,63 @@ func (s *Server) handleUnclaim(w http.ResponseWriter, r *http.Request) {
|
||||
pageTmpl["slots"].ExecuteTemplate(w, "slots-inner", data)
|
||||
}
|
||||
|
||||
// --- RSVP ---
|
||||
|
||||
func (s *Server) handleRsvp(w http.ResponseWriter, r *http.Request) {
|
||||
slug := chi.URLParam(r, "slug")
|
||||
r.ParseForm()
|
||||
|
||||
name := strings.TrimSpace(r.FormValue("name"))
|
||||
if name == "" {
|
||||
http.Error(w, "Name is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
note := strings.TrimSpace(r.FormValue("note"))
|
||||
|
||||
event, err := s.q.GetEventBySlug(r.Context(), slug)
|
||||
if err != nil {
|
||||
http.Error(w, "Event not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.q.CreateRsvp(r.Context(), db.CreateRsvpParams{
|
||||
EventID: event.ID, Name: name, Note: note,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("create rsvp: %v", err)
|
||||
http.Error(w, "Failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
s.notify(slug)
|
||||
|
||||
data, err := s.loadEventPage(r, slug, false)
|
||||
if err != nil {
|
||||
http.Error(w, "error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
pageTmpl["slots"].ExecuteTemplate(w, "slots-inner", data)
|
||||
}
|
||||
|
||||
func (s *Server) handleUnrsvp(w http.ResponseWriter, r *http.Request) {
|
||||
slug := chi.URLParam(r, "slug")
|
||||
rsvpID, err := strconv.ParseInt(chi.URLParam(r, "rsvpID"), 10, 64)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid RSVP", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
s.q.DeleteRsvp(r.Context(), rsvpID)
|
||||
s.notify(slug)
|
||||
|
||||
data, err := s.loadEventPage(r, slug, false)
|
||||
if err != nil {
|
||||
http.Error(w, "error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
pageTmpl["slots"].ExecuteTemplate(w, "slots-inner", data)
|
||||
}
|
||||
|
||||
// --- SSE ---
|
||||
|
||||
func (s *Server) handleSSE(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user