2021-07-01 02:17:22 +03:00

104 lines
3.3 KiB
TypeScript

import { useCallback, useEffect, useMemo } from '../../../../lib/teact/teact';
import { ApiFormattedText, ApiMessage } from '../../../../api/types';
import { GlobalActions } from '../../../../global/types';
import { DRAFT_DEBOUNCE, EDITABLE_INPUT_ID } from '../../../../config';
import usePrevious from '../../../../hooks/usePrevious';
import { debounce } from '../../../../util/schedulers';
import focusEditableElement from '../../../../util/focusEditableElement';
import parseMessageInput from '../helpers/parseMessageInput';
import getMessageTextAsHtml from '../helpers/getMessageTextAsHtml';
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
import useBeforeUnload from '../../../../hooks/useBeforeUnload';
// Used to avoid running debounced callbacks when chat changes.
let currentChatId: number | undefined;
let currentThreadId: number | undefined;
export default (
draft: ApiFormattedText | undefined,
chatId: number,
threadId: number,
html: string,
htmlRef: { current: string },
setHtml: (html: string) => void,
editedMessage: ApiMessage | undefined,
saveDraft: GlobalActions['saveDraft'],
clearDraft: GlobalActions['clearDraft'],
) => {
const updateDraft = useCallback((draftChatId: number, draftThreadId: number) => {
if (htmlRef.current.length && !editedMessage) {
saveDraft({ chatId: draftChatId, threadId: draftThreadId, draft: parseMessageInput(htmlRef.current!) });
} else {
clearDraft({ chatId: draftChatId, threadId: draftThreadId });
}
}, [clearDraft, editedMessage, htmlRef, saveDraft]);
// eslint-disable-next-line react-hooks/exhaustive-deps
const runDebouncedForSaveDraft = useMemo(() => debounce((cb) => cb(), DRAFT_DEBOUNCE, false), [chatId]);
const prevChatId = usePrevious(chatId);
const prevThreadId = usePrevious(threadId);
// Save draft on chat change
useEffect(() => {
currentChatId = chatId;
currentThreadId = threadId;
return () => {
currentChatId = undefined;
currentThreadId = undefined;
updateDraft(chatId, threadId);
};
}, [chatId, threadId, updateDraft]);
// Restore draft on chat change
useEffect(() => {
if (chatId === prevChatId && threadId === prevThreadId) {
return;
}
if (!draft) {
return;
}
setHtml(getMessageTextAsHtml(draft));
requestAnimationFrame(() => {
const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;
focusEditableElement(messageInput, true);
});
}, [chatId, threadId, draft, setHtml, updateDraft, prevChatId, prevThreadId]);
// Update draft when input changes
const prevHtml = usePrevious(html);
useEffect(() => {
if (!chatId || !threadId || prevChatId !== chatId || prevThreadId !== threadId || prevHtml === html) {
return;
}
if (html.length) {
runDebouncedForSaveDraft(() => {
if (currentChatId !== chatId || currentThreadId !== threadId) {
return;
}
updateDraft(chatId, threadId);
});
} else {
updateDraft(chatId, threadId);
}
}, [chatId, html, prevChatId, prevHtml, prevThreadId, runDebouncedForSaveDraft, threadId, updateDraft]);
const handleBlur = useCallback(() => {
if (chatId && threadId) {
updateDraft(chatId, threadId);
}
}, [chatId, threadId, updateDraft]);
useBackgroundMode(handleBlur);
useBeforeUnload(handleBlur);
};