diff --git a/apps/web/features/issues/components/issue-detail.tsx b/apps/web/features/issues/components/issue-detail.tsx index e267b8be..a8ae42c3 100644 --- a/apps/web/features/issues/components/issue-detail.tsx +++ b/apps/web/features/issues/components/issue-detail.tsx @@ -275,10 +275,10 @@ export function IssueDetail({ issueId, onDelete }: IssueDetailProps) { if (!issue) return; try { if (currentlySubscribed) { - await api.unsubscribeFromIssue(id, userId); + await api.unsubscribeFromIssue(id, userId, userType); setSubscribers((prev) => prev.filter((s) => !(s.user_id === userId && s.user_type === userType))); } else { - await api.subscribeToIssue(id, userId); + await api.subscribeToIssue(id, userId, userType); setSubscribers((prev) => [ ...prev, { issue_id: id, user_type: userType, user_id: userId, reason: "manual" as const, created_at: new Date().toISOString() }, diff --git a/apps/web/shared/api/client.ts b/apps/web/shared/api/client.ts index 61332e5e..b9b34dc4 100644 --- a/apps/web/shared/api/client.ts +++ b/apps/web/shared/api/client.ts @@ -206,17 +206,23 @@ export class ApiClient { return this.fetch(`/api/issues/${issueId}/subscribers`); } - async subscribeToIssue(issueId: string, userId?: string): Promise { + async subscribeToIssue(issueId: string, userId?: string, userType?: string): Promise { + const body: Record = {}; + if (userId) body.user_id = userId; + if (userType) body.user_type = userType; await this.fetch(`/api/issues/${issueId}/subscribe`, { method: "POST", - body: JSON.stringify(userId ? { user_id: userId } : {}), + body: JSON.stringify(body), }); } - async unsubscribeFromIssue(issueId: string, userId?: string): Promise { + async unsubscribeFromIssue(issueId: string, userId?: string, userType?: string): Promise { + const body: Record = {}; + if (userId) body.user_id = userId; + if (userType) body.user_type = userType; await this.fetch(`/api/issues/${issueId}/unsubscribe`, { method: "POST", - body: JSON.stringify(userId ? { user_id: userId } : {}), + body: JSON.stringify(body), }); } diff --git a/server/internal/handler/subscriber.go b/server/internal/handler/subscriber.go index 56373861..f0904f9f 100644 --- a/server/internal/handler/subscriber.go +++ b/server/internal/handler/subscriber.go @@ -59,10 +59,12 @@ func (h *Handler) SubscribeToIssue(w http.ResponseWriter, r *http.Request) { return } - // Default to current user; allow specifying another user + // Default to current user as member; allow specifying another user/agent targetUserID := requestUserID(r) + targetUserType := "member" var req struct { - UserID *string `json:"user_id"` + UserID *string `json:"user_id"` + UserType *string `json:"user_type"` } if r.Body != nil { json.NewDecoder(r.Body).Decode(&req) @@ -70,10 +72,13 @@ func (h *Handler) SubscribeToIssue(w http.ResponseWriter, r *http.Request) { if req.UserID != nil && *req.UserID != "" { targetUserID = *req.UserID } + if req.UserType != nil && *req.UserType != "" { + targetUserType = *req.UserType + } err := h.Queries.AddIssueSubscriber(r.Context(), db.AddIssueSubscriberParams{ IssueID: issue.ID, - UserType: "member", + UserType: targetUserType, UserID: parseUUID(targetUserID), Reason: "manual", }) @@ -86,7 +91,7 @@ func (h *Handler) SubscribeToIssue(w http.ResponseWriter, r *http.Request) { callerID := requestUserID(r) h.publish(protocol.EventSubscriberAdded, workspaceID, "member", callerID, map[string]any{ "issue_id": issueID, - "user_type": "member", + "user_type": targetUserType, "user_id": targetUserID, "reason": "manual", }) @@ -104,8 +109,10 @@ func (h *Handler) UnsubscribeFromIssue(w http.ResponseWriter, r *http.Request) { } targetUserID := requestUserID(r) + targetUserType := "member" var req struct { - UserID *string `json:"user_id"` + UserID *string `json:"user_id"` + UserType *string `json:"user_type"` } if r.Body != nil { json.NewDecoder(r.Body).Decode(&req) @@ -113,10 +120,13 @@ func (h *Handler) UnsubscribeFromIssue(w http.ResponseWriter, r *http.Request) { if req.UserID != nil && *req.UserID != "" { targetUserID = *req.UserID } + if req.UserType != nil && *req.UserType != "" { + targetUserType = *req.UserType + } err := h.Queries.RemoveIssueSubscriber(r.Context(), db.RemoveIssueSubscriberParams{ IssueID: issue.ID, - UserType: "member", + UserType: targetUserType, UserID: parseUUID(targetUserID), }) if err != nil { @@ -128,7 +138,7 @@ func (h *Handler) UnsubscribeFromIssue(w http.ResponseWriter, r *http.Request) { callerID := requestUserID(r) h.publish(protocol.EventSubscriberRemoved, workspaceID, "member", callerID, map[string]any{ "issue_id": issueID, - "user_type": "member", + "user_type": targetUserType, "user_id": targetUserID, })