Attachment Modal: Support scheduling (#1740)

This commit is contained in:
Alexander Zinchuk 2022-03-04 16:21:03 +03:00
parent 40889f6d1f
commit 01002f8eb3
5 changed files with 67 additions and 14 deletions

View File

@ -128,4 +128,19 @@
border-radius: var(--border-radius-default); border-radius: var(--border-radius-default);
} }
} }
&--send-wrapper {
position: relative;
}
.CustomSendMenu {
bottom: auto;
.is-pointer-env & > .backdrop {
width: 100%;
top: -2.25rem;
bottom: auto;
height: 2.75rem;
}
}
} }

View File

@ -17,6 +17,7 @@ import useMentionTooltip from './hooks/useMentionTooltip';
import useEmojiTooltip from './hooks/useEmojiTooltip'; import useEmojiTooltip from './hooks/useEmojiTooltip';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
import { useStateRef } from '../../../hooks/useStateRef'; import { useStateRef } from '../../../hooks/useStateRef';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
@ -25,6 +26,7 @@ import File from '../../common/File';
import MessageInput from './MessageInput'; import MessageInput from './MessageInput';
import MentionTooltip from './MentionTooltip'; import MentionTooltip from './MentionTooltip';
import EmojiTooltip from './EmojiTooltip.async'; import EmojiTooltip from './EmojiTooltip.async';
import CustomSendMenu from './CustomSendMenu.async';
import './AttachmentModal.scss'; import './AttachmentModal.scss';
@ -33,7 +35,9 @@ export type OwnProps = {
threadId: number; threadId: number;
attachments: ApiAttachment[]; attachments: ApiAttachment[];
caption: string; caption: string;
canShowCustomSendMenu?: boolean;
isReady?: boolean; isReady?: boolean;
isChatWithSelf?: boolean;
currentUserId?: string; currentUserId?: string;
groupChatMembers?: ApiChatMember[]; groupChatMembers?: ApiChatMember[];
recentEmojis: string[]; recentEmojis: string[];
@ -44,6 +48,8 @@ export type OwnProps = {
onSend: () => void; onSend: () => void;
onFileAppend: (files: File[], isQuick: boolean) => void; onFileAppend: (files: File[], isQuick: boolean) => void;
onClear: () => void; onClear: () => void;
onSilentSend: () => void;
openCalendar: () => void;
}; };
const DROP_LEAVE_TIMEOUT_MS = 150; const DROP_LEAVE_TIMEOUT_MS = 150;
@ -53,7 +59,9 @@ const AttachmentModal: FC<OwnProps> = ({
threadId, threadId,
attachments, attachments,
caption, caption,
canShowCustomSendMenu,
isReady, isReady,
isChatWithSelf,
currentUserId, currentUserId,
groupChatMembers, groupChatMembers,
recentEmojis, recentEmojis,
@ -64,8 +72,12 @@ const AttachmentModal: FC<OwnProps> = ({
onSend, onSend,
onFileAppend, onFileAppend,
onClear, onClear,
onSilentSend,
openCalendar,
}) => { }) => {
const captionRef = useStateRef(caption); const captionRef = useStateRef(caption);
// eslint-disable-next-line no-null/no-null
const mainButtonRef = useStateRef<HTMLButtonElement | null>(null);
const hideTimeoutRef = useRef<number>(); const hideTimeoutRef = useRef<number>();
const prevAttachments = usePrevious(attachments); const prevAttachments = usePrevious(attachments);
const renderingAttachments = attachments.length ? attachments : prevAttachments; const renderingAttachments = attachments.length ? attachments : prevAttachments;
@ -100,6 +112,13 @@ const AttachmentModal: FC<OwnProps> = ({
useEffect(() => (isOpen ? captureEscKeyListener(onClear) : undefined), [isOpen, onClear]); useEffect(() => (isOpen ? captureEscKeyListener(onClear) : undefined), [isOpen, onClear]);
const {
isContextMenuOpen: isCustomSendMenuOpen,
handleContextMenu,
handleContextMenuClose,
handleContextMenuHide,
} = useContextMenuHandlers(mainButtonRef, !canShowCustomSendMenu || !isOpen);
const sendAttachments = useCallback(() => { const sendAttachments = useCallback(() => {
if (isOpen) { if (isOpen) {
onSend(); onSend();
@ -183,14 +202,28 @@ const AttachmentModal: FC<OwnProps> = ({
<i className="icon-close" /> <i className="icon-close" />
</Button> </Button>
<div className="modal-title">{title}</div> <div className="modal-title">{title}</div>
<Button <div className="AttachmentModal--send-wrapper">
color="primary" <Button
size="smaller" ref={mainButtonRef}
className="modal-action-button" color="primary"
onClick={sendAttachments} size="smaller"
> className="modal-action-button"
{lang('Send')} onClick={sendAttachments}
</Button> onContextMenu={canShowCustomSendMenu ? handleContextMenu : undefined}
>
{lang('Send')}
</Button>
{canShowCustomSendMenu && (
<CustomSendMenu
isOpen={isCustomSendMenuOpen}
isOpenToBottom
onSilentSend={!isChatWithSelf ? onSilentSend : undefined}
onScheduleSend={openCalendar}
onClose={handleContextMenuClose}
onCloseAnimationEnd={handleContextMenuHide}
/>
)}
</div>
</div> </div>
); );
} }

View File

@ -849,16 +849,20 @@ const Composer: FC<OwnProps & StateProps> = ({
<AttachmentModal <AttachmentModal
chatId={chatId} chatId={chatId}
threadId={threadId} threadId={threadId}
canShowCustomSendMenu={canShowCustomSendMenu}
attachments={attachments} attachments={attachments}
caption={attachments.length ? html : ''} caption={attachments.length ? html : ''}
groupChatMembers={groupChatMembers} groupChatMembers={groupChatMembers}
currentUserId={currentUserId} currentUserId={currentUserId}
recentEmojis={recentEmojis} recentEmojis={recentEmojis}
isReady={isReady} isReady={isReady}
isChatWithSelf={isChatWithSelf}
onCaptionUpdate={setHtml} onCaptionUpdate={setHtml}
baseEmojiKeywords={baseEmojiKeywords} baseEmojiKeywords={baseEmojiKeywords}
emojiKeywords={emojiKeywords} emojiKeywords={emojiKeywords}
addRecentEmoji={addRecentEmoji} addRecentEmoji={addRecentEmoji}
onSilentSend={handleSilentSend}
openCalendar={openCalendar}
onSend={shouldSchedule ? openCalendar : handleSend} onSend={shouldSchedule ? openCalendar : handleSend}
onFileAppend={handleAppendFiles} onFileAppend={handleAppendFiles}
onClear={handleClearAttachment} onClear={handleClearAttachment}

View File

@ -11,6 +11,7 @@ import './CustomSendMenu.scss';
export type OwnProps = { export type OwnProps = {
isOpen: boolean; isOpen: boolean;
isOpenToBottom?: boolean;
onSilentSend?: NoneToVoidFunction; onSilentSend?: NoneToVoidFunction;
onScheduleSend?: NoneToVoidFunction; onScheduleSend?: NoneToVoidFunction;
onClose: NoneToVoidFunction; onClose: NoneToVoidFunction;
@ -18,7 +19,7 @@ export type OwnProps = {
}; };
const CustomSendMenu: FC<OwnProps> = ({ const CustomSendMenu: FC<OwnProps> = ({
isOpen, onSilentSend, onScheduleSend, onClose, onCloseAnimationEnd, isOpen, isOpenToBottom = false, onSilentSend, onScheduleSend, onClose, onCloseAnimationEnd,
}) => { }) => {
const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose); const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose);
@ -29,7 +30,7 @@ const CustomSendMenu: FC<OwnProps> = ({
isOpen={isOpen} isOpen={isOpen}
autoClose autoClose
positionX="right" positionX="right"
positionY="bottom" positionY={isOpenToBottom ? 'top' : 'bottom'}
className="CustomSendMenu" className="CustomSendMenu"
onClose={onClose} onClose={onClose}
onCloseAnimationEnd={onCloseAnimationEnd} onCloseAnimationEnd={onCloseAnimationEnd}

View File

@ -43,10 +43,6 @@
transition: opacity 0.15s !important; transition: opacity 0.15s !important;
} }
body.has-open-dialog & {
transition: none !important;
}
--offset-y: calc(100% + 0.5rem); --offset-y: calc(100% + 0.5rem);
--offset-x: 0; --offset-x: 0;
@ -71,6 +67,10 @@
} }
} }
body.has-open-dialog &:not(.CustomSendMenu) .bubble {
transition: none !important;
}
.footer { .footer {
padding: 0.5rem 0; padding: 0.5rem 0;
background: var(--color-chat-hover); background: var(--color-chat-hover);