fixes from review
This commit is contained in:
@@ -406,6 +406,7 @@ export function EmailComposer({
|
||||
const [smimePassphraseError, setSmimePassphraseError] = useState('');
|
||||
const [showAttachmentWarning, setShowAttachmentWarning] = useState(false);
|
||||
const [attachmentWarningKeyword, setAttachmentWarningKeyword] = useState('');
|
||||
const [attachmentWarningDelayedUntil, setAttachmentWarningDelayedUntil] = useState<string | undefined>();
|
||||
const [showScheduleDialog, setShowScheduleDialog] = useState(false);
|
||||
const [scheduleValue, setScheduleValue] = useState('');
|
||||
const [scheduleError, setScheduleError] = useState('');
|
||||
@@ -1227,8 +1228,8 @@ export function EmailComposer({
|
||||
const time = new Date(value).getTime();
|
||||
if (!Number.isFinite(time)) return t('schedule_send_invalid');
|
||||
if (time <= Date.now()) return t('schedule_send_future');
|
||||
if (client) {
|
||||
const maxDelayedSend = client.getMaxDelayedSend();
|
||||
if (composerClient) {
|
||||
const maxDelayedSend = composerClient.getMaxDelayedSend();
|
||||
if (maxDelayedSend > 0 && time > Date.now() + maxDelayedSend * 1000) {
|
||||
return t('schedule_send_too_late');
|
||||
}
|
||||
@@ -1239,7 +1240,7 @@ export function EmailComposer({
|
||||
const resolveDelayedUntil = async (requestedDelayedUntil?: string): Promise<string | undefined> => {
|
||||
if (requestedDelayedUntil) return requestedDelayedUntil;
|
||||
if (sendDelaySeconds === 0) return undefined;
|
||||
if (client?.hasDelayedSend()) {
|
||||
if (composerClient?.hasDelayedSend()) {
|
||||
return new Date(Date.now() + sendDelaySeconds * 1000).toISOString();
|
||||
}
|
||||
const confirmed = window.confirm(t('send_delay_unsupported_confirm'));
|
||||
@@ -1320,6 +1321,7 @@ export function EmailComposer({
|
||||
const matched = attachmentReminderKeywords.find(kw => searchText.includes(kw.toLowerCase()));
|
||||
if (matched) {
|
||||
setAttachmentWarningKeyword(matched);
|
||||
setAttachmentWarningDelayedUntil(delayedUntil);
|
||||
setShowAttachmentWarning(true);
|
||||
return;
|
||||
}
|
||||
@@ -1654,7 +1656,7 @@ export function EmailComposer({
|
||||
};
|
||||
|
||||
const handleScheduleSend = () => {
|
||||
if (!client?.hasDelayedSend()) {
|
||||
if (!composerClient?.hasDelayedSend()) {
|
||||
setScheduleError(t('schedule_send_unsupported'));
|
||||
return;
|
||||
}
|
||||
@@ -1742,7 +1744,7 @@ export function EmailComposer({
|
||||
|
||||
if (isScheduleShortcut) {
|
||||
e.preventDefault();
|
||||
if (!e.repeat && client?.hasDelayedSend()) openScheduleDialog();
|
||||
if (!e.repeat && composerClient?.hasDelayedSend()) openScheduleDialog();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2225,7 +2227,7 @@ export function EmailComposer({
|
||||
>
|
||||
{t('discard')}
|
||||
</button>
|
||||
{client?.hasDelayedSend() ? (
|
||||
{composerClient?.hasDelayedSend() ? (
|
||||
<div ref={sendMenuRef} className="relative hidden md:inline-flex">
|
||||
<Button
|
||||
onClick={() => handleSend()}
|
||||
@@ -2412,7 +2414,7 @@ export function EmailComposer({
|
||||
<Button variant="outline" onClick={() => setShowAttachmentWarning(false)}>
|
||||
{t('forgot_attachment.back')}
|
||||
</Button>
|
||||
<Button onClick={() => { setShowAttachmentWarning(false); handleSend(true); }}>
|
||||
<Button onClick={() => { setShowAttachmentWarning(false); handleSend(true, attachmentWarningDelayedUntil); setAttachmentWarningDelayedUntil(undefined); }}>
|
||||
{t('forgot_attachment.send_anyway')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -471,7 +471,7 @@ export function EmailList({
|
||||
onToggleExpand={() => handleToggleThreadExpansion(thread.threadId)}
|
||||
onEmailSelect={(email) => onEmailSelect?.(email)}
|
||||
onEmailDoubleClick={onEmailDoubleClick ? (email) => onEmailDoubleClick(email) : undefined}
|
||||
onContextMenu={isScheduledView ? undefined : openContextMenu}
|
||||
onContextMenu={openContextMenu}
|
||||
onOpenConversation={onOpenConversation}
|
||||
onToggleStar={onToggleStar ? (email) => onToggleStar(email) : undefined}
|
||||
onMarkAsRead={onMarkAsRead ? (email, read) => onMarkAsRead(email, read) : undefined}
|
||||
@@ -535,8 +535,8 @@ export function EmailList({
|
||||
onMarkAsSpam={() => onMarkAsSpam?.(contextMenu.data!)}
|
||||
onUndoSpam={() => onUndoSpam?.(contextMenu.data!)}
|
||||
onEditDraft={() => onEditDraft?.(contextMenu.data!)}
|
||||
onCancelScheduled={isScheduledView ? undefined : () => onCancelScheduled?.(contextMenu.data!)}
|
||||
onCancelScheduledForEdit={isScheduledView ? undefined : () => onCancelScheduledForEdit?.(contextMenu.data!)}
|
||||
onCancelScheduled={() => onCancelScheduled?.(contextMenu.data!)}
|
||||
onCancelScheduledForEdit={() => onCancelScheduledForEdit?.(contextMenu.data!)}
|
||||
onRescheduleScheduled={undefined}
|
||||
onBatchMarkAsRead={(read) => client && batchMarkAsRead(client, read)}
|
||||
onBatchDelete={() => client && batchDelete(client)}
|
||||
|
||||
@@ -39,7 +39,7 @@ export function ProComposeTabBody({ tabId, data }: ProComposeTabBodyProps) {
|
||||
const handleSend = useCallback(async (sendData: Parameters<NonNullable<React.ComponentProps<typeof EmailComposer>['onSend']>>[0]) => {
|
||||
if (!client) return;
|
||||
try {
|
||||
await sendEmail(
|
||||
const result = await sendEmail(
|
||||
client,
|
||||
sendData.to,
|
||||
sendData.subject,
|
||||
@@ -58,6 +58,11 @@ export function ProComposeTabBody({ tabId, data }: ProComposeTabBodyProps) {
|
||||
sendData.envelopeMailFrom,
|
||||
);
|
||||
|
||||
if (result.scheduled) {
|
||||
closeTab(tabIdRef.current);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark the original message as $answered / $forwarded so the standard
|
||||
// viewer and list reflect the action (same behaviour as inline compose).
|
||||
if (data.sourceEmailId && (data.mode === 'reply' || data.mode === 'replyAll')) {
|
||||
|
||||
@@ -2606,7 +2606,13 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
||||
|
||||
cancelUndoSend: async (client, pending) => {
|
||||
await client.cancelEmailSubmission(pending.submissionId);
|
||||
if (pending.emailId && !pending.isSmime) {
|
||||
if (pending.emailId && pending.isSmime) {
|
||||
await client.deleteEmail(pending.emailId);
|
||||
set(state => ({
|
||||
selectedEmail: state.selectedEmail?.id === pending.emailId ? null : state.selectedEmail,
|
||||
selectedEmailIds: new Set(Array.from(state.selectedEmailIds).filter(id => id !== pending.emailId)),
|
||||
}));
|
||||
} else if (pending.emailId) {
|
||||
const mailboxes = get().mailboxes.length > 0 ? get().mailboxes : await client.getMailboxes();
|
||||
const draftsMailbox = mailboxes.find(mb => mb.role === 'drafts');
|
||||
const sentMailbox = mailboxes.find(mb => mb.role === 'sent');
|
||||
@@ -2616,7 +2622,7 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
||||
}
|
||||
await get().refreshScheduledMetadata(client);
|
||||
set({ pendingUndoSend: null });
|
||||
return pending.emailId ? client.getEmail(pending.emailId) : null;
|
||||
return pending.emailId && !pending.isSmime ? client.getEmail(pending.emailId) : null;
|
||||
},
|
||||
|
||||
loadMockData: () => {
|
||||
|
||||
Reference in New Issue
Block a user