From b75d064f20e309097470e9476bb6816c865b5943 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:38:11 +0100 Subject: [PATCH] feat: add plain text only setting for email composer #105 --- app/admin/policy/page.tsx | 1 + components/email/email-composer.tsx | 105 ++++++++++++++++++------- components/settings/email-settings.tsx | 9 +++ locales/de/common.json | 4 + locales/en/common.json | 4 + locales/es/common.json | 4 + locales/fr/common.json | 4 + locales/it/common.json | 4 + locales/ja/common.json | 4 + locales/nl/common.json | 4 + locales/pt/common.json | 4 + locales/ru/common.json | 4 + stores/settings-store.ts | 3 + 13 files changed, 125 insertions(+), 29 deletions(-) diff --git a/app/admin/policy/page.tsx b/app/admin/policy/page.tsx index 24b1744a..427e4cc1 100644 --- a/app/admin/policy/page.tsx +++ b/app/admin/policy/page.tsx @@ -32,6 +32,7 @@ const RESTRICTABLE_SETTINGS = [ { key: 'externalContentPolicy', label: 'External Content Policy', category: 'Email', type: 'enum', allowedValues: ['allow', 'block', 'ask'] }, { key: 'sendConfirmation', label: 'Send Confirmation', category: 'Composer', type: 'boolean' }, { key: 'defaultReplyMode', label: 'Default Reply Mode', category: 'Composer', type: 'enum', allowedValues: ['reply', 'reply-all'] }, + { key: 'plainTextMode', label: 'Plain Text Only', category: 'Composer', type: 'boolean' }, { key: 'sessionTimeout', label: 'Session Timeout', category: 'Privacy', type: 'number' }, { key: 'emailNotificationsEnabled', label: 'Email Notifications', category: 'Notifications', type: 'boolean' }, { key: 'calendarNotificationsEnabled', label: 'Calendar Notifications', category: 'Notifications', type: 'boolean' }, diff --git a/components/email/email-composer.tsx b/components/email/email-composer.tsx index 5de479d8..5a452745 100644 --- a/components/email/email-composer.tsx +++ b/components/email/email-composer.tsx @@ -99,6 +99,7 @@ export function EmailComposer({ const t = useTranslations('email_composer'); const tCommon = useTranslations('common'); const timeFormat = useSettingsStore((state) => state.timeFormat); + const plainTextMode = useSettingsStore((state) => state.plainTextMode); // Initialize with reply/forward data if provided const getInitialTo = () => { @@ -134,6 +135,26 @@ export function EmailComposer({ }; const getInitialBody = () => { + if (plainTextMode) { + // Plain text mode: produce plain text body with no HTML + const prefix = initialDraftText || ""; + if (!replyTo?.body && !replyTo?.htmlBody) return prefix; + + const date = replyTo.receivedAt ? formatDateTime(replyTo.receivedAt, timeFormat, { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' }) : ""; + const from = replyTo.from?.[0]; + const fromStr = from ? `${from.name || from.email}` : tCommon('unknown'); + + const originalText = replyTo.body || (replyTo.htmlBody ? htmlToPlainText(replyTo.htmlBody) : ''); + const quotedText = originalText.split('\n').map(line => `> ${line}`).join('\n'); + + if (mode === 'forward') { + return `${prefix}\n\n---------- Forwarded message ----------\nFrom: ${fromStr}\nDate: ${date}\nSubject: ${replyTo.subject || ''}\n\n${originalText}`; + } else if (mode === 'reply' || mode === 'replyAll') { + return `${prefix}\n\nOn ${date}, ${fromStr} wrote:\n${quotedText}`; + } + return prefix; + } + const prefix = initialDraftText ? `
${initialDraftText.replace(/&/g, '&').replace(//g, '>').replace(/\n/g, '
')}
${filledBody.replace(/&/g, '&').replace(//g, '>').replace(/\n/g, '
')}
${filledBody.replace(/&/g, '&').replace(//g, '>').replace(/\n/g, '
')}