2024-07-15 15:50:42 +02:00

177 lines
5.6 KiB
TypeScript

import type { FC, TeactNode } from '../../../lib/teact/teact';
import React, { memo, useMemo } from '../../../lib/teact/teact';
import { getActions } from '../../../global';
import type {
ApiAvailableReaction, ApiMessage, ApiMessageOutgoingStatus, ApiThreadInfo,
} from '../../../api/types';
import buildClassName from '../../../util/buildClassName';
import { formatDateTimeToString, formatPastTimeShort, formatTime } from '../../../util/dates/dateFormat';
import { formatIntegerCompact } from '../../../util/textFormat';
import renderText from '../../common/helpers/renderText';
import useFlag from '../../../hooks/useFlag';
import useOldLang from '../../../hooks/useOldLang';
import AnimatedCounter from '../../common/AnimatedCounter';
import Icon from '../../common/icons/Icon';
import MessageOutgoingStatus from '../../common/MessageOutgoingStatus';
import './MessageMeta.scss';
type OwnProps = {
message: ApiMessage;
withReactionOffset?: boolean;
outgoingStatus?: ApiMessageOutgoingStatus;
signature?: string;
availableReactions?: ApiAvailableReaction[];
noReplies?: boolean;
repliesThreadInfo?: ApiThreadInfo;
isTranslated?: boolean;
isPinned?: boolean;
withFullDate?: boolean;
effectEmoji?: string;
onClick: (e: React.MouseEvent<HTMLDivElement>) => void;
onTranslationClick: (e: React.MouseEvent<HTMLDivElement>) => void;
onEffectClick: (e: React.MouseEvent<HTMLDivElement>) => void;
renderQuickReactionButton?: () => TeactNode | undefined;
onOpenThread: NoneToVoidFunction;
};
const MessageMeta: FC<OwnProps> = ({
message,
outgoingStatus,
signature,
withReactionOffset,
repliesThreadInfo,
renderQuickReactionButton,
noReplies,
isTranslated,
isPinned,
withFullDate,
effectEmoji,
onClick,
onTranslationClick,
onEffectClick,
onOpenThread,
}) => {
const { showNotification } = getActions();
const lang = useOldLang();
const [isActivated, markActivated] = useFlag();
function handleImportedClick(e: React.MouseEvent) {
e.stopPropagation();
showNotification({
message: lang('ImportedInfo'),
});
}
function handleOpenThread(e: React.MouseEvent) {
e.stopPropagation();
onOpenThread();
}
const title = useMemo(() => {
if (!isActivated) return undefined;
const createDateTime = formatDateTimeToString(message.date * 1000, lang.code, undefined, lang.timeFormat);
const editDateTime = message.isEdited
&& formatDateTimeToString(message.editDate! * 1000, lang.code, undefined, lang.timeFormat);
const forwardedDateTime = message.forwardInfo
&& formatDateTimeToString(
(message.forwardInfo.savedDate || message.forwardInfo.date) * 1000,
lang.code,
undefined,
lang.timeFormat,
);
let text = createDateTime;
if (editDateTime) {
text += '\n';
text += lang('lng_edited_date').replace('{date}', editDateTime);
}
if (forwardedDateTime) {
text += '\n';
text += lang('lng_forwarded_date').replace('{date}', forwardedDateTime);
}
return text;
// We need to listen to timeformat change
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
}, [isActivated, lang, message, lang.timeFormat]);
const date = useMemo(() => {
const time = formatTime(lang, message.date * 1000);
if (!withFullDate) {
return time;
}
return formatPastTimeShort(lang, (message.forwardInfo?.date || message.date) * 1000, true);
}, [lang, message.date, message.forwardInfo?.date, withFullDate]);
const fullClassName = buildClassName(
'MessageMeta',
withReactionOffset && 'reactions-offset',
message.forwardInfo?.isImported && 'is-imported',
);
return (
<span
className={fullClassName}
dir={lang.isRtl ? 'rtl' : 'ltr'}
onClick={onClick}
data-ignore-on-paste
>
{effectEmoji && (
<span className="message-effect-icon" onClick={onEffectClick}>
{renderText(effectEmoji)}
</span>
)}
{isTranslated && (
<Icon name="language" className="message-translated" onClick={onTranslationClick} />
)}
{Boolean(message.viewsCount) && (
<>
<span className="message-views">
{formatIntegerCompact(message.viewsCount!)}
</span>
<Icon name="channelviews" />
</>
)}
{!noReplies && Boolean(repliesThreadInfo?.messagesCount) && (
<span onClick={handleOpenThread} className="message-replies-wrapper">
<span className="message-replies">
<AnimatedCounter text={formatIntegerCompact(repliesThreadInfo!.messagesCount!)} />
</span>
<Icon name="reply-filled" />
</span>
)}
{isPinned && (
<Icon name="pinned-message" className="message-pinned" />
)}
{signature && (
<span className="message-signature">{renderText(signature)}</span>
)}
<span className="message-time" title={title} onMouseEnter={markActivated}>
{message.forwardInfo?.isImported && (
<>
<span className="message-imported" onClick={handleImportedClick}>
{formatDateTimeToString(message.forwardInfo.date * 1000, lang.code, true)}
</span>
<span className="message-imported" onClick={handleImportedClick}>{lang('ImportedMessage')}</span>
</>
)}
{message.isEdited && `${lang('EditedMessage')} `}
{date}
</span>
{outgoingStatus && (
<MessageOutgoingStatus status={outgoingStatus} />
)}
{renderQuickReactionButton && renderQuickReactionButton()}
</span>
);
};
export default memo(MessageMeta);