Skip to content

feat(chat): group DMs behind group_messages flag - #14749

Merged
dylanjeffers merged 4 commits into
mainfrom
feat/group-dms
Nov 11, 2026
Merged

dylanjeffers merged 4 commits into
mainfrom
feat/group-dms

Conversation

@dylanjeffers

Copy link
Copy Markdown
Contributor

Summary

Group DMs on web and mobile, behind a new group_messages flag (on in dev, off in prod). The flag only gates creating groups; a group someone else made always renders correctly. Backend: AudiusProject/api#1067. Push copy: AudiusProject/pedalboard#109.

Changes

SDK (changeset: minor)

  • chats.create with more than one invitee makes a group with a grp_<ulid> id (optional chatId param). 1:1 ids are unchanged.
  • New chats.leave({ chatId }) → chat.leave RPC.
  • UserChat.is_group, plus the makeGroupChatId / isGroupChatId helpers.

Common

  • FeatureFlags.GROUP_MESSAGES.
  • createChat({ userIds }) with 2+ users creates a group, or reuses an already-loaded group with exactly the same members. On failure it backs out of the optimistic navigation and shows a group-specific toast.
  • leaveChat({ chatId }) saga.
  • useCanSendMessage always allows sending in groups. useCanCreateChat and getUserList ignore group chats, so sharing a group never counts as an existing 1:1.
  • New helpers: useIsGroupChat, formatGroupChatTitle ("Ann, Bo & 2 others"), isFirstInSenderRun, and MAX_GROUP_CHAT_MEMBERS (10, matches the api).

Web

  • New Message modal: when the flag is on, each user gets a checkbox; users you can't message can't be selected. Once anything is selected, clicking a row toggles it, and the footer becomes "Start Chat" (1 selected) or "Start Group Chat (n)".
  • Group inbox row and header: stacked avatars, member names, "N members".
  • Header menu: View Members, Priority/General, Delete Conversation, Leave Group. Clicking the title opens the members list.
  • In groups, others' messages show the sender's name at the start of a run and their avatar on the last message of a run. Messages from users you've blocked are hidden.

Mobile: the same set.

  • Select circles in the new-message screen, with a sticky "Start chat" / "Start group chat (n)" button.
  • Group inbox row and header.
  • Members screen (ChatMembers route).
  • Group variant of the actions drawer, with a Leave Group confirm drawer.
  • Sender name and avatar on group messages; blocked senders hidden.

Test plan

  • packages/common: vitest run src/store/pages/chat src/utils src/hooks/chats → 106 passed. New saga tests cover a new group id, reusing a group with the same members, the 1:1 id staying deterministic, and leave.
  • packages/web: tsc --noEmit, eslint on changed files, chat-page vitest (9 passed).
  • packages/mobile: tsc --noEmit, eslint on changed files.
  • Web, local stack (api#1067 running on localhost against a seeded local Postgres; web dev server with VITE_API_URL=http://localhost:1323; four local-only test wallets, nothing on prod):
    • Ann selected Bo and Cy. Di, whose inbox is closed, showed "Cannot Be Messaged" and couldn't be checked.
    • "Start Group Chat (2)" created grp_… and opened a header reading "Local Cy & Local Bo · 3 members".
    • Bo and Cy each decrypted Ann's message, with sender name, avatar and unread badge. Bo replied, and Cy saw both senders attributed.
    • View Members listed all three.
    • After Cy blocked Bo, Bo's message was hidden for Cy.
    • Cy left via Leave Group: the chat was removed and the "You left the group" toast showed. Ann then saw "Local Bo · 2 members".
    • 1:1 regression: Ann → Bo from Bo's profile opened the deterministic a:b chat, not the group, and sent normally.
  • Mobile on a simulator: not run yet. It needs a build pointed at a local api; sims are signed in to prod accounts, so test with local accounts only.
  • With the flag off, confirm the new-message flows look exactly as before (no checkboxes).

Rollout

Merge api#1067 first. Keep group_messages off in prod until mobile has been checked on a device.

Not in this PR

  • Group names.
  • Adding members: the SDK has chats.invite, but the api has no chat.invite handler.
  • A "X left the group" system message.

🤖 Generated with Claude Code

@changeset-bot

changeset-bot Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6ea2727

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@audius/sdk Minor
@audius/sdk-legacy Patch
@audius/protocol-dashboard Patch
@audius/sp-actions Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

dylanjeffers and others added 4 commits November 11, 2026 13:31
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New-message modal multi-select, group inbox rows and header, member list,
leave group, and sender name/avatar on group messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Multi-select in the new-message screen, group inbox rows and header,
members screen, leave group drawer, and sender name/avatar on group
messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dylanjeffers
dylanjeffers merged commit 277b3b5 into main Nov 11, 2026
33 checks passed
@dylanjeffers
dylanjeffers deleted the feat/group-dms branch November 11, 2026 21:43
dylanjeffers added a commit that referenced this pull request Nov 13, 2026
Since #14749 (group DMs), a message that is only a track or playlist
link renders as a narrow card showing just the artwork and repost count,
in 1:1 chats too. Messages with text plus a link look fine because the
text sets the bubble's width. Prod predates #14749, so it only shows on
RC.

**Cause:** #14749 wrapped every bubble in a `Flex` row so the group
sender's avatar can sit beside it. That row is a shrink-to-fit flex item
of the message column, so the link-only bubble's `width: min(448px,
100%)` resolves against the row's content width instead of the list.

**Fix:** the row is now `w='100%'`, justified `flex-end` for your own
messages and `flex-start` for others. Text bubbles keep their content
width (`max-width` is unchanged).

**Checked:** in a static reproduction of the bubble CSS, the current
layout gives the link-only bubble 354px (and less with the real unfurl
contents), and the fix restores 448px, matching the pre-#14749 layout.
Author bubbles stay right-aligned and a text-only bubble keeps its 172px
content width. Not yet checked in the running app: please look at a
link-only message on RC after merge.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant