diff --git a/internal/dm/handlers.go b/internal/dm/handlers.go index 64e4b21..6bbea73 100644 --- a/internal/dm/handlers.go +++ b/internal/dm/handlers.go @@ -82,10 +82,7 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request) { memberSet[uid] = struct{}{} } } - if len(memberSet) == 1 { - http.Error(w, `{"error":"cannot create conversation with yourself"}`, http.StatusBadRequest) - return - } + // ponytail: allow self-DM (notes to self) — len(memberSet)==1 is fine memberIDs := make([]string, 0, len(memberSet)) for uid := range memberSet { @@ -94,7 +91,24 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request) { sort.Strings(memberIDs) // For a 1:1 DM, check if it already exists. - if len(memberIDs) == 2 { + if len(memberIDs) == 1 { + var existingID string + err := h.db.QueryRowContext(r.Context(), ` + SELECT c.id FROM conversations c + WHERE c.type = 'dm' + AND (SELECT COUNT(*) FROM conversation_members cm WHERE cm.conversation_id = c.id) = 1 + AND EXISTS (SELECT 1 FROM conversation_members cm2 WHERE cm2.conversation_id = c.id AND cm2.user_id = $1) + LIMIT 1 + `, memberIDs[0]).Scan(&existingID) + if err == nil { + h.getByID(w, r, existingID) + return + } + if !errors.Is(err, sql.ErrNoRows) { + http.Error(w, `{"error":"server error"}`, http.StatusInternalServerError) + return + } + } else if len(memberIDs) == 2 { var existingID string err := h.db.QueryRowContext(r.Context(), ` SELECT c.id FROM conversations c diff --git a/web/src/components/ConversationList.tsx b/web/src/components/ConversationList.tsx index 462a920..c137a79 100644 --- a/web/src/components/ConversationList.tsx +++ b/web/src/components/ConversationList.tsx @@ -8,11 +8,16 @@ function otherMemberName(conv: { members: { id: string; username: string }[] }, return other?.username || "unknown"; } +function isSelfDM(conv: { members: { id: string }[] }, currentUserId: string) { + return conv.members.length === 1 && conv.members[0].id === currentUserId; +} + export function ConversationList() { const conversations = useConversationStore((s) => s.conversations); const activeId = useConversationStore((s) => s.activeConversationId); const fetchConversations = useConversationStore((s) => s.fetchConversations); const setActive = useConversationStore((s) => s.setActiveConversation); + const createConversation = useConversationStore((s) => s.createConversation); const currentUser = useAuthStore((s) => s.user); const [showNew, setShowNew] = useState(false); @@ -20,25 +25,48 @@ export function ConversationList() { fetchConversations(); }, [fetchConversations]); + const openNotes = async () => { + // Find existing self-DM or create one + const existing = conversations.find((c) => isSelfDM(c, currentUser?.id || "")); + if (existing) { + setActive(existing.id); + return; + } + try { + await createConversation([]); + } catch { /* ignore */ } + }; + return (
[no conversations]
)} {conversations.map((conv) => { - const name = - conv.type === "group_dm" + const self = isSelfDM(conv, currentUser?.id || ""); + const name = self + ? "Notes" + : conv.type === "group_dm" ? conv.name || conv.members.map((m) => m.username).join(", ") : otherMemberName(conv, currentUser?.id || ""); return ( @@ -51,7 +79,7 @@ export function ConversationList() { : "hover:bg-gb-bg-t text-gb-fg-s" }`} > - @ + {self ? "📝" : "@"} {name} ); diff --git a/web/src/components/DMChat.tsx b/web/src/components/DMChat.tsx index 5fd13f4..441ad8d 100644 --- a/web/src/components/DMChat.tsx +++ b/web/src/components/DMChat.tsx @@ -75,13 +75,16 @@ export function DMChat() { } }; - const title = conversation - ? conversation.type === "group_dm" - ? conversation.name || conversation.members.map((m) => m.username).join(", ") - : conversation.members.find((m) => m.id !== currentUser?.id)?.username || "DM" - : id - ? "[LOADING...]" - : "[NO CONVERSATION]"; + const selfDM = conversation && conversation.members.length === 1 && conversation.members[0].id === currentUser?.id; + const title = selfDM + ? "Notes" + : conversation + ? conversation.type === "group_dm" + ? conversation.name || conversation.members.map((m) => m.username).join(", ") + : conversation.members.find((m) => m.id !== currentUser?.id)?.username || "DM" + : id + ? "[LOADING...]" + : "[NO CONVERSATION]"; return (