import { ChecksIcon, CircleNotchIcon, MegaphoneIcon, WarningCircleIcon, } from '@phosphor-icons/react' import classNames from 'classnames' import { MessageStatus, useChannelStateContext, useMessageContext, } from 'stream-chat-react' import type { OutboundClickHandler, ResolvedOutbound } from '../../types' import { hasPaidDeliveryTag } from './MessageTag' import { isTipMessage } from './TipMessage' /** * Message status stamps for sending and terminal `MessageStatus` states * (sent / delivered / read), plus failed messages. * * Two reasons this is more than a static label: * * 1. `MessageStatus` picks its `delivered`/`read` branches ahead of `sent` * whenever Stream has `deliveredTo`/`readBy`, and — unlike `sent` — those * branches aren't gated to the last message. So we override all three * terminal slots with this same label (never Stream's default delivered * icon / read avatars — Read is out of scope) and re-apply the "latest * message in the thread" gate ourselves. * * 2. We derive "latest message" from **live channel state**, not the message * context's `lastOwnMessage`/`lastReceivedId`. Stream's `Message` is * memoised by `areMessagePropsEqual`, which does not compare those props; * a previous own row whose message/grouping props are unchanged (e.g. * after an intervening incoming message) never re-renders, so the old * bubble would keep showing "Delivered" beside the new one. * `useChannelStateContext` gets a fresh `messages` array on every new * message and, being a context, re-renders this leaf straight through the * stale `Message`/`MessageStatus` memos — so the label reliably clears * once a reply lands. We still skip non-participant rows (`system`, * `ephemeral`, `deleted`) when finding the last real message so a trailing * system event does not clear the label. * * Rendered inside stream's `.str-chat__message-status` span, which supplies * the flex layout; icon and copy are styled via that span in `styles.css`. */ const useIsLatestRealMessage = () => { const { message } = useMessageContext('SentMessageDeliveryStatus') const { messages } = useChannelStateContext('SentMessageDeliveryStatus') const lastMessageId = (() => { if (!messages) { return undefined } for (let index = messages.length - 1; index >= 0; index -= 1) { const lastMessage = messages[index] if ( lastMessage.type === 'system' || lastMessage.type === 'ephemeral' || lastMessage.type === 'deleted' ) { continue } return lastMessage.id } return undefined })() return message.id === lastMessageId } const DeliveredStatus = () => { if (!useIsLatestRealMessage()) return null return ( <>