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 } 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' | '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 }); 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(); 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 --- 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('Funzionalità salvate!'); 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 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 }); 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 }); 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 }; 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 getCondoName = (id: string) => condos.find(c => c.id === id)?.name || 'Sconosciuto'; 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: } ); 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 (
{/* HEADER */}

Impostazioni

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

{/* TABS NAVIGATION */}
{tabs.map(tab => ( ))}
{/* 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 (ADMIN ONLY) */} {isSuperAdmin && activeTab === 'features' && globalSettings && (

Funzionalità Piattaforma

{/* Toggles */}

Gestione Multicondominio

Abilita la gestione di più stabili.

Gestione Tickets

Abilita il sistema di segnalazione guasti.

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.

{/* NEW TOGGLE for Condo Financials View */}

Visualizza Spese Condominiali agli Utenti

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

{successMsg}
)} {/* 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 />
{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' && (
{!activeCondo ? (

Seleziona o crea un condominio per gestire le famiglie.

) : ( <>
Famiglie in: {activeCondo.name}
{families.map(family => ( ))}
NomeDettagliEmailQuotaAzioni
{family.name}
Int: {family.unitNumber || '-'}{(family.stair || family.floor) && ({family.stair ? `Scala: ${family.stair} ` : ''} {family.floor ? `Piano: ${family.floor}` : ''})}
{family.contactEmail} {family.customMonthlyQuota ? (€ {family.customMonthlyQuota}) : (Default (€ {activeCondo.defaultMonthlyQuota}))}
)}
)} {/* USERS TAB */} {isPrivileged && activeTab === 'users' && (
{users.map(u => ())}
UtenteRuoloAzioni
{u.name}
{u.email}
{u.role}
)} {/* NOTICES TAB */} {isPrivileged && activeTab === 'notices' && (

Bacheca Condominiale

Pubblica avvisi visibili a tutti i condomini.

{notices.map(notice => { const isTargeted = notice.targetFamilyIds && notice.targetFamilyIds.length > 0; return (
{notice.type === 'warning' ? : notice.type === 'maintenance' ? : notice.type === 'event' ? : }

{notice.title}{isTargeted && ( Privato)}

{getCondoName(notice.condoId)} • {new Date(notice.date).toLocaleDateString()}

{notice.content}

{notice.link && Allegato}{isTargeted && (

Visibile a: {notice.targetFamilyIds!.length} famiglie

)}
); })} {notices.length === 0 &&
Nessun avviso pubblicato.
}
)} {/* ALERTS TAB */} {isPrivileged && activeTab === 'alerts' && (

Avvisi Automatici

Configura email automatiche per scadenze.

{alerts.map(alert => (

{alert.subject}

{alert.body}

Offset: {alert.daysOffset} giorni ({alert.offsetType})Ore: {alert.sendHour}:00{alert.active ? 'Attivo' : 'Inattivo'}
))} {alerts.length === 0 &&
Nessun alert configurato.
}
)} {/* --- MODALS --- */} {/* Notice Modal */} {showNoticeModal && (

{editingNotice ? 'Modifica Avviso' : 'Nuovo Avviso'}

setNoticeForm({...noticeForm, title: e.target.value})} required />

Lasciare vuoto per usare il default del condominio (€ {activeCondo?.defaultMonthlyQuota})

setFamilyForm({...familyForm, customMonthlyQuota: e.target.value})} className="w-full border rounded-lg p-2.5 text-slate-700" placeholder="Es. 120.00"/>
)} {/* Alert Modal */} {showAlertModal && (

{editingAlert ? 'Modifica Avviso' : 'Nuovo Avviso Automatico'}

setAlertForm({...alertForm, subject: e.target.value})} required />