ooo containing html
This commit is contained in:
@@ -13,6 +13,14 @@ const TABS = [
|
||||
{ id: 'block', label: 'Blocklist', icon: FiSlash },
|
||||
];
|
||||
|
||||
const emptyRule = (email) => ({
|
||||
email_address: email,
|
||||
ooo_active: false,
|
||||
ooo_message: '',
|
||||
ooo_content_type: 'text',
|
||||
forwards: [],
|
||||
});
|
||||
|
||||
const MailboxSettingsModal = ({ open, email, initialTab = 'fwd', onClose, onToast }) => {
|
||||
const [activeTab, setActiveTab] = useState(initialTab);
|
||||
const [rule, setRule] = useState(null);
|
||||
@@ -29,15 +37,13 @@ const MailboxSettingsModal = ({ open, email, initialTab = 'fwd', onClose, onToas
|
||||
setLoading(true);
|
||||
try {
|
||||
const [r, b] = await Promise.all([
|
||||
mailboxesAPI.getRules(email).catch(() => ({
|
||||
email_address: email, ooo_active: false, ooo_message: '', forwards: [],
|
||||
})),
|
||||
mailboxesAPI.getRules(email).catch(() => emptyRule(email)),
|
||||
mailboxesAPI.getBlocklist(email).catch(() => ({
|
||||
email_address: email, blocked_patterns: [],
|
||||
})),
|
||||
]);
|
||||
if (cancelled) return;
|
||||
setRule(r || { email_address: email, ooo_active: false, ooo_message: '', forwards: [] });
|
||||
setRule(r ? { ...emptyRule(email), ...r } : emptyRule(email));
|
||||
setBlocklist(b || { email_address: email, blocked_patterns: [] });
|
||||
} catch (err) {
|
||||
if (!cancelled) onToast?.(`Failed to load settings: ${err.message}`, 'error');
|
||||
@@ -50,10 +56,12 @@ const MailboxSettingsModal = ({ open, email, initialTab = 'fwd', onClose, onToas
|
||||
|
||||
// Merge updates with existing rule and persist.
|
||||
const saveRule = async (updates) => {
|
||||
const base = rule || emptyRule(email);
|
||||
const merged = {
|
||||
ooo_active: rule?.ooo_active ?? false,
|
||||
ooo_message: rule?.ooo_message ?? '',
|
||||
forwards: rule?.forwards ?? [],
|
||||
ooo_active: base.ooo_active ?? false,
|
||||
ooo_message: base.ooo_message ?? '',
|
||||
ooo_content_type: base.ooo_content_type ?? 'text',
|
||||
forwards: base.forwards ?? [],
|
||||
...updates,
|
||||
};
|
||||
try {
|
||||
@@ -127,4 +135,4 @@ const MailboxSettingsModal = ({ open, email, initialTab = 'fwd', onClose, onToas
|
||||
);
|
||||
};
|
||||
|
||||
export default MailboxSettingsModal;
|
||||
export default MailboxSettingsModal;
|
||||
@@ -1,15 +1,22 @@
|
||||
import React, { useState } from 'react';
|
||||
import { FiCalendar } from 'react-icons/fi';
|
||||
import { FiCalendar, FiFileText } from 'react-icons/fi';
|
||||
|
||||
const OutOfOffice = ({ rule, onSave }) => {
|
||||
const [isActive, setIsActive] = useState(rule?.ooo_active || false);
|
||||
const [message, setMessage] = useState(rule?.ooo_message || '');
|
||||
const [contentType, setContentType] = useState(
|
||||
rule?.ooo_content_type === 'html' ? 'html' : 'text'
|
||||
);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const handleSave = async () => {
|
||||
setIsSaving(true);
|
||||
try {
|
||||
await onSave({ ooo_active: isActive, ooo_message: message });
|
||||
await onSave({
|
||||
ooo_active: isActive,
|
||||
ooo_message: message,
|
||||
ooo_content_type: contentType,
|
||||
});
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
@@ -17,6 +24,7 @@ const OutOfOffice = ({ rule, onSave }) => {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Toggle Active/Inactive */}
|
||||
<div className="flex items-center justify-between p-4 bg-gray-50 rounded-lg border border-gray-200">
|
||||
<div className="flex items-center gap-3">
|
||||
<FiCalendar className="w-5 h-5 text-gray-600" />
|
||||
@@ -43,6 +51,40 @@ const OutOfOffice = ({ rule, onSave }) => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Content Type Selector */}
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">
|
||||
Message Format
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setContentType('text')}
|
||||
className={`flex-1 px-4 py-2 rounded-lg border-2 transition-all ${
|
||||
contentType === 'text'
|
||||
? 'border-primary-600 bg-primary-50 text-primary-700 font-semibold'
|
||||
: 'border-gray-300 bg-white text-gray-700 hover:border-gray-400'
|
||||
}`}
|
||||
>
|
||||
<FiFileText className="inline w-4 h-4 mr-2" />
|
||||
Plain Text
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setContentType('html')}
|
||||
className={`flex-1 px-4 py-2 rounded-lg border-2 transition-all ${
|
||||
contentType === 'html'
|
||||
? 'border-primary-600 bg-primary-50 text-primary-700 font-semibold'
|
||||
: 'border-gray-300 bg-white text-gray-700 hover:border-gray-400'
|
||||
}`}
|
||||
>
|
||||
<span className="font-mono text-sm mr-2"></></span>
|
||||
HTML
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Message Editor */}
|
||||
<div>
|
||||
<label htmlFor="ooo-message" className="block text-sm font-semibold text-gray-700 mb-2">
|
||||
Auto-Reply Message
|
||||
@@ -52,22 +94,36 @@ const OutOfOffice = ({ rule, onSave }) => {
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
rows={8}
|
||||
placeholder="I am currently out of office until [date]. Best regards, Your Name"
|
||||
placeholder={
|
||||
contentType === 'html'
|
||||
? '<p>I am currently out of office until [date].</p>\n<p>Best regards,<br>Your Name</p>'
|
||||
: 'I am currently out of office until [date].\n\nBest regards,\nYour Name'
|
||||
}
|
||||
className="input-field font-mono text-sm resize-none"
|
||||
disabled={!isActive}
|
||||
/>
|
||||
<p className="mt-2 text-xs text-gray-500">
|
||||
Plain text message that gets returned automatically to senders.
|
||||
{contentType === 'html'
|
||||
? 'You can use HTML tags for formatting. The reply will be sent as text/html.'
|
||||
: 'Plain text message that gets returned automatically to senders.'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Message Preview */}
|
||||
{isActive && message && (
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">
|
||||
Message Preview
|
||||
</label>
|
||||
<div className="p-4 bg-gray-50 border border-gray-200 rounded-lg">
|
||||
<pre className="text-sm text-gray-800 whitespace-pre-wrap font-sans">{message}</pre>
|
||||
{contentType === 'html' ? (
|
||||
<div
|
||||
className="prose prose-sm max-w-none text-sm text-gray-800"
|
||||
dangerouslySetInnerHTML={{ __html: message }}
|
||||
/>
|
||||
) : (
|
||||
<pre className="text-sm text-gray-800 whitespace-pre-wrap font-sans">{message}</pre>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -85,4 +141,4 @@ const OutOfOffice = ({ rule, onSave }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default OutOfOffice;
|
||||
export default OutOfOffice;
|
||||
Reference in New Issue
Block a user