Update Settings.tsx
This commit is contained in:
@@ -7,7 +7,8 @@ import {
|
||||
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
|
||||
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> = {
|
||||
@@ -263,10 +264,34 @@ export const SettingsPage: React.FC = () => {
|
||||
<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><input type="text" value={profileForm.name} onChange={(e) => setProfileForm({...profileForm, name: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none" required /></div>
|
||||
<div><label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Email</label><input type="email" value={currentUser?.email || ''} disabled className="w-full border border-slate-100 bg-slate-50 p-3 rounded-xl text-slate-400 cursor-not-allowed" /></div>
|
||||
<div><label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Telefono</label><input type="tel" value={profileForm.phone} onChange={(e) => setProfileForm({...profileForm, phone: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none" /></div>
|
||||
<div><label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Password</label><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 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none" /></div>
|
||||
<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>
|
||||
@@ -277,7 +302,13 @@ export const SettingsPage: React.FC = () => {
|
||||
<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><input className="w-full border border-slate-200 p-3 rounded-xl font-bold text-slate-800" value={brandingForm.appName} onChange={e => setBrandingForm({...brandingForm, appName: e.target.value})}/></div>
|
||||
<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">
|
||||
@@ -285,7 +316,13 @@ export const SettingsPage: React.FC = () => {
|
||||
<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"/><input type="text" value={brandingForm.primaryColor} onChange={e => setBrandingForm({...brandingForm, primaryColor: e.target.value})} className="w-28 text-sm font-mono border border-slate-200 rounded-xl p-3 uppercase font-bold"/></div>
|
||||
<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">
|
||||
@@ -332,25 +369,56 @@ export const SettingsPage: React.FC = () => {
|
||||
<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><input type="text" value={activeCondo.name} onChange={e => setActiveCondo({...activeCondo, name: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl font-bold" required /></div>
|
||||
<div><label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Indirizzo</label><input type="text" value={activeCondo.address || ''} onChange={e => setActiveCondo({...activeCondo, address: e.target.value})} className="w-full border border-slate-200 p-3 rounded-xl" required /></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>
|
||||
<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">Quota Mensile</label><input type="number" value={activeCondo.defaultMonthlyQuota} onChange={e => setActiveCondo({...activeCondo, defaultMonthlyQuota: parseFloat(e.target.value)})} className="w-full border border-slate-200 p-3 rounded-xl font-bold" /></div>
|
||||
<div><label className="text-xs font-bold text-slate-500 uppercase mb-2 block">Scadenza (Giorno)</label><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 rounded-xl" /></div>
|
||||
<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 rounded-xl text-xs font-mono pr-10"
|
||||
className="w-full border border-slate-200 p-3 pl-10 rounded-xl text-xs font-mono pr-10"
|
||||
placeholder="sandbox_..."
|
||||
/>
|
||||
<button
|
||||
@@ -391,22 +459,43 @@ export const SettingsPage: React.FC = () => {
|
||||
<div className="space-y-6 p-6 bg-slate-50 rounded-2xl border border-slate-100">
|
||||
{storageForm.provider === 's3' && (
|
||||
<>
|
||||
<input value={storageForm.bucket || ''} onChange={e => setStorageForm({...storageForm, bucket: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Bucket Name" />
|
||||
<input value={storageForm.region || ''} onChange={e => setStorageForm({...storageForm, region: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Region (es. eu-central-1)" />
|
||||
<input value={storageForm.apiKey || ''} onChange={e => setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Access Key ID" />
|
||||
<input value={storageForm.apiSecret || ''} onChange={e => setStorageForm({...storageForm, apiSecret: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Secret Access Key" type="password" />
|
||||
<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' && (
|
||||
<>
|
||||
<input value={storageForm.bucket || ''} onChange={e => setStorageForm({...storageForm, bucket: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Parent Folder ID (Opzionale)" />
|
||||
<input value={storageForm.apiKey || ''} onChange={e => setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Service Account Email (client_email)" />
|
||||
<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') && (
|
||||
<>
|
||||
<input value={storageForm.apiKey || ''} onChange={e => setStorageForm({...storageForm, apiKey: e.target.value})} className="w-full border p-3 rounded-xl" placeholder="Access Token" type="password" />
|
||||
<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>
|
||||
</>
|
||||
)}
|
||||
@@ -494,7 +583,7 @@ export const SettingsPage: React.FC = () => {
|
||||
{!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-center"><div><h4 className="font-bold text-slate-800">{n.title}</h4><p className="text-sm text-slate-500 line-clamp-1">{n.content}</p></div><div className="flex gap-2"><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 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>
|
||||
)}
|
||||
</>
|
||||
@@ -521,8 +610,14 @@ export const SettingsPage: React.FC = () => {
|
||||
<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">
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Nome Condominio" value={condoForm.name} onChange={e => setCondoForm({...condoForm, name: e.target.value})} required />
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Indirizzo" value={condoForm.address} onChange={e => setCondoForm({...condoForm, address: e.target.value})} />
|
||||
<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>
|
||||
@@ -534,10 +629,22 @@ export const SettingsPage: React.FC = () => {
|
||||
<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">
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Nome (es. Fam. Rossi)" value={familyForm.name} onChange={e => setFamilyForm({...familyForm, name: e.target.value})} required />
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Interno / Unità" value={familyForm.unitNumber} onChange={e => setFamilyForm({...familyForm, unitNumber: e.target.value})} required />
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Email Contatto" type="email" value={familyForm.contactEmail} onChange={e => setFamilyForm({...familyForm, contactEmail: e.target.value})} />
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Quota Personalizzata (Opzionale)" type="number" step="0.01" value={familyForm.customMonthlyQuota} onChange={e => setFamilyForm({...familyForm, customMonthlyQuota: e.target.value})} />
|
||||
<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>
|
||||
@@ -549,10 +656,22 @@ export const SettingsPage: React.FC = () => {
|
||||
<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">
|
||||
<input type="email" className="w-full border p-3 rounded-xl" placeholder="Email" value={userForm.email} onChange={e => setUserForm({...userForm, email: e.target.value})} required />
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Nome" value={userForm.name} onChange={e => setUserForm({...userForm, name: e.target.value})} />
|
||||
<input type="tel" className="w-full border p-3 rounded-xl" placeholder="Telefono" value={userForm.phone} onChange={e => setUserForm({...userForm, phone: e.target.value})} />
|
||||
<input type="password" className="w-full border p-3 rounded-xl" placeholder="Password (lascia vuoto se invariata)" value={userForm.password} onChange={e => setUserForm({...userForm, password: e.target.value})} />
|
||||
<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})}>
|
||||
@@ -581,8 +700,14 @@ export const SettingsPage: React.FC = () => {
|
||||
<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">
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Titolo" value={noticeForm.title} onChange={e => setNoticeForm({...noticeForm, title: e.target.value})} required />
|
||||
<textarea className="w-full border p-3 rounded-xl h-24" placeholder="Contenuto..." value={noticeForm.content} onChange={e => setNoticeForm({...noticeForm, content: e.target.value})} required />
|
||||
<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>
|
||||
@@ -619,7 +744,10 @@ export const SettingsPage: React.FC = () => {
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Link esterno (es. PDF Drive)" value={noticeForm.link} onChange={e => setNoticeForm({...noticeForm, link: e.target.value})} />
|
||||
<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>
|
||||
@@ -631,8 +759,14 @@ export const SettingsPage: React.FC = () => {
|
||||
<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">
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Oggetto Email" value={alertForm.subject} onChange={e => setAlertForm({...alertForm, subject: e.target.value})} required />
|
||||
<textarea className="w-full border p-3 rounded-xl h-24" placeholder="Testo Email..." value={alertForm.body} onChange={e => setAlertForm({...alertForm, body: e.target.value})} required />
|
||||
<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>
|
||||
@@ -655,14 +789,29 @@ export const SettingsPage: React.FC = () => {
|
||||
setGlobalSettings(updated);
|
||||
setShowSmtpModal(false);
|
||||
}} className="space-y-4">
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Host (smtp.gmail.com)" value={globalSettings.smtpConfig.host} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, host: e.target.value}})} required />
|
||||
<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">
|
||||
<input type="number" className="w-full border p-3 rounded-xl" placeholder="Porta (465)" value={globalSettings.smtpConfig.port} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, port: parseInt(e.target.value)}})} required />
|
||||
<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>
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="Utente/Email" value={globalSettings.smtpConfig.user} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, user: e.target.value}})} required />
|
||||
<input className="w-full border p-3 rounded-xl" type="password" placeholder="Password" value={globalSettings.smtpConfig.pass} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, pass: e.target.value}})} required />
|
||||
<input className="w-full border p-3 rounded-xl" placeholder="From Email (Opzionale)" value={globalSettings.smtpConfig.fromEmail || ''} onChange={e => setGlobalSettings({...globalSettings, smtpConfig: {...globalSettings.smtpConfig!, fromEmail: e.target.value}})} />
|
||||
<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>}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user