import React, { useEffect, useState } from 'react'; import { CondoService } from '../services/mockDb'; 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, EyeOff, Calendar, List, UserCog, Mail, Power, MapPin, CreditCard, ToggleLeft, ToggleRight, LayoutGrid, PieChart, Users, Send, Cloud, HardDrive, ChevronRight, Palette, Image as ImageIcon, Upload, Phone, Hash, Type, Globe, Key, Database, AlignLeft, Euro } from 'lucide-react'; 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(); const isSuperAdmin = currentUser?.role === 'admin'; const isPrivileged = currentUser?.role === 'admin' || currentUser?.role === 'poweruser'; type TabType = 'profile' | 'features' | 'branding' | 'general' | 'storage' | 'condos' | 'families' | 'users' | 'notices' | 'alerts'; const [activeTab, setActiveTab] = useState(isPrivileged ? 'general' : 'profile'); const [loading, setLoading] = useState(true); // Profile Form const [profileForm, setProfileForm] = useState({ name: currentUser?.name || '', phone: currentUser?.phone || '', password: '', receiveAlerts: currentUser?.receiveAlerts ?? true }); const [profileSaving, setProfileSaving] = useState(false); const [profileMsg, setProfileMsg] = useState(''); // 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 [showPayPalKey, setShowPayPalKey] = useState(false); // State for PayPal input visibility 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' 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: '', 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(); const gSettings = await CondoService.getSettings(); setActiveCondo(activeC); setGlobalSettings(gSettings); setBrandingForm(gSettings.branding || { appName: 'CondoPay', primaryColor: 'blue', logoUrl: '', loginBackgroundUrl: '' }); 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)); setAlerts(await CondoService.getAlerts(activeC.id)); const allNotices = await CondoService.getNotices(activeC.id); setNotices(allNotices); const stats: Record = {}; for (const n of allNotices) { try { stats[n.id] = await CondoService.getNoticeReadStatus(n.id); } catch(e) {} } setNoticeReadStats(stats); } } } 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); 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); setSuccessMsg(''); try { const updated = { ...globalSettings, branding: brandingForm }; await CondoService.updateSettings(updated); setGlobalSettings(updated); window.dispatchEvent(new Event('branding-updated')); setSuccessMsg('Branding salvato!'); setTimeout(() => setSuccessMsg(''), 3000); } catch(e) { console.error(e); alert('Errore salvataggio branding'); } finally { setSaving(false); } }; const handleStorageSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!globalSettings) return; setSaving(true); setSuccessMsg(''); 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 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: 'Il Tuo Profilo', icon: }, ]; if (isSuperAdmin) { 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: '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: }); } // 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 (

Pannello di Controllo

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

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

Il Tuo Profilo

setProfileForm({...profileForm, name: e.target.value})} className="w-full border border-slate-200 p-3 pl-10 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 pl-10 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 pl-10 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none" />
{profileMsg &&

{profileMsg}

}
)} {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-32 text-sm font-mono border border-slate-200 rounded-xl p-3 pl-8 uppercase font-bold"/>
{brandingForm.logoUrl ? Logo : }
{brandingForm.loginBackgroundUrl ? Bg : }
{successMsg && {successMsg}}
)} {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()}
))}
{successMsg && {successMsg}}
)} {/* TAB CONDOMINIO (GENERAL) */} {activeTab === 'general' && ( <> {!activeCondo ? : (

Dati Condominio

setActiveCondo({...activeCondo, name: e.target.value})} className="w-full border border-slate-200 p-3 pl-10 rounded-xl font-bold" required />
setActiveCondo({...activeCondo, address: e.target.value})} className="w-full border border-slate-200 p-3 pl-10 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 pl-10 rounded-xl font-bold" />
setActiveCondo({...activeCondo, dueDay: parseInt(e.target.value)})} className="w-full border border-slate-200 p-3 pl-10 rounded-xl" />
setActiveCondo({...activeCondo, paypalClientId: e.target.value})} className="w-full border border-slate-200 p-3 pl-10 rounded-xl text-xs font-mono pr-10" placeholder="sandbox_..." />

Necessario per abilitare i pagamenti online.

{successMsg && {successMsg}}
)} )} {/* TAB STORAGE */} {activeTab === 'storage' && (

Storage Cloud

{storageForm.provider !== 'local_db' && (
{storageForm.provider === 's3' && ( <>
setStorageForm({...storageForm, bucket: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Bucket Name" />
setStorageForm({...storageForm, region: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Region (es. eu-central-1)" />
setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Access Key ID" />
setStorageForm({...storageForm, apiSecret: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Secret Access Key" type="password" />
)} {storageForm.provider === 'google_drive' && ( <>
setStorageForm({...storageForm, bucket: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Parent Folder ID (Opzionale)" />
setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Service Account Email (client_email)" />