add invite to space feature

This commit is contained in:
juancwu 2026-01-14 21:11:16 +00:00
commit 4d6e6799a0
10 changed files with 407 additions and 8 deletions

View file

@ -20,14 +20,16 @@ type SpaceHandler struct {
tagService *service.TagService
listService *service.ShoppingListService
expenseService *service.ExpenseService
inviteService *service.InviteService
}
func NewSpaceHandler(ss *service.SpaceService, ts *service.TagService, sls *service.ShoppingListService, es *service.ExpenseService) *SpaceHandler {
func NewSpaceHandler(ss *service.SpaceService, ts *service.TagService, sls *service.ShoppingListService, es *service.ExpenseService, is *service.InviteService) *SpaceHandler {
return &SpaceHandler{
spaceService: ss,
tagService: ts,
listService: sls,
expenseService: es,
inviteService: is,
}
}
@ -353,3 +355,57 @@ func (h *SpaceHandler) CreateExpense(w http.ResponseWriter, r *http.Request) {
ui.Render(w, r, pages.ExpenseCreatedResponse(newExpense, balance))
}
func (h *SpaceHandler) CreateInvite(w http.ResponseWriter, r *http.Request) {
spaceID := r.PathValue("spaceID")
user := ctxkeys.User(r.Context())
if err := r.ParseForm(); err != nil {
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
email := r.FormValue("email")
if email == "" {
http.Error(w, "Email is required", http.StatusBadRequest)
return
}
_, err := h.inviteService.CreateInvite(spaceID, user.ID, email)
if err != nil {
slog.Error("failed to create invite", "error", err, "space_id", spaceID)
http.Error(w, "Failed to create invite", http.StatusInternalServerError)
return
}
// TODO: Return a nice UI response (toast or list update)
w.Write([]byte("Invitation sent!"))
}
func (h *SpaceHandler) JoinSpace(w http.ResponseWriter, r *http.Request) {
token := r.PathValue("token")
user := ctxkeys.User(r.Context())
if user != nil {
spaceID, err := h.inviteService.AcceptInvite(token, user.ID)
if err != nil {
slog.Error("failed to accept invite", "error", err, "token", token)
http.Error(w, "Failed to join space: "+err.Error(), http.StatusBadRequest)
return
}
http.Redirect(w, r, "/app/spaces/"+spaceID, http.StatusSeeOther)
return
}
// Not logged in: set cookie and redirect to auth
http.SetCookie(w, &http.Cookie{
Name: "pending_invite",
Value: token,
Path: "/",
Expires: time.Now().Add(1 * time.Hour),
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
})
http.Redirect(w, r, "/auth?invite=true", http.StatusTemporaryRedirect)
}