feat: right-click context menus for channels, groups, and servers
ContextMenu: reusable hook-based component that positions a menu at
the cursor and auto-closes on outside click or Escape.
ChannelList:
- Right-click channel -> Edit Name, Permissions, Delete Channel
- Right-click group header -> Edit Name, Create Channel Here, Delete Group
- Inline rename: replacing name text with an input, commits on Enter/blur
- CreateChannelModal now accepts defaultGroupId to pre-select a group
ServerBar:
- Right-click server icon -> Server Settings, Invite People, Leave Server
- Leave calls DELETE /servers/{id}/members/me
Backend:
- Added LeaveServer handler (DELETE /servers/{serverID}/members/me)
- Server owner cannot leave; must transfer or delete
This commit is contained in:
@@ -24,6 +24,7 @@ func (h *Handler) RegisterRoutes(r chi.Router) {
|
||||
r.Get("/{serverID}", h.Get)
|
||||
r.Patch("/{serverID}", h.Update)
|
||||
r.Delete("/{serverID}", h.Delete)
|
||||
r.Delete("/{serverID}/members/me", h.LeaveServer)
|
||||
}
|
||||
|
||||
type createServerRequest struct {
|
||||
@@ -315,3 +316,38 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (h *Handler) LeaveServer(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.UserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
serverID := chi.URLParam(r, "serverID")
|
||||
|
||||
// Cannot leave a server you own
|
||||
var ownerID string
|
||||
err := h.db.QueryRowContext(r.Context(), `SELECT owner_id FROM servers WHERE id = $1`, serverID).Scan(&ownerID)
|
||||
if err != nil {
|
||||
http.Error(w, `{"error":"server not found"}`, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if ownerID == userID {
|
||||
http.Error(w, `{"error":"server owner cannot leave; transfer ownership or delete the server"}`, http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.db.ExecContext(r.Context(), `DELETE FROM members WHERE user_id = $1 AND server_id = $2`, userID, serverID)
|
||||
if err != nil {
|
||||
http.Error(w, `{"error":"failed to leave server"}`, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
rows, _ := result.RowsAffected()
|
||||
if rows == 0 {
|
||||
http.Error(w, `{"error":"not a member"}`, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user