Update Settings.tsx
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user