feat(users): idioma por defecto con banderas SVG + conmutador coherente

- Campo "Idioma por defecto" al crear/editar usuario (columna locale ya existente),
  como desplegable Alpine con banderas SVG reales (no emoji, que en Windows se ven
  como "ES"/"GB") servidas localmente: public/images/flags/{es,gb}.svg.
- User: locale añadido a fillable. UserForm: propiedad/validación/guardado de locale.
- LanguageSwitcher de la cabecera usa las mismas banderas SVG.
- Regla CSS [x-cloak] en el layout para evitar parpadeo de desplegables Alpine.

Tests: UserLocaleTest (2) — crear/editar persisten el idioma.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-18 13:10:27 +02:00
parent 8c774d075d
commit 19e1f57983
8 changed files with 150 additions and 3 deletions
+13
View File
@@ -36,6 +36,9 @@ class UserForm extends Component
// Permisos
public string $formRole = '';
// Preferencias
public string $locale = 'es';
// Notas
public string $notes = '';
@@ -43,6 +46,12 @@ class UserForm extends Component
public $roles;
public $companies;
/** Idiomas disponibles (código => nombre + archivo de bandera). */
public array $languages = [
'es' => ['name' => 'Español', 'flag' => 'es.svg'],
'en' => ['name' => 'English', 'flag' => 'gb.svg'],
];
public function mount(?User $user = null): void
{
abort_unless(Auth::user()->can('create users') || Auth::user()->can('edit users'), 403);
@@ -65,6 +74,7 @@ class UserForm extends Component
$this->email = $user->email;
$this->notes = $user->notes ?? '';
$this->formRole = $user->roles->first()?->name ?? $this->formRole;
$this->locale = $user->locale ?? $this->locale;
}
}
@@ -83,6 +93,7 @@ class UserForm extends Component
'phone' => 'nullable|string|max:30',
'email' => "required|email|max:255|unique:users,email,{$id}",
'formRole' => 'required|exists:roles,name',
'locale' => 'required|in:' . implode(',', array_keys($this->languages)),
];
if (!$this->user) {
@@ -103,6 +114,7 @@ class UserForm extends Component
'companyId' => 'empresa',
'formPassword'=> 'contraseña',
'formRole' => 'rol',
'locale' => 'idioma',
];
public function copyCompanyAddress(): void
@@ -139,6 +151,7 @@ class UserForm extends Component
'phone' => $this->phone ?: null,
'email' => $this->email,
'notes' => $this->notes ?: null,
'locale' => $this->locale,
];
if ($this->formPassword !== '') {