From 0f382ed88592b8c4c2f75d9295b2ecac5df59af6 Mon Sep 17 00:00:00 2001 From: gosangam Date: Sat, 29 Aug 2026 18:56:45 +0530 Subject: [PATCH] fix: no attachment broadcast fix --- components/chat/message-group.tsx | 2 +- components/notifications/broadcast-modal.tsx | 4 +++- lib/broadcasts.ts | 10 ++++++++-- lib/chat-format.ts | 7 ++++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/components/chat/message-group.tsx b/components/chat/message-group.tsx index 6a308819..6d4dce3b 100644 --- a/components/chat/message-group.tsx +++ b/components/chat/message-group.tsx @@ -190,7 +190,7 @@ export function MessageGroup({ {/* An optimistic bubble for a captionless attachment has nothing to draw until the server answers — say so rather than render an empty box. */} - {m.pending && !m.body && m.attachments.length === 0 && ( + {m.pending && !m.body && !m.attachments?.length && ( Sending attachment… diff --git a/components/notifications/broadcast-modal.tsx b/components/notifications/broadcast-modal.tsx index b1662a25..1d8441e0 100644 --- a/components/notifications/broadcast-modal.tsx +++ b/components/notifications/broadcast-modal.tsx @@ -60,7 +60,9 @@ export function BroadcastModal() { } }, [item, dismissing]); - if (!item) return null; + // Guard on the shape, not just presence: a malformed payload must not put + // an empty modal over every page in the app. + if (!item?.id || !item.title) return null; return ( (path: string, init?: RequestInit): Promise { }); if (!res.ok) throw new Error(`broadcast request failed: ${res.status}`); if (res.status === 204) return undefined as T; - const json = await res.json(); - return (json?.data ?? json) as T; + const body = (await res.json().catch(() => ({}))) as { + data?: T; + success?: boolean; + }; + // NOT `body.data ?? body`: /pending answers {data: null} when nothing is + // waiting, and `??` would fall through and hand back the whole envelope — + // which is truthy, so the modal would try to render it as an announcement. + return (body.data ?? (null as unknown as T)) as T; } export type Broadcast = { diff --git a/lib/chat-format.ts b/lib/chat-format.ts index 120839b6..86555414 100644 --- a/lib/chat-format.ts +++ b/lib/chat-format.ts @@ -29,10 +29,15 @@ export function buildEntityTree( body: string, entities: MessageEntity[], ): EntityNode[] { + // Defensive on both inputs: this renders content from the network, and a + // missing body should show nothing rather than take down the screen it is + // on. The broadcast modal renders through here too, and it mounts on every + // page — so a crash here is not confined to chat. + const text = body ?? ""; const sorted = [...(entities ?? [])].sort( (a, b) => a.offset - b.offset || b.length - a.length, ); - return build(body, 0, body.length, sorted); + return build(text, 0, text.length, sorted); } function build(