Files
Condopay/pages/Settings.tsx
2026-01-10 00:12:47 +01:00

866 lines
74 KiB
TypeScript

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<string, string> = {
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<TabType>(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<Condo | undefined>(undefined);
const [globalSettings, setGlobalSettings] = useState<AppSettings | null>(null);
const [brandingForm, setBrandingForm] = useState<BrandingConfig>({ appName: 'CondoPay', primaryColor: 'blue', logoUrl: '', loginBackgroundUrl: '' });
// Condos List
const [condos, setCondos] = useState<Condo[]>([]);
const [showCondoModal, setShowCondoModal] = useState(false);
const [editingCondo, setEditingCondo] = useState<Condo | null>(null);
const [condoForm, setCondoForm] = useState<Partial<Condo>>({
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<Family[]>([]);
const [showFamilyModal, setShowFamilyModal] = useState(false);
const [editingFamily, setEditingFamily] = useState<Family | null>(null);
const [familyForm, setFamilyForm] = useState({ name: '', unitNumber: '', stair: '', floor: '', notes: '', contactEmail: '', customMonthlyQuota: '' });
// Users Management
const [users, setUsers] = useState<User[]>([]);
const [showUserModal, setShowUserModal] = useState(false);
const [editingUser, setEditingUser] = useState<User | null>(null);
const [userForm, setUserForm] = useState({ name: '', email: '', password: '', phone: '', role: 'user' as User['role'], familyId: '', receiveAlerts: true });
// Alerts & Email Rules
const [alerts, setAlerts] = useState<AlertDefinition[]>([]);
const [showAlertModal, setShowAlertModal] = useState(false);
const [editingAlert, setEditingAlert] = useState<AlertDefinition | null>(null);
const [alertForm, setAlertForm] = useState<Partial<AlertDefinition>>({ 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<Notice[]>([]);
const [showNoticeModal, setShowNoticeModal] = useState(false);
const [editingNotice, setEditingNotice] = useState<Notice | null>(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<Record<string, NoticeRead[]>>({});
const [showReadDetailsModal, setShowReadDetailsModal] = useState(false);
const [selectedNoticeId, setSelectedNoticeId] = useState<string | null>(null);
// Cloud Storage Settings
const [storageForm, setStorageForm] = useState<StorageConfig>({ 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<string, NoticeRead[]> = {};
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<HTMLInputElement>) => {
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<HTMLInputElement>) => {
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: <UserIcon className="w-4 h-4"/> },
];
if (isSuperAdmin) {
tabs.push(
{ id: 'features', label: 'Funzionalità', icon: <LayoutGrid className="w-4 h-4"/> },
{ id: 'branding', label: 'Personalizzazione', icon: <Palette className="w-4 h-4"/> }
);
}
if (isPrivileged) {
tabs.push({ id: 'general', label: 'Condominio', icon: <Building className="w-4 h-4"/> });
if (globalSettings?.features.documents) tabs.push({ id: 'storage', label: 'Cloud Storage', icon: <HardDrive className="w-4 h-4"/> });
if (globalSettings?.features.multiCondo) tabs.push({ id: 'condos', label: 'Lista Condomini', icon: <List className="w-4 h-4"/> });
tabs.push(
{ id: 'families', label: 'Famiglie', icon: <Coins className="w-4 h-4"/> },
{ id: 'users', label: 'Account Utenti', icon: <UserCog className="w-4 h-4"/> }
);
if (globalSettings?.features.notices) tabs.push({ id: 'notices', label: 'Bacheca Avvisi', icon: <Megaphone className="w-4 h-4"/> });
tabs.push({ id: 'alerts', label: 'Scadenze & Email', icon: <Bell className="w-4 h-4"/> });
}
// Componente per lo stato vuoto quando non c'è un condominio attivo
const NoCondoState = () => (
<div className="bg-amber-50 border border-amber-200 rounded-2xl p-8 text-center">
<Building className="w-12 h-12 text-amber-400 mx-auto mb-4" />
<h3 className="text-xl font-bold text-amber-800 mb-2">Nessun Condominio Selezionato</h3>
<p className="text-amber-700 mb-6">Per accedere a questa sezione devi prima creare o selezionare un condominio.</p>
<button onClick={openAddCondoModal} className="bg-amber-600 text-white px-6 py-3 rounded-xl font-bold hover:bg-amber-700 inline-flex items-center gap-2 justify-center">
<Plus className="w-5 h-5"/> Crea il tuo primo Condominio
</button>
</div>
);
if (loading) return <div className="p-12 text-center text-slate-400">Inizializzazione impostazioni...</div>;
return (
<div className="max-w-6xl mx-auto pb-32 animate-fade-in">
<div className="mb-8">
<h2 className="text-3xl font-bold text-slate-900">Pannello di Controllo</h2>
<p className="text-slate-500 mt-1">{activeCondo ? `Configurazione per: ${activeCondo.name}` : 'Benvenuto! Inizia configurando il tuo stabile.'}</p>
</div>
<div className="flex flex-col md:flex-row gap-8">
{/* Sidebar Nav */}
<div className="md:w-72 flex-shrink-0">
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden sticky top-4">
<div className="flex md:flex-col overflow-x-auto no-scrollbar p-3 gap-1.5">
{tabs.map(tab => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-bold transition-all whitespace-nowrap ${activeTab === tab.id ? 'bg-blue-600 text-white shadow-lg shadow-blue-200' : 'text-slate-600 hover:bg-slate-50'}`}
>
{tab.icon}
<span>{tab.label}</span>
</button>
))}
</div>
</div>
</div>
{/* Content Area */}
<div className="flex-1 min-w-0">
{activeTab === 'profile' && (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex items-center gap-3 mb-8"><div className="p-3 bg-blue-50 rounded-2xl text-blue-600"><UserIcon className="w-6 h-6" /></div><h3 className="text-xl font-bold text-slate-800">Il Tuo Profilo</h3></div>
<form onSubmit={handleProfileSubmit} className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Nome Completo</label>
<div className="relative">
<UserIcon className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="text" value={profileForm.name} onChange={(e) => 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 />
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Email</label>
<div className="relative">
<Mail className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="email" value={currentUser?.email || ''} disabled className="w-full border border-slate-100 bg-slate-50 p-3 pl-10 rounded-xl text-slate-400 cursor-not-allowed" />
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Telefono</label>
<div className="relative">
<Phone className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="tel" value={profileForm.phone} onChange={(e) => 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" />
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Password</label>
<div className="relative">
<Lock className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="password" placeholder="Opzionale" value={profileForm.password} onChange={(e) => 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" />
</div>
</div>
</div>
<div className="pt-2 border-t flex justify-between items-center"><button type="submit" disabled={profileSaving} className="bg-blue-600 text-white px-8 py-3 rounded-xl font-bold flex items-center justify-center gap-2 hover:bg-blue-700 shadow-lg shadow-blue-200 disabled:opacity-50"><Save className="w-4 h-4" /> {profileSaving ? '...' : 'Salva'}</button>{profileMsg && <p className="text-sm font-bold text-green-600">{profileMsg}</p>}</div>
</form>
</div>
)}
{isSuperAdmin && activeTab === 'branding' && globalSettings && (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex items-center gap-3 mb-8"><div className="p-3 bg-purple-50 rounded-2xl text-purple-600"><Palette className="w-6 h-6" /></div><h3 className="text-xl font-bold text-slate-800">Branding</h3></div>
<form onSubmit={handleBrandingSubmit} className="space-y-8">
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Nome App</label>
<div className="relative">
<Type className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border border-slate-200 p-3 pl-10 rounded-xl font-bold text-slate-800" value={brandingForm.appName} onChange={e => setBrandingForm({...brandingForm, appName: e.target.value})}/>
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-4 block">Colore Primario</label>
<div className="flex gap-4 flex-wrap items-center bg-slate-50 p-6 rounded-2xl border border-slate-100">
{Object.keys(COLOR_MAP).map(colorKey => (
<button key={colorKey} type="button" onClick={() => setBrandingForm({...brandingForm, primaryColor: colorKey})} className={`w-12 h-12 rounded-2xl border-4 transition-all hover:scale-110 flex items-center justify-center shadow-sm ${brandingForm.primaryColor === colorKey ? 'border-white ring-4 ring-slate-900' : 'border-transparent'}`} style={{ backgroundColor: COLOR_MAP[colorKey] }}>{brandingForm.primaryColor === colorKey && <CheckCircle2 className="w-6 h-6 text-white"/>}</button>
))}
<div className="h-10 w-px bg-slate-200 mx-2" />
<div className="flex items-center gap-2">
<input type="color" value={brandingForm.primaryColor.startsWith('#') ? brandingForm.primaryColor : '#2563eb'} onChange={e => setBrandingForm({...brandingForm, primaryColor: e.target.value})} className="w-12 h-12 rounded-2xl border-2 cursor-pointer p-0 bg-transparent"/>
<div className="relative">
<Hash className="absolute left-2 top-3.5 w-4 h-4 text-slate-400" />
<input type="text" value={brandingForm.primaryColor} onChange={e => 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"/>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div><label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Logo</label><div className="border-4 border-dashed border-slate-100 rounded-3xl p-8 text-center relative h-48 flex items-center justify-center bg-slate-50/50 hover:bg-slate-50 transition-colors"><input type="file" onChange={handleLogoUpload} className="absolute inset-0 opacity-0 cursor-pointer z-10" />{brandingForm.logoUrl ? <img src={brandingForm.logoUrl} alt="Logo" className="max-h-full max-w-full object-contain" /> : <ImageIcon className="w-12 h-12 text-slate-300"/>}</div></div>
<div><label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Sfondo Login</label><div className="border-4 border-dashed border-slate-100 rounded-3xl p-8 text-center relative h-48 flex items-center justify-center bg-slate-50/50 hover:bg-slate-50 transition-colors"><input type="file" onChange={handleBgUpload} className="absolute inset-0 opacity-0 cursor-pointer z-10" />{brandingForm.loginBackgroundUrl ? <img src={brandingForm.loginBackgroundUrl} alt="Bg" className="w-full h-full object-cover rounded-xl" /> : <Upload className="w-12 h-12 text-slate-300"/>}</div></div>
</div>
<div className="pt-6 border-t flex justify-between items-center">
<div className="flex-1">{successMsg && <span className="text-green-600 font-bold flex items-center gap-2"><CheckCircle2 className="w-5 h-5"/> {successMsg}</span>}</div>
<button type="submit" disabled={saving} className="bg-slate-900 text-white px-10 py-4 rounded-2xl font-bold hover:bg-black shadow-xl flex items-center justify-center gap-2 disabled:opacity-50">
{saving ? 'Salvataggio...' : <><Save className="w-5 h-5" /> Applica</>}
</button>
</div>
</form>
</div>
)}
{isSuperAdmin && activeTab === 'features' && globalSettings && (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex items-center gap-3 mb-8"><div className="p-3 bg-green-50 rounded-2xl text-green-600"><LayoutGrid className="w-6 h-6" /></div><h3 className="text-xl font-bold text-slate-800">Moduli</h3></div>
<form onSubmit={handleFeaturesSubmit} className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{['multiCondo', 'tickets', 'documents', 'payPal', 'notices', 'reports', 'extraordinaryExpenses', 'condoFinancialsView'].map(k => (
<div key={k} onClick={() => 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'}`}>
<span className="font-bold text-slate-800 capitalize">{k.replace(/([A-Z])/g, ' $1').trim()}</span>
<span className={`h-6 w-11 rounded-full relative transition-colors ${globalSettings.features[k as keyof AppSettings['features']] ? 'bg-blue-600' : 'bg-slate-300'}`}><span className={`absolute top-1 left-1 bg-white w-4 h-4 rounded-full transition-transform ${globalSettings.features[k as keyof AppSettings['features']] ? 'translate-x-5' : ''}`}/></span>
</div>
))}
</div>
<div className="pt-8 border-t flex justify-between items-center">
<div className="flex-1">{successMsg && <span className="text-green-600 font-bold flex items-center gap-2"><CheckCircle2 className="w-5 h-5"/> {successMsg}</span>}</div>
<button type="submit" disabled={saving} className="bg-blue-600 text-white px-8 py-3 rounded-xl font-bold hover:bg-blue-700 shadow-lg flex items-center justify-center gap-2 disabled:opacity-50">
{saving ? '...' : 'Salva'}
</button>
</div>
</form>
</div>
)}
{/* TAB CONDOMINIO (GENERAL) */}
{activeTab === 'general' && (
<>
{!activeCondo ? <NoCondoState /> : (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex items-center gap-3 mb-8"><div className="p-3 bg-blue-50 rounded-2xl text-blue-600"><Building className="w-6 h-6" /></div><h3 className="text-xl font-bold text-slate-800">Dati Condominio</h3></div>
<form onSubmit={handleGeneralSubmit} className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Nome</label>
<div className="relative">
<Building className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="text" value={activeCondo.name} onChange={e => setActiveCondo({...activeCondo, name: e.target.value})} className="w-full border border-slate-200 p-3 pl-10 rounded-xl font-bold" required />
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Indirizzo</label>
<div className="relative">
<MapPin className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="text" value={activeCondo.address || ''} onChange={e => setActiveCondo({...activeCondo, address: e.target.value})} className="w-full border border-slate-200 p-3 pl-10 rounded-xl" required />
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Città</label>
<input type="text" value={activeCondo.city || ''} onChange={e => setActiveCondo({...activeCondo, city: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl" />
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Prov</label>
<input type="text" value={activeCondo.province || ''} onChange={e => setActiveCondo({...activeCondo, province: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl" />
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Quota Mensile</label>
<div className="relative">
<Euro className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="number" value={activeCondo.defaultMonthlyQuota} onChange={e => setActiveCondo({...activeCondo, defaultMonthlyQuota: parseFloat(e.target.value)})} className="w-full border border-slate-200 p-3 pl-10 rounded-xl font-bold" />
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Scadenza (Giorno)</label>
<div className="relative">
<Calendar className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="number" value={activeCondo.dueDay || 10} onChange={e => setActiveCondo({...activeCondo, dueDay: parseInt(e.target.value)})} className="w-full border border-slate-200 p-3 pl-10 rounded-xl" />
</div>
</div>
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-2 block">PayPal Client ID</label>
<div className="relative">
<CreditCard className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input
type={showPayPalKey ? "text" : "password"}
value={activeCondo.paypalClientId || ''}
onChange={e => 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_..."
/>
<button
type="button"
onClick={() => setShowPayPalKey(!showPayPalKey)}
className="absolute right-3 top-3 text-slate-400 hover:text-blue-600 transition-colors"
>
{showPayPalKey ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
<p className="text-[10px] text-slate-400 mt-1">Necessario per abilitare i pagamenti online.</p>
</div>
<div className="pt-6 border-t flex justify-between items-center">
<div className="flex-1">{successMsg && <span className="text-green-600 font-bold flex items-center gap-2"><CheckCircle2 className="w-5 h-5"/> {successMsg}</span>}</div>
<button type="submit" disabled={saving} className="bg-blue-600 text-white px-8 py-3 rounded-xl font-bold hover:bg-blue-700 shadow-lg flex items-center justify-center gap-2 disabled:opacity-50">
{saving ? '...' : 'Salva Dati'}
</button>
</div>
</form>
</div>
)}
</>
)}
{/* TAB STORAGE */}
{activeTab === 'storage' && (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex items-center gap-3 mb-8"><div className="p-3 bg-amber-50 rounded-2xl text-amber-600"><HardDrive className="w-6 h-6" /></div><h3 className="text-xl font-bold text-slate-800">Storage Cloud</h3></div>
<form onSubmit={handleStorageSubmit} className="space-y-6">
<select value={storageForm.provider} onChange={e => setStorageForm({...storageForm, provider: e.target.value as any})} className="w-full border border-slate-200 p-3 rounded-xl font-bold text-slate-700">
<option value="local_db">Database Locale (Default)</option>
<option value="s3">Amazon S3</option>
<option value="google_drive">Google Drive</option>
<option value="dropbox">Dropbox</option>
<option value="onedrive">Microsoft OneDrive</option>
</select>
{storageForm.provider !== 'local_db' && (
<div className="space-y-6 p-6 bg-slate-50 rounded-2xl border border-slate-100">
{storageForm.provider === 's3' && (
<>
<div className="relative">
<Database className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input value={storageForm.bucket || ''} onChange={e => setStorageForm({...storageForm, bucket: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Bucket Name" />
</div>
<div className="relative">
<Globe className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input value={storageForm.region || ''} onChange={e => setStorageForm({...storageForm, region: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Region (es. eu-central-1)" />
</div>
<div className="relative">
<Key className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input value={storageForm.apiKey || ''} onChange={e => setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Access Key ID" />
</div>
<div className="relative">
<Lock className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input value={storageForm.apiSecret || ''} onChange={e => setStorageForm({...storageForm, apiSecret: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Secret Access Key" type="password" />
</div>
</>
)}
{storageForm.provider === 'google_drive' && (
<>
<div className="relative">
<Database className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input value={storageForm.bucket || ''} onChange={e => setStorageForm({...storageForm, bucket: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Parent Folder ID (Opzionale)" />
</div>
<div className="relative">
<Mail className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input value={storageForm.apiKey || ''} onChange={e => setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Service Account Email (client_email)" />
</div>
<textarea value={storageForm.apiSecret || ''} onChange={e => setStorageForm({...storageForm, apiSecret: e.target.value})} className="w-full border p-3 rounded-xl h-32 text-xs font-mono" placeholder="Private Key (-----BEGIN PRIVATE KEY...)" />
</>
)}
{(storageForm.provider === 'dropbox' || storageForm.provider === 'onedrive') && (
<>
<div className="relative">
<Key className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input value={storageForm.apiKey || ''} onChange={e => setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 pl-10 rounded-xl" placeholder="Access Token" type="password" />
</div>
<p className="text-xs text-slate-500">Nota: Inserisci un Access Token valido a lunga durata.</p>
</>
)}
</div>
)}
<div className="pt-4 border-t flex justify-between items-center">
<div className="flex-1">{successMsg && <span className="text-green-600 font-bold flex items-center gap-2"><CheckCircle2 className="w-5 h-5"/> {successMsg}</span>}</div>
<button type="submit" disabled={saving} className="bg-slate-900 text-white px-8 py-3 rounded-xl font-bold flex items-center justify-center gap-2 disabled:opacity-50">
{saving ? '...' : 'Salva'}
</button>
</div>
</form>
</div>
)}
{/* TAB LISTA CONDOMINI */}
{activeTab === 'condos' && (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex justify-between items-center mb-8"><h3 className="text-xl font-bold text-slate-800">Elenco Condomini</h3><button onClick={openAddCondoModal} className="bg-blue-600 text-white px-4 py-2 rounded-xl font-bold flex items-center justify-center gap-2"><Plus className="w-4 h-4"/> Aggiungi</button></div>
<div className="grid gap-4">
{condos.map(c => (
<div key={c.id} className="flex items-center justify-between p-5 rounded-2xl border bg-slate-50 border-slate-100">
<div><p className="font-bold text-slate-800">{c.name}</p><p className="text-xs text-slate-500">{c.city}</p></div>
<div className="flex gap-2">
<button onClick={() => CondoService.setActiveCondo(c.id)} className="px-4 py-2 bg-white border border-slate-200 rounded-lg text-xs font-bold hover:bg-slate-50">Usa</button>
<button onClick={() => openEditCondoModal(c)} className="p-2 text-blue-600 hover:bg-blue-100 rounded-lg"><Pencil className="w-5 h-5"/></button>
<button onClick={() => handleDeleteCondo(c.id)} className="p-2 text-red-500 hover:bg-red-50 rounded-lg"><Trash2 className="w-5 h-5"/></button>
</div>
</div>
))}
</div>
</div>
)}
{/* TAB FAMIGLIE */}
{activeTab === 'families' && (
<>
{!activeCondo ? <NoCondoState /> : (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex justify-between items-center mb-8"><h3 className="text-xl font-bold text-slate-800">Famiglie</h3><button onClick={openAddFamilyModal} className="bg-blue-600 text-white px-4 py-2 rounded-xl font-bold flex items-center justify-center gap-2"><Plus className="w-4 h-4"/> Aggiungi</button></div>
<div className="overflow-x-auto border border-slate-100 rounded-2xl">
<table className="w-full text-sm text-left">
<thead className="bg-slate-50 text-slate-500 font-bold uppercase text-[10px]"><tr><th className="px-6 py-4">Nome</th><th className="px-6 py-4">Unità</th><th className="px-6 py-4 text-right">Azioni</th></tr></thead>
<tbody className="divide-y divide-slate-50">{families.map(f => (<tr key={f.id} className="hover:bg-slate-50"><td className="px-6 py-4 font-bold text-slate-800">{f.name}</td><td className="px-6 py-4">{f.unitNumber}</td><td className="px-6 py-4 text-right"><div className="flex justify-end gap-2"><button onClick={() => openEditFamilyModal(f)} className="text-blue-600 p-2"><Pencil className="w-4 h-4"/></button><button onClick={() => handleDeleteFamily(f.id)} className="text-red-500 p-2"><Trash2 className="w-4 h-4"/></button></div></td></tr>))}</tbody>
</table>
</div>
</div>
)}
</>
)}
{/* TAB USERS (ADMIN) */}
{activeTab === 'users' && (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex justify-between items-center mb-8"><h3 className="text-xl font-bold text-slate-800">Utenti</h3><button onClick={openAddUserModal} className="bg-blue-600 text-white px-4 py-2 rounded-xl font-bold flex items-center justify-center gap-2"><Plus className="w-4 h-4"/> Aggiungi</button></div>
<div className="grid gap-4 md:grid-cols-2">
{users.map(u => {
const isTargetAdmin = u.role === 'admin';
// Logic: PowerUsers cannot edit/delete Admins
const canManage = !(currentUser?.role === 'poweruser' && isTargetAdmin);
return (
<div key={u.id} className="p-5 border border-slate-100 rounded-2xl bg-slate-50 flex items-center justify-between">
<div><p className="font-bold text-slate-800">{u.name}</p><p className="text-xs text-slate-400">{u.email}</p><span className="text-[10px] uppercase font-bold bg-white px-2 py-0.5 rounded border border-slate-200 mt-1 inline-block">{u.role}</span></div>
<div className="flex gap-1">
{canManage ? (
<>
<button onClick={() => openEditUserModal(u)} className="p-2 text-blue-600 hover:bg-white rounded-lg"><Pencil className="w-4 h-4"/></button>
<button onClick={() => handleDeleteUser(u.id)} className="p-2 text-red-500 hover:bg-white rounded-lg"><Trash2 className="w-4 h-4"/></button>
</>
) : (
<span className="text-[10px] text-slate-400 font-medium italic px-2 py-1">Protetto</span>
)}
</div>
</div>
);
})}
</div>
</div>
)}
{/* TAB NOTICES */}
{activeTab === 'notices' && (
<>
{!activeCondo ? <NoCondoState /> : (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex justify-between items-center mb-8"><h3 className="text-xl font-bold text-slate-800">Bacheca</h3><button onClick={openAddNoticeModal} className="bg-blue-600 text-white px-4 py-2 rounded-xl font-bold flex items-center justify-center gap-2"><Plus className="w-4 h-4"/> Pubblica</button></div>
<div className="grid gap-4">{notices.map(n => (<div key={n.id} className="p-5 border rounded-2xl flex justify-between items-start gap-4"><div className="min-w-0 flex-1"><h4 className="font-bold text-slate-800 break-words">{n.title}</h4><p className="text-sm text-slate-500 break-words mt-1">{n.content}</p></div><div className="flex gap-2 flex-shrink-0"><button onClick={() => { setSelectedNoticeId(n.id); setShowReadDetailsModal(true); }} className="p-2 text-slate-500 bg-slate-50 rounded-lg"><Eye className="w-4 h-4"/></button><button onClick={() => openEditNoticeModal(n)} className="p-2 text-blue-600 bg-blue-50 rounded-lg"><Pencil className="w-4 h-4"/></button><button onClick={() => handleDeleteNotice(n.id)} className="p-2 text-red-500 bg-red-50 rounded-lg"><Trash2 className="w-4 h-4"/></button></div></div>))}</div>
</div>
)}
</>
)}
{/* TAB ALERTS */}
{activeTab === 'alerts' && (
<>
{!activeCondo ? <NoCondoState /> : (
<div className="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div className="flex justify-between items-center mb-8"><h3 className="text-xl font-bold text-slate-800">Alerts</h3><div className="flex gap-2"><button onClick={() => setShowSmtpModal(true)} className="bg-slate-100 text-slate-700 px-4 py-2 rounded-xl font-bold">SMTP</button><button onClick={openAddAlertModal} className="bg-blue-600 text-white px-4 py-2 rounded-xl font-bold flex items-center justify-center gap-2"><Plus className="w-4 h-4"/></button></div></div>
<div className="grid gap-4">{alerts.map(a => (<div key={a.id} className="p-5 border rounded-2xl flex justify-between"><div><h4 className="font-bold text-slate-800">{a.subject}</h4><p className="text-xs text-slate-500">{a.daysOffset}gg {a.offsetType}</p></div><button onClick={() => handleDeleteAlert(a.id)} className="text-red-500"><Trash2 className="w-4 h-4"/></button></div>))}</div>
</div>
)}
</>
)}
</div>
</div>
{/* --- MODALS (Omitted unchanged modals like Condo, Family, User for brevity, assuming standard implementation) --- */}
{/* Keeping just the essential parts that rely on state to prove functionality */}
{showCondoModal && (
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-lg p-8 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-2xl mb-6 text-slate-800">{editingCondo ? 'Modifica Condominio' : 'Nuovo Condominio'}</h3>
<form onSubmit={handleCondoSubmit} className="space-y-4">
<div className="relative">
<Building className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Nome Condominio" value={condoForm.name} onChange={e => setCondoForm({...condoForm, name: e.target.value})} required />
</div>
<div className="relative">
<MapPin className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Indirizzo" value={condoForm.address} onChange={e => setCondoForm({...condoForm, address: e.target.value})} />
</div>
<div className="flex gap-4 pt-4"><button type="button" onClick={() => setShowCondoModal(false)} className="flex-1 bg-slate-100 py-3 rounded-xl font-bold hover:bg-slate-200">Annulla</button><button type="submit" className="flex-1 bg-blue-600 text-white py-3 rounded-xl font-bold hover:bg-blue-700">Salva</button></div>
</form>
</div>
</div>
)}
{showFamilyModal && (
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-md p-8 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-2xl mb-6 text-slate-800">{editingFamily ? 'Modifica Famiglia' : 'Nuova Famiglia'}</h3>
<form onSubmit={handleFamilySubmit} className="space-y-4">
<div className="relative">
<UserIcon className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Nome (es. Fam. Rossi)" value={familyForm.name} onChange={e => setFamilyForm({...familyForm, name: e.target.value})} required />
</div>
<div className="relative">
<Building className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Interno / Unità" value={familyForm.unitNumber} onChange={e => setFamilyForm({...familyForm, unitNumber: e.target.value})} required />
</div>
<div className="relative">
<Mail className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Email Contatto" type="email" value={familyForm.contactEmail} onChange={e => setFamilyForm({...familyForm, contactEmail: e.target.value})} />
</div>
<div className="relative">
<Euro className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Quota Personalizzata (Opzionale)" type="number" step="0.01" value={familyForm.customMonthlyQuota} onChange={e => setFamilyForm({...familyForm, customMonthlyQuota: e.target.value})} />
</div>
<div className="flex gap-4 pt-4"><button type="button" onClick={() => setShowFamilyModal(false)} className="flex-1 bg-slate-100 py-3 rounded-xl font-bold hover:bg-slate-200">Annulla</button><button type="submit" className="flex-1 bg-blue-600 text-white py-3 rounded-xl font-bold hover:bg-blue-700">Salva</button></div>
</form>
</div>
</div>
)}
{showUserModal && (
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-md p-8 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-2xl mb-6 text-slate-800">{editingUser ? 'Modifica Utente' : 'Nuovo Utente'}</h3>
<form onSubmit={handleUserSubmit} className="space-y-4">
<div className="relative">
<Mail className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="email" className="w-full border p-3 pl-10 rounded-xl" placeholder="Email" value={userForm.email} onChange={e => setUserForm({...userForm, email: e.target.value})} required />
</div>
<div className="relative">
<UserIcon className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Nome" value={userForm.name} onChange={e => setUserForm({...userForm, name: e.target.value})} />
</div>
<div className="relative">
<Phone className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="tel" className="w-full border p-3 pl-10 rounded-xl" placeholder="Telefono" value={userForm.phone} onChange={e => setUserForm({...userForm, phone: e.target.value})} />
</div>
<div className="relative">
<Lock className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="password" className="w-full border p-3 pl-10 rounded-xl" placeholder="Password (lascia vuoto se invariata)" value={userForm.password} onChange={e => setUserForm({...userForm, password: e.target.value})} />
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Ruolo</label>
<select className="w-full border p-3 rounded-xl bg-white" value={userForm.role} onChange={(e: any) => setUserForm({...userForm, role: e.target.value})}>
<option value="user">Utente Standard</option>
<option value="poweruser">Power User</option>
<option value="admin">Amministratore</option>
</select>
</div>
{userForm.role === 'user' && (
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Associa Famiglia</label>
<select className="w-full border p-3 rounded-xl bg-white" value={userForm.familyId} onChange={(e) => setUserForm({...userForm, familyId: e.target.value})}>
<option value="">Nessuna</option>
{families.map(f => <option key={f.id} value={f.id}>{f.name} ({f.unitNumber})</option>)}
</select>
</div>
)}
<div className="flex gap-4 pt-4"><button type="button" onClick={() => setShowUserModal(false)} className="flex-1 bg-slate-100 py-3 rounded-xl font-bold hover:bg-slate-200">Annulla</button><button type="submit" className="flex-1 bg-blue-600 text-white py-3 rounded-xl font-bold hover:bg-blue-700">Salva</button></div>
</form>
</div>
</div>
)}
{showNoticeModal && (
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-lg p-8 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-2xl mb-6 text-slate-800">{editingNotice ? 'Modifica Avviso' : 'Nuovo Avviso'}</h3>
<form onSubmit={handleNoticeSubmit} className="space-y-4">
<div className="relative">
<Type className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Titolo" value={noticeForm.title} onChange={e => setNoticeForm({...noticeForm, title: e.target.value})} required />
</div>
<div className="relative">
<AlignLeft className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<textarea className="w-full border p-3 pl-10 rounded-xl h-24" placeholder="Contenuto..." value={noticeForm.content} onChange={e => setNoticeForm({...noticeForm, content: e.target.value})} required />
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Tipo</label>
<select className="w-full border p-3 rounded-xl bg-white" value={noticeForm.type} onChange={(e: any) => setNoticeForm({...noticeForm, type: e.target.value})}>
<option value="info">Info</option>
<option value="warning">Avviso</option>
<option value="maintenance">Lavori</option>
<option value="event">Evento</option>
</select>
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Visibilità</label>
<div className="flex gap-2 mt-2">
<button type="button" onClick={() => setNoticeTargetMode('all')} className={`flex-1 py-2 rounded-lg text-xs font-bold border ${noticeTargetMode === 'all' ? 'bg-blue-50 border-blue-200 text-blue-600' : 'bg-white border-slate-200 text-slate-500'}`}>Tutti</button>
<button type="button" onClick={() => setNoticeTargetMode('specific')} className={`flex-1 py-2 rounded-lg text-xs font-bold border ${noticeTargetMode === 'specific' ? 'bg-blue-50 border-blue-200 text-blue-600' : 'bg-white border-slate-200 text-slate-500'}`}>Specifici</button>
</div>
</div>
</div>
{noticeTargetMode === 'specific' && (
<div className="border rounded-xl p-2 max-h-32 overflow-y-auto">
{families.map(f => (
<label key={f.id} className="flex items-center gap-2 p-2 hover:bg-slate-50 rounded cursor-pointer">
<input
type="checkbox"
checked={noticeForm.targetFamilyIds.includes(f.id)}
onChange={e => {
if (e.target.checked) setNoticeForm(prev => ({...prev, targetFamilyIds: [...prev.targetFamilyIds, f.id]}));
else setNoticeForm(prev => ({...prev, targetFamilyIds: prev.targetFamilyIds.filter(id => id !== f.id)}));
}}
className="rounded text-blue-600"
/>
<span className="text-sm text-slate-700">{f.name}</span>
</label>
))}
</div>
)}
<div className="relative">
<LinkIcon className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Link esterno (es. PDF Drive)" value={noticeForm.link} onChange={e => setNoticeForm({...noticeForm, link: e.target.value})} />
</div>
<div className="flex gap-4 pt-4"><button type="button" onClick={() => setShowNoticeModal(false)} className="flex-1 bg-slate-100 py-3 rounded-xl font-bold hover:bg-slate-200">Annulla</button><button type="submit" className="flex-1 bg-blue-600 text-white py-3 rounded-xl font-bold hover:bg-blue-700">Pubblica</button></div>
</form>
</div>
</div>
)}
{showAlertModal && (
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-lg p-8 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-2xl mb-6 text-slate-800">Regola Avviso Automatico</h3>
<form onSubmit={handleAlertSubmit} className="space-y-4">
<div className="relative">
<Type className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Oggetto Email" value={alertForm.subject} onChange={e => setAlertForm({...alertForm, subject: e.target.value})} required />
</div>
<div className="relative">
<AlignLeft className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<textarea className="w-full border p-3 pl-10 rounded-xl h-24" placeholder="Testo Email..." value={alertForm.body} onChange={e => setAlertForm({...alertForm, body: e.target.value})} required />
</div>
<div className="grid grid-cols-2 gap-4">
<div><label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Giorni Offset</label><input type="number" className="w-full border p-3 rounded-xl" value={alertForm.daysOffset} onChange={e => setAlertForm({...alertForm, daysOffset: parseInt(e.target.value)})} /></div>
<div><label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Tipo Offset</label><select className="w-full border p-3 rounded-xl bg-white" value={alertForm.offsetType} onChange={(e: any) => setAlertForm({...alertForm, offsetType: e.target.value})}><option value="before_next_month">Giorni prima scadenza</option><option value="after_current_month">Giorni dopo scadenza</option></select></div>
</div>
<div className="flex gap-4 pt-4"><button type="button" onClick={() => setShowAlertModal(false)} className="flex-1 bg-slate-100 py-3 rounded-xl font-bold hover:bg-slate-200">Annulla</button><button type="submit" className="flex-1 bg-blue-600 text-white py-3 rounded-xl font-bold hover:bg-blue-700">Salva</button></div>
</form>
</div>
</div>
)}
{showSmtpModal && globalSettings?.smtpConfig && (
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-md p-8 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-2xl mb-6 text-slate-800">Configurazione SMTP</h3>
<form onSubmit={async (e) => {
e.preventDefault();
// Update settings directly via API
const updated = { ...globalSettings, smtpConfig: globalSettings.smtpConfig };
await CondoService.updateSettings(updated);
setGlobalSettings(updated);
setShowSmtpModal(false);
}} className="space-y-4">
<div className="relative">
<Server className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Host (smtp.gmail.com)" value={globalSettings.smtpConfig.host} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, host: e.target.value}})} required />
</div>
<div className="grid grid-cols-2 gap-4">
<div className="relative">
<Hash className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input type="number" className="w-full border p-3 pl-10 rounded-xl" placeholder="Porta (465)" value={globalSettings.smtpConfig.port} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, port: parseInt(e.target.value)}})} required />
</div>
<label className="flex items-center gap-2 border p-3 rounded-xl bg-slate-50 cursor-pointer"><input type="checkbox" checked={globalSettings.smtpConfig.secure} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, secure: e.target.checked}})} /> <span className="text-sm font-bold text-slate-600">SSL/TLS</span></label>
</div>
<div className="relative">
<UserIcon className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="Utente/Email" value={globalSettings.smtpConfig.user} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, user: e.target.value}})} required />
</div>
<div className="relative">
<Lock className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" type="password" placeholder="Password" value={globalSettings.smtpConfig.pass} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, pass: e.target.value}})} required />
</div>
<div className="relative">
<Mail className="absolute left-3 top-3.5 w-5 h-5 text-slate-400" />
<input className="w-full border p-3 pl-10 rounded-xl" placeholder="From Email (Opzionale)" value={globalSettings.smtpConfig.fromEmail || ''} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, fromEmail: e.target.value}})} />
</div>
{testSmtpMsg && <div className={`p-3 rounded-xl text-sm font-bold text-center ${testSmtpMsg.includes('Errore') ? 'bg-red-50 text-red-600' : 'bg-green-50 text-green-600'}`}>{testSmtpMsg}</div>}
<div className="flex gap-2 pt-2">
<button type="button" onClick={handleTestSmtp} disabled={testingSmtp} className="flex-1 bg-slate-100 text-slate-600 py-3 rounded-xl font-bold hover:bg-slate-200">{testingSmtp ? '...' : 'Test'}</button>
<button type="submit" className="flex-1 bg-blue-600 text-white py-3 rounded-xl font-bold hover:bg-blue-700">Salva Config</button>
</div>
</form>
<button onClick={() => setShowSmtpModal(false)} className="absolute top-4 right-4 text-slate-400 hover:text-slate-600"><X className="w-6 h-6"/></button>
</div>
</div>
)}
{showReadDetailsModal && selectedNoticeId && (
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-md p-6 animate-in fade-in zoom-in duration-200 max-h-[80vh] flex flex-col">
<div className="flex justify-between items-center mb-4">
<h3 className="font-bold text-lg text-slate-800">Stato Lettura</h3>
<button onClick={() => setShowReadDetailsModal(false)}><X className="w-5 h-5 text-slate-400"/></button>
</div>
<div className="flex-1 overflow-y-auto">
{users.length === 0 ? <p className="text-center text-slate-400">Nessun utente.</p> : (
<div className="space-y-2">
{users.map(u => {
const readInfo = noticeReadStats[selectedNoticeId]?.find(r => r.userId === u.id);
return (
<div key={u.id} className="flex items-center justify-between p-3 border rounded-xl bg-slate-50">
<div>
<p className="font-bold text-sm text-slate-700">{u.name}</p>
<p className="text-xs text-slate-400">{u.email}</p>
</div>
{readInfo ? (
<div className="text-right">
<span className="text-xs font-bold text-green-600 bg-green-100 px-2 py-1 rounded-full flex items-center gap-1 justify-end"><CheckCircle2 className="w-3 h-3"/> Letto</span>
<p className="text-[10px] text-slate-400 mt-1">{new Date(readInfo.readAt).toLocaleString()}</p>
</div>
) : (
<span className="text-xs font-bold text-slate-400 bg-white border px-2 py-1 rounded-full">Non letto</span>
)}
</div>
);
})}
</div>
)}
</div>
</div>
</div>
)}
</div>
);
};