diff --git a/pages/Settings.tsx b/pages/Settings.tsx index afbc926..9d6e897 100644 --- a/pages/Settings.tsx +++ b/pages/Settings.tsx @@ -1,25 +1,23 @@ import React, { useEffect, useState } from 'react'; import { CondoService } from '../services/mockDb'; -import { AppSettings, Family, User, AlertDefinition, Condo, Notice, NoticeIconType, NoticeRead } from '../types'; +import { AppSettings, Family, User, AlertDefinition, Condo, Notice, NoticeIconType, NoticeRead, BrandingConfig, StorageConfig } 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, Palette, Monitor, - Sun, Moon, Check + ToggleLeft, ToggleRight, LayoutGrid, PieChart, Users, Send, Cloud, HardDrive, ChevronRight, Palette, Image as ImageIcon, Upload } from 'lucide-react'; -const PALETTES = [ - { name: 'Blue (Standard)', color: '#2563eb' }, - { name: 'Indigo', color: '#4f46e5' }, - { name: 'Emerald', color: '#059669' }, - { name: 'Rose', color: '#e11d48' }, - { name: 'Amber', color: '#d97706' }, - { name: 'Slate', color: '#475569' }, - { name: 'Purple', color: '#9333ea' } -]; +const COLOR_MAP: Record = { + blue: '#2563eb', + purple: '#9333ea', + green: '#16a34a', + red: '#dc2626', + orange: '#ea580c', + slate: '#475569' +}; export const SettingsPage: React.FC = () => { const currentUser = CondoService.getCurrentUser(); @@ -31,75 +29,80 @@ export const SettingsPage: React.FC = () => { const [activeTab, setActiveTab] = useState(isPrivileged ? 'general' : 'profile'); const [loading, setLoading] = useState(true); - // Profile State + // Profile Form const [profileForm, setProfileForm] = useState({ name: currentUser?.name || '', phone: currentUser?.phone || '', password: '', - receiveAlerts: currentUser?.receiveAlerts ?? true, - theme: localStorage.getItem('app-theme') || 'light' + receiveAlerts: currentUser?.receiveAlerts ?? true }); const [profileSaving, setProfileSaving] = useState(false); const [profileMsg, setProfileMsg] = useState(''); - // Branding State - const [brandingForm, setBrandingForm] = useState({ - appName: '', - appIcon: '', - loginBg: '', - primaryColor: '#2563eb' - }); - + // Branding & Features const [activeCondo, setActiveCondo] = useState(undefined); const [globalSettings, setGlobalSettings] = useState(null); + const [brandingForm, setBrandingForm] = useState({ appName: 'CondoPay', primaryColor: 'blue', logoUrl: '', loginBackgroundUrl: '' }); + + // Condos List 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 [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 Management const [families, setFamilies] = useState([]); const [showFamilyModal, setShowFamilyModal] = useState(false); const [editingFamily, setEditingFamily] = useState(null); const [familyForm, setFamilyForm] = useState({ name: '', unitNumber: '', stair: '', floor: '', notes: '', contactEmail: '', customMonthlyQuota: '' }); + + // Users Management 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 }); + const [userForm, setUserForm] = useState({ name: '', email: '', password: '', phone: '', role: 'user' as User['role'], familyId: '', receiveAlerts: true }); + + // Alerts & Email Rules 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 }); + const [showSmtpModal, setShowSmtpModal] = useState(false); const [testingSmtp, setTestingSmtp] = useState(false); const [testSmtpMsg, setTestSmtpMsg] = useState(''); + + // Notices (Bacheca) 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: 'info' | 'warning' | 'maintenance' | 'event'; link: string; condoId: string; active: boolean; targetFamilyIds: string[]; }>({ title: '', content: '', type: 'info', link: '', condoId: '', active: true, targetFamilyIds: [] }); + const [noticeForm, setNoticeForm] = useState({ title: '', content: '', type: 'info' as NoticeIconType, link: '', condoId: '', active: true, targetFamilyIds: [] as string[] }); const [noticeReadStats, setNoticeReadStats] = useState>({}); const [showReadDetailsModal, setShowReadDetailsModal] = useState(false); const [selectedNoticeId, setSelectedNoticeId] = useState(null); + // Cloud Storage Settings + const [storageForm, setStorageForm] = useState({ provider: 'local_db', apiKey: '', apiSecret: '', bucket: '', region: '' }); + useEffect(() => { const fetchData = async () => { try { const activeC = await CondoService.getActiveCondo(); - setActiveCondo(activeC); + const gSettings = await CondoService.getSettings(); - if (isPrivileged) { - const condoList = await CondoService.getCondos(); - const gSettings = await CondoService.getSettings(); - setCondos(condoList); - setGlobalSettings(gSettings); - setBrandingForm({ - appName: gSettings.branding?.appName || 'CondoPay', - appIcon: gSettings.branding?.appIcon || '', - loginBg: gSettings.branding?.loginBg || '', - primaryColor: gSettings.branding?.primaryColor || '#2563eb' - }); + setActiveCondo(activeC); + setGlobalSettings(gSettings); + setBrandingForm(gSettings.branding || { appName: 'CondoPay', primaryColor: 'blue' }); + setStorageForm(gSettings.storageConfig || { provider: 'local_db', apiKey: '', apiSecret: '', bucket: '', region: '' }); + if (isPrivileged) { + setCondos(await CondoService.getCondos()); if (activeC) { setFamilies(await CondoService.getFamilies(activeC.id)); setUsers(await CondoService.getUsers(activeC.id)); @@ -113,211 +116,520 @@ export const SettingsPage: React.FC = () => { setNoticeReadStats(stats); } } - } catch(e) { console.error(e); } finally { setLoading(false); } + } catch(e) { console.error("Error loading settings data", e); } finally { setLoading(false); } }; fetchData(); }, [isPrivileged]); + // --- SUBMIT HANDLERS --- const handleProfileSubmit = async (e: React.FormEvent) => { e.preventDefault(); setProfileSaving(true); setProfileMsg(''); - try { - await CondoService.updateProfile(profileForm); - // Apply theme - localStorage.setItem('app-theme', profileForm.theme); - if (profileForm.theme === 'dark') document.documentElement.classList.add('dark'); - else document.documentElement.classList.remove('dark'); - - setProfileMsg('Profilo aggiornato!'); - setTimeout(() => setProfileMsg(''), 3000); - } catch (e) { setProfileMsg('Errore'); } finally { setProfileSaving(false); } + 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); setCondos(await CondoService.getCondos()); } 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(''); window.location.reload(); }, 1500); } catch (e) { console.error(e); } finally { setSaving(false); } }; - const handleBrandingSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (!globalSettings) return; - setSaving(true); - try { + e.preventDefault(); if (!globalSettings) return; setSaving(true); + try { const updated = { ...globalSettings, branding: brandingForm }; await CondoService.updateSettings(updated); setGlobalSettings(updated); - setSuccessMsg('Branding aggiornato!'); window.dispatchEvent(new Event('branding-updated')); - // Apply color immediately to UI - document.documentElement.style.setProperty('--primary-color', brandingForm.primaryColor); - setTimeout(() => setSuccessMsg(''), 3000); + setSuccessMsg('Branding salvato!'); setTimeout(() => setSuccessMsg(''), 3000); } catch(e) { console.error(e); } finally { setSaving(false); } }; + const handleStorageSubmit = async (e: React.FormEvent) => { + e.preventDefault(); if (!globalSettings) return; setSaving(true); + try { const updated = { ...globalSettings, storageConfig: storageForm }; await CondoService.updateSettings(updated); setGlobalSettings(updated); setSuccessMsg('Configurazione Storage salvata!'); setTimeout(() => setSuccessMsg(''), 3000); } catch (e) { console.error(e); } finally { setSaving(false); } + }; + const handleLogoUpload = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file) { const reader = new FileReader(); reader.onload = (ev) => setBrandingForm(prev => ({...prev, logoUrl: ev.target?.result as string})); reader.readAsDataURL(file); } + }; + const handleBgUpload = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file) { const reader = new FileReader(); reader.onload = (ev) => setBrandingForm(prev => ({...prev, loginBackgroundUrl: ev.target?.result as string})); reader.readAsDataURL(file); } + }; - // --- CRUD Handlers (Simplified for brevity as logic is unchanged) --- - const handleGeneralSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!activeCondo) return; setSaving(true); try { await CondoService.saveCondo(activeCondo); setSuccessMsg('Aggiornato!'); setTimeout(() => setSuccessMsg(''), 3000); } catch (e) {} finally { setSaving(false); } }; - const handleFeaturesSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!globalSettings) return; setSaving(true); try { await CondoService.updateSettings(globalSettings); setSuccessMsg('Salvato!'); window.location.reload(); } catch (e) {} finally { setSaving(false); } }; - const handleSmtpSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!globalSettings) return; setSaving(true); try { await CondoService.updateSettings(globalSettings); setShowSmtpModal(false); } catch (e) {} finally { setSaving(false); } }; - const handleStorageSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!globalSettings) return; setSaving(true); try { await CondoService.updateSettings(globalSettings); setSuccessMsg('Salvato!'); } catch (e) {} finally { setSaving(false); } }; - const handleCondoSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await CondoService.saveCondo({ id: editingCondo?.id || '', ...condoForm }); setCondos(await CondoService.getCondos()); setShowCondoModal(false); } catch (e) {} }; - const handleDeleteCondo = async (id: string) => { if(!confirm("Eliminare?")) return; await CondoService.deleteCondo(id); setCondos(await CondoService.getCondos()); }; - const handleFamilySubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const quota = familyForm.customMonthlyQuota ? parseFloat(familyForm.customMonthlyQuota) : undefined; if (editingFamily) { await CondoService.updateFamily({ ...editingFamily, ...familyForm, customMonthlyQuota: quota }); } else { await CondoService.addFamily({ ...familyForm, customMonthlyQuota: quota }); } setFamilies(await CondoService.getFamilies(activeCondo?.id)); setShowFamilyModal(false); } catch (e) {} }; - const handleDeleteFamily = async (id: string) => { if(!confirm("Eliminare?")) return; await CondoService.deleteFamily(id); setFamilies(families.filter(f => f.id !== id)); }; - 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) {} }; - const handleDeleteUser = async (id: string) => { if(!confirm("Eliminare?")) return; await CondoService.deleteUser(id); setUsers(users.filter(u => u.id !== id)); }; - const handleNoticeSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const now = new Date(); const sqlDate = now.toISOString().slice(0, 19).replace('T', ' '); await CondoService.saveNotice({ id: editingNotice?.id || '', ...noticeForm, targetFamilyIds: noticeTargetMode === 'all' ? [] : noticeForm.targetFamilyIds, date: editingNotice ? editingNotice.date : sqlDate }); setNotices(await CondoService.getNotices(activeCondo?.id)); setShowNoticeModal(false); } catch (e) {} }; - const handleDeleteNotice = async (id: string) => { if(!confirm("Eliminare?")) return; await CondoService.deleteNotice(id); setNotices(notices.filter(n => n.id !== id)); }; - const handleAlertSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await CondoService.saveAlert({ id: editingAlert?.id || '', ...alertForm } as any); setAlerts(await CondoService.getAlerts(activeCondo?.id)); setShowAlertModal(false); } catch (e) {} }; - const handleDeleteAlert = async (id: string) => { if(!confirm("Eliminare?")) return; await CondoService.deleteAlert(id); setAlerts(alerts.filter(a => a.id !== id)); }; + // --- CRUD HELPERS --- + 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(c); setShowCondoModal(true); }; + const handleCondoSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await CondoService.saveCondo({ id: editingCondo?.id || '', ...condoForm } as Condo); setCondos(await CondoService.getCondos()); setShowCondoModal(false); window.dispatchEvent(new Event('condo-updated')); } catch (e) { alert("Errore"); } }; + const handleDeleteCondo = async (id: string) => { if(window.confirm("Eliminare definitivamente il condominio?")) { await CondoService.deleteCondo(id); setCondos(await CondoService.getCondos()); } }; + + const openAddFamilyModal = () => { setEditingFamily(null); setFamilyForm({ name: '', unitNumber: '', stair: '', floor: '', notes: '', contactEmail: '', customMonthlyQuota: '' }); setShowFamilyModal(true); }; + const openEditFamilyModal = (f: Family) => { setEditingFamily(f); setFamilyForm({ name: f.name, unitNumber: f.unitNumber, stair: f.stair || '', floor: f.floor || '', notes: f.notes || '', contactEmail: f.contactEmail || '', customMonthlyQuota: f.customMonthlyQuota?.toString() || '' }); setShowFamilyModal(true); }; + const handleFamilySubmit = async (e: React.FormEvent) => { e.preventDefault(); try { if (editingFamily) { await CondoService.updateFamily({ ...editingFamily, ...familyForm, customMonthlyQuota: familyForm.customMonthlyQuota ? parseFloat(familyForm.customMonthlyQuota) : undefined }); } else { await CondoService.addFamily({ ...familyForm, customMonthlyQuota: familyForm.customMonthlyQuota ? parseFloat(familyForm.customMonthlyQuota) : undefined }); } setFamilies(await CondoService.getFamilies(activeCondo?.id)); setShowFamilyModal(false); } catch (e) { alert("Errore"); } }; + const handleDeleteFamily = async (id: string) => { if (window.confirm("Eliminare la famiglia?")) { await CondoService.deleteFamily(id); setFamilies(await CondoService.getFamilies(activeCondo?.id)); } }; + const openAddUserModal = () => { setEditingUser(null); setUserForm({ name: '', email: '', password: '', phone: '', role: 'user', familyId: '', receiveAlerts: true }); setShowUserModal(true); }; + const openEditUserModal = (u: User) => { setEditingUser(u); setUserForm({ name: u.name || '', email: u.email, password: '', phone: u.phone || '', role: u.role || 'user', familyId: u.familyId || '', receiveAlerts: u.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 salvataggio utente"); } }; + const handleDeleteUser = async (id: string) => { if(window.confirm("Eliminare questo account utente?")) { await CondoService.deleteUser(id); setUsers(await CondoService.getUsers(activeCondo?.id)); } }; + + const openAddNoticeModal = () => { setEditingNotice(null); setNoticeForm({ title: '', content: '', type: 'info', link: '', condoId: activeCondo?.id || '', active: true, targetFamilyIds: [] }); setNoticeTargetMode('all'); 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, targetFamilyIds: n.targetFamilyIds || [] }); setNoticeTargetMode(n.targetFamilyIds && n.targetFamilyIds.length > 0 ? 'specific' : 'all'); setShowNoticeModal(true); }; + const handleNoticeSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const payload = { ...noticeForm, targetFamilyIds: noticeTargetMode === 'all' ? [] : noticeForm.targetFamilyIds }; if (editingNotice) { await CondoService.saveNotice({ ...editingNotice, ...payload }); } else { await CondoService.saveNotice(payload as any); } setNotices(await CondoService.getNotices(activeCondo?.id)); setShowNoticeModal(false); } catch (e) { alert("Errore"); } }; + const handleDeleteNotice = async (id: string) => { if(confirm('Eliminare l\'avviso?')) { await CondoService.deleteNotice(id); setNotices(await CondoService.getNotices(activeCondo?.id)); } }; + + const openAddAlertModal = () => { setEditingAlert(null); setAlertForm({ subject: '', body: '', daysOffset: 1, offsetType: 'before_next_month', sendHour: 9, active: true }); setShowAlertModal(true); }; + const openEditAlertModal = (a: AlertDefinition) => { setEditingAlert(a); setAlertForm(a); setShowAlertModal(true); }; + const handleAlertSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await CondoService.saveAlert({ ...editingAlert, ...alertForm } as AlertDefinition); setAlerts(await CondoService.getAlerts(activeCondo?.id)); setShowAlertModal(false); } catch(e) { alert("Errore"); } }; + const handleDeleteAlert = async (id: string) => { if(window.confirm("Eliminare la regola di avviso?")) { await CondoService.deleteAlert(id); setAlerts(await CondoService.getAlerts(activeCondo?.id)); } }; + + const handleTestSmtp = async (e: React.FormEvent) => { + e.preventDefault(); if (!globalSettings?.smtpConfig) return; setTestingSmtp(true); setTestSmtpMsg(''); + try { await CondoService.testSmtpConfig(globalSettings.smtpConfig); setTestSmtpMsg('Invio riuscito!'); } catch (e: any) { setTestSmtpMsg('Errore: ' + e.message); } finally { setTestingSmtp(false); } + }; + + const toggleFeature = (key: keyof AppSettings['features']) => { + if (!globalSettings) return; + setGlobalSettings({ ...globalSettings, features: { ...globalSettings.features, [key]: !globalSettings.features[key] } }); + }; + + // --- RENDER HELPERS --- const tabs: {id: TabType, label: string, icon: React.ReactNode}[] = [ - { id: 'profile', label: 'Profilo & Tema', icon: }, + { id: 'profile', label: 'Il Tuo Profilo', icon: }, ]; if (isSuperAdmin) { - tabs.push({ id: 'features', label: 'Funzionalità', icon: }); - tabs.push({ id: 'branding', label: 'Personalizzazione', icon: }); + tabs.push( + { id: 'features', label: 'Funzionalità', icon: }, + { id: 'branding', label: 'Personalizzazione', icon: } + ); } if (isPrivileged) { tabs.push({ id: 'general', label: 'Condominio', icon: }); - if (globalSettings?.features.documents) tabs.push({ id: 'storage', label: 'Storage', icon: }); - if (globalSettings?.features.multiCondo) tabs.push({ id: 'condos', label: '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', icon: }); + 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: 'Account Utenti', icon: } + ); + if (globalSettings?.features.notices) tabs.push({ id: 'notices', label: 'Bacheca Avvisi', icon: }); + tabs.push({ id: 'alerts', label: 'Scadenze & Email', icon: }); } - if (loading) return
Caricamento...
; + // Componente per lo stato vuoto quando non c'è un condominio attivo + const NoCondoState = () => ( +
+ +

Nessun Condominio Selezionato

+

Per accedere a questa sezione devi prima creare o selezionare un condominio.

+ +
+ ); + + if (loading) return
Inizializzazione impostazioni...
; return ( -
-
-

Impostazioni

-

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

+
+
+

Pannello di Controllo

+

{activeCondo ? `Configurazione per: ${activeCondo.name}` : 'Benvenuto! Inizia configurando il tuo stabile.'}

-
-
-
-
+
+ {/* Sidebar Nav */} +
+
+
{tabs.map(tab => ( - ))}
+ {/* Content Area */}
{activeTab === 'profile' && ( -
-

Profilo & Preferenze

+
+

Il Tuo Profilo

-
-
setProfileForm({...profileForm, name: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700 dark:bg-slate-700 dark:text-slate-100"/>
-
-
- - -
-
-
setProfileForm({...profileForm, phone: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700 dark:bg-slate-700 dark:text-slate-100"/>
-
setProfileForm({...profileForm, password: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700 dark:bg-slate-700 dark:text-slate-100"/>
+
+
setProfileForm({...profileForm, name: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none" required />
+
+
setProfileForm({...profileForm, phone: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none" />
+
setProfileForm({...profileForm, password: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none" />
- - {profileMsg &&

{profileMsg}

} +
{profileMsg &&

{profileMsg}

}
)} - {activeTab === 'branding' && isSuperAdmin && ( -
-

Personalizzazione Piattaforma

-
-
-
- - setBrandingForm({...brandingForm, appName: e.target.value})} placeholder="Es: MyCondo Manager" /> -
-
- - setBrandingForm({...brandingForm, appIcon: e.target.value})} placeholder="https://image.com/logo.png" /> -
-
- - setBrandingForm({...brandingForm, loginBg: e.target.value})} placeholder="https://image.com/bg.jpg" /> -
-
- -
- {PALETTES.map(p => ( - - ))} -
- setBrandingForm({...brandingForm, primaryColor: e.target.value})} className="h-10 w-10 border-none bg-transparent cursor-pointer" /> - Scegli un colore personalizzato ({brandingForm.primaryColor}) -
-
+ {isSuperAdmin && activeTab === 'branding' && globalSettings && ( +
+

Branding

+ +
setBrandingForm({...brandingForm, appName: e.target.value})}/>
+
+ +
+ {Object.keys(COLOR_MAP).map(colorKey => ( + + ))} +
+
setBrandingForm({...brandingForm, primaryColor: e.target.value})} className="w-12 h-12 rounded-2xl border-2 cursor-pointer p-0 bg-transparent"/> setBrandingForm({...brandingForm, primaryColor: e.target.value})} className="w-28 text-sm font-mono border border-slate-200 rounded-xl p-3 uppercase font-bold"/>
-
- - {successMsg &&

{successMsg}

} +
+
{brandingForm.logoUrl ? Logo : }
+
{brandingForm.loginBackgroundUrl ? Bg : }
+
)} - {activeTab === 'features' && isSuperAdmin && globalSettings && ( -
-
-

Funzionalità Piattaforma

-
-
-
- {Object.keys(globalSettings.features).map((key) => ( -
-

{key.replace(/([A-Z])/g, ' $1')}

- + {isSuperAdmin && activeTab === 'features' && globalSettings && ( +
+

Moduli

+ +
+ {['multiCondo', 'tickets', 'documents', 'payPal', 'notices', 'reports', 'extraordinaryExpenses', 'condoFinancialsView'].map(k => ( +
toggleFeature(k as any)} className={`flex items-center justify-between p-5 rounded-2xl border cursor-pointer ${globalSettings.features[k as keyof AppSettings['features']] ? 'bg-blue-50 border-blue-200' : 'bg-white border-slate-200'}`}> + {k.replace(/([A-Z])/g, ' $1').trim()} +
))}
- +
)} - - {activeTab === 'general' && isPrivileged && activeCondo && ( -
-

Dati Condominio

-
- setActiveCondo({...activeCondo, name: e.target.value})} placeholder="Nome" required /> -
- setActiveCondo({...activeCondo, address: e.target.value})} placeholder="Indirizzo" required /> - setActiveCondo({...activeCondo, city: e.target.value})} placeholder="Città" required /> + + {/* TAB CONDOMINIO (GENERAL) */} + {activeTab === 'general' && ( + <> + {!activeCondo ? : ( +
+

Dati Condominio

+ +
+
setActiveCondo({...activeCondo, name: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl font-bold" required />
+
setActiveCondo({...activeCondo, address: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl" required />
+
+
setActiveCondo({...activeCondo, city: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl" />
+
setActiveCondo({...activeCondo, province: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl" />
+
+
+
setActiveCondo({...activeCondo, defaultMonthlyQuota: parseFloat(e.target.value)})} className="w-full border border-slate-200 p-3 rounded-xl font-bold" />
+
setActiveCondo({...activeCondo, dueDay: parseInt(e.target.value)})} className="w-full border border-slate-200 p-3 rounded-xl" />
+
+
+
setActiveCondo({...activeCondo, paypalClientId: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl text-xs font-mono" />
+
+
-
-
- - setActiveCondo({...activeCondo, defaultMonthlyQuota: parseFloat(e.target.value)})} required /> + )} + + )} + + {/* TAB STORAGE */} + {activeTab === 'storage' && ( +
+

Storage Cloud

+
+ + {storageForm.provider !== 'local_db' && ( +
+ setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="API Key / Access Key" /> + setStorageForm({...storageForm, apiSecret: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Secret Key" type="password" /> + setStorageForm({...storageForm, bucket: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Bucket Name" />
-
- - setActiveCondo({...activeCondo, dueDay: parseInt(e.target.value)})} required /> -
-
- + )} +
)} + + {/* TAB LISTA CONDOMINI */} + {activeTab === 'condos' && ( +
+

Elenco Condomini

+
+ {condos.map(c => ( +
+

{c.name}

{c.city}

+
+ + + +
+
+ ))} +
+
+ )} + + {/* TAB FAMIGLIE */} + {activeTab === 'families' && ( + <> + {!activeCondo ? : ( +
+

Famiglie

+
+ + + {families.map(f => ())} +
NomeUnitàAzioni
{f.name}{f.unitNumber}
+
+
+ )} + + )} + + {/* TAB USERS (ADMIN) */} + {activeTab === 'users' && ( +
+

Utenti

+
+ {users.map(u => ( +
+

{u.name}

{u.email}

{u.role}
+
+
+ ))} +
+
+ )} + + {/* TAB NOTICES */} + {activeTab === 'notices' && ( + <> + {!activeCondo ? : ( +
+

Bacheca

+
{notices.map(n => (

{n.title}

{n.content}

))}
+
+ )} + + )} + + {/* TAB ALERTS */} + {activeTab === 'alerts' && ( + <> + {!activeCondo ? : ( +
+

Alerts

+
{alerts.map(a => (

{a.subject}

{a.daysOffset}gg {a.offsetType}

))}
+
+ )} + + )}
+ + {/* --- MODALS --- */} + {showCondoModal && ( +
+
+

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

+
+ setCondoForm({...condoForm, name: e.target.value})} required /> + setCondoForm({...condoForm, address: e.target.value})} /> +
+
+
+
+ )} + + {showFamilyModal && ( +
+
+

{editingFamily ? 'Modifica Famiglia' : 'Nuova Famiglia'}

+
+ setFamilyForm({...familyForm, name: e.target.value})} required /> + setFamilyForm({...familyForm, unitNumber: e.target.value})} required /> + setFamilyForm({...familyForm, contactEmail: e.target.value})} /> + setFamilyForm({...familyForm, customMonthlyQuota: e.target.value})} /> +
+
+
+
+ )} + + {showUserModal && ( +
+
+

{editingUser ? 'Modifica Utente' : 'Nuovo Utente'}

+
+ setUserForm({...userForm, email: e.target.value})} required /> + setUserForm({...userForm, name: e.target.value})} /> + setUserForm({...userForm, password: e.target.value})} /> +
+ + +
+ {userForm.role === 'user' && ( +
+ + +
+ )} +
+
+
+
+ )} + + {showNoticeModal && ( +
+
+

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

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