feat(invite): show toast when invited to workspace

member:added event now includes workspace_name. Frontend shows a toast
notification when the current user is invited. Also clears stale member
list on workspace switch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Naiyuan Qing 2026-03-29 17:42:55 +08:00
parent 4914f1d5dd
commit 8d34e079e8
4 changed files with 11 additions and 4 deletions

View file

@ -96,11 +96,13 @@ export function useRealtimeSync(ws: WSClient | null) {
});
const unsubMemberAdded = ws.on("member:added", (p) => {
const { member } = p as MemberAddedPayload;
const { member, workspace_name } = p as MemberAddedPayload;
const myUserId = useAuthStore.getState().user?.id;
if (member.user_id === myUserId) {
// I was invited to a new workspace — refresh workspace list
useWorkspaceStore.getState().refreshWorkspaces();
toast.info(
`You were invited to ${workspace_name ?? "a workspace"}`,
);
}
});

View file

@ -96,7 +96,7 @@ export const useWorkspaceStore = create<WorkspaceStore>((set, get) => ({
// Clear stale data from other stores before switching
useIssueStore.getState().setIssues([]);
useInboxStore.getState().setItems([]);
set({ agents: [], skills: [] });
set({ members: [], agents: [], skills: [] });
await hydrateWorkspace(workspaces, ws.id);
},

View file

@ -121,6 +121,7 @@ export interface MemberUpdatedPayload {
export interface MemberAddedPayload {
member: MemberWithUser;
workspace_id: string;
workspace_name?: string;
}
export interface MemberRemovedPayload {

View file

@ -389,7 +389,11 @@ func (h *Handler) CreateMember(w http.ResponseWriter, r *http.Request) {
slog.Info("member added", append(logger.RequestAttrs(r), "member_id", uuidToString(member.ID), "workspace_id", workspaceID, "email", email, "role", role)...)
userID := requestUserID(r)
h.publish(protocol.EventMemberAdded, workspaceID, "member", userID, map[string]any{"member": memberWithUserResponse(member, user)})
eventPayload := map[string]any{"member": memberWithUserResponse(member, user)}
if ws, err := h.Queries.GetWorkspace(r.Context(), parseUUID(workspaceID)); err == nil {
eventPayload["workspace_name"] = ws.Name
}
h.publish(protocol.EventMemberAdded, workspaceID, "member", userID, eventPayload)
writeJSON(w, http.StatusCreated, memberWithUserResponse(member, user))
}