// SPDX-License-Identifier: AGPL-3.0-or-later import Authentication from '@app/features/auth/state/Authentication'; import {useCollapsedMessageVisibility} from '@app/features/channel/components/CollapsedMessageVisibilityContext'; import {PreloadableUserPopout} from '@app/features/channel/components/PreloadableUserPopout'; import GuildMembers from '@app/features/member/state/GuildMembers'; import {SafeMarkdown} from '@app/features/messaging/components/markdown'; import {MarkdownContext} from '@app/features/messaging/components/markdown/renderers/RendererTypes'; import type {Message} from '@app/features/messaging/models/MessagingMessage'; import MessageReferences, {MessageReferenceState} from '@app/features/messaging/state/MessageReferences'; import {goToMessage} from '@app/features/messaging/utils/MessageNavigator'; import LocalUserSpamOverride from '@app/features/moderation/state/LocalUserSpamOverride'; import markupStyles from '@app/features/theme/styles/Markup.module.css'; import styles from '@app/features/theme/styles/Message.module.css'; import {Avatar} from '@app/features/ui/components/Avatar'; import FocusRing from '@app/features/ui/focus_ring/FocusRing'; import * as NicknameUtils from '@app/features/user/utils/NicknameUtils'; import {msg} from '@lingui/core/macro'; import {useLingui} from '@lingui/react/macro'; import {ArrowBendUpLeftIcon} from '@phosphor-icons/react'; import {clsx} from 'clsx'; import {observer} from 'mobx-react-lite'; import {type CSSProperties, useCallback} from 'react'; const ORIGINAL_MESSAGE_WAS_DELETED_DESCRIPTOR = msg({ message: 'Original message was deleted', comment: 'Label in the channel and chat reply preview. Keep the tone plain and specific.', }); const ORIGINAL_MESSAGE_FAILED_TO_LOAD_DESCRIPTOR = msg({ message: 'Original message failed to load', comment: 'Error message in the channel and chat reply preview.', }); const REPLY_HIDDEN_BECAUSE_THE_ORIGINAL_AUTHOR_IS_BLOCKED_DESCRIPTOR = msg({ message: 'Reply hidden because the original author is blocked.', comment: 'Error message in the channel and chat reply preview. Keep the tone plain and specific.', }); const REPLY_HIDDEN_BECAUSE_THE_ORIGINAL_AUTHOR_IS_MARKED_DESCRIPTOR = msg({ message: 'Reply hidden because the original author is marked as a spammer.', comment: 'Description text in the channel and chat reply preview. Keep the tone plain and specific.', }); const MESSAGE_CONTAINS_ATTACHED_MEDIA_DESCRIPTOR = msg({ message: 'Message contains attached media', comment: 'Label in the channel and chat reply preview.', }); export const ReplyPreview = observer( ({ message, channelId, guildId, messageDisplayCompact, }: { message: Message; channelId: string; guildId?: string; messageDisplayCompact: boolean; }) => { const {i18n} = useLingui(); const resolution = MessageReferences.getMessageReference( message.messageReference?.channel_id ?? '', message.messageReference?.message_id ?? '', ); const {isMessageRevealed} = useCollapsedMessageVisibility(); const resolvedGuildId = guildId ?? message.guildId ?? message.messageReference?.guild_id; const referenceChannelId = message.messageReference?.channel_id ?? message.channelId; const jumpToRepliedMessage = useCallback(() => { if (message.messageReference?.message_id) { goToMessage(referenceChannelId, message.messageReference.message_id, { returnToMessageId: message.id, returnChannelId: message.channelId, }); } }, [referenceChannelId, message.channelId, message.id, message.messageReference]); if (!message.messageReference) return null; if (resolution.state !== MessageReferenceState.LOADED) { const isDeleted = resolution.state === MessageReferenceState.DELETED; return (