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 } from 'lucide-react'; export const SettingsPage: React.FC = () => { const currentUser = CondoService.getCurrentUser(); const isAdmin = currentUser?.role === 'admin'; // Tab configuration type TabType = 'profile' | 'features' | 'general' | 'condos' | 'families' | 'users' | 'notices' | 'alerts' | 'smtp'; const [activeTab, setActiveTab] = useState(isAdmin ? '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 }); // Notices (Bacheca) State const [notices, setNotices] = useState([]); const [showNoticeModal, setShowNoticeModal] = useState(false); const [editingNotice, setEditingNotice] = useState(null); const [noticeForm, setNoticeForm] = useState<{ title: string; content: string; type: NoticeIconType; link: string; condoId: string; active: boolean; }>({ title: '', content: '', type: 'info', link: '', condoId: '', active: true }); const [noticeReadStats, setNoticeReadStats] = useState>({}); // Notice Details Modal const [showReadDetailsModal, setShowReadDetailsModal] = useState(false); const [selectedNoticeId, setSelectedNoticeId] = useState(null); useEffect(() => { const fetchData = async () => { try { if (isAdmin) { // 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 ONLY if there is an active condo if (activeC) { const [fams, usrs, alrts, allNotices] = await Promise.all([ CondoService.getFamilies(activeC.id), CondoService.getUsers(activeC.id), CondoService.getAlerts(activeC.id), CondoService.getNotices(activeC.id) ]); setFamilies(fams); setUsers(usrs); setAlerts(alrts); setNotices(allNotices); // Fetch read stats for notices const stats: Record = {}; for (const n of allNotices) { const reads = await CondoService.getNoticeReadStatus(n.id); stats[n.id] = reads; } setNoticeReadStats(stats); } else { setFamilies([]); setUsers([]); setAlerts([]); setNotices([]); } } else { const activeC = await CondoService.getActiveCondo(); setActiveCondo(activeC); } } catch(e) { console.error(e); } finally { setLoading(false); } }; fetchData(); }, [isAdmin]); // --- Profile 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); } }; // --- General Handlers --- 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(); // Refresh to apply changes to layout } 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(''), 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); } } }; // --- Condo Management 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); } // Auto-select if it's the first one or none selected 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); } }; // --- Family Handlers --- 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 { // Handle parsing safely 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. Controlla i permessi."}`); } }; // --- User Handlers --- 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); } // Refresh user list for active condo 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)); }; // --- Notice Handlers --- const openAddNoticeModal = () => { setEditingNotice(null); setNoticeForm({ title: '', content: '', type: 'info', link: '', condoId: activeCondo?.id || '', active: true }); setShowNoticeModal(true); }; const openEditNoticeModal = (n: Notice) => { setEditingNotice(n); setNoticeForm({ title: n.title, content: n.content, type: n.type, link: n.link || '', condoId: n.condoId, active: n.active }); setShowNoticeModal(true); }; const handleNoticeSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const payload: Notice = { id: editingNotice ? editingNotice.id : '', ...noticeForm, date: editingNotice ? editingNotice.date : new Date().toISOString() }; await CondoService.saveNotice(payload); // Refresh notices for active condo 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 openReadDetails = (noticeId: string) => { setSelectedNoticeId(noticeId); setShowReadDetailsModal(true); }; // --- Alert Handlers --- 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! }; // Save alert with current condoId 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'; // Helpers for Toggle Feature const toggleFeature = (key: keyof AppSettings['features']) => { if (!globalSettings) return; setGlobalSettings({ ...globalSettings, features: { ...globalSettings.features, [key]: !globalSettings.features[key] } }); }; // --- TABS CONFIG --- const tabs: {id: TabType, label: string, icon: React.ReactNode}[] = [ { id: 'profile', label: 'Profilo', icon: }, ]; if (isAdmin) { tabs.push( { id: 'features', label: 'Funzionalità', icon: }, { 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: }, { id: 'smtp', label: 'SMTP', icon: } ); } if (loading) return
Caricamento...
; return (

Impostazioni

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

{/* Tabs */}
{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"/>
)} {/* Features Tab */} {isAdmin && activeTab === 'features' && globalSettings && (

Funzionalità Piattaforma

{/* Multi Condo */}

Gestione Multicondominio

Abilita la gestione di più stabili. Se disattivo, il sistema gestirà un solo condominio.

{/* Tickets */}

Gestione Tickets

Abilita il sistema di segnalazione guasti e richieste (Segnalazioni).

{/* PayPal */}

Pagamenti PayPal

Permetti ai condomini di pagare le rate tramite PayPal.

{/* Notices */}

Bacheca Avvisi

Mostra la bacheca digitale per comunicazioni ai condomini.

{successMsg}
)} {/* General Tab */} {isAdmin && 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/>
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 */} {isAdmin && 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 */} {isAdmin && 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 */} {isAdmin && activeTab === 'users' && (
{users.map(u => ( ))}
UtenteRuoloAzioni
{u.name}
{u.email}
{u.role}
)} {/* NOTICES (BACHECA) TAB */} {isAdmin && activeTab === 'notices' && (

Bacheca Condominiale

Pubblica avvisi visibili a tutti i condomini.

{notices.map(notice => (
{notice.type === 'warning' ? : notice.type === 'maintenance' ? : notice.type === 'event' ? : }

{notice.title}

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

{notice.content}

{notice.link && Allegato}
{/* Toggle Active */} {/* Reads Counter */}
))} {notices.length === 0 &&
Nessun avviso pubblicato.
}
)} {/* ALERTS TAB */} {isAdmin && 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.
}
)} {/* SMTP TAB */} {isAdmin && activeTab === 'smtp' && (

Configurazione SMTP

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"/>
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"/>
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"/>
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"/>
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"/>
setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), secure: e.target.checked} as any} : null)} className="w-4 h-4"/>
{successMsg}
)} {/* ALERT MODAL (Existing) */} {showAlertModal && (

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

setAlertForm({...alertForm, subject: 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" />
)} ); };