feat: Add email alerts tab to settings
Introduces a new tab in the settings section dedicated to configuring email alerts. This allows administrators to manage automatic email notifications for various events within the Condopay application.
This commit is contained in:
@@ -473,7 +473,7 @@ export const SettingsPage: React.FC = () => {
|
||||
{ id: 'users', label: 'Utenti', icon: <UserCog className="w-4 h-4"/> },
|
||||
{ id: 'notices', label: 'Bacheca', icon: <Megaphone className="w-4 h-4"/> },
|
||||
{ id: 'alerts', label: 'Avvisi Email', icon: <Bell className="w-4 h-4"/> },
|
||||
{ id: 'smtp', label: 'Impostazioni Posta', icon: <Mail className="w-4 h-4"/> }
|
||||
{ id: 'smtp', label: 'SMTP', icon: <Mail className="w-4 h-4"/> }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -741,6 +741,54 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ALERTS TAB */}
|
||||
{isAdmin && activeTab === 'alerts' && (
|
||||
<div className="space-y-4 animate-fade-in">
|
||||
<div className="flex justify-between items-center bg-blue-50 p-4 rounded-xl border border-blue-100">
|
||||
<div><h3 className="font-bold text-blue-800">Avvisi Automatici</h3><p className="text-sm text-blue-600">Configura email automatiche per scadenze.</p></div>
|
||||
<button onClick={openAddAlertModal} className="bg-blue-600 text-white px-4 py-2 rounded-lg font-medium flex items-center gap-2"><Plus className="w-4 h-4" /> Nuovo Avviso</button>
|
||||
</div>
|
||||
<div className="grid gap-4">
|
||||
{alerts.map(alert => (
|
||||
<div key={alert.id} className="bg-white p-5 rounded-xl border border-slate-200 shadow-sm relative">
|
||||
<h4 className="font-bold text-slate-800">{alert.subject}</h4>
|
||||
<p className="text-sm text-slate-600 mt-1">{alert.body}</p>
|
||||
<div className="mt-3 flex gap-2 text-xs font-bold text-slate-500 uppercase">
|
||||
<span className="bg-slate-100 px-2 py-1 rounded">Offset: {alert.daysOffset} giorni ({alert.offsetType})</span>
|
||||
<span className="bg-slate-100 px-2 py-1 rounded">Ore: {alert.sendHour}:00</span>
|
||||
<span className={`px-2 py-1 rounded ${alert.active ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>{alert.active ? 'Attivo' : 'Inattivo'}</span>
|
||||
</div>
|
||||
<div className="mt-4 pt-3 border-t border-slate-100 flex justify-end gap-2">
|
||||
<button onClick={() => openEditAlertModal(alert)} className="text-blue-600 text-sm font-medium">Modifica</button>
|
||||
<button onClick={() => handleDeleteAlert(alert.id)} className="text-red-600 text-sm font-medium">Elimina</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{alerts.length === 0 && <div className="text-center p-8 text-slate-400">Nessun alert configurato.</div>}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* SMTP TAB */}
|
||||
{isAdmin && activeTab === 'smtp' && (
|
||||
<div className="animate-fade-in bg-white rounded-xl shadow-sm border border-slate-200 p-6 max-w-2xl">
|
||||
<h3 className="text-lg font-bold text-slate-800 mb-6 flex items-center gap-2"><Server className="w-5 h-5 text-blue-600"/> Configurazione SMTP</h3>
|
||||
<form onSubmit={handleSmtpSubmit} className="space-y-5">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div><label className="text-sm font-bold text-slate-700">Host</label><input type="text" value={globalSettings?.smtpConfig?.host || ''} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), host: e.target.value} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
|
||||
<div><label className="text-sm font-bold text-slate-700">Porta</label><input type="number" value={globalSettings?.smtpConfig?.port || 0} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), port: parseInt(e.target.value)} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div><label className="text-sm font-bold text-slate-700">Utente</label><input type="text" value={globalSettings?.smtpConfig?.user || ''} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), user: e.target.value} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
|
||||
<div><label className="text-sm font-bold text-slate-700">Password</label><input type="password" value={globalSettings?.smtpConfig?.pass || ''} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), pass: e.target.value} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
|
||||
</div>
|
||||
<div><label className="text-sm font-bold text-slate-700">Email Mittente</label><input type="email" value={globalSettings?.smtpConfig?.fromEmail || ''} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), fromEmail: e.target.value} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
|
||||
<div className="flex items-center gap-2"><input type="checkbox" checked={globalSettings?.smtpConfig?.secure || false} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), secure: e.target.checked} as any} : null)} className="w-4 h-4"/><label className="text-sm text-slate-700">Usa SSL/TLS (Secure)</label></div>
|
||||
<div className="pt-2 flex justify-between"><span className="text-green-600">{successMsg}</span><button type="submit" className="bg-blue-600 text-white px-6 py-2.5 rounded-lg hover:bg-blue-700">Salva Configurazione</button></div>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ALERT MODAL */}
|
||||
{showAlertModal && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
@@ -778,6 +826,48 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* NOTICE MODAL */}
|
||||
{showNoticeModal && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-lg p-6 animate-in fade-in zoom-in duration-200">
|
||||
<h3 className="font-bold text-lg mb-4 text-slate-800">{editingNotice ? 'Modifica Avviso' : 'Nuovo Avviso'}</h3>
|
||||
<form onSubmit={handleNoticeSubmit} className="space-y-4">
|
||||
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Titolo" value={noticeForm.title} onChange={e => setNoticeForm({...noticeForm, title: e.target.value})} required />
|
||||
<textarea className="w-full border p-2.5 rounded-lg text-slate-700 h-24" placeholder="Contenuto avviso..." value={noticeForm.content} onChange={e => setNoticeForm({...noticeForm, content: e.target.value})} required />
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500 font-bold uppercase mb-1 block">Tipo</label>
|
||||
<select className="w-full border p-2.5 rounded-lg text-slate-700 bg-white" value={noticeForm.type} onChange={e => setNoticeForm({...noticeForm, type: e.target.value as any})}>
|
||||
<option value="info">Info</option>
|
||||
<option value="warning">Avviso</option>
|
||||
<option value="maintenance">Manutenzione</option>
|
||||
<option value="event">Evento</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500 font-bold uppercase mb-1 block">Stato</label>
|
||||
<select className="w-full border p-2.5 rounded-lg text-slate-700 bg-white" value={noticeForm.active ? 'true' : 'false'} onChange={e => setNoticeForm({...noticeForm, active: e.target.value === 'true'})}>
|
||||
<option value="true">Attivo</option>
|
||||
<option value="false">Bozza / Nascosto</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-xs text-slate-500 font-bold uppercase mb-1 block">Link Esterno (Opzionale)</label>
|
||||
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="https://..." value={noticeForm.link} onChange={e => setNoticeForm({...noticeForm, link: e.target.value})} />
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 pt-2">
|
||||
<button type="button" onClick={() => setShowNoticeModal(false)} className="flex-1 border p-2.5 rounded-lg text-slate-600 hover:bg-slate-50">Annulla</button>
|
||||
<button type="submit" className="flex-1 bg-blue-600 text-white p-2.5 rounded-lg hover:bg-blue-700">Salva</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* READ DETAILS MODAL */}
|
||||
{showReadDetailsModal && selectedNoticeId && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
|
||||
Reference in New Issue
Block a user