cheogram-www

created pr with cheogram-www/multi-dm.1 on 2026-11-10T19:08:58Z · by 9e834e0d
changed pr name to New UI for starting chats with multiDM support on 2026-11-10T19:32:17Z · by 9e834e0d
added cheogram-www/multi-dm.2 on 2026-11-10T19:32:24Z · by 9e834e0d
1: 8f55142 < -: ------- Add UI to create private channel
2: ea160a8 ! 1: e758cfd New UI for starting chats
3: faa9d23 = 2: eb5c50d Special case for group texts
4: 0d9f850 = 3: 2217816 Only enable non-group-text multiDM experimentally
cmds
checkout latest patchset:
ssh pr.pico.sh pull cheogram-www:multi-dm | git am -3
checkout specific patchset revision:
ssh pr.pico.sh pull cheogram-www:multi-dm [rev] | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh cheogram-www:multi-dm
add comment to patch request:
ssh pr.pico.sh comment cheogram-www:multi-dm "lgtm!"
+56 -0 src/components/NewChatDialog.test.tsx #
......@@ -152,6 +152,62 @@ describe("NewChatDialog", () => {
152152 expect(startChat).toHaveBeenCalledWith(alice);
153153 });
154154
155+ it("replaces Cheogram selections when mixing with other counterparts", async () => {
156+ const sms = availableChat("15551234567@cheogram.com", "SMS");
157+ const alice = availableChat("alice@example.com", "Alice");
158+ const { startChat, onStarted, chat } = setup([sms, alice]);
159+
160+ fireEvent.click(await search("example.com", "SMS"));
161+ fireEvent.click(screen.getByText("Alice"));
162+
163+ expect(screen.queryByRole("alert")).toBeNull();
164+
165+ fireEvent.click(screen.getByRole("button", { name: "Start Chat" }));
166+
167+ await waitFor(() => expect(onStarted).toHaveBeenCalledWith(chat));
168+ expect(startChat).toHaveBeenCalledWith(alice);
169+ });
170+
171+ it("starts a group text with a sorted Cheogram target", async () => {
172+ const first = availableChat("789@cheogram.com", "Seven");
173+ const second = availableChat("123@cheogram.com", "One");
174+ const { startMultiChat, onStarted, multiChat } = setup([first, second]);
175+
176+ fireEvent.click(await search("cheogram.com", "Seven"));
177+ fireEvent.click(screen.getByText("One"));
178+
179+ fireEvent.click(screen.getByRole("button", { name: "Start Group Text" }));
180+
181+ await waitFor(() => expect(onStarted).toHaveBeenCalledWith(multiChat));
182+ expect(startMultiChat).toHaveBeenCalledWith(
183+ [first, second],
184+ "123,789@cheogram.com",
185+ );
186+ });
187+
188+ it("deduplicates comma-separated Cheogram targets", async () => {
189+ const first = availableChat("789@cheogram.com", "Seven");
190+ const group = availableChat("123,456@cheogram.com", "Group");
191+ const duplicate = availableChat("456@cheogram.com", "Four");
192+ const { startMultiChat, onStarted, multiChat } = setup([
193+ first,
194+ group,
195+ duplicate,
196+ ]);
197+
198+ fireEvent.click(await search("cheogram.com", "Seven"));
199+ fireEvent.click(screen.getByText("Group"));
200+ fireEvent.click(screen.getByText("Four"));
201+
202+ fireEvent.click(screen.getByRole("button", { name: "Start Group Text" }));
203+
204+ await waitFor(() => expect(onStarted).toHaveBeenCalledWith(multiChat));
205+ expect(startMultiChat).toHaveBeenCalledWith(
206+ [first, group, duplicate],
207+ "123,456,789@cheogram.com",
208+ );
209+ });
210+
155211 it("does not mix channels with other selections", async () => {
156212 const alice = availableChat("alice@example.com", "Alice");
157213 const channel = availableChat("room@example.com", "Room", true);
+37 -4 src/components/NewChatDialog.tsx #
......@@ -20,6 +20,11 @@ import { useDebounce } from "../hooks/use-debounce";
2020
2121 import { findAvailableChats } from "../util";
2222
23+const CHEOGRAM_DOMAIN = "@cheogram.com";
24+
25+const isCheogramChat = (availableChat: borogove.AvailableChat) =>
26+ availableChat.chatId.endsWith(CHEOGRAM_DOMAIN);
27+
2328 export const NewChatDialog = ({
2429 open,
2530 client,
......@@ -111,9 +116,15 @@ export const NewChatDialog = ({
111116 return existing.filter((c) => c.chatId !== availableChat.chatId);
112117 }
113118
114- // A multiDM cannot include a channel, so a channel selection
119+ // A multiDM cannot include a channel, and Cheogram contacts can only be
120+ // grouped with other Cheogram contacts, so an incompatible selection
115121 // replaces any other selections.
116- if (availableChat.isChannel() || existing.some((c) => c.isChannel())) {
122+ if (
123+ availableChat.isChannel() ||
124+ existing.some((c) => c.isChannel()) ||
125+ (existing.length > 0 &&
126+ isCheogramChat(availableChat) !== existing.every(isCheogramChat))
127+ ) {
117128 return [availableChat];
118129 }
119130
......@@ -121,6 +132,22 @@ export const NewChatDialog = ({
121132 });
122133 };
123134
135+ const allCheogram = selected.length > 1 && selected.every(isCheogramChat);
136+ const groupTextTarget = allCheogram
137+ ? [
138+ ...new Set(
139+ selected.flatMap((c) =>
140+ c.chatId
141+ .slice(0, -CHEOGRAM_DOMAIN.length)
142+ .split(",")
143+ .filter((part) => part !== ""),
144+ ),
145+ ),
146+ ]
147+ .sort()
148+ .join(",") + CHEOGRAM_DOMAIN
149+ : null;
150+
124151 const startChat = (event: React.FormEvent<HTMLFormElement>) => {
125152 event.preventDefault();
126153 if (starting || selected.length === 0) return;
......@@ -132,7 +159,9 @@ export const NewChatDialog = ({
132159 const chat =
133160 selected.length === 1
134161 ? client.startChat(selected[0])
135- : client.startMultiChat(selected);
162+ : groupTextTarget
163+ ? client.startMultiChat(selected, groupTextTarget)
164+ : client.startMultiChat(selected);
136165 reset();
137166 onStarted(chat);
138167 } catch (e) {
......@@ -234,7 +263,11 @@ export const NewChatDialog = ({
234263 variant="contained"
235264 disabled={starting || selected.length === 0}
236265 >
237- {starting ? "Starting..." : "Start Chat"}
266+ {starting
267+ ? "Starting..."
268+ : allCheogram
269+ ? "Start Group Text"
270+ : "Start Chat"}
238271 </Button>
239272 </DialogActions>
240273 </form>
Back to top