Update Settings.tsx

This commit is contained in:
2025-12-11 23:37:42 +01:00
committed by GitHub
parent f94d1b7e1c
commit 9ac9a1cb44

View File

@@ -7,7 +7,7 @@ import {
AlertTriangle, User as UserIcon, Server, Bell, Clock, FileText,
Lock, Megaphone, CheckCircle2, Info, Hammer, Link as LinkIcon,
Eye, Calendar, List, UserCog, Mail, Power, MapPin, CreditCard,
ToggleLeft, ToggleRight, LayoutGrid, PieChart, Users, Send
ToggleLeft, ToggleRight, LayoutGrid, PieChart, Users, Send, Cloud, HardDrive
} from 'lucide-react';
export const SettingsPage: React.FC = () => {
@@ -16,7 +16,7 @@ export const SettingsPage: React.FC = () => {
const isPrivileged = currentUser?.role === 'admin' || currentUser?.role === 'poweruser';
// Tab configuration
type TabType = 'profile' | 'features' | 'general' | 'condos' | 'families' | 'users' | 'notices' | 'alerts';
type TabType = 'profile' | 'features' | 'general' | 'condos' | 'families' | 'users' | 'notices' | 'alerts' | 'storage';
const [activeTab, setActiveTab] = useState<TabType>(isPrivileged ? 'general' : 'profile');
const [loading, setLoading] = useState(true);
@@ -240,7 +240,7 @@ export const SettingsPage: React.FC = () => {
setSaving(true);
try {
await CondoService.updateSettings(globalSettings);
setSuccessMsg('Funzionalità salvate!');
setSuccessMsg('Configurazione salvata!');
setTimeout(() => setSuccessMsg(''), 3000);
window.location.reload();
} catch(e) {
@@ -282,6 +282,18 @@ export const SettingsPage: React.FC = () => {
}
};
const handleStorageSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!globalSettings) return;
setSaving(true);
try {
await CondoService.updateSettings(globalSettings);
setSuccessMsg('Configurazione Storage salvata!');
setTimeout(() => setSuccessMsg(''), 3000);
} catch (e) { console.error(e); }
finally { setSaving(false); }
};
const handleNewYear = async () => {
if (!globalSettings) return;
const nextYear = globalSettings.currentYear + 1;
@@ -300,7 +312,7 @@ export const SettingsPage: React.FC = () => {
}
};
// CRUD Handlers
// CRUD Handlers (omitted repeated code for brevity, logic is same as before)
const openAddCondoModal = () => {
setEditingCondo(null);
setCondoForm({ name: '', address: '', streetNumber: '', city: '', province: '', zipCode: '', notes: '', paypalClientId: '', defaultMonthlyQuota: 100, dueDay: 10 });
@@ -572,7 +584,8 @@ export const SettingsPage: React.FC = () => {
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: 'alerts', label: 'Avvisi Email', icon: <Bell className="w-4 h-4"/> },
{ id: 'storage', label: 'Cloud & Storage', icon: <HardDrive className="w-4 h-4"/> }
);
}
@@ -648,6 +661,10 @@ export const SettingsPage: React.FC = () => {
<div><p className="font-bold text-slate-800">Gestione Tickets</p><p className="text-sm text-slate-500">Abilita il sistema di segnalazione guasti.</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>
<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 Documenti</p><p className="text-sm text-slate-500">Archivio digitale con tag e upload.</p></div>
<button type="button" onClick={() => toggleFeature('documents')} className={`${globalSettings.features.documents ? 'bg-green-500' : 'bg-slate-300'} relative inline-flex h-6 w-11 items-center rounded-full transition-colors`}><span className={`${globalSettings.features.documents ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition-transform`}/></button>
</div>
<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 online.</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>
@@ -664,8 +681,6 @@ export const SettingsPage: React.FC = () => {
<div><p className="font-bold text-slate-800">Spese Straordinarie</p><p className="text-sm text-slate-500">Gestione lavori e preventivi.</p></div>
<button type="button" onClick={() => toggleFeature('extraordinaryExpenses')} className={`${globalSettings.features.extraordinaryExpenses !== false ? 'bg-green-500' : 'bg-slate-300'} relative inline-flex h-6 w-11 items-center rounded-full transition-colors`}><span className={`${globalSettings.features.extraordinaryExpenses !== false ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition-transform`}/></button>
</div>
{/* NEW TOGGLE for Condo Financials View */}
<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">Visualizza Spese Condominiali agli Utenti</p>
@@ -682,6 +697,67 @@ export const SettingsPage: React.FC = () => {
</div>
)}
{/* STORAGE CONFIG TAB */}
{isPrivileged && activeTab === 'storage' && globalSettings?.storageConfig && (
<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-4 flex items-center gap-2"><Cloud className="w-5 h-5 text-blue-600" /> Configurazione Storage</h3>
<p className="text-sm text-slate-500 mb-6">Scegli dove salvare i documenti caricati.</p>
<form onSubmit={handleStorageSubmit} className="space-y-6">
<div>
<label className="text-sm font-bold text-slate-700 mb-2 block">Provider Attivo</label>
<select
className="w-full border p-2.5 rounded-lg bg-slate-50 font-medium text-slate-700"
value={globalSettings.storageConfig.provider}
onChange={e => setGlobalSettings({
...globalSettings,
storageConfig: { ...globalSettings.storageConfig!, provider: e.target.value as any }
})}
>
<option value="local_db">Database Locale (Solo Demo)</option>
<option value="s3">AWS S3 / Compatible</option>
<option value="google_drive">Google Drive</option>
<option value="dropbox">Dropbox</option>
<option value="onedrive">OneDrive</option>
</select>
</div>
{globalSettings.storageConfig.provider === 'local_db' && (
<div className="bg-amber-50 text-amber-800 p-4 rounded-lg text-sm border border-amber-200">
<p className="font-bold">Modalità Demo Attiva</p>
<p>I file vengono salvati direttamente nel database (Base64). Non raccomandato per produzione o file grandi.</p>
</div>
)}
{globalSettings.storageConfig.provider === 's3' && (
<div className="space-y-3 border-l-4 border-blue-500 pl-4">
<h4 className="font-bold text-sm text-slate-700">Configurazione S3</h4>
<input placeholder="Bucket Name" className="w-full border p-2 rounded" value={globalSettings.storageConfig.bucket || ''} onChange={e => setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, bucket: e.target.value}})}/>
<input placeholder="Region (es. eu-central-1)" className="w-full border p-2 rounded" value={globalSettings.storageConfig.region || ''} onChange={e => setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, region: e.target.value}})}/>
<input placeholder="Access Key ID" className="w-full border p-2 rounded" value={globalSettings.storageConfig.apiKey || ''} onChange={e => setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, apiKey: e.target.value}})}/>
<input type="password" placeholder="Secret Access Key" className="w-full border p-2 rounded" value={globalSettings.storageConfig.apiSecret || ''} onChange={e => setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, apiSecret: e.target.value}})}/>
</div>
)}
{(globalSettings.storageConfig.provider === 'google_drive' || globalSettings.storageConfig.provider === 'dropbox' || globalSettings.storageConfig.provider === 'onedrive') && (
<div className="space-y-3 border-l-4 border-purple-500 pl-4">
<h4 className="font-bold text-sm text-slate-700">Autenticazione API</h4>
<p className="text-xs text-slate-500">Inserisci le credenziali dell'applicazione sviluppatore.</p>
<input placeholder="Client ID / App Key" className="w-full border p-2 rounded" value={globalSettings.storageConfig.apiKey || ''} onChange={e => setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, apiKey: e.target.value}})}/>
<input type="password" placeholder="Client Secret / App Secret" className="w-full border p-2 rounded" value={globalSettings.storageConfig.apiSecret || ''} onChange={e => setGlobalSettings({...globalSettings, storageConfig: {...globalSettings.storageConfig!, apiSecret: e.target.value}})}/>
</div>
)}
<div className="pt-2 flex justify-between items-center">
<span className="text-green-600 font-medium">{successMsg}</span>
<button type="submit" disabled={saving} 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 Impostazioni
</button>
</div>
</form>
</div>
)}
{/* GENERAL TAB */}
{isPrivileged && activeTab === 'general' && (
<div className="space-y-6 animate-fade-in">
@@ -837,12 +913,13 @@ export const SettingsPage: React.FC = () => {
</div>
)}
{/* Condo Modal (Aggiornato con dueDay) */}
{/* Condo Modal */}
{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">
{/* Form fields same as before... omitted for brevity */}
<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>