chore: import DH V2 D5.6.4 production baseline
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { FormEvent } from 'react';
|
||||
import { Link, useNavigate } from 'react-router';
|
||||
import { Alert, LoadingBlock, errorMessage } from '../components/Feedback';
|
||||
import { Icon } from '../components/Icon';
|
||||
import { createUser, listRoles } from '../lib/api';
|
||||
import type { AdministrativeRole } from '../lib/api';
|
||||
|
||||
export function NewUserPage() {
|
||||
const navigate = useNavigate();
|
||||
const [roles, setRoles] = useState<AdministrativeRole[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [roleIds, setRoleIds] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
listRoles().then(setRoles).catch((requestError) => setError(errorMessage(requestError))).finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
const toggleRole = (id: string) => setRoleIds((current) => current.includes(id) ? current.filter((value) => value !== id) : [...current, id]);
|
||||
|
||||
const submit = async (event: FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
setError('');
|
||||
setSubmitting(true);
|
||||
const data = new FormData(event.currentTarget);
|
||||
try {
|
||||
const created = await createUser({
|
||||
username: String(data.get('username')),
|
||||
email: String(data.get('email') ?? '') || undefined,
|
||||
firstName: String(data.get('firstName')),
|
||||
lastName: String(data.get('lastName')),
|
||||
password: String(data.get('password')),
|
||||
mustChangePassword: data.get('mustChangePassword') === 'on',
|
||||
roleIds,
|
||||
});
|
||||
navigate(`/admin/users/${created.id}`, { replace: true, state: { created: true } });
|
||||
} catch (requestError) {
|
||||
setError(errorMessage(requestError));
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return <section className="narrow-section">
|
||||
<div className="breadcrumb"><Link to="/admin/users">Usuarios</Link><span>/</span><strong>Nuevo usuario</strong></div>
|
||||
<div className="page-heading"><div><span className="eyebrow">NUEVO ACCESO</span><h1>Crear usuario</h1><p>La contraseña inicial puede obligarse a cambiar en el primer ingreso.</p></div></div>
|
||||
{error && <Alert>{error}</Alert>}
|
||||
{loading ? <LoadingBlock /> : <form className="panel form-panel" onSubmit={submit}>
|
||||
<div className="form-section"><h2>Datos personales</h2><div className="form-grid"><label className="field"><span>Nombre</span><input name="firstName" required maxLength={120} /></label><label className="field"><span>Apellido</span><input name="lastName" required maxLength={120} /></label><label className="field"><span>Usuario</span><input name="username" required minLength={3} maxLength={80} pattern="[a-zA-Z][a-zA-Z0-9._-]+" /></label><label className="field"><span>Email <em>opcional</em></span><input name="email" type="email" maxLength={320} /></label></div></div>
|
||||
<div className="form-section"><h2>Seguridad</h2><label className="field"><span>Contraseña temporal</span><input name="password" type="password" minLength={12} maxLength={128} required autoComplete="new-password" /><small>Mínimo 12 caracteres.</small></label><label className="check-row"><input name="mustChangePassword" type="checkbox" defaultChecked /><span><strong>Exigir cambio de contraseña</strong><small>El usuario no podrá acceder a otros módulos hasta actualizarla.</small></span></label></div>
|
||||
<div className="form-section"><h2>Roles</h2><div className="choice-grid">{roles.map((role) => <label className={`choice-card ${roleIds.includes(role.id) ? 'selected' : ''}`} key={role.id}><input type="checkbox" checked={roleIds.includes(role.id)} onChange={() => toggleRole(role.id)} /><span><strong>{role.name}</strong><small>{role.description}</small></span><Icon name="check" /></label>)}</div></div>
|
||||
<div className="form-actions"><Link className="button secondary" to="/admin/users">Cancelar</Link><button className="button primary" disabled={submitting}>{submitting ? 'Creando…' : 'Crear usuario'}</button></div>
|
||||
</form>}
|
||||
</section>;
|
||||
}
|
||||
Reference in New Issue
Block a user