import { useState, useEffect, useRef, useCallback } from 'react'; import { api } from '../../api.js'; import { useAuth } from '../../context/AuthContext.jsx'; /* ── Icône œil (show/hide password) ───────────────────────────────────── */ function IconEye({ open }) { return open ? : ; } /* ── Toggle switch ─────────────────────────────────────────────────────── */ function Toggle({ checked, onChange, id }) { return ( ); } /* ── Ligne de paramètre ────────────────────────────────────────────────── */ function SettingRow({ label, description, children }) { return (
{label}
{description &&
{description}
}
{children}
); } const DEFAULT_STATE = { enabled: false, host: '', port: 587, secure: false, email: '', username: '', password: '', allowUnauth: false, }; export default function SmtpSection() { const { user } = useAuth(); const [form, setForm] = useState(DEFAULT_STATE); const [hasPassword, setHasPassword] = useState(false); const [showPassword, setShowPassword] = useState(false); const passwordTyped = useRef(false); // true uniquement si l'utilisateur a tapé manuellement const [testEmail, setTestEmail] = useState(user?.email || ''); const [result, setResult] = useState(null); // { ok, msg } const [testResult, setTestResult] = useState(null); const [loading, setLoading] = useState(false); const [testing, setTesting] = useState(false); const [loadingEnv, setLoadingEnv] = useState(false); const [saveStatus, setSaveStatus] = useState(null); // 'saving' | 'saved' | 'error' const debounceRef = useRef(null); const isFirstLoad = useRef(true); const hasPasswordRef = useRef(false); useEffect(() => { api.get('/admin/smtp').then(data => { setForm({ enabled: !!data.enabled, host: data.host || '', port: data.port || 587, secure: !!data.secure, email: data.email || '', username: data.username || '', password: '', allowUnauth: !!data.allowUnauth, }); setHasPassword(!!data.hasPassword); hasPasswordRef.current = !!data.hasPassword; }); }, []); const doSave = useCallback(async (currentForm) => { setSaveStatus('saving'); try { const payload = { ...currentForm }; // N'envoyer le mot de passe que si l'utilisateur l'a tapé manuellement if (!payload.password || !passwordTyped.current) delete payload.password; await api.put('/admin/smtp', payload); if (payload.password) { setHasPassword(true); hasPasswordRef.current = true; } setSaveStatus('saved'); setTimeout(() => setSaveStatus(null), 2500); } catch (e) { setSaveStatus('error'); setResult({ ok: false, msg: e.message || 'Erreur lors de la sauvegarde.' }); } }, []); const set = (key, value) => { setForm(f => { const next = { ...f, [key]: value }; // Ne pas déclencher l'auto-save au chargement initial if (isFirstLoad.current) { isFirstLoad.current = false; return next; } clearTimeout(debounceRef.current); debounceRef.current = setTimeout(() => doSave(next), 1500); return next; }); }; // Nettoyage du timer au démontage useEffect(() => () => clearTimeout(debounceRef.current), []); const handleTest = async () => { if (!testEmail) return; setTesting(true); setTestResult(null); try { const data = await api.post('/admin/smtp/test', { to: testEmail }); setTestResult({ ok: data.ok, msg: data.msg }); } catch (e) { setTestResult({ ok: false, msg: e.message || 'Erreur lors du test.' }); } finally { setTesting(false); } }; const handleLoadEnv = async () => { setLoadingEnv(true); try { const data = await api.get('/admin/smtp/env'); setForm(f => { const next = { ...f, host: data.host || f.host, port: data.port || f.port, email: data.email || f.email, username: data.username || f.username, password: '', }; clearTimeout(debounceRef.current); debounceRef.current = setTimeout(() => doSave(next), 1500); return next; }); if (data.hasPassword) { setHasPassword(true); hasPasswordRef.current = true; } } catch (e) { setResult({ ok: false, msg: 'Impossible de charger les valeurs .env.' }); } finally { setLoadingEnv(false); } }; return (

SMTP

{saveStatus === 'saving' && ( Sauvegarde… )} {saveStatus === 'saved' && ( ✓ Sauvegardé )} {saveStatus === 'error' && ( Erreur )}

Configuration du serveur de messagerie sortant. Utilisée pour les alertes, rapports et réinitialisation de mot de passe.

{result && (
{result.msg}
)}
{/* Activer */} set('enabled', v)} /> {/* Hôte */} set('host', e.target.value)} placeholder="smtp.example.com" style={{ width: 280 }} /> {/* Port */} set('port', parseInt(e.target.value, 10) || 587)} min={1} max={65535} style={{ width: 120 }} /> {/* Connexion sécurisée (TLS) */} set('secure', v)} /> {/* Courriel */} set('email', e.target.value)} placeholder="no-reply@example.com" style={{ width: 280 }} /> {/* Nom d'utilisateur */} set('username', e.target.value)} placeholder="user@example.com" autoComplete="off" style={{ width: 280 }} /> {/* Mot de passe */}
{ passwordTyped.current = true; set('password', e.target.value); }} placeholder={hasPassword ? '••••••••' : 'Mot de passe'} autoComplete="new-password" style={{ width: '100%', paddingRight: 36 }} />
{/* Certificats non autorisés */} set('allowUnauth', v)} />
{/* Section email de test */}

Envoyer un email de test

Vérifiez que votre configuration SMTP fonctionne en envoyant un email de test. Sauvegardez d'abord vos paramètres.

{testResult && (
{testResult.msg}
)}
setTestEmail(e.target.value)} placeholder="destinataire@example.com" style={{ flex: 1, maxWidth: 320 }} onKeyDown={e => e.key === 'Enter' && handleTest()} />
); }