Attachment Modal: Support scheduling (#1740)
This commit is contained in:
parent
40889f6d1f
commit
01002f8eb3
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user