mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-04 16:06:41 +00:00
fix: keep the text typed in quick reply when opening the full composer
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import type { Email } from '../../api/types';
|
||||||
|
import { replyComposeParams } from '../reply-compose';
|
||||||
|
|
||||||
|
const source = {
|
||||||
|
id: 'm1',
|
||||||
|
threadId: 't1',
|
||||||
|
mailboxIds: {},
|
||||||
|
keywords: {},
|
||||||
|
size: 1,
|
||||||
|
receivedAt: '2026-10-14T10:00:00Z',
|
||||||
|
subject: 'Hello',
|
||||||
|
from: [{ name: 'Petra', email: 'petra@example.net' }],
|
||||||
|
textBody: [{ partId: '1', type: 'text/plain' }],
|
||||||
|
bodyValues: { 1: { value: 'Please confirm.' } },
|
||||||
|
} as unknown as Email;
|
||||||
|
|
||||||
|
describe('replyComposeParams', () => {
|
||||||
|
it('carries the text typed in quick reply into the composer', () => {
|
||||||
|
const params = replyComposeParams('reply', source, undefined, 'Got it, thanks!');
|
||||||
|
expect(params?.prefillBody).toBe('Got it, thanks!');
|
||||||
|
expect(params?.replyTo?.from.email).toBe('petra@example.net');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds nothing when nothing was typed', () => {
|
||||||
|
expect(replyComposeParams('reply', source)?.prefillBody).toBeUndefined();
|
||||||
|
expect(replyComposeParams('reply', source, undefined, ' ')?.prefillBody).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -5,12 +5,15 @@ import { pickEmailBody, plainTextBody } from './email-body';
|
|||||||
/**
|
/**
|
||||||
* Composer params for a reply / reply-all / forward of `source`. Shared by
|
* Composer params for a reply / reply-all / forward of `source`. Shared by
|
||||||
* the thread viewer and the `mail/message/<id>?action=reply` deep link (the
|
* the thread viewer and the `mail/message/<id>?action=reply` deep link (the
|
||||||
* triage widget). Null when there is nobody to reply to.
|
* triage widget). Null when there is nobody to reply to. `typed` is text
|
||||||
|
* the user already wrote (quick reply's "More options"); it goes above the
|
||||||
|
* quote.
|
||||||
*/
|
*/
|
||||||
export function replyComposeParams(
|
export function replyComposeParams(
|
||||||
mode: 'reply' | 'replyAll' | 'forward',
|
mode: 'reply' | 'replyAll' | 'forward',
|
||||||
source: Email,
|
source: Email,
|
||||||
ownerAccountId?: string,
|
ownerAccountId?: string,
|
||||||
|
typed?: string,
|
||||||
): NonNullable<RootStackParamList['Compose']> | null {
|
): NonNullable<RootStackParamList['Compose']> | null {
|
||||||
const from = source.from?.[0];
|
const from = source.from?.[0];
|
||||||
if (!from && mode !== 'forward') return null;
|
if (!from && mode !== 'forward') return null;
|
||||||
@@ -24,6 +27,7 @@ export function replyComposeParams(
|
|||||||
const body = !quoteHtml || picked.text ? plainTextBody(source) : undefined;
|
const body = !quoteHtml || picked.text ? plainTextBody(source) : undefined;
|
||||||
return {
|
return {
|
||||||
mode,
|
mode,
|
||||||
|
...(typed?.trim() ? { prefillBody: typed } : null),
|
||||||
replyTo: {
|
replyTo: {
|
||||||
from: from ?? { email: '' },
|
from: from ?? { email: '' },
|
||||||
to: source.to,
|
to: source.to,
|
||||||
|
|||||||
@@ -557,10 +557,10 @@ function EmailViewer({ route, navigation, embedded = false, onActiveChange }: Pr
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Reply / forward the given message (a thread card's own, or the active one).
|
// Reply / forward the given message (a thread card's own, or the active one).
|
||||||
const navigateCompose = React.useCallback((mode: 'reply' | 'replyAll' | 'forward', target?: Email) => {
|
const navigateCompose = React.useCallback((mode: 'reply' | 'replyAll' | 'forward', target?: Email, typed?: string) => {
|
||||||
const source = target ?? email;
|
const source = target ?? email;
|
||||||
if (!source) return;
|
if (!source) return;
|
||||||
const params = replyComposeParams(mode, source, ownerAccountId);
|
const params = replyComposeParams(mode, source, ownerAccountId, typed);
|
||||||
if (params) navigation.navigate('Compose', params);
|
if (params) navigation.navigate('Compose', params);
|
||||||
}, [email, navigation, ownerAccountId]);
|
}, [email, navigation, ownerAccountId]);
|
||||||
|
|
||||||
@@ -961,7 +961,7 @@ interface EmailPaneProps {
|
|||||||
onToggleStar: (email: Email) => void;
|
onToggleStar: (email: Email) => void;
|
||||||
onAddressPress: (address: EmailAddress) => void;
|
onAddressPress: (address: EmailAddress) => void;
|
||||||
onEmailPatched: (email: Email) => void;
|
onEmailPatched: (email: Email) => void;
|
||||||
onReply: (mode: 'reply' | 'replyAll' | 'forward', email: Email) => void;
|
onReply: (mode: 'reply' | 'replyAll' | 'forward', email: Email, typed?: string) => void;
|
||||||
onSwipe: (direction: 'prev' | 'next') => void;
|
onSwipe: (direction: 'prev' | 'next') => void;
|
||||||
onZoomChange: (zoom: { pinching: boolean; zoomed: boolean }) => void;
|
onZoomChange: (zoom: { pinching: boolean; zoomed: boolean }) => void;
|
||||||
}
|
}
|
||||||
@@ -1182,7 +1182,8 @@ function EmailPane({
|
|||||||
<QuickReplyBox
|
<QuickReplyBox
|
||||||
email={newest}
|
email={newest}
|
||||||
jmapAccountId={jmapAccountId}
|
jmapAccountId={jmapAccountId}
|
||||||
onMoreOptions={() => onReply('reply', newest)}
|
// The text typed so far moves into the full composer.
|
||||||
|
onMoreOptions={(draft) => onReply('reply', newest, draft)}
|
||||||
onSent={onEmailPatched}
|
onSent={onEmailPatched}
|
||||||
onFocus={handleQuickReplyFocus}
|
onFocus={handleQuickReplyFocus}
|
||||||
onBlur={handleQuickReplyBlur}
|
onBlur={handleQuickReplyBlur}
|
||||||
|
|||||||
Reference in New Issue
Block a user