mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
vbox funzionanti
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* SettingsPage – impostazioni profilo dell'utente corrente.
|
||||
*
|
||||
* Sezioni:
|
||||
* - Informazioni profilo (nome visualizzato, email, ruolo)
|
||||
* - Modifica nome
|
||||
* - Cambio password
|
||||
*/
|
||||
|
||||
import { useState } from 'react'
|
||||
import { Settings, User, Lock, Save } from 'lucide-react'
|
||||
import { useAuth } from '@/hooks/useAuth'
|
||||
import { useAuthStore } from '@/store/auth.store'
|
||||
import { usersApi } from '@/api/users.api'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { Input } from '@/components/ui/Input'
|
||||
import { Label } from '@/components/ui/Label'
|
||||
import { Card } from '@/components/ui/Card'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
// ─── Etichetta ruolo ─────────────────────────────────────────────────────────
|
||||
|
||||
function roleLabel(role: string): string {
|
||||
switch (role) {
|
||||
case 'super_admin':
|
||||
return 'Super Amministratore'
|
||||
case 'admin':
|
||||
return 'Amministratore'
|
||||
case 'operator':
|
||||
return 'Operatore'
|
||||
default:
|
||||
return role
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Pagina ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export function SettingsPage() {
|
||||
const { user } = useAuth()
|
||||
const loadUser = useAuthStore((s) => s.loadUser)
|
||||
|
||||
/* ── Stato modifica nome ── */
|
||||
const [fullName, setFullName] = useState(user?.full_name ?? '')
|
||||
const [savingName, setSavingName] = useState(false)
|
||||
|
||||
/* ── Stato cambio password ── */
|
||||
const [newPassword, setNewPassword] = useState('')
|
||||
const [confirmPassword, setConfirmPassword] = useState('')
|
||||
const [savingPwd, setSavingPwd] = useState(false)
|
||||
|
||||
/* ── Salva nome ── */
|
||||
const handleSaveName = async () => {
|
||||
if (!user) return
|
||||
if (!fullName.trim()) {
|
||||
toast.error('Il nome non può essere vuoto')
|
||||
return
|
||||
}
|
||||
setSavingName(true)
|
||||
try {
|
||||
await usersApi.update(user.id, { full_name: fullName.trim() })
|
||||
await loadUser()
|
||||
toast.success('Nome aggiornato con successo')
|
||||
} catch {
|
||||
toast.error('Errore durante il salvataggio del nome')
|
||||
} finally {
|
||||
setSavingName(false)
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Cambia password ── */
|
||||
const handleChangePassword = async () => {
|
||||
if (!user) return
|
||||
if (newPassword.length < 8) {
|
||||
toast.error('La password deve essere di almeno 8 caratteri')
|
||||
return
|
||||
}
|
||||
if (newPassword !== confirmPassword) {
|
||||
toast.error('Le password non coincidono')
|
||||
return
|
||||
}
|
||||
setSavingPwd(true)
|
||||
try {
|
||||
await usersApi.resetPassword(user.id, newPassword)
|
||||
setNewPassword('')
|
||||
setConfirmPassword('')
|
||||
toast.success('Password aggiornata con successo')
|
||||
} catch {
|
||||
toast.error('Errore durante il cambio della password')
|
||||
} finally {
|
||||
setSavingPwd(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!user) return null
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-2xl mx-auto space-y-6">
|
||||
|
||||
{/* ── Intestazione ── */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="h-10 w-10 rounded-lg bg-blue-600 flex items-center justify-center">
|
||||
<Settings className="h-5 w-5 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-gray-900">Impostazioni</h1>
|
||||
<p className="text-sm text-gray-500">Gestisci il tuo profilo e le credenziali di accesso</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Card: Informazioni account ── */}
|
||||
<Card className="p-5 space-y-4">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<User className="h-4 w-4 text-gray-500" />
|
||||
<h2 className="text-sm font-semibold text-gray-700 uppercase tracking-wide">
|
||||
Informazioni account
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||||
<div>
|
||||
<span className="text-gray-500">Email</span>
|
||||
<p className="mt-0.5 font-medium text-gray-800">{user.email}</p>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-gray-500">Ruolo</span>
|
||||
<p className="mt-0.5 font-medium text-gray-800">{roleLabel(user.role)}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="border-gray-100" />
|
||||
|
||||
{/* Modifica nome */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="full_name">Nome visualizzato</Label>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
id="full_name"
|
||||
value={fullName}
|
||||
onChange={(e) => setFullName(e.target.value)}
|
||||
placeholder="Il tuo nome"
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button
|
||||
onClick={handleSaveName}
|
||||
disabled={savingName || fullName.trim() === (user.full_name ?? '')}
|
||||
size="sm"
|
||||
>
|
||||
<Save className="h-4 w-4 mr-1.5" />
|
||||
{savingName ? 'Salvataggio…' : 'Salva'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* ── Card: Cambio password ── */}
|
||||
<Card className="p-5 space-y-4">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<Lock className="h-4 w-4 text-gray-500" />
|
||||
<h2 className="text-sm font-semibold text-gray-700 uppercase tracking-wide">
|
||||
Cambio password
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="new_password">Nuova password</Label>
|
||||
<Input
|
||||
id="new_password"
|
||||
type="password"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
placeholder="Minimo 8 caratteri"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="confirm_password">Conferma password</Label>
|
||||
<Input
|
||||
id="confirm_password"
|
||||
type="password"
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
placeholder="Ripeti la nuova password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
onClick={handleChangePassword}
|
||||
disabled={savingPwd || !newPassword || !confirmPassword}
|
||||
>
|
||||
<Lock className="h-4 w-4 mr-1.5" />
|
||||
{savingPwd ? 'Aggiornamento…' : 'Aggiorna password'}
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user