138 lines
4.6 KiB
JavaScript
138 lines
4.6 KiB
JavaScript
import React, { useEffect, useState } from 'react';
|
|
import { FiCornerUpRight, FiCalendar, FiSlash } from 'react-icons/fi';
|
|
import Modal from './Modal';
|
|
import LoadingOverlay from './LoadingOverlay';
|
|
import Forwarding from './Forwarding';
|
|
import OutOfOffice from './OutOfOffice';
|
|
import BlockedSenders from './BlockedSenders';
|
|
import { mailboxesAPI } from '../services/api';
|
|
|
|
const TABS = [
|
|
{ id: 'fwd', label: 'Forwarding', icon: FiCornerUpRight },
|
|
{ id: 'ooo', label: 'Out of Office', icon: FiCalendar },
|
|
{ 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);
|
|
const [blocklist, setBlocklist] = useState(null);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => { setActiveTab(initialTab); }, [initialTab, email]);
|
|
|
|
// Load both /rules and /blocklist in parallel when the modal opens.
|
|
useEffect(() => {
|
|
if (!open || !email) return;
|
|
let cancelled = false;
|
|
(async () => {
|
|
setLoading(true);
|
|
try {
|
|
const [r, b] = await Promise.all([
|
|
mailboxesAPI.getRules(email).catch(() => emptyRule(email)),
|
|
mailboxesAPI.getBlocklist(email).catch(() => ({
|
|
email_address: email, blocked_patterns: [],
|
|
})),
|
|
]);
|
|
if (cancelled) return;
|
|
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');
|
|
} finally {
|
|
if (!cancelled) setLoading(false);
|
|
}
|
|
})();
|
|
return () => { cancelled = true; };
|
|
}, [open, email, onToast]);
|
|
|
|
// Merge updates with existing rule and persist.
|
|
const saveRule = async (updates) => {
|
|
const base = rule || emptyRule(email);
|
|
const merged = {
|
|
ooo_active: base.ooo_active ?? false,
|
|
ooo_message: base.ooo_message ?? '',
|
|
ooo_content_type: base.ooo_content_type ?? 'text',
|
|
forwards: base.forwards ?? [],
|
|
...updates,
|
|
};
|
|
try {
|
|
const saved = await mailboxesAPI.putRules(email, merged);
|
|
setRule({ email_address: email, ...merged, ...saved });
|
|
onToast?.('Rule saved', 'success');
|
|
} catch (err) {
|
|
onToast?.(`Failed to save: ${err.message}`, 'error');
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
const saveBlocklist = async (patterns) => {
|
|
try {
|
|
const saved = await mailboxesAPI.putBlocklist(email, patterns);
|
|
setBlocklist({ email_address: email, blocked_patterns: patterns, ...saved });
|
|
onToast?.('Block list saved', 'success');
|
|
} catch (err) {
|
|
onToast?.(`Failed to save: ${err.message}`, 'error');
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Modal
|
|
open={open}
|
|
onClose={onClose}
|
|
title={email || 'Mailbox settings'}
|
|
subtitle="Forwarding, auto-reply and blocklist"
|
|
size="md"
|
|
>
|
|
<div className="relative min-h-[400px]">
|
|
{/* Tabs */}
|
|
<div className="border-b border-gray-200 mb-6">
|
|
<div className="flex gap-1">
|
|
{TABS.map((t) => {
|
|
const Icon = t.icon;
|
|
const isActive = activeTab === t.id;
|
|
return (
|
|
<button
|
|
key={t.id}
|
|
onClick={() => setActiveTab(t.id)}
|
|
className={`flex items-center gap-2 px-4 py-3 text-sm font-medium transition-colors ${
|
|
isActive
|
|
? 'border-b-2 border-primary-600 text-primary-700 -mb-px'
|
|
: 'border-b-2 border-transparent text-gray-600 hover:text-gray-900 hover:border-gray-300'
|
|
}`}
|
|
>
|
|
<Icon className="w-4 h-4" />
|
|
{t.label}
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
{loading || !rule || !blocklist ? (
|
|
<div className="py-16 flex items-center justify-center">
|
|
<LoadingOverlay message="Loading settings..." />
|
|
</div>
|
|
) : (
|
|
<>
|
|
{activeTab === 'fwd' && <Forwarding rule={rule} onSave={saveRule} />}
|
|
{activeTab === 'ooo' && <OutOfOffice rule={rule} onSave={saveRule} />}
|
|
{activeTab === 'block' && <BlockedSenders blocklist={blocklist} onSave={saveBlocklist} />}
|
|
</>
|
|
)}
|
|
</div>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
export default MailboxSettingsModal; |