diff --git a/pages/Settings.tsx b/pages/Settings.tsx index 2b7d3ba..aa2fee7 100644 --- a/pages/Settings.tsx +++ b/pages/Settings.tsx @@ -7,7 +7,7 @@ import { 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 + ToggleLeft, ToggleRight, LayoutGrid, PieChart, Users, Send, Cloud, HardDrive, ChevronRight } from 'lucide-react'; export const SettingsPage: React.FC = () => { @@ -203,359 +203,62 @@ export const SettingsPage: React.FC = () => { fetchData(); }, [isPrivileged]); - // --- HANDLERS --- - + // --- 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); - } + 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); - } + 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); - } + 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); - } + 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); - } + 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); } + 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); - } - } + 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 (omitted repeated code for brevity, logic is same as before) - 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); - }; - + // 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."); - } + 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 getCondoName = (id: string) => condos.find(c => c.id === id)?.name || 'Sconosciuto'; + 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; @@ -577,7 +280,7 @@ export const SettingsPage: React.FC = () => { if (isPrivileged) { tabs.push( { id: 'general', label: 'Condominio', icon: }, - { id: 'storage', label: 'Cloud & Storage', icon: } // Moved up here + { id: 'storage', label: 'Cloud & Storage', icon: } ); if (globalSettings?.features.multiCondo) { tabs.push({ id: 'condos', label: 'Lista Condomini', icon: }); @@ -597,332 +300,348 @@ export const SettingsPage: React.FC = () => { if (loading) return
Caricamento...
; return ( -
- {/* HEADER */} -
+
+

Impostazioni

-

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

+

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

- {/* TABS NAVIGATION */} -
- {tabs.map(tab => ( - - ))} -
+
+ {/* NAVIGATION SIDEBAR / MOBILE SCROLL */} +
+
+
+

Menu

+
+ {/* Mobile: Horizontal Scroll, Desktop: Vertical List */} +
+ {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.

- -
-
-

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 */} - {isPrivileged && activeTab === 'storage' && ( -
-

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 /> + {/* 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"/>
-
- - setActiveCondo({ ...activeCondo, dueDay: parseInt(e.target.value) })} className="w-full border p-2.5 rounded-lg text-slate-700" required /> +
+ + +
+
+ + 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"/>
- -
{successMsg}
+ + {profileMsg &&

{profileMsg}

}
- )} - {globalSettings && (

Anno Fiscale

Corrente: {globalSettings.currentYear}

)} + )} + + {/* 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 */} + {isPrivileged && activeTab === 'storage' && ( +
+

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.
} +
+
+ )}
- )} - - {/* 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 && (