import React, { useEffect, useState } from 'react'; import { CondoService } from '../services/mockDb'; import { AppSettings, Family, User, AlertDefinition, Condo, Notice, NoticeIconType, NoticeRead } from '../types'; import { Save, Building, Coins, Plus, Pencil, Trash2, X, CalendarCheck, AlertTriangle, User as UserIcon, Server, Bell, Clock, FileText, Lock, Megaphone, CheckCircle2, Info, Hammer, Link as LinkIcon, Eye, Calendar, List, UserCog, Mail, Power, MapPin, CreditCard, ToggleLeft, ToggleRight, LayoutGrid, PieChart, Users, Send, Cloud, HardDrive, ChevronRight } from 'lucide-react'; export const SettingsPage: React.FC = () => { const currentUser = CondoService.getCurrentUser(); const isSuperAdmin = currentUser?.role === 'admin'; const isPrivileged = currentUser?.role === 'admin' || currentUser?.role === 'poweruser'; // Tab configuration type TabType = 'profile' | 'features' | 'general' | 'storage' | 'condos' | 'families' | 'users' | 'notices' | 'alerts'; const [activeTab, setActiveTab] = useState(isPrivileged ? 'general' : 'profile'); const [loading, setLoading] = useState(true); // Profile State const [profileForm, setProfileForm] = useState({ name: currentUser?.name || '', phone: currentUser?.phone || '', password: '', receiveAlerts: currentUser?.receiveAlerts ?? true }); const [profileSaving, setProfileSaving] = useState(false); const [profileMsg, setProfileMsg] = useState(''); // General Settings State const [activeCondo, setActiveCondo] = useState(undefined); const [globalSettings, setGlobalSettings] = useState(null); // Condos Management State const [condos, setCondos] = useState([]); const [showCondoModal, setShowCondoModal] = useState(false); const [editingCondo, setEditingCondo] = useState(null); const [condoForm, setCondoForm] = useState({ name: '', address: '', streetNumber: '', city: '', province: '', zipCode: '', notes: '', paypalClientId: '', defaultMonthlyQuota: 100, dueDay: 10 }); const [saving, setSaving] = useState(false); const [successMsg, setSuccessMsg] = useState(''); // Families State const [families, setFamilies] = useState([]); const [showFamilyModal, setShowFamilyModal] = useState(false); const [editingFamily, setEditingFamily] = useState(null); const [familyForm, setFamilyForm] = useState<{ name: string; unitNumber: string; stair: string; floor: string; notes: string; contactEmail: string; customMonthlyQuota: string; }>({ name: '', unitNumber: '', stair: '', floor: '', notes: '', contactEmail: '', customMonthlyQuota: '' }); // Users State const [users, setUsers] = useState([]); const [showUserModal, setShowUserModal] = useState(false); const [editingUser, setEditingUser] = useState(null); const [userForm, setUserForm] = useState({ name: '', email: '', password: '', phone: '', role: 'user', familyId: '', receiveAlerts: true }); // Alerts State const [alerts, setAlerts] = useState([]); const [showAlertModal, setShowAlertModal] = useState(false); const [editingAlert, setEditingAlert] = useState(null); const [alertForm, setAlertForm] = useState>({ subject: '', body: '', daysOffset: 1, offsetType: 'before_next_month', sendHour: 9, active: true }); // SMTP Modal State const [showSmtpModal, setShowSmtpModal] = useState(false); const [testingSmtp, setTestingSmtp] = useState(false); const [testSmtpMsg, setTestSmtpMsg] = useState(''); // Notices (Bacheca) State const [notices, setNotices] = useState([]); const [showNoticeModal, setShowNoticeModal] = useState(false); const [editingNotice, setEditingNotice] = useState(null); const [noticeTargetMode, setNoticeTargetMode] = useState<'all' | 'specific'>('all'); const [noticeForm, setNoticeForm] = useState<{ title: string; content: string; type: NoticeIconType; link: string; condoId: string; active: boolean; targetFamilyIds: string[]; }>({ title: '', content: '', type: 'info', link: '', condoId: '', active: true, targetFamilyIds: [] }); const [noticeReadStats, setNoticeReadStats] = useState>({}); // Notice Details Modal const [showReadDetailsModal, setShowReadDetailsModal] = useState(false); const [selectedNoticeId, setSelectedNoticeId] = useState(null); useEffect(() => { const fetchData = async () => { try { if (isPrivileged) { // First fetch global/structural data const condoList = await CondoService.getCondos(); const activeC = await CondoService.getActiveCondo(); const gSettings = await CondoService.getSettings(); // Ensure storageConfig exists locally even if API missed it if (!gSettings.storageConfig) { gSettings.storageConfig = { provider: 'local_db' }; } setCondos(condoList); setActiveCondo(activeC); setGlobalSettings(gSettings); // Fetch condo-specific data individually to prevent one failure from blocking others if (activeC) { // Families try { const fams = await CondoService.getFamilies(activeC.id); setFamilies(fams); } catch(e) { console.error("Error fetching families", e); } // Users try { const usrs = await CondoService.getUsers(activeC.id); setUsers(usrs); } catch(e) { console.error("Error fetching users", e); } // Alerts try { const alrts = await CondoService.getAlerts(activeC.id); setAlerts(alrts); } catch(e) { console.error("Error fetching alerts", e); } // Notices try { const allNotices = await CondoService.getNotices(activeC.id); setNotices(allNotices); // Fetch read stats for notices const stats: Record = {}; for (const n of allNotices) { try { const reads = await CondoService.getNoticeReadStatus(n.id); stats[n.id] = reads; } catch(e) { console.warn("Error reading notice status", e); } } setNoticeReadStats(stats); } catch(e) { console.error("Error fetching notices", e); } } else { setFamilies([]); setUsers([]); setAlerts([]); setNotices([]); } } else { const activeC = await CondoService.getActiveCondo(); setActiveCondo(activeC); } } catch(e) { console.error("Global fetch error", e); } finally { setLoading(false); } }; fetchData(); }, [isPrivileged]); // --- HANDLERS (Omitted details for brevity as they are unchanged) --- const handleProfileSubmit = async (e: React.FormEvent) => { e.preventDefault(); setProfileSaving(true); setProfileMsg(''); try { await CondoService.updateProfile(profileForm); setProfileMsg('Profilo aggiornato con successo!'); setTimeout(() => setProfileMsg(''), 3000); setProfileForm(prev => ({ ...prev, password: '' })); } catch (e) { setProfileMsg('Errore aggiornamento profilo'); } finally { setProfileSaving(false); } }; const handleGeneralSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!activeCondo) return; setSaving(true); setSuccessMsg(''); try { await CondoService.saveCondo(activeCondo); setSuccessMsg('Dati condominio aggiornati!'); setTimeout(() => setSuccessMsg(''), 3000); const list = await CondoService.getCondos(); setCondos(list); } catch (e) { console.error(e); } finally { setSaving(false); } }; const handleFeaturesSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!globalSettings) return; setSaving(true); try { await CondoService.updateSettings(globalSettings); setSuccessMsg('Configurazione salvata!'); setTimeout(() => setSuccessMsg(''), 3000); window.location.reload(); } catch(e) { console.error(e); } finally { setSaving(false); } }; const handleSmtpSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!globalSettings) return; setSaving(true); try { await CondoService.updateSettings(globalSettings); setSuccessMsg('Configurazione SMTP salvata!'); setTimeout(() => { setSuccessMsg(''); setShowSmtpModal(false); }, 2000); } catch (e) { console.error(e); } finally { setSaving(false); } }; const handleSmtpTest = async () => { if (!globalSettings?.smtpConfig) return; setTestingSmtp(true); setTestSmtpMsg(''); try { await CondoService.testSmtpConfig(globalSettings.smtpConfig); setTestSmtpMsg('Successo! Email di prova inviata.'); } catch(e: any) { setTestSmtpMsg('Errore: ' + (e.message || "Impossibile connettersi")); } finally { setTestingSmtp(false); } }; const handleStorageSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!globalSettings) return; setSaving(true); try { await CondoService.updateSettings(globalSettings); setSuccessMsg('Configurazione Storage salvata!'); setTimeout(() => setSuccessMsg(''), 3000); } catch (e) { console.error(e); } finally { setSaving(false); } }; const handleNewYear = async () => { if (!globalSettings) return; const nextYear = globalSettings.currentYear + 1; if (window.confirm(`Sei sicuro di voler chiudere l'anno ${globalSettings.currentYear} e aprire il ${nextYear}?`)) { setSaving(true); try { const newSettings = { ...globalSettings, currentYear: nextYear }; await CondoService.updateSettings(newSettings); setGlobalSettings(newSettings); setSuccessMsg(`Anno ${nextYear} aperto!`); } catch(e) { console.error(e); } finally { setSaving(false); } } }; // CRUD Handlers const openAddCondoModal = () => { setEditingCondo(null); setCondoForm({ name: '', address: '', streetNumber: '', city: '', province: '', zipCode: '', notes: '', paypalClientId: '', defaultMonthlyQuota: 100, dueDay: 10 }); setShowCondoModal(true); }; const openEditCondoModal = (c: Condo) => { setEditingCondo(c); setCondoForm({ name: c.name, address: c.address || '', streetNumber: c.streetNumber || '', city: c.city || '', province: c.province || '', zipCode: c.zipCode || '', notes: c.notes || '', paypalClientId: c.paypalClientId || '', defaultMonthlyQuota: c.defaultMonthlyQuota, dueDay: c.dueDay || 10 }); setShowCondoModal(true); }; const handleCondoSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const payload: Condo = { id: editingCondo ? editingCondo.id : '', name: condoForm.name, address: condoForm.address, streetNumber: condoForm.streetNumber, city: condoForm.city, province: condoForm.province, zipCode: condoForm.zipCode, notes: condoForm.notes, paypalClientId: condoForm.paypalClientId, defaultMonthlyQuota: condoForm.defaultMonthlyQuota, dueDay: condoForm.dueDay }; const savedCondo = await CondoService.saveCondo(payload); const list = await CondoService.getCondos(); setCondos(list); if (activeCondo?.id === savedCondo.id) { setActiveCondo(savedCondo); } if (!activeCondo && list.length === 1) { CondoService.setActiveCondo(savedCondo.id); } setShowCondoModal(false); window.dispatchEvent(new Event('condo-updated')); } catch (e) { console.error(e); alert("Errore nel salvataggio del condominio. Assicurati di essere amministratore."); } }; const handleDeleteCondo = async (id: string) => { if(!window.confirm("Eliminare questo condominio? Attenzione: operazione irreversibile.")) return; try { await CondoService.deleteCondo(id); setCondos(await CondoService.getCondos()); window.dispatchEvent(new Event('condo-updated')); } catch (e) { console.error(e); } }; const openAddFamilyModal = () => { setEditingFamily(null); setFamilyForm({ name: '', unitNumber: '', stair: '', floor: '', notes: '', contactEmail: '', customMonthlyQuota: '' }); setShowFamilyModal(true); }; const openEditFamilyModal = (family: Family) => { setEditingFamily(family); setFamilyForm({ name: family.name, unitNumber: family.unitNumber, stair: family.stair || '', floor: family.floor || '', notes: family.notes || '', contactEmail: family.contactEmail || '', customMonthlyQuota: family.customMonthlyQuota ? family.customMonthlyQuota.toString() : '' }); setShowFamilyModal(true); }; const handleDeleteFamily = async (id: string) => { if (!window.confirm('Eliminare questa famiglia?')) return; try { await CondoService.deleteFamily(id); setFamilies(families.filter(f => f.id !== id)); } catch (e) { console.error(e); } }; const handleFamilySubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const quota = familyForm.customMonthlyQuota && familyForm.customMonthlyQuota.trim() !== '' ? parseFloat(familyForm.customMonthlyQuota) : undefined; const payload: any = { name: familyForm.name, unitNumber: familyForm.unitNumber, stair: familyForm.stair, floor: familyForm.floor, notes: familyForm.notes, contactEmail: familyForm.contactEmail, customMonthlyQuota: quota }; if (editingFamily) { const updatedFamily = { ...editingFamily, ...payload }; await CondoService.updateFamily(updatedFamily); setFamilies(families.map(f => f.id === updatedFamily.id ? updatedFamily : f)); } else { const newFamily = await CondoService.addFamily(payload); setFamilies([...families, newFamily]); } setShowFamilyModal(false); } catch (e: any) { console.error(e); alert(`Errore: ${e.message || "Impossibile salvare la famiglia."}`); } }; const openAddUserModal = () => { setEditingUser(null); setUserForm({ name: '', email: '', password: '', phone: '', role: 'user', familyId: '', receiveAlerts: true }); setShowUserModal(true); }; const openEditUserModal = (user: User) => { setEditingUser(user); setUserForm({ name: user.name || '', email: user.email, password: '', phone: user.phone || '', role: user.role || 'user', familyId: user.familyId || '', receiveAlerts: user.receiveAlerts ?? true }); setShowUserModal(true); }; const handleUserSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { if (editingUser) { await CondoService.updateUser(editingUser.id, userForm); } else { await CondoService.createUser(userForm); } setUsers(await CondoService.getUsers(activeCondo?.id)); setShowUserModal(false); } catch (e) { alert("Errore nel salvataggio utente"); } }; const handleDeleteUser = async (id: string) => { if(!window.confirm("Eliminare utente?")) return; await CondoService.deleteUser(id); setUsers(users.filter(u => u.id !== id)); }; const openAddNoticeModal = () => { setEditingNotice(null); setNoticeTargetMode('all'); setNoticeForm({ title: '', content: '', type: 'info', link: '', condoId: activeCondo?.id || '', active: true, targetFamilyIds: [] }); setShowNoticeModal(true); }; const openEditNoticeModal = (n: Notice) => { setEditingNotice(n); const isTargeted = n.targetFamilyIds && n.targetFamilyIds.length > 0; setNoticeTargetMode(isTargeted ? 'specific' : 'all'); setNoticeForm({ title: n.title, content: n.content, type: n.type, link: n.link || '', condoId: n.condoId, active: n.active, targetFamilyIds: n.targetFamilyIds || [] }); setShowNoticeModal(true); }; const handleNoticeSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const payload: Notice = { id: editingNotice ? editingNotice.id : '', ...noticeForm, targetFamilyIds: noticeTargetMode === 'all' ? [] : noticeForm.targetFamilyIds, date: editingNotice ? editingNotice.date : new Date().toISOString() }; await CondoService.saveNotice(payload); setNotices(await CondoService.getNotices(activeCondo?.id)); setShowNoticeModal(false); } catch (e) { console.error(e); } }; const handleDeleteNotice = async (id: string) => { if(!window.confirm("Eliminare annuncio?")) return; await CondoService.deleteNotice(id); setNotices(notices.filter(n => n.id !== id)); }; const toggleNoticeActive = async (notice: Notice) => { try { const updated = { ...notice, active: !notice.active }; await CondoService.saveNotice(updated); setNotices(notices.map(n => n.id === notice.id ? updated : n)); } catch (e) { console.error(e); } }; const toggleNoticeFamilyTarget = (familyId: string) => { setNoticeForm(prev => { const current = prev.targetFamilyIds; if (current.includes(familyId)) { return { ...prev, targetFamilyIds: current.filter(id => id !== familyId) }; } else { return { ...prev, targetFamilyIds: [...current, familyId] }; } }); }; const openReadDetails = (noticeId: string) => { setSelectedNoticeId(noticeId); setShowReadDetailsModal(true); }; const openAddAlertModal = () => { setEditingAlert(null); setAlertForm({ subject: '', body: '', daysOffset: 1, offsetType: 'before_next_month', sendHour: 9, active: true }); setShowAlertModal(true); }; const openEditAlertModal = (alert: AlertDefinition) => { setEditingAlert(alert); setAlertForm(alert); setShowAlertModal(true); }; const handleAlertSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const payload: AlertDefinition = { id: editingAlert ? editingAlert.id : '', subject: alertForm.subject!, body: alertForm.body!, daysOffset: Number(alertForm.daysOffset), offsetType: alertForm.offsetType as any, sendHour: Number(alertForm.sendHour), active: alertForm.active! }; const saved = await CondoService.saveAlert(payload); setAlerts(editingAlert ? alerts.map(a => a.id === saved.id ? saved : a) : [...alerts, saved]); setShowAlertModal(false); } catch (e) { console.error(e); } }; const handleDeleteAlert = async (id: string) => { if(!window.confirm("Eliminare avviso?")) return; await CondoService.deleteAlert(id); setAlerts(alerts.filter(a => a.id !== id)); }; const toggleFeature = (key: keyof AppSettings['features']) => { if (!globalSettings) return; setGlobalSettings({ ...globalSettings, features: { ...globalSettings.features, [key]: !globalSettings.features[key] } }); }; const tabs: {id: TabType, label: string, icon: React.ReactNode}[] = [ { id: 'profile', label: 'Profilo', icon: }, ]; if (isSuperAdmin) { tabs.push({ id: 'features', label: 'Funzionalità', icon: }); } if (isPrivileged) { tabs.push({ id: 'general', label: 'Condominio', icon: }); // Only show Storage tab if Documents feature is enabled if (globalSettings?.features.documents) { tabs.push({ id: 'storage', label: 'Cloud & Storage', icon: }); } if (globalSettings?.features.multiCondo) { tabs.push({ id: 'condos', label: 'Lista Condomini', icon: }); } tabs.push( { id: 'families', label: 'Famiglie', icon: }, { id: 'users', label: 'Utenti', icon: } ); if (globalSettings?.features.notices) { tabs.push({ id: 'notices', label: 'Bacheca', icon: }); } tabs.push( { id: 'alerts', label: 'Avvisi Email', icon: } ); } if (loading) return
Caricamento...
; return (

Impostazioni

{activeCondo ? `Gestione: ${activeCondo.name}` : 'Pannello di Controllo'}

{/* NAVIGATION SIDEBAR / MOBILE SCROLL */}

Menu

{/* Mobile: Horizontal Scroll, Desktop: Vertical List */}
{tabs.map(tab => ( ))}
{/* CONTENT AREA */}
{/* PROFILE TAB */} {activeTab === 'profile' && (

Il Tuo Profilo

setProfileForm({...profileForm, name: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700"/>
setProfileForm({...profileForm, phone: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700"/>
setProfileForm({...profileForm, password: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700"/>
{profileMsg &&

{profileMsg}

}
)} {/* FEATURES TAB */} {isSuperAdmin && activeTab === 'features' && globalSettings && (

Funzionalità Piattaforma

{/* Toggles */}

Gestione Multicondominio

Abilita la gestione di più stabili.

Gestione Tickets

Abilita il sistema di segnalazione guasti.

Gestione Documenti

Archivio digitale con tag e upload.

Pagamenti PayPal

Permetti ai condomini di pagare online.

Bacheca Avvisi

Mostra la bacheca digitale.

Reportistica Avanzata

Abilita grafici incassi e bilancio.

Spese Straordinarie

Gestione lavori e preventivi.

Visualizza Spese Condominiali agli Utenti

Se attivo, gli utenti potranno vedere (sola lettura) il registro delle spese condominiali.

{successMsg}
)} {/* STORAGE CONFIG TAB - CONDITIONAL */} {isPrivileged && activeTab === 'storage' && globalSettings?.features.documents && (

Configurazione Storage

Scegli dove salvare i documenti caricati.

{globalSettings?.storageConfig ? ( <>
{globalSettings.storageConfig.provider === 'local_db' && (

Modalità Demo Attiva

I file vengono salvati direttamente nel database (Base64). Non raccomandato per produzione o file grandi.

)} {globalSettings.storageConfig.provider === 's3' && (

Configurazione S3

setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, bucket: e.target.value}})}/> setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, region: e.target.value}})}/> setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, apiKey: e.target.value}})}/> setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, apiSecret: e.target.value}})}/>
)} {(globalSettings.storageConfig.provider === 'google_drive' || globalSettings.storageConfig.provider === 'dropbox' || globalSettings.storageConfig.provider === 'onedrive') && (

Autenticazione API

Inserisci le credenziali dell'applicazione sviluppatore.

setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, apiKey: e.target.value}})}/> setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, apiSecret: e.target.value}})}/>
)}
{successMsg}
) : (
Inizializzazione configurazione storage...
)}
)} {/* GENERAL TAB */} {isPrivileged && activeTab === 'general' && (
{!activeCondo ?
Nessun condominio selezionato.
: (

Dati Condominio Corrente

setActiveCondo({ ...activeCondo, name: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Nome" required />
setActiveCondo({ ...activeCondo, address: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Via/Piazza..." required/>
setActiveCondo({ ...activeCondo, streetNumber: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" required/>
setActiveCondo({ ...activeCondo, zipCode: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700"/>
setActiveCondo({ ...activeCondo, city: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" required/>
setActiveCondo({ ...activeCondo, province: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" required/>
{globalSettings?.features.payPal && (
Configurazione Pagamenti
setActiveCondo({...activeCondo, paypalClientId: e.target.value})} />

Necessario per abilitare i pagamenti online delle rate.

)}
setActiveCondo({ ...activeCondo, defaultMonthlyQuota: parseFloat(e.target.value) })} className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Quota Default" required />
setActiveCondo({ ...activeCondo, dueDay: parseInt(e.target.value) })} className="w-full border p-2.5 rounded-lg text-slate-700" required />
{successMsg}
)} {globalSettings && (

Anno Fiscale

Corrente: {globalSettings.currentYear}

)}
)} {/* CONDOS LIST TAB */} {isPrivileged && activeTab === 'condos' && (

I Tuoi Condomini

{condos.map(condo => (
{activeCondo?.id === condo.id &&
Attivo
}

{condo.name}

{condo.address} {condo.streetNumber}

{condo.city &&

{condo.zipCode} {condo.city} ({condo.province})

}
))}
)} {/* FAMILIES TAB */} {isPrivileged && activeTab === 'families' && (

Elenco Famiglie

Condominio: {activeCondo?.name}

{families.map(f => ( ))} {families.length === 0 && }
NominativoInternoEmailAzioni
{f.name}{f.unitNumber}{f.contactEmail}
Nessuna famiglia registrata.
)} {/* USERS TAB */} {isPrivileged && activeTab === 'users' && (

Utenti & Accessi

Gestione account di accesso

{users.map(u => { const fam = families.find(f => f.id === u.familyId); return ( ); })}
EmailRuoloFamigliaAzioni
{u.email}{u.role}{fam ? `${fam.name} (${fam.unitNumber})` : '-'}
)} {/* NOTICES TAB */} {isPrivileged && activeTab === 'notices' && (

Bacheca Avvisi

{notices.map(notice => { const reads = noticeReadStats[notice.id] || []; const targetCount = notice.targetFamilyIds?.length || 0; return (

{notice.title}

{notice.active ? 'Attivo' : 'Archiviato'} • {new Date(notice.date).toLocaleDateString()}

{notice.content}

Destinatari: {targetCount === 0 ? 'Tutti' : `${targetCount} Famiglie`}
); })} {notices.length === 0 &&
Nessun avviso in bacheca.
}
)} {/* ALERTS TAB */} {isPrivileged && activeTab === 'alerts' && (

Avvisi Automatici Email

Configura email periodiche

{alerts.map(alert => (

{alert.subject}

Invia {alert.daysOffset} giorni {alert.offsetType === 'before_next_month' ? 'prima del prossimo mese' : 'dopo il mese corrente'} alle {alert.sendHour}:00

))} {alerts.length === 0 &&
Nessun alert configurato.
}
)}
{/* Condo Modal */} {showCondoModal && (

{editingCondo ? 'Modifica Condominio' : 'Nuovo Condominio'}

{/* Form fields same as before... omitted for brevity */}
setCondoForm({...condoForm, name: e.target.value})} required />
setCondoForm({...condoForm, address: e.target.value})} required />
setCondoForm({...condoForm, streetNumber: e.target.value})} required />
setCondoForm({...condoForm, zipCode: e.target.value})} />
setCondoForm({...condoForm, city: e.target.value})} required />
setCondoForm({...condoForm, province: e.target.value})} required />
{globalSettings?.features.payPal && (
Configurazione Pagamenti
setCondoForm({...condoForm, paypalClientId: e.target.value})} />

Necessario per abilitare i pagamenti online delle rate.

)}