import React, { FC, memo, useCallback, useEffect, useRef, } from '../../../lib/teact/teact'; import { ApiAttachment, ApiChatMember, ApiUser } from '../../../api/types'; import { CONTENT_TYPES_FOR_QUICK_UPLOAD, EDITABLE_INPUT_MODAL_ID } from '../../../config'; import { getFileExtension } from '../../common/helpers/documentInfo'; import captureEscKeyListener from '../../../util/captureEscKeyListener'; import usePrevious from '../../../hooks/usePrevious'; import useMentionTooltip from './hooks/useMentionTooltip'; import useEmojiTooltip from './hooks/useEmojiTooltip'; import useLang from '../../../hooks/useLang'; import useFlag from '../../../hooks/useFlag'; import Button from '../../ui/Button'; import Modal from '../../ui/Modal'; import File from '../../common/File'; import MessageInput from './MessageInput'; import MentionTooltip from './MentionTooltip'; import EmojiTooltip from './EmojiTooltip.async'; import './AttachmentModal.scss'; export type OwnProps = { attachments: ApiAttachment[]; caption: string; isReady?: boolean; currentUserId?: number; groupChatMembers?: ApiChatMember[]; usersById?: Record; recentEmojis: string[]; baseEmojiKeywords?: Record; emojiKeywords?: Record; addRecentEmoji: AnyToVoidFunction; onCaptionUpdate: (html: string) => void; onSend: () => void; onFileAppend: (files: File[], isQuick: boolean) => void; onClear: () => void; }; const DROP_LEAVE_TIMEOUT_MS = 150; const AttachmentModal: FC = ({ attachments, caption, isReady, currentUserId, groupChatMembers, usersById, recentEmojis, baseEmojiKeywords, emojiKeywords, addRecentEmoji, onCaptionUpdate, onSend, onFileAppend, onClear, }) => { // eslint-disable-next-line no-null/no-null const hideTimeoutRef = useRef(null); const prevAttachments = usePrevious(attachments); const renderingAttachments = attachments.length ? attachments : prevAttachments; const isOpen = Boolean(attachments.length); const [isHovered, markHovered, unmarkHovered] = useFlag(); const isQuick = Boolean(renderingAttachments && renderingAttachments.every((a) => a.quick)); const lang = useLang(); const { isMentionTooltipOpen, mentionFilter, closeMentionTooltip, insertMention, mentionFilteredUsers, } = useMentionTooltip( isOpen, caption, onCaptionUpdate, EDITABLE_INPUT_MODAL_ID, groupChatMembers, undefined, currentUserId, usersById, ); const { isEmojiTooltipOpen, closeEmojiTooltip, filteredEmojis, insertEmoji, } = useEmojiTooltip( isOpen, caption, recentEmojis, EDITABLE_INPUT_MODAL_ID, onCaptionUpdate, baseEmojiKeywords, emojiKeywords, !isReady, ); useEffect(() => (isOpen ? captureEscKeyListener(onClear) : undefined), [isOpen, onClear]); const sendAttachments = useCallback(() => { if (isOpen) { onSend(); } }, [isOpen, onSend]); const handleDragLeave = (e: React.DragEvent) => { const { relatedTarget: toTarget, target: fromTarget } = e; // Esc button pressed during drag event if ((fromTarget as HTMLDivElement).matches('.drop-target') && !toTarget) { hideTimeoutRef.current = window.setTimeout(unmarkHovered, DROP_LEAVE_TIMEOUT_MS); } // Prevent DragLeave event from firing when the pointer moves inside the AttachmentModal drop target if (fromTarget && (fromTarget as HTMLElement).closest('.AttachmentModal.hovered')) { return; } if (toTarget) { e.stopPropagation(); } unmarkHovered(); }; const handleFilesDrop = useCallback((e: React.DragEvent) => { e.preventDefault(); unmarkHovered(); const { dataTransfer: { files } } = e; if (files && files.length) { const newFiles = isQuick ? Array.from(files).filter((file) => { return file.type && CONTENT_TYPES_FOR_QUICK_UPLOAD.has(file.type); }) : Array.from(files); onFileAppend(newFiles, isQuick); } }, [isQuick, onFileAppend, unmarkHovered]); function handleDragOver(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); if (hideTimeoutRef.current) { window.clearTimeout(hideTimeoutRef.current); } } if (!renderingAttachments) { return undefined; } const areAllPhotos = renderingAttachments.every((a) => a.mimeType.startsWith('image/')); const areAllVideos = renderingAttachments.every((a) => a.mimeType.startsWith('video/')); let title = ''; if (areAllPhotos) { title = lang('PreviewSender.SendPhoto', renderingAttachments.length, 'i'); } else if (areAllVideos) { title = lang('PreviewSender.SendVideo', renderingAttachments.length, 'i'); } else { title = lang('PreviewSender.SendFile', renderingAttachments.length, 'i'); } function renderHeader() { if (!renderingAttachments) { return undefined; } return (
{title}
); } return (
{isQuick ? (
{renderingAttachments.map((attachment) => ( attachment.mimeType.startsWith('image/') ? :
) : (
{renderingAttachments.map((attachment) => ( ))}
)}
); }; export default memo(AttachmentModal);