Files
Condopay/pages/Settings.tsx
frakarr 919be985c9 feat: Introduce app feature flags
This commit refactors the application settings to include a new `AppFeatures` interface. This allows for granular control over which features are enabled for the application.

The `AppFeatures` object includes boolean flags for:
- `multiCondo`: Enables or disables the multi-condominium management feature.
- `tickets`: Placeholder for future ticket system integration.
- `payPal`: Enables or disables PayPal payment gateway integration.
- `notices`: Enables or disables the display and management of notices.

These flags are now fetched and stored in the application state, influencing UI elements and logic across various pages to conditionally render features based on their enabled status. For example, the multi-condo selection in `Layout.tsx` and the notice display in `FamilyList.tsx` are now gated by these feature flags. The `FamilyDetail.tsx` page also uses the `payPal` flag to conditionally enable the PayPal payment option.

The `SettingsPage.tsx` has been updated to include a new 'features' tab for managing these flags.
2025-12-07 20:21:01 +01:00

1197 lines
70 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { CondoService } from '../services/mockDb';
import { AppSettings, Family, User, AlertDefinition, Condo, Notice, NoticeIconType, NoticeRead } from '../types';
import { Save, Building, Coins, Plus, Pencil, Trash2, X, CalendarCheck, AlertTriangle, User as UserIcon, Server, Bell, Clock, FileText, Lock, Megaphone, CheckCircle2, Info, Hammer, Link as LinkIcon, Eye, Calendar, List, UserCog, Mail, Power, MapPin, CreditCard, ToggleLeft, ToggleRight, LayoutGrid } from 'lucide-react';
export const SettingsPage: React.FC = () => {
const currentUser = CondoService.getCurrentUser();
const isAdmin = currentUser?.role === 'admin';
// Tab configuration
type TabType = 'profile' | 'features' | 'general' | 'condos' | 'families' | 'users' | 'notices' | 'alerts' | 'smtp';
const [activeTab, setActiveTab] = useState<TabType>(isAdmin ? 'general' : 'profile');
const [loading, setLoading] = useState(true);
// Profile State
const [profileForm, setProfileForm] = useState({
name: currentUser?.name || '',
phone: currentUser?.phone || '',
password: '',
receiveAlerts: currentUser?.receiveAlerts ?? true
});
const [profileSaving, setProfileSaving] = useState(false);
const [profileMsg, setProfileMsg] = useState('');
// General Settings State
const [activeCondo, setActiveCondo] = useState<Condo | undefined>(undefined);
const [globalSettings, setGlobalSettings] = useState<AppSettings | null>(null);
// Condos Management State
const [condos, setCondos] = useState<Condo[]>([]);
const [showCondoModal, setShowCondoModal] = useState(false);
const [editingCondo, setEditingCondo] = useState<Condo | null>(null);
const [condoForm, setCondoForm] = useState({
name: '',
address: '',
streetNumber: '',
city: '',
province: '',
zipCode: '',
notes: '',
paypalClientId: '',
defaultMonthlyQuota: 100
});
const [saving, setSaving] = useState(false);
const [successMsg, setSuccessMsg] = useState('');
// Families State
const [families, setFamilies] = useState<Family[]>([]);
const [showFamilyModal, setShowFamilyModal] = useState(false);
const [editingFamily, setEditingFamily] = useState<Family | null>(null);
const [familyForm, setFamilyForm] = useState<{
name: string;
unitNumber: string;
stair: string;
floor: string;
notes: string;
contactEmail: string;
customMonthlyQuota: string;
}>({ name: '', unitNumber: '', stair: '', floor: '', notes: '', contactEmail: '', customMonthlyQuota: '' });
// Users State
const [users, setUsers] = useState<User[]>([]);
const [showUserModal, setShowUserModal] = useState(false);
const [editingUser, setEditingUser] = useState<User | null>(null);
const [userForm, setUserForm] = useState({
name: '',
email: '',
password: '',
phone: '',
role: 'user',
familyId: '',
receiveAlerts: true
});
// Alerts State
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
});
// Notices (Bacheca) State
const [notices, setNotices] = useState<Notice[]>([]);
const [showNoticeModal, setShowNoticeModal] = useState(false);
const [editingNotice, setEditingNotice] = useState<Notice | null>(null);
const [noticeForm, setNoticeForm] = useState<{
title: string;
content: string;
type: NoticeIconType;
link: string;
condoId: string;
active: boolean;
}>({
title: '',
content: '',
type: 'info',
link: '',
condoId: '',
active: true
});
const [noticeReadStats, setNoticeReadStats] = useState<Record<string, NoticeRead[]>>({});
// Notice Details Modal
const [showReadDetailsModal, setShowReadDetailsModal] = useState(false);
const [selectedNoticeId, setSelectedNoticeId] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
if (isAdmin) {
// First fetch global/structural data
const condoList = await CondoService.getCondos();
const activeC = await CondoService.getActiveCondo();
const gSettings = await CondoService.getSettings();
setCondos(condoList);
setActiveCondo(activeC);
setGlobalSettings(gSettings);
// Fetch condo-specific data ONLY if there is an active condo
if (activeC) {
const [fams, usrs, alrts, allNotices] = await Promise.all([
CondoService.getFamilies(activeC.id),
CondoService.getUsers(activeC.id),
CondoService.getAlerts(activeC.id),
CondoService.getNotices(activeC.id)
]);
setFamilies(fams);
setUsers(usrs);
setAlerts(alrts);
setNotices(allNotices);
// Fetch read stats for notices
const stats: Record<string, NoticeRead[]> = {};
for (const n of allNotices) {
const reads = await CondoService.getNoticeReadStatus(n.id);
stats[n.id] = reads;
}
setNoticeReadStats(stats);
} else {
setFamilies([]);
setUsers([]);
setAlerts([]);
setNotices([]);
}
} else {
const activeC = await CondoService.getActiveCondo();
setActiveCondo(activeC);
}
} catch(e) {
console.error(e);
} finally {
setLoading(false);
}
};
fetchData();
}, [isAdmin]);
// --- Profile Handlers ---
const handleProfileSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setProfileSaving(true);
setProfileMsg('');
try {
await CondoService.updateProfile(profileForm);
setProfileMsg('Profilo aggiornato con successo!');
setTimeout(() => setProfileMsg(''), 3000);
setProfileForm(prev => ({ ...prev, password: '' }));
} catch (e) {
setProfileMsg('Errore aggiornamento profilo');
} finally {
setProfileSaving(false);
}
};
// --- General Handlers ---
const handleGeneralSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!activeCondo) return;
setSaving(true);
setSuccessMsg('');
try {
await CondoService.saveCondo(activeCondo);
setSuccessMsg('Dati condominio aggiornati!');
setTimeout(() => setSuccessMsg(''), 3000);
const list = await CondoService.getCondos();
setCondos(list);
} catch (e) {
console.error(e);
} finally {
setSaving(false);
}
};
const handleFeaturesSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!globalSettings) return;
setSaving(true);
try {
await CondoService.updateSettings(globalSettings);
setSuccessMsg('Funzionalità salvate!');
setTimeout(() => setSuccessMsg(''), 3000);
window.location.reload(); // Refresh to apply changes to layout
} catch(e) { console.error(e); } finally { setSaving(false); }
};
const handleSmtpSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!globalSettings) return;
setSaving(true);
try {
await CondoService.updateSettings(globalSettings);
setSuccessMsg('Configurazione SMTP salvata!');
setTimeout(() => setSuccessMsg(''), 3000);
} catch (e) {
console.error(e);
} finally {
setSaving(false);
}
};
const handleNewYear = async () => {
if (!globalSettings) return;
const nextYear = globalSettings.currentYear + 1;
if (window.confirm(`Sei sicuro di voler chiudere l'anno ${globalSettings.currentYear} e aprire il ${nextYear}?`)) {
setSaving(true);
try {
const newSettings = { ...globalSettings, currentYear: nextYear };
await CondoService.updateSettings(newSettings);
setGlobalSettings(newSettings);
setSuccessMsg(`Anno ${nextYear} aperto!`);
} catch(e) { console.error(e); } finally { setSaving(false); }
}
};
// --- Condo Management Handlers ---
const openAddCondoModal = () => {
setEditingCondo(null);
setCondoForm({ name: '', address: '', streetNumber: '', city: '', province: '', zipCode: '', notes: '', paypalClientId: '', defaultMonthlyQuota: 100 });
setShowCondoModal(true);
};
const openEditCondoModal = (c: Condo) => {
setEditingCondo(c);
setCondoForm({
name: c.name,
address: c.address || '',
streetNumber: c.streetNumber || '',
city: c.city || '',
province: c.province || '',
zipCode: c.zipCode || '',
notes: c.notes || '',
paypalClientId: c.paypalClientId || '',
defaultMonthlyQuota: c.defaultMonthlyQuota
});
setShowCondoModal(true);
};
const handleCondoSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const payload: Condo = {
id: editingCondo ? editingCondo.id : '',
name: condoForm.name,
address: condoForm.address,
streetNumber: condoForm.streetNumber,
city: condoForm.city,
province: condoForm.province,
zipCode: condoForm.zipCode,
notes: condoForm.notes,
paypalClientId: condoForm.paypalClientId,
defaultMonthlyQuota: condoForm.defaultMonthlyQuota
};
const savedCondo = await CondoService.saveCondo(payload);
const list = await CondoService.getCondos();
setCondos(list);
if (activeCondo?.id === savedCondo.id) {
setActiveCondo(savedCondo);
}
// Auto-select if it's the first one or none selected
if (!activeCondo && list.length === 1) {
CondoService.setActiveCondo(savedCondo.id);
}
setShowCondoModal(false);
window.dispatchEvent(new Event('condo-updated'));
} catch (e) {
console.error(e);
alert("Errore nel salvataggio del condominio. Assicurati di essere amministratore.");
}
};
const handleDeleteCondo = async (id: string) => {
if(!window.confirm("Eliminare questo condominio? Attenzione: operazione irreversibile.")) return;
try {
await CondoService.deleteCondo(id);
setCondos(await CondoService.getCondos());
window.dispatchEvent(new Event('condo-updated'));
} catch (e) { console.error(e); }
};
// --- Family Handlers ---
const openAddFamilyModal = () => {
setEditingFamily(null);
setFamilyForm({ name: '', unitNumber: '', stair: '', floor: '', notes: '', contactEmail: '', customMonthlyQuota: '' });
setShowFamilyModal(true);
};
const openEditFamilyModal = (family: Family) => {
setEditingFamily(family);
setFamilyForm({
name: family.name,
unitNumber: family.unitNumber,
stair: family.stair || '',
floor: family.floor || '',
notes: family.notes || '',
contactEmail: family.contactEmail || '',
customMonthlyQuota: family.customMonthlyQuota ? family.customMonthlyQuota.toString() : ''
});
setShowFamilyModal(true);
};
const handleDeleteFamily = async (id: string) => {
if (!window.confirm('Eliminare questa famiglia?')) return;
try {
await CondoService.deleteFamily(id);
setFamilies(families.filter(f => f.id !== id));
} catch (e) { console.error(e); }
};
const handleFamilySubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
// Handle parsing safely
const quota = familyForm.customMonthlyQuota && familyForm.customMonthlyQuota.trim() !== ''
? parseFloat(familyForm.customMonthlyQuota)
: undefined;
const payload: any = {
name: familyForm.name,
unitNumber: familyForm.unitNumber,
stair: familyForm.stair,
floor: familyForm.floor,
notes: familyForm.notes,
contactEmail: familyForm.contactEmail,
customMonthlyQuota: quota
};
if (editingFamily) {
const updatedFamily = { ...editingFamily, ...payload };
await CondoService.updateFamily(updatedFamily);
setFamilies(families.map(f => f.id === updatedFamily.id ? updatedFamily : f));
} else {
const newFamily = await CondoService.addFamily(payload);
setFamilies([...families, newFamily]);
}
setShowFamilyModal(false);
} catch (e: any) {
console.error(e);
alert(`Errore: ${e.message || "Impossibile salvare la famiglia. Controlla i permessi."}`);
}
};
// --- User Handlers ---
const openAddUserModal = () => {
setEditingUser(null);
setUserForm({ name: '', email: '', password: '', phone: '', role: 'user', familyId: '', receiveAlerts: true });
setShowUserModal(true);
};
const openEditUserModal = (user: User) => {
setEditingUser(user);
setUserForm({
name: user.name || '',
email: user.email,
password: '',
phone: user.phone || '',
role: user.role || 'user',
familyId: user.familyId || '',
receiveAlerts: user.receiveAlerts ?? true
});
setShowUserModal(true);
};
const handleUserSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
if (editingUser) {
await CondoService.updateUser(editingUser.id, userForm);
} else {
await CondoService.createUser(userForm);
}
// Refresh user list for active condo
setUsers(await CondoService.getUsers(activeCondo?.id));
setShowUserModal(false);
} catch (e) { alert("Errore nel salvataggio utente"); }
};
const handleDeleteUser = async (id: string) => {
if(!window.confirm("Eliminare utente?")) return;
await CondoService.deleteUser(id);
setUsers(users.filter(u => u.id !== id));
};
// --- Notice Handlers ---
const openAddNoticeModal = () => {
setEditingNotice(null);
setNoticeForm({ title: '', content: '', type: 'info', link: '', condoId: activeCondo?.id || '', active: true });
setShowNoticeModal(true);
};
const openEditNoticeModal = (n: Notice) => {
setEditingNotice(n);
setNoticeForm({ title: n.title, content: n.content, type: n.type, link: n.link || '', condoId: n.condoId, active: n.active });
setShowNoticeModal(true);
};
const handleNoticeSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const payload: Notice = {
id: editingNotice ? editingNotice.id : '',
...noticeForm,
date: editingNotice ? editingNotice.date : new Date().toISOString()
};
await CondoService.saveNotice(payload);
// Refresh notices for active condo
setNotices(await CondoService.getNotices(activeCondo?.id));
setShowNoticeModal(false);
} catch (e) { console.error(e); }
};
const handleDeleteNotice = async (id: string) => {
if(!window.confirm("Eliminare annuncio?")) return;
await CondoService.deleteNotice(id);
setNotices(notices.filter(n => n.id !== id));
};
const toggleNoticeActive = async (notice: Notice) => {
try {
const updated = { ...notice, active: !notice.active };
await CondoService.saveNotice(updated);
setNotices(notices.map(n => n.id === notice.id ? updated : n));
} catch(e) { console.error(e); }
};
const openReadDetails = (noticeId: string) => {
setSelectedNoticeId(noticeId);
setShowReadDetailsModal(true);
};
// --- Alert Handlers ---
const openAddAlertModal = () => { setEditingAlert(null); setAlertForm({ subject: '', body: '', daysOffset: 1, offsetType: 'before_next_month', sendHour: 9, active: true }); setShowAlertModal(true); };
const openEditAlertModal = (alert: AlertDefinition) => { setEditingAlert(alert); setAlertForm(alert); setShowAlertModal(true); };
const handleAlertSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const payload: AlertDefinition = { id: editingAlert ? editingAlert.id : '', subject: alertForm.subject!, body: alertForm.body!, daysOffset: Number(alertForm.daysOffset), offsetType: alertForm.offsetType as any, sendHour: Number(alertForm.sendHour), active: alertForm.active! };
// Save alert with current condoId
const saved = await CondoService.saveAlert(payload);
setAlerts(editingAlert ? alerts.map(a => a.id === saved.id ? saved : a) : [...alerts, saved]);
setShowAlertModal(false);
} catch (e) { console.error(e); }
};
const handleDeleteAlert = async (id: string) => { if(!window.confirm("Eliminare avviso?")) return; await CondoService.deleteAlert(id); setAlerts(alerts.filter(a => a.id !== id)); };
const getCondoName = (id: string) => condos.find(c => c.id === id)?.name || 'Sconosciuto';
// Helpers for Toggle Feature
const toggleFeature = (key: keyof AppSettings['features']) => {
if (!globalSettings) return;
setGlobalSettings({
...globalSettings,
features: {
...globalSettings.features,
[key]: !globalSettings.features[key]
}
});
};
// --- TABS CONFIG ---
const tabs: {id: TabType, label: string, icon: React.ReactNode}[] = [
{ id: 'profile', label: 'Profilo', icon: <UserIcon className="w-4 h-4"/> },
];
if (isAdmin) {
tabs.push(
{ id: 'features', label: 'Funzionalità', icon: <LayoutGrid className="w-4 h-4"/> },
{ id: 'general', label: 'Condominio', icon: <Building 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: 'Utenti', icon: <UserCog className="w-4 h-4"/> }
);
if (globalSettings?.features.notices) {
tabs.push({ id: 'notices', label: 'Bacheca', icon: <Megaphone className="w-4 h-4"/> });
}
tabs.push(
{ id: 'alerts', label: 'Avvisi Email', icon: <Bell className="w-4 h-4"/> },
{ id: 'smtp', label: 'SMTP', icon: <Mail className="w-4 h-4"/> }
);
}
if (loading) return <div className="p-8 text-center text-slate-400">Caricamento...</div>;
return (
<div className="max-w-5xl mx-auto space-y-6 pb-20">
<div>
<h2 className="text-2xl font-bold text-slate-800">Impostazioni</h2>
<p className="text-slate-500 text-sm md:text-base">
{activeCondo ? `Gestione: ${activeCondo.name}` : 'Pannello di Controllo'}
</p>
</div>
{/* Tabs */}
<div className="flex border-b border-slate-200 overflow-x-auto no-scrollbar pb-1 gap-1">
{tabs.map(tab => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`px-4 py-3 font-medium text-sm whitespace-nowrap flex items-center gap-2 rounded-t-lg transition-colors ${activeTab === tab.id ? 'text-blue-600 border-b-2 border-blue-600 bg-blue-50/50' : 'text-slate-500 hover:text-slate-700 hover:bg-slate-50'}`}
>
{tab.icon}
{tab.label}
</button>
))}
</div>
{/* Profile Tab */}
{activeTab === 'profile' && (
<div className="animate-fade-in bg-white rounded-xl shadow-sm border border-slate-200 p-6 max-w-2xl">
<h3 className="text-lg font-bold text-slate-800 mb-6 flex items-center gap-2">
<UserIcon className="w-5 h-5 text-blue-600" /> Il Tuo Profilo
</h3>
<form onSubmit={handleProfileSubmit} className="space-y-5">
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
<div><label className="text-sm font-medium text-slate-700">Nome</label><input type="text" value={profileForm.name} onChange={(e) => setProfileForm({...profileForm, name: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
<div><label className="text-sm font-medium text-slate-700">Email</label><input type="email" value={currentUser?.email || ''} disabled className="w-full border bg-slate-50 p-2.5 rounded-lg text-slate-500"/></div>
<div><label className="text-sm font-medium text-slate-700">Telefono</label><input type="tel" value={profileForm.phone} onChange={(e) => setProfileForm({...profileForm, phone: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
<div><label className="text-sm font-medium text-slate-700">Password</label><input type="password" placeholder="Opzionale" value={profileForm.password} onChange={(e) => setProfileForm({...profileForm, password: e.target.value})} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
</div>
<button type="submit" disabled={profileSaving} className="bg-blue-600 text-white px-6 py-2.5 rounded-lg font-medium hover:bg-blue-700 flex gap-2"><Save className="w-4 h-4" /> Aggiorna</button>
</form>
</div>
)}
{/* Features Tab */}
{isAdmin && activeTab === 'features' && globalSettings && (
<div className="animate-fade-in bg-white rounded-xl shadow-sm border border-slate-200 p-6 max-w-3xl">
<div className="flex items-center justify-between mb-6">
<h3 className="text-lg font-bold text-slate-800 flex items-center gap-2">
<LayoutGrid className="w-5 h-5 text-blue-600" /> Funzionalità Piattaforma
</h3>
</div>
<form onSubmit={handleFeaturesSubmit} className="space-y-6">
<div className="space-y-4">
{/* Multi Condo */}
<div className="flex items-center justify-between p-4 bg-slate-50 rounded-xl border border-slate-100">
<div>
<p className="font-bold text-slate-800">Gestione Multicondominio</p>
<p className="text-sm text-slate-500">Abilita la gestione di più stabili. Se disattivo, il sistema gestirà un solo condominio.</p>
</div>
<button type="button" onClick={() => toggleFeature('multiCondo')} className={`${globalSettings.features.multiCondo ? 'bg-green-500' : 'bg-slate-300'} relative inline-flex h-6 w-11 items-center rounded-full transition-colors`}>
<span className={`${globalSettings.features.multiCondo ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition-transform`}/>
</button>
</div>
{/* Tickets */}
<div className="flex items-center justify-between p-4 bg-slate-50 rounded-xl border border-slate-100">
<div>
<p className="font-bold text-slate-800">Gestione Tickets</p>
<p className="text-sm text-slate-500">Abilita il sistema di segnalazione guasti e richieste (Segnalazioni).</p>
</div>
<button type="button" onClick={() => toggleFeature('tickets')} className={`${globalSettings.features.tickets ? 'bg-green-500' : 'bg-slate-300'} relative inline-flex h-6 w-11 items-center rounded-full transition-colors`}>
<span className={`${globalSettings.features.tickets ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition-transform`}/>
</button>
</div>
{/* PayPal */}
<div className="flex items-center justify-between p-4 bg-slate-50 rounded-xl border border-slate-100">
<div>
<p className="font-bold text-slate-800">Pagamenti PayPal</p>
<p className="text-sm text-slate-500">Permetti ai condomini di pagare le rate tramite PayPal.</p>
</div>
<button type="button" onClick={() => toggleFeature('payPal')} className={`${globalSettings.features.payPal ? 'bg-green-500' : 'bg-slate-300'} relative inline-flex h-6 w-11 items-center rounded-full transition-colors`}>
<span className={`${globalSettings.features.payPal ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition-transform`}/>
</button>
</div>
{/* Notices */}
<div className="flex items-center justify-between p-4 bg-slate-50 rounded-xl border border-slate-100">
<div>
<p className="font-bold text-slate-800">Bacheca Avvisi</p>
<p className="text-sm text-slate-500">Mostra la bacheca digitale per comunicazioni ai condomini.</p>
</div>
<button type="button" onClick={() => toggleFeature('notices')} className={`${globalSettings.features.notices ? 'bg-green-500' : 'bg-slate-300'} relative inline-flex h-6 w-11 items-center rounded-full transition-colors`}>
<span className={`${globalSettings.features.notices ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition-transform`}/>
</button>
</div>
</div>
<div className="pt-2 flex justify-between items-center">
<span className="text-green-600 font-medium">{successMsg}</span>
<button type="submit" className="bg-blue-600 text-white px-6 py-2.5 rounded-lg font-medium hover:bg-blue-700 flex gap-2">
<Save className="w-4 h-4" /> Salva Configurazione
</button>
</div>
</form>
</div>
)}
{/* General Tab */}
{isAdmin && activeTab === 'general' && (
<div className="space-y-6 animate-fade-in">
{!activeCondo ? (
<div className="bg-amber-50 border border-amber-200 text-amber-800 p-4 rounded-lg">Nessun condominio selezionato.</div>
) : (
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6 md:p-8 max-w-2xl">
<h3 className="text-lg font-bold text-slate-800 mb-4 flex items-center gap-2"><Building className="w-5 h-5 text-blue-600" /> Dati Condominio Corrente</h3>
<form onSubmit={handleGeneralSubmit} className="space-y-5">
<input type="text" value={activeCondo.name} onChange={(e) => setActiveCondo({ ...activeCondo, name: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Nome" required />
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">Indirizzo</label>
<input type="text" value={activeCondo.address || ''} onChange={(e) => setActiveCondo({ ...activeCondo, address: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Via/Piazza..." required/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">Civico</label>
<input type="text" value={activeCondo.streetNumber || ''} onChange={(e) => setActiveCondo({ ...activeCondo, streetNumber: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" required/>
</div>
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">CAP</label>
<input type="text" value={activeCondo.zipCode || ''} onChange={(e) => setActiveCondo({ ...activeCondo, zipCode: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700"/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">Città</label>
<input type="text" value={activeCondo.city || ''} onChange={(e) => setActiveCondo({ ...activeCondo, city: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" required/>
</div>
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">Provincia</label>
<input type="text" value={activeCondo.province || ''} onChange={(e) => setActiveCondo({ ...activeCondo, province: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700" required/>
</div>
</div>
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">Note (Opzionali)</label>
<textarea value={activeCondo.notes || ''} onChange={(e) => setActiveCondo({ ...activeCondo, notes: e.target.value })} className="w-full border p-2.5 rounded-lg text-slate-700 h-24"></textarea>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">Quota Mensile Standard ()</label>
<input type="number" value={activeCondo.defaultMonthlyQuota} onChange={(e) => setActiveCondo({ ...activeCondo, defaultMonthlyQuota: parseFloat(e.target.value) })} className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Quota Default" required />
</div>
<div className="pt-2 flex justify-between"><span className="text-green-600">{successMsg}</span><button type="submit" className="bg-blue-600 text-white px-6 py-2.5 rounded-lg hover:bg-blue-700 flex gap-2"><Save className="w-4 h-4"/> Salva</button></div>
</form>
</div>
)}
{globalSettings && (
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6 md:p-8 max-w-2xl">
<h3 className="font-bold text-slate-800 mb-2">Anno Fiscale</h3>
<p className="text-slate-600 mb-4">Corrente: <strong>{globalSettings.currentYear}</strong></p>
<button type="button" onClick={handleNewYear} className="bg-slate-800 text-white px-4 py-2 rounded-lg text-sm">Chiudi Anno {globalSettings.currentYear}</button>
</div>
)}
</div>
)}
{/* Condos List Tab */}
{isAdmin && activeTab === 'condos' && (
<div className="space-y-4 animate-fade-in">
<div className="flex justify-between items-center bg-blue-50 p-4 rounded-xl border border-blue-100">
<div><h3 className="font-bold text-blue-800">I Tuoi Condomini</h3></div>
<button onClick={openAddCondoModal} className="bg-blue-600 text-white px-4 py-2 rounded-lg font-medium flex gap-2"><Plus className="w-4 h-4" /> Aggiungi</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{condos.map(condo => (
<div key={condo.id} className={`bg-white p-5 rounded-xl border shadow-sm relative ${activeCondo?.id === condo.id ? 'border-blue-500 ring-1 ring-blue-500' : 'border-slate-200'}`}>
{activeCondo?.id === condo.id && <div className="absolute top-3 right-3 text-xs bg-blue-100 text-blue-700 px-2 py-0.5 rounded font-bold uppercase">Attivo</div>}
<h4 className="font-bold text-slate-800 text-lg mb-1">{condo.name}</h4>
<div className="text-sm text-slate-500 mb-3 space-y-1">
<p className="flex items-center gap-1"><MapPin className="w-3 h-3"/> {condo.address} {condo.streetNumber}</p>
{condo.city && <p className="pl-4">{condo.zipCode} {condo.city} ({condo.province})</p>}
</div>
<div className="border-t pt-3 flex gap-2">
<button onClick={() => openEditCondoModal(condo)} className="flex-1 py-1.5 bg-slate-50 text-slate-700 rounded text-sm font-medium hover:bg-slate-100">Modifica</button>
<button onClick={() => handleDeleteCondo(condo.id)} className="flex-1 py-1.5 bg-red-50 text-red-600 rounded text-sm font-medium hover:bg-red-100">Elimina</button>
</div>
</div>
))}
</div>
</div>
)}
{/* Families Tab */}
{isAdmin && activeTab === 'families' && (
<div className="space-y-4 animate-fade-in">
{!activeCondo ? (
<div className="p-8 text-center bg-slate-50 rounded-xl border border-dashed border-slate-300">
<p className="text-slate-500">Seleziona o crea un condominio per gestire le famiglie.</p>
</div>
) : (
<>
<div className="flex justify-between items-center">
<div className="text-sm text-slate-500">Famiglie in: <span className="font-bold text-slate-800">{activeCondo.name}</span></div>
<button onClick={openAddFamilyModal} className="bg-blue-600 text-white px-4 py-2 rounded-lg font-medium flex items-center gap-2"><Plus className="w-4 h-4" /> Aggiungi</button>
</div>
<div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<table className="w-full text-left text-sm text-slate-600">
<thead className="bg-slate-50 text-slate-700 font-semibold border-b"><tr><th className="px-6 py-4">Nome</th><th className="px-6 py-4">Dettagli</th><th className="px-6 py-4">Email</th><th className="px-6 py-4">Quota</th><th className="px-6 py-4 text-right">Azioni</th></tr></thead>
<tbody className="divide-y divide-slate-100">
{families.map(family => (
<tr key={family.id} className="hover:bg-slate-50">
<td className="px-6 py-4 font-medium text-slate-900">{family.name}</td>
<td className="px-6 py-4 text-xs">
<div className="space-y-0.5">
<span className="block text-slate-700 font-medium">Int: {family.unitNumber || '-'}</span>
{(family.stair || family.floor) && (
<span className="block text-slate-500">
{family.stair ? `Scala: ${family.stair} ` : ''}
{family.floor ? `Piano: ${family.floor}` : ''}
</span>
)}
</div>
</td>
<td className="px-6 py-4 text-slate-400">{family.contactEmail}</td>
<td className="px-6 py-4">
{family.customMonthlyQuota ? (
<span className="font-bold text-blue-600"> {family.customMonthlyQuota}</span>
) : (
<span className="text-slate-400 italic">Default ( {activeCondo.defaultMonthlyQuota})</span>
)}
</td>
<td className="px-6 py-4 text-right"><div className="flex justify-end gap-2"><button onClick={() => openEditFamilyModal(family)} className="text-blue-600"><Pencil className="w-4 h-4" /></button><button onClick={() => handleDeleteFamily(family.id)} className="text-red-600"><Trash2 className="w-4 h-4" /></button></div></td>
</tr>
))}
</tbody>
</table>
</div>
</>
)}
</div>
)}
{/* Users Tab */}
{isAdmin && activeTab === 'users' && (
<div className="space-y-4 animate-fade-in">
<div className="flex justify-end">
<button
onClick={openAddUserModal}
className="bg-blue-600 text-white px-4 py-2 rounded-lg font-medium flex items-center gap-2 hover:bg-blue-700 transition-colors"
type="button"
>
<Plus className="w-4 h-4" /> Nuovo Utente
</button>
</div>
<div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<table className="w-full text-left text-sm text-slate-600">
<thead className="bg-slate-50 text-slate-700 font-semibold border-b"><tr><th className="px-6 py-4">Utente</th><th className="px-6 py-4">Ruolo</th><th className="px-6 py-4 text-right">Azioni</th></tr></thead>
<tbody className="divide-y divide-slate-100">
{users.map(u => (
<tr key={u.id} className="hover:bg-slate-50">
<td className="px-6 py-4"><div className="font-medium text-slate-900">{u.name}</div><div className="text-xs text-slate-400">{u.email}</div></td>
<td className="px-6 py-4"><span className="bg-slate-100 px-2 py-1 rounded text-xs font-bold uppercase">{u.role}</span></td>
<td className="px-6 py-4 text-right"><div className="flex justify-end gap-2"><button onClick={() => openEditUserModal(u)} className="text-blue-600"><Pencil className="w-4 h-4"/></button><button onClick={() => handleDeleteUser(u.id)} className="text-red-600"><Trash2 className="w-4 h-4"/></button></div></td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* NOTICES (BACHECA) TAB */}
{isAdmin && activeTab === 'notices' && (
<div className="space-y-4 animate-fade-in">
<div className="flex justify-between items-center bg-blue-50 p-4 rounded-xl border border-blue-100">
<div><h3 className="font-bold text-blue-800">Bacheca Condominiale</h3><p className="text-sm text-blue-600">Pubblica avvisi visibili a tutti i condomini.</p></div>
<button onClick={openAddNoticeModal} className="bg-blue-600 text-white px-4 py-2 rounded-lg font-medium flex items-center gap-2 hover:bg-blue-700 transition-colors"><Plus className="w-4 h-4" /> Nuovo Avviso</button>
</div>
<div className="grid gap-4">
{notices.map(notice => (
<div key={notice.id} className={`bg-white p-5 rounded-xl border shadow-sm relative transition-all ${notice.active ? 'border-slate-200' : 'border-slate-100 opacity-60 bg-slate-50'}`}>
<div className="flex items-start justify-between">
<div className="flex items-start gap-3">
<div className={`p-2 rounded-lg ${notice.type === 'warning' ? 'bg-amber-100 text-amber-600' : notice.type === 'maintenance' ? 'bg-orange-100 text-orange-600' : 'bg-blue-100 text-blue-600'}`}>
{notice.type === 'warning' ? <AlertTriangle className="w-5 h-5"/> : notice.type === 'maintenance' ? <Hammer className="w-5 h-5"/> : notice.type === 'event' ? <Calendar className="w-5 h-5"/> : <Info className="w-5 h-5"/>}
</div>
<div>
<h4 className="font-bold text-slate-800">{notice.title}</h4>
<p className="text-xs text-slate-400 font-medium uppercase tracking-wide mb-1">{getCondoName(notice.condoId)} {new Date(notice.date).toLocaleDateString()}</p>
<p className="text-sm text-slate-600 line-clamp-2">{notice.content}</p>
{notice.link && <a href={notice.link} className="text-xs text-blue-600 underline mt-1 flex items-center gap-1"><LinkIcon className="w-3 h-3"/> Allegato</a>}
</div>
</div>
<div className="flex flex-col items-end gap-3">
{/* Toggle Active */}
<button
onClick={() => toggleNoticeActive(notice)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${notice.active ? 'bg-green-500' : 'bg-slate-300'}`}
title={notice.active ? "Attivo" : "Disattivato"}
>
<span className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${notice.active ? 'translate-x-6' : 'translate-x-1'}`} />
</button>
{/* Reads Counter */}
<button
onClick={() => openReadDetails(notice.id)}
className="text-center group"
title="Vedi dettaglio letture"
>
<span className="block text-lg font-bold text-slate-700 group-hover:text-blue-600">{noticeReadStats[notice.id]?.length || 0}</span>
<span className="text-[10px] text-slate-400 uppercase font-bold flex items-center gap-1 group-hover:text-blue-500"><Eye className="w-3 h-3"/> Letture</span>
</button>
</div>
</div>
<div className="mt-4 pt-3 border-t border-slate-100 flex justify-end gap-2">
<button onClick={() => openEditNoticeModal(notice)} className="text-sm text-blue-600 font-medium px-3 py-1 hover:bg-blue-50 rounded">Modifica</button>
<button onClick={() => handleDeleteNotice(notice.id)} className="text-sm text-red-600 font-medium px-3 py-1 hover:bg-red-50 rounded">Elimina</button>
</div>
</div>
))}
{notices.length === 0 && <div className="text-center p-8 text-slate-400">Nessun avviso pubblicato.</div>}
</div>
</div>
)}
{/* ALERTS TAB */}
{isAdmin && activeTab === 'alerts' && (
<div className="space-y-4 animate-fade-in">
<div className="flex justify-between items-center bg-blue-50 p-4 rounded-xl border border-blue-100">
<div><h3 className="font-bold text-blue-800">Avvisi Automatici</h3><p className="text-sm text-blue-600">Configura email automatiche per scadenze.</p></div>
<button onClick={openAddAlertModal} className="bg-blue-600 text-white px-4 py-2 rounded-lg font-medium flex items-center gap-2"><Plus className="w-4 h-4" /> Nuovo Avviso</button>
</div>
<div className="grid gap-4">
{alerts.map(alert => (
<div key={alert.id} className="bg-white p-5 rounded-xl border border-slate-200 shadow-sm relative">
<h4 className="font-bold text-slate-800">{alert.subject}</h4>
<p className="text-sm text-slate-600 mt-1">{alert.body}</p>
<div className="mt-3 flex gap-2 text-xs font-bold text-slate-500 uppercase">
<span className="bg-slate-100 px-2 py-1 rounded">Offset: {alert.daysOffset} giorni ({alert.offsetType})</span>
<span className="bg-slate-100 px-2 py-1 rounded">Ore: {alert.sendHour}:00</span>
<span className={`px-2 py-1 rounded ${alert.active ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>{alert.active ? 'Attivo' : 'Inattivo'}</span>
</div>
<div className="mt-4 pt-3 border-t border-slate-100 flex justify-end gap-2">
<button onClick={() => openEditAlertModal(alert)} className="text-blue-600 text-sm font-medium">Modifica</button>
<button onClick={() => handleDeleteAlert(alert.id)} className="text-red-600 text-sm font-medium">Elimina</button>
</div>
</div>
))}
{alerts.length === 0 && <div className="text-center p-8 text-slate-400">Nessun alert configurato.</div>}
</div>
</div>
)}
{/* SMTP TAB */}
{isAdmin && activeTab === 'smtp' && (
<div className="animate-fade-in bg-white rounded-xl shadow-sm border border-slate-200 p-6 max-w-2xl">
<h3 className="text-lg font-bold text-slate-800 mb-6 flex items-center gap-2"><Server className="w-5 h-5 text-blue-600"/> Configurazione SMTP</h3>
<form onSubmit={handleSmtpSubmit} className="space-y-5">
<div className="grid grid-cols-2 gap-4">
<div><label className="text-sm font-bold text-slate-700">Host</label><input type="text" value={globalSettings?.smtpConfig?.host || ''} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), host: e.target.value} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
<div><label className="text-sm font-bold text-slate-700">Porta</label><input type="number" value={globalSettings?.smtpConfig?.port || 0} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), port: parseInt(e.target.value)} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
</div>
<div className="grid grid-cols-2 gap-4">
<div><label className="text-sm font-bold text-slate-700">Utente</label><input type="text" value={globalSettings?.smtpConfig?.user || ''} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), user: e.target.value} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
<div><label className="text-sm font-bold text-slate-700">Password</label><input type="password" value={globalSettings?.smtpConfig?.pass || ''} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), pass: e.target.value} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
</div>
<div><label className="text-sm font-bold text-slate-700">Email Mittente</label><input type="email" value={globalSettings?.smtpConfig?.fromEmail || ''} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), fromEmail: e.target.value} as any} : null)} className="w-full border p-2.5 rounded-lg text-slate-700"/></div>
<div className="flex items-center gap-2"><input type="checkbox" checked={globalSettings?.smtpConfig?.secure || false} onChange={(e) => setGlobalSettings(prev => prev ? {...prev, smtpConfig: {...(prev.smtpConfig || {}), secure: e.target.checked} as any} : null)} className="w-4 h-4"/><label className="text-sm text-slate-700">Usa SSL/TLS (Secure)</label></div>
<div className="pt-2 flex justify-between"><span className="text-green-600">{successMsg}</span><button type="submit" className="bg-blue-600 text-white px-6 py-2.5 rounded-lg hover:bg-blue-700">Salva Configurazione</button></div>
</form>
</div>
)}
{/* ALERT MODAL (Existing) */}
{showAlertModal && (
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-xl shadow-xl w-full max-w-md p-6 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-lg mb-4 text-slate-800">{editingAlert ? 'Modifica Avviso' : 'Nuovo Avviso Automatico'}</h3>
<form onSubmit={handleAlertSubmit} className="space-y-4">
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Oggetto Email" value={alertForm.subject} onChange={e => setAlertForm({...alertForm, subject: e.target.value})} required />
<textarea className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Corpo Email" value={alertForm.body} onChange={e => setAlertForm({...alertForm, body: e.target.value})} required />
<div className="grid grid-cols-2 gap-3">
<div>
<label className="text-xs text-slate-500 font-bold uppercase">Giorni Offset</label>
<input type="number" className="w-full border p-2.5 rounded-lg text-slate-700" value={alertForm.daysOffset} onChange={e => setAlertForm({...alertForm, daysOffset: parseInt(e.target.value)})} />
</div>
<div>
<label className="text-xs text-slate-500 font-bold uppercase">Ora Invio</label>
<input type="number" min="0" max="23" className="w-full border p-2.5 rounded-lg text-slate-700" value={alertForm.sendHour} onChange={e => setAlertForm({...alertForm, sendHour: parseInt(e.target.value)})} />
</div>
</div>
<div>
<label className="text-xs text-slate-500 font-bold uppercase">Tipo Offset</label>
<select className="w-full border p-2.5 rounded-lg text-slate-700 bg-white" value={alertForm.offsetType} onChange={e => setAlertForm({...alertForm, offsetType: e.target.value as any})}>
<option value="before_next_month">Giorni prima del prossimo mese</option>
<option value="after_current_month">Giorni dopo inizio mese</option>
</select>
</div>
<div className="flex gap-2 pt-2">
<button type="button" onClick={() => setShowAlertModal(false)} className="flex-1 border p-2.5 rounded-lg text-slate-600">Annulla</button>
<button type="submit" className="flex-1 bg-blue-600 text-white p-2.5 rounded-lg">Salva</button>
</div>
</form>
</div>
</div>
)}
{/* NOTICE MODAL (Existing) */}
{showNoticeModal && (
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-xl shadow-xl w-full max-w-lg p-6 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-lg mb-4 text-slate-800">{editingNotice ? 'Modifica Avviso' : 'Nuovo Avviso'}</h3>
<form onSubmit={handleNoticeSubmit} className="space-y-4">
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Titolo" value={noticeForm.title} onChange={e => setNoticeForm({...noticeForm, title: e.target.value})} required />
<textarea className="w-full border p-2.5 rounded-lg text-slate-700 h-24" placeholder="Contenuto avviso..." value={noticeForm.content} onChange={e => setNoticeForm({...noticeForm, content: e.target.value})} required />
<div className="grid grid-cols-2 gap-3">
<div>
<label className="text-xs text-slate-500 font-bold uppercase mb-1 block">Tipo</label>
<select className="w-full border p-2.5 rounded-lg text-slate-700 bg-white" value={noticeForm.type} onChange={e => setNoticeForm({...noticeForm, type: e.target.value as any})}>
<option value="info">Info</option>
<option value="warning">Avviso</option>
<option value="maintenance">Manutenzione</option>
<option value="event">Evento</option>
</select>
</div>
<div>
<label className="text-xs text-slate-500 font-bold uppercase mb-1 block">Stato</label>
<select className="w-full border p-2.5 rounded-lg text-slate-700 bg-white" value={noticeForm.active ? 'true' : 'false'} onChange={e => setNoticeForm({...noticeForm, active: e.target.value === 'true'})}>
<option value="true">Attivo</option>
<option value="false">Bozza / Nascosto</option>
</select>
</div>
</div>
<div>
<label className="text-xs text-slate-500 font-bold uppercase mb-1 block">Link Esterno (Opzionale)</label>
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="https://..." value={noticeForm.link} onChange={e => setNoticeForm({...noticeForm, link: e.target.value})} />
</div>
<div className="flex gap-2 pt-2">
<button type="button" onClick={() => setShowNoticeModal(false)} className="flex-1 border p-2.5 rounded-lg text-slate-600 hover:bg-slate-50">Annulla</button>
<button type="submit" className="flex-1 bg-blue-600 text-white p-2.5 rounded-lg hover:bg-blue-700">Salva</button>
</div>
</form>
</div>
</div>
)}
{/* READ DETAILS MODAL (Existing) */}
{showReadDetailsModal && selectedNoticeId && (
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-xl shadow-xl w-full max-w-md p-6 animate-in fade-in zoom-in duration-200">
<div className="flex justify-between items-center mb-4">
<h3 className="font-bold text-lg text-slate-800">Dettaglio Letture</h3>
<button onClick={() => setShowReadDetailsModal(false)} className="p-1 rounded hover:bg-slate-100 text-slate-500"><X className="w-5 h-5"/></button>
</div>
<div className="max-h-64 overflow-y-auto pr-2">
{noticeReadStats[selectedNoticeId] && noticeReadStats[selectedNoticeId].length > 0 ? (
<div className="space-y-3">
{noticeReadStats[selectedNoticeId].map((read, idx) => {
const user = users.find(u => u.id === read.userId);
return (
<div key={idx} className="flex items-center justify-between p-3 bg-slate-50 rounded-lg border border-slate-100">
<div className="flex items-center gap-3">
<div className="bg-blue-100 p-2 rounded-full"><UserIcon className="w-4 h-4 text-blue-600"/></div>
<div>
<p className="text-sm font-bold text-slate-800">{user?.name || 'Utente Sconosciuto'}</p>
<p className="text-xs text-slate-500">{user?.email}</p>
</div>
</div>
<div className="text-right">
<p className="text-xs text-slate-500">{new Date(read.readAt).toLocaleDateString()}</p>
<p className="text-xs font-mono text-slate-400">{new Date(read.readAt).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</p>
</div>
</div>
);
})}
</div>
) : (
<p className="text-center text-slate-400 py-8">Nessuna lettura registrata.</p>
)}
</div>
</div>
</div>
)}
{/* USER MODAL (Existing) */}
{showUserModal && (
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-xl shadow-xl w-full max-w-md p-6 animate-in fade-in zoom-in duration-200">
<h3 className="font-bold text-lg mb-4 text-slate-800">{editingUser ? 'Modifica Utente' : 'Nuovo Utente'}</h3>
<form onSubmit={handleUserSubmit} className="space-y-4">
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Nome Completo" value={userForm.name} onChange={e => setUserForm({...userForm, name: e.target.value})} required />
<input className="w-full border p-2.5 rounded-lg text-slate-700" type="email" placeholder="Email" value={userForm.email} onChange={e => setUserForm({...userForm, email: e.target.value})} required />
<input className="w-full border p-2.5 rounded-lg text-slate-700" type="tel" placeholder="Telefono" value={userForm.phone} onChange={e => setUserForm({...userForm, phone: e.target.value})} />
<input className="w-full border p-2.5 rounded-lg text-slate-700" type="password" placeholder={editingUser ? "Nuova Password (opzionale)" : "Password"} value={userForm.password} onChange={e => setUserForm({...userForm, password: e.target.value})} required={!editingUser} />
<div className="grid grid-cols-2 gap-3">
<div>
<label className="text-xs text-slate-500 font-bold uppercase mb-1 block">Ruolo</label>
<select className="w-full border p-2.5 rounded-lg text-slate-700 bg-white" value={userForm.role} onChange={e => setUserForm({...userForm, role: e.target.value as any})}>
<option value="user">Utente</option>
<option value="admin">Admin</option>
<option value="poweruser">Power User</option>
</select>
</div>
<div>
<label className="text-xs text-slate-500 font-bold uppercase mb-1 block">Famiglia</label>
<select className="w-full border p-2.5 rounded-lg text-slate-700 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}</option>)}
</select>
</div>
</div>
<div className="flex items-center gap-2">
<input type="checkbox" checked={userForm.receiveAlerts} onChange={e => setUserForm({...userForm, receiveAlerts: e.target.checked})} className="w-4 h-4 text-blue-600"/>
<span className="text-sm font-medium text-slate-700">Ricevi avvisi email</span>
</div>
<div className="flex gap-2 pt-2">
<button type="button" onClick={() => setShowUserModal(false)} className="flex-1 border p-2.5 rounded-lg text-slate-600 hover:bg-slate-50">Annulla</button>
<button type="submit" className="flex-1 bg-blue-600 text-white p-2.5 rounded-lg hover:bg-blue-700">Salva</button>
</div>
</form>
</div>
</div>
)}
{/* CONDO MODAL (UPDATED) */}
{showCondoModal && (
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-xl shadow-xl w-full max-w-lg p-6 animate-in fade-in zoom-in duration-200 overflow-y-auto max-h-[90vh]">
<h3 className="font-bold text-lg mb-4 text-slate-800">{editingCondo ? 'Modifica Condominio' : 'Nuovo Condominio'}</h3>
<form onSubmit={handleCondoSubmit} className="space-y-4">
{/* Name */}
<div>
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Nome Condominio" value={condoForm.name} onChange={e => setCondoForm({...condoForm, name: e.target.value})} required />
</div>
{/* Address Line 1 */}
<div className="grid grid-cols-12 gap-3">
<div className="col-span-9">
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Via/Piazza..." value={condoForm.address} onChange={e => setCondoForm({...condoForm, address: e.target.value})} required />
</div>
<div className="col-span-3">
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Civico" value={condoForm.streetNumber} onChange={e => setCondoForm({...condoForm, streetNumber: e.target.value})} required />
</div>
</div>
{/* Address Line 2 */}
<div className="grid grid-cols-12 gap-3">
<div className="col-span-3">
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="CAP" value={condoForm.zipCode} onChange={e => setCondoForm({...condoForm, zipCode: e.target.value})} />
</div>
<div className="col-span-5">
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Città" value={condoForm.city} onChange={e => setCondoForm({...condoForm, city: e.target.value})} required />
</div>
<div className="col-span-4">
<input className="w-full border p-2.5 rounded-lg text-slate-700" placeholder="Provincia" value={condoForm.province} onChange={e => setCondoForm({...condoForm, province: e.target.value})} required />
</div>
</div>
{/* PayPal Integration Section */}
{globalSettings?.features.payPal && (
<div className="bg-blue-50 p-3 rounded-lg border border-blue-100">
<div className="flex items-center gap-2 mb-2 text-blue-800">
<CreditCard className="w-4 h-4"/>
<span className="text-xs font-bold uppercase">Configurazione Pagamenti</span>
</div>
<div>
<label className="text-xs font-semibold text-slate-600 block mb-1">PayPal Client ID (REST API App)</label>
<input
className="w-full border p-2 rounded text-slate-700 text-sm"
placeholder="Es: Afg... (Ottienilo da developer.paypal.com)"
value={condoForm.paypalClientId}
onChange={e => setCondoForm({...condoForm, paypalClientId: e.target.value})}
/>
<p className="text-[10px] text-slate-500 mt-1">Necessario per abilitare i pagamenti online delle rate.</p>
</div>
</div>
)}
{/* Notes */}
<div>
<textarea className="w-full border p-2.5 rounded-lg text-slate-700 h-16" placeholder="Note (opzionali)" value={condoForm.notes} onChange={e => setCondoForm({...condoForm, notes: e.target.value})} />
</div>
{/* Quota */}
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-slate-600">Quota Default </span>
<input type="number" className="border p-2 rounded w-24 text-slate-700" value={condoForm.defaultMonthlyQuota} onChange={e => setCondoForm({...condoForm, defaultMonthlyQuota: parseFloat(e.target.value)})} />
</div>
<div className="flex gap-2 pt-2">
<button type="button" onClick={() => setShowCondoModal(false)} className="flex-1 border p-2.5 rounded-lg text-slate-600 hover:bg-slate-50">Annulla</button>
<button type="submit" className="flex-1 bg-blue-600 text-white p-2.5 rounded-lg hover:bg-blue-700">Salva</button>
</div>
</form>
</div>
</div>
)}
{/* FAMILY MODAL (Existing) */}
{showFamilyModal && (
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-2xl shadow-xl w-full max-w-lg p-6">
<h3 className="font-bold text-lg mb-4 text-slate-800">{editingFamily ? 'Modifica Famiglia' : 'Nuova Famiglia'}</h3>
<form onSubmit={handleFamilySubmit} className="space-y-4">
{/* Name & Email */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="md:col-span-2">
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Nome Famiglia</label>
<input type="text" required value={familyForm.name} onChange={(e) => setFamilyForm({...familyForm, name: e.target.value})} className="w-full border rounded-lg p-2.5 text-slate-700" placeholder="Es. Rossi"/>
</div>
<div className="md:col-span-2">
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Email Contatto (Obbligatoria)</label>
<input type="email" required value={familyForm.contactEmail} onChange={(e) => setFamilyForm({...familyForm, contactEmail: e.target.value})} className="w-full border rounded-lg p-2.5 text-slate-700" placeholder="email@esempio.it"/>
</div>
</div>
{/* Location Details */}
<div className="grid grid-cols-3 gap-3">
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Interno</label>
<input type="text" value={familyForm.unitNumber} onChange={(e) => setFamilyForm({...familyForm, unitNumber: e.target.value})} className="w-full border rounded-lg p-2.5 text-slate-700" />
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Scala</label>
<input type="text" value={familyForm.stair} onChange={(e) => setFamilyForm({...familyForm, stair: e.target.value})} className="w-full border rounded-lg p-2.5 text-slate-700" />
</div>
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Piano</label>
<input type="text" value={familyForm.floor} onChange={(e) => setFamilyForm({...familyForm, floor: e.target.value})} className="w-full border rounded-lg p-2.5 text-slate-700" />
</div>
</div>
{/* Notes */}
<div>
<label className="text-xs font-bold text-slate-500 uppercase mb-1 block">Note</label>
<textarea value={familyForm.notes} onChange={(e) => setFamilyForm({...familyForm, notes: e.target.value})} className="w-full border rounded-lg p-2.5 text-slate-700 h-16" placeholder="Note opzionali..."></textarea>
</div>
<div className="pt-2 border-t border-slate-100">
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">Quota Mensile Personalizzata</label>
<p className="text-xs text-slate-400 mb-2">Lasciare vuoto per usare il default del condominio ( {activeCondo?.defaultMonthlyQuota})</p>
<input
type="number"
step="0.01"
value={familyForm.customMonthlyQuota}
onChange={(e) => setFamilyForm({...familyForm, customMonthlyQuota: e.target.value})}
className="w-full border rounded-lg p-2.5 text-slate-700"
placeholder="Es. 120.00"
/>
</div>
<div className="flex gap-3 pt-4">
<button type="button" onClick={() => setShowFamilyModal(false)} className="flex-1 p-3 border rounded-lg text-slate-600">Annulla</button>
<button type="submit" className="flex-1 p-3 bg-blue-600 text-white rounded-lg">Salva</button>
</div>
</form>
</div>
</div>
)}
</div>
);
};