diff --git a/src/components/middle/composer/Composer.tsx b/src/components/middle/composer/Composer.tsx index 6853886ad..071cf19ca 100644 --- a/src/components/middle/composer/Composer.tsx +++ b/src/components/middle/composer/Composer.tsx @@ -4,7 +4,9 @@ import React, { } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; -import type { TabState, MessageListType, GlobalState } from '../../../global/types'; +import type { + TabState, MessageListType, GlobalState, ApiDraft, +} from '../../../global/types'; import type { ApiAttachment, ApiBotInlineResult, @@ -147,7 +149,7 @@ type StateProps = { editingMessage?: ApiMessage; chat?: ApiChat; - draft?: ApiFormattedText; + draft?: ApiDraft; isChatWithBot?: boolean; isChatWithSelf?: boolean; isChannel?: boolean; diff --git a/src/components/middle/composer/hooks/useDraft.ts b/src/components/middle/composer/hooks/useDraft.ts index 3904aba48..c699499e9 100644 --- a/src/components/middle/composer/hooks/useDraft.ts +++ b/src/components/middle/composer/hooks/useDraft.ts @@ -1,7 +1,8 @@ import { useCallback, useEffect } from '../../../../lib/teact/teact'; import { getActions } from '../../../../global'; -import type { ApiFormattedText, ApiMessage } from '../../../../api/types'; +import type { ApiDraft } from '../../../../global/types'; +import type { ApiMessage } from '../../../../api/types'; import type { Signal } from '../../../../util/signals'; import { ApiMessageEntityTypes } from '../../../../api/types'; @@ -26,7 +27,7 @@ function freeze() { } const useDraft = ( - draft: ApiFormattedText | undefined, + draft: ApiDraft | undefined, chatId: string, threadId: number, getHtml: Signal, @@ -38,7 +39,7 @@ const useDraft = ( const isEditing = Boolean(editedMessage); - const updateDraft = useCallback((prevState: { chatId?: string; threadId?: number } = {}) => { + const updateDraft = useCallback((prevState: { chatId?: string; threadId?: number } = {}, shouldForce = false) => { if (isEditing || !lastSyncTime) return; const html = getHtml(); @@ -48,15 +49,21 @@ const useDraft = ( chatId: prevState.chatId ?? chatId, threadId: prevState.threadId ?? threadId, draft: parseMessageInput(html), + shouldForce, }); } else { clearDraft({ chatId: prevState.chatId ?? chatId, threadId: prevState.threadId ?? threadId, + shouldForce, }); } }, [chatId, threadId, isEditing, lastSyncTime, getHtml, saveDraft, clearDraft]); + const forceUpdateDraft = useCallback(() => { + updateDraft(undefined, true); + }, [updateDraft]); + const updateDraftRef = useStateRef(updateDraft); const runDebouncedForSaveDraft = useRunDebounced(DRAFT_DEBOUNCE, true, undefined, [chatId, threadId]); @@ -67,7 +74,9 @@ const useDraft = ( setHtml(''); } - return; + if (!draft?.shouldForce) { + return; + } } if (editedMessage || !draft) { @@ -130,8 +139,8 @@ const useDraft = ( }); }, [chatIdRef, getHtml, runDebouncedForSaveDraft, threadIdRef, updateDraftRef]); - useBackgroundMode(updateDraft); - useBeforeUnload(updateDraft); + useBackgroundMode(forceUpdateDraft); + useBeforeUnload(forceUpdateDraft); }; export default useDraft; diff --git a/src/global/actions/api/messages.ts b/src/global/actions/api/messages.ts index e2a6ba645..24b67c8d6 100644 --- a/src/global/actions/api/messages.ts +++ b/src/global/actions/api/messages.ts @@ -2,7 +2,7 @@ import type { RequiredGlobalActions } from '../../index'; import { addActionHandler, getGlobal, setGlobal } from '../../index'; import type { - ActionReturnType, GlobalState, TabArgs, + ActionReturnType, ApiDraft, GlobalState, TabArgs, } from '../../types'; import type { ApiAttachment, @@ -356,7 +356,9 @@ addActionHandler('cancelSendingMessage', (global, actions, payload): ActionRetur }); addActionHandler('saveDraft', async (global, actions, payload): Promise => { - const { chatId, threadId, draft } = payload!; + const { + chatId, threadId, draft, shouldForce, + } = payload; if (!draft) { return; } @@ -366,6 +368,13 @@ addActionHandler('saveDraft', async (global, actions, payload): Promise => const user = selectUser(global, chatId)!; if (user && isDeletedUser(user)) return; + draft.isLocal = true; + draft.shouldForce = shouldForce; + global = replaceThreadParam(global, chatId, threadId, 'draft', draft); + global = updateChat(global, chatId, { draftDate: Math.round(Date.now() / 1000) }); + + setGlobal(global); + const result = await callApi('saveDraft', { chat, text, @@ -374,8 +383,8 @@ addActionHandler('saveDraft', async (global, actions, payload): Promise => threadId: selectThreadTopMessageId(global, chatId, threadId), }); - if (!result) { - draft.isLocal = true; + if (result) { + draft.isLocal = false; } global = getGlobal(); @@ -386,7 +395,9 @@ addActionHandler('saveDraft', async (global, actions, payload): Promise => }); addActionHandler('clearDraft', (global, actions, payload): ActionReturnType => { - const { chatId, threadId = MAIN_THREAD_ID, localOnly } = payload!; + const { + chatId, threadId = MAIN_THREAD_ID, localOnly, shouldForce, + } = payload; if (!selectDraft(global, chatId, threadId)) { return undefined; } @@ -397,7 +408,8 @@ addActionHandler('clearDraft', (global, actions, payload): ActionReturnType => { void callApi('clearDraft', chat, selectThreadTopMessageId(global, chatId, threadId)); } - global = replaceThreadParam(global, chatId, threadId, 'draft', undefined); + const newDraft: ApiDraft | undefined = shouldForce ? { shouldForce, text: '' } : undefined; + global = replaceThreadParam(global, chatId, threadId, 'draft', newDraft); global = updateChat(global, chatId, { draftDate: undefined }); return global; diff --git a/src/global/types.ts b/src/global/types.ts index ba01b6171..cbb45f05b 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -799,7 +799,7 @@ export type CallbackAction = Values<{ } }>; -export type ApiDraft = ApiFormattedText & { isLocal?: boolean }; +export type ApiDraft = ApiFormattedText & { isLocal?: boolean; shouldForce?: boolean }; type WithTabId = { tabId?: number }; @@ -1237,11 +1237,13 @@ export interface ActionPayloads { chatId: string; threadId: number; draft: ApiDraft; + shouldForce?: boolean; }; clearDraft: { chatId: string; threadId?: number; localOnly?: boolean; + shouldForce?: boolean; }; loadPinnedMessages: { chatId: string;