/* * Wire * Copyright (C) 2018 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * */ import {FC, Fragment, MouseEvent as ReactMouseEvent, useEffect, useState} from 'react'; import {QualifiedId} from '@wireapp/api-client/lib/user'; import {amplify} from 'amplify'; import cx from 'classnames'; import {WebAppEvents} from '@wireapp/webapp-events'; import * as Icon from 'Components/Icon'; import {AssetImage} from 'Components/Image'; import {Text} from 'src/script/entity/message/Text'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {includesOnlyEmojis} from 'Util/EmojiUtil'; import {t} from 'Util/LocalizerUtil'; import {formatDateNumeral, formatTimeShort, isBeforeToday} from 'Util/TimeUtil'; import {AudioAsset} from './asset/AudioAsset'; import {FileAsset} from './asset/FileAssetComponent'; import {LocationAsset} from './asset/LocationAsset'; import {TextMessageRenderer} from './asset/TextMessageRenderer'; import {VideoAsset} from './asset/VideoAsset'; import {MessageActions} from '..'; import type {Conversation} from '../../../../entity/Conversation'; import {ContentMessage} from '../../../../entity/message/ContentMessage'; import {User} from '../../../../entity/User'; import {ConversationError} from '../../../../error/ConversationError'; import {QuoteEntity} from '../../../../message/QuoteEntity'; import {useMessageFocusedTabIndex} from '../util'; function createPlaceholderMessage() { const message = new ContentMessage(); const user = new User(); user.name(' '); message.user(user); const textAsset = new Text('fake-text', ' '); message.assets.push(textAsset); return message; } export interface QuoteProps { conversation: Conversation; findMessage: (conversation: Conversation, messageId: string) => Promise; focusMessage: (id: string) => void; handleClickOnMessage: MessageActions['onClickMessage']; quote: QuoteEntity; selfId: QualifiedId; showDetail: (message: ContentMessage, event: ReactMouseEvent) => void; showUserDetails: (user: User) => void; isMessageFocused: boolean; } export const Quote: FC = ({ conversation, findMessage, focusMessage, handleClickOnMessage, quote, selfId, showDetail, showUserDetails, isMessageFocused, }) => { const [quotedMessage, setQuotedMessage] = useState(); const [error, setError] = useState(quote.error); useEffect(() => { const handleQuoteDeleted = (messageId: string) => { if (quotedMessage?.id === messageId) { setError(QuoteEntity.ERROR.MESSAGE_NOT_FOUND); setQuotedMessage(undefined); } }; const handleQuoteUpdated = (originalMessageId: string, messageEntity: ContentMessage) => { if (quotedMessage?.id === originalMessageId) { setQuotedMessage(messageEntity); } }; amplify.subscribe(WebAppEvents.CONVERSATION.MESSAGE.REMOVED, handleQuoteDeleted); amplify.subscribe(WebAppEvents.CONVERSATION.MESSAGE.UPDATED, handleQuoteUpdated); return () => { amplify.unsubscribe(WebAppEvents.CONVERSATION.MESSAGE.REMOVED, handleQuoteDeleted); amplify.unsubscribe(WebAppEvents.CONVERSATION.MESSAGE.UPDATED, handleQuoteUpdated); }; }, [quotedMessage]); useEffect(() => { if (!error && quote.messageId) { findMessage(conversation, quote.messageId) .then(message => { setQuotedMessage(message as ContentMessage); }) .catch(error => { if (error.type === ConversationError.TYPE.MESSAGE_NOT_FOUND) { return setError(QuoteEntity.ERROR.MESSAGE_NOT_FOUND); } throw error; }); } }, [quote, error]); return (
{error ? (
{t('replyQuoteError')}
) : ( )}
); }; interface QuotedMessageProps { focusMessage: (id: string) => void; handleClickOnMessage: MessageActions['onClickMessage']; quotedMessage: ContentMessage; selfId: QualifiedId; showDetail: (message: ContentMessage, event: ReactMouseEvent) => void; showUserDetails: (user: User) => void; isMessageFocused: boolean; } const QuotedMessage: FC = ({ quotedMessage, focusMessage, selfId, handleClickOnMessage, showDetail, showUserDetails, isMessageFocused, }) => { const {user, assets, senderName, was_edited, timestamp} = useKoSubscribableChildren(quotedMessage, [ 'user', 'assets', 'senderName', 'was_edited', 'timestamp', ]); const messageFocusedTabIndex = useMessageFocusedTabIndex(isMessageFocused); return ( <>
{was_edited && ( )}
{assets.map((asset, index) => ( {asset.isImage() && (
showDetail(quotedMessage, event)} />
)} {asset.isText() && ( )} {asset.isVideo() && ( )} {asset.isAudio() && ( )} {asset.isFile() && ( )} {asset.isLocation() && }
))} ); };