import React, { ReactElement, RefObject, useReducer } from 'react'; import { MessageEntity } from '../../../../Domain/entity/MessageEntity'; import { getTimeShort24hFormat } from '../../../../utils/DateTimeFormatter'; import Message from '../../../ui-components/Message/Message'; import TextBubble from '../../../ui-components/Message/Bubble/TextBubble/TextBubble'; import AttachmentBubble from '../../../ui-components/Message/Bubble/AttachmentBubble/AttachmentBubble'; import AIAssist from '../AIComponents/AIAssist/AIAssist'; import MessageContextMenu from '../MessageContextMenu/MessageContextMenu'; import { FunctionTypeMessageEntityToVoid } from '../../../../CommonTypes/BaseViewModel'; import AITranslate from '../AIComponents/AITranslate/AITranslate'; import { AIMessageWidget } from '../AIWidgets/AIMessageWidget'; import Loader from '../../../ui-components/Loader/Loader'; import MessageSeparator from '../../../ui-components/MessageSeparator/MessageSeparator'; import { MessageDTOMapper } from '../../../../Data/source/remote/Mapper/MessageDTOMapper'; import Avatar from '../../../ui-components/Avatar/Avatar'; import UserSvg from '../../../icons/contents/user.svg?react'; import './MessageItem.scss'; export type MessageItemProps = { message: MessageEntity; avatar?: ReactElement; currentUserId?: number; AITranslateWidget?: AIMessageWidget; AIAssistWidget?: AIMessageWidget; maxTokens: number; defaultTranslationLanguage: string; languagesForAITranslate: string[]; enableForwarding: boolean; enableReplying: boolean; onReply: FunctionTypeMessageEntityToVoid; onForward: FunctionTypeMessageEntityToVoid; // defaultGetSenderName: GetUserNameFct; listRef?: RefObject; messagesToView: MessageEntity[]; onError: (messageError: string) => void; disableAction?: boolean; }; interface MessageStates { loading: boolean; translatedText: string; } type Action = | { type: 'SET_LOADING'; id: string; payload: boolean } | { type: 'SET_TRANSLATED_TEXT'; id: string; payload: string }; function reducer( state: Record, action: Action, ): Record { switch (action.type) { case 'SET_LOADING': return { ...state, [action.id]: { ...state[action.id], loading: action.payload }, }; case 'SET_TRANSLATED_TEXT': return { ...state, [action.id]: { ...state[action.id], translatedText: action.payload }, }; default: return state; } } export default function MessageItem({ message, avatar, currentUserId, enableForwarding, enableReplying, onReply, onForward, // eslint-disable-next-line @typescript-eslint/no-unused-vars listRef, messagesToView, AITranslateWidget, AIAssistWidget, maxTokens, defaultTranslationLanguage, languagesForAITranslate, onError, disableAction = false, }: MessageItemProps) { const messageStates: Record = {}; const [state, dispatch] = useReducer(reducer, messageStates); const senderName = message.sender?.full_name || message.sender?.login || message.sender?.email || ''; const TypeSystemMessage = 'system'; const TypeIncomingMessage = 'incoming'; const TypeOutgoingMessage = 'outgoing'; const subTypeMessage = message.qb_message_action?.includes('forward') ? 'forward' : 'reply'; function checkMessageType(m: MessageEntity): string { if (m.notification_type && m.notification_type.length > 0) { return TypeSystemMessage; } if ( (m.sender && m.sender.id.toString() !== currentUserId?.toString()) || m.sender_id.toString() !== currentUserId?.toString() ) { return TypeIncomingMessage; } return TypeOutgoingMessage; } function translatedHandler(id: string, textTranslated: string) { dispatch({ type: 'SET_TRANSLATED_TEXT', id, payload: textTranslated }); } function fetchingHandler(isFetching: boolean, id: string) { dispatch({ type: 'SET_LOADING', id, payload: isFetching }); } function getStatusMessage(messageEntity: MessageEntity) { if ( Array.isArray(messageEntity.delivered_ids) && messageEntity.delivered_ids.length > 0 && messageEntity.delivered_ids.some((id) => id !== currentUserId) ) { if ( Array.isArray(messageEntity.read_ids) && messageEntity.read_ids.length > 0 && messageEntity.read_ids.some((id) => id !== currentUserId) ) { return 'viewed'; } return 'delivered'; } return 'sent'; } function renderAdditionalPart( currentMessageType: 'incoming' | 'outgoing', item: MessageEntity, ) { return (
onReply(item)} onForward={() => onForward(item)} enableReplying={enableReplying} enableForwarding={enableForwarding} disableActions={disableAction} /> {currentMessageType === 'incoming' && state[item.id]?.loading && ( )} {currentMessageType === 'incoming' && !(item.attachments && item.attachments.length > 0) && AIAssistWidget && ( fetchingHandler(isFetching, id) } onError={onError} messageToAssist={item} messageHistory={messagesToView} currentUserId={currentUserId} maxTokens={maxTokens} /> )}
); } function renderForwardedReplyMessageSegment( currentMessageType: 'incoming' | 'outgoing', ) { if ( message.qb_original_messages && message.qb_original_messages?.length > 0 ) { return ( <> {message.qb_original_messages.map((nestedMessage) => { const senderNameNestedMessage = nestedMessage.sender?.full_name || nestedMessage.sender?.login || nestedMessage.sender?.email || ''; return ( 0 ) && AITranslateWidget ? ( fetchingHandler(isFetching, id) } onError={onError} messageToTranslate={nestedMessage} messageHistory={messagesToView} currentUserId={currentUserId} maxTokens={maxTokens} onTranslated={(id, textTranslated) => translatedHandler(id, textTranslated) } /> ) : undefined } additionalPart={
{renderAdditionalPart(currentMessageType, nestedMessage)}
} > {nestedMessage.attachments && nestedMessage.attachments.length > 0 ? (
{/* eslint-disable-next-line @typescript-eslint/no-shadow */} {nestedMessage.attachments.map((attachment) => { return ( ); })}
) : ( )}
); })} ); } return null; } const messageTypes: string = checkMessageType(message); if (messageTypes === TypeSystemMessage) { return ; } if ( messageTypes === TypeIncomingMessage || messageTypes === TypeOutgoingMessage ) { return (
{renderForwardedReplyMessageSegment(messageTypes)} {!message.message.includes(MessageDTOMapper.FORWARD_MESSAGE_PREFIX) && ( } size="md" /> } userName={senderName} status={getStatusMessage(message)} time={getTimeShort24hFormat(message.date_sent)} type={messageTypes} bottomPart={ !(message.attachments && message.attachments.length > 0) && AITranslateWidget ? ( fetchingHandler(isFetching, id) } onError={onError} messageToTranslate={message} messageHistory={messagesToView} currentUserId={currentUserId} maxTokens={maxTokens} onTranslated={(id, textTranslated) => translatedHandler(id, textTranslated) } /> ) : undefined } additionalPart={
{renderAdditionalPart(messageTypes, message)}
} > {message.attachments && message.attachments.length > 0 ? ( <> {message.attachments.map((attachment) => { return ( ); })} ) : ( )}
)}
); } return null; }