diff --git a/src/web/src/features/medios/components/MedioForm.tsx b/src/web/src/features/medios/components/MedioForm.tsx
index e802a76..1c87169 100644
--- a/src/web/src/features/medios/components/MedioForm.tsx
+++ b/src/web/src/features/medios/components/MedioForm.tsx
@@ -15,6 +15,13 @@ import {
FormLabel,
FormMessage,
} from '@/components/ui/form'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
import { TIPO_MEDIO_OPTIONS } from '../tipoMedio'
import type { MedioDetail } from '../types'
@@ -136,22 +143,24 @@ export function MedioForm({ initialData, isPending, error, onSubmit }: MedioForm
render={({ field }) => (
Tipo
-
-
+
+
)}
diff --git a/src/web/src/features/medios/pages/MediosListPage.tsx b/src/web/src/features/medios/pages/MediosListPage.tsx
index 5f91688..842eba8 100644
--- a/src/web/src/features/medios/pages/MediosListPage.tsx
+++ b/src/web/src/features/medios/pages/MediosListPage.tsx
@@ -5,6 +5,13 @@ import { Input } from '@/components/ui/input'
import { Skeleton } from '@/components/ui/skeleton'
import { CanPerform } from '@/components/auth/CanPerform'
import { useDebouncedValue } from '@/hooks/useDebouncedValue'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
import { MediosTable } from '../components/MediosTable'
import { useMediosList } from '../hooks/useMediosList'
import { TIPO_MEDIO_OPTIONS } from '../tipoMedio'
@@ -70,28 +77,36 @@ export function MediosListPage() {
aria-label="Buscar medios"
/>
- handleTipoChange(e.target.value)}
- className="flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
+ handleTipoChange(v === '__all__' ? '' : v)}
>
-
- {TIPO_MEDIO_OPTIONS.map((o) => (
-
- ))}
-
+
+
+
+
+ Todos los tipos
+ {TIPO_MEDIO_OPTIONS.map((o) => (
+
+ {o.label}
+
+ ))}
+
+
- handleActivoChange(e.target.value)}
- className="flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
+ handleActivoChange(v === '__all__' ? '' : v)}
>
-
-
-
-
+
+
+
+
+ Todos
+ Activos
+ Inactivos
+
+
{isLoading ? (
diff --git a/src/web/src/features/permisos/pages/RolPermisosPage.tsx b/src/web/src/features/permisos/pages/RolPermisosPage.tsx
index 7c79c8d..63fb3c1 100644
--- a/src/web/src/features/permisos/pages/RolPermisosPage.tsx
+++ b/src/web/src/features/permisos/pages/RolPermisosPage.tsx
@@ -6,6 +6,13 @@ import {
CardHeader,
CardTitle,
} from '@/components/ui/card'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
import { useRoles } from '../../roles/hooks/useRoles'
import { RolPermisosEditor } from '../components/RolPermisosEditor'
@@ -28,28 +35,28 @@ export function RolPermisosPage() {
{/* Selector de rol */}
-
diff --git a/src/web/src/features/secciones/components/SeccionForm.tsx b/src/web/src/features/secciones/components/SeccionForm.tsx
index 701a0e4..1d188fb 100644
--- a/src/web/src/features/secciones/components/SeccionForm.tsx
+++ b/src/web/src/features/secciones/components/SeccionForm.tsx
@@ -15,6 +15,13 @@ import {
FormLabel,
FormMessage,
} from '@/components/ui/form'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
import { useMediosList } from '@/features/medios/hooks/useMediosList'
import { TIPO_SECCION_OPTIONS } from '../tipoSeccion'
import type { SeccionDetail, TipoSeccion } from '../types'
@@ -100,22 +107,24 @@ export function SeccionForm({ initialData, isPending, error, onSubmit }: Seccion
render={({ field }) => (
Medio
-
-
-
+ field.onChange(Number(v))}
+ disabled={isPending || isEdit}
+ >
+
+
+
+
+
+
{medios.map((m) => (
-
+
))}
-
-
+
+
)}
@@ -165,22 +174,24 @@ export function SeccionForm({ initialData, isPending, error, onSubmit }: Seccion
render={({ field }) => (
Tipo
-
-
-
+ field.onChange(v as TipoSeccion)}
+ disabled={isPending}
+ >
+
+
+
+
+
+
{TIPO_SECCION_OPTIONS.map((o) => (
-
+
))}
-
-
+
+
)}
diff --git a/src/web/src/features/secciones/components/SeccionesFilters.tsx b/src/web/src/features/secciones/components/SeccionesFilters.tsx
index 5197b3f..25598ab 100644
--- a/src/web/src/features/secciones/components/SeccionesFilters.tsx
+++ b/src/web/src/features/secciones/components/SeccionesFilters.tsx
@@ -1,6 +1,13 @@
import { useEffect, useState } from 'react'
import { Input } from '@/components/ui/input'
import { useDebouncedValue } from '@/hooks/useDebouncedValue'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
import { useMediosList } from '@/features/medios/hooks/useMediosList'
import { TIPO_SECCION_OPTIONS } from '../tipoSeccion'
import type { TipoSeccion } from '../types'
@@ -40,51 +47,56 @@ export function SeccionesFilters({
aria-label="Buscar secciones"
/>
- {
- const v = e.target.value
- onMedioIdChange(v === '' ? undefined : Number(v))
- }}
- className="flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
+ onMedioIdChange(v === '__all__' ? undefined : Number(v))}
>
-
- {medios.map((m) => (
-
- ))}
-
+
+
+
+
+ Todos los medios
+ {medios.map((m) => (
+
+ {m.nombre}
+
+ ))}
+
+
- {
- const v = e.target.value
- onTipoChange(v === '' ? undefined : (v as TipoSeccion))
- }}
- className="flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
+ onTipoChange(v === '__all__' ? undefined : (v as TipoSeccion))}
>
-
- {TIPO_SECCION_OPTIONS.map((o) => (
-
- ))}
-
+
+
+
+
+ Todos los tipos
+ {TIPO_SECCION_OPTIONS.map((o) => (
+
+ {o.label}
+
+ ))}
+
+
- {
- const v = e.target.value
- if (v === '') onActivoChange(undefined)
+ {
+ if (v === '__all__') onActivoChange(undefined)
else onActivoChange(v === 'true')
}}
- className="flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
>
-
-
-
-
+
+
+
+
+ Todos
+ Activos
+ Inactivos
+
+
)
}
diff --git a/src/web/src/features/users/components/UserForm.tsx b/src/web/src/features/users/components/UserForm.tsx
index 792adc3..7df874c 100644
--- a/src/web/src/features/users/components/UserForm.tsx
+++ b/src/web/src/features/users/components/UserForm.tsx
@@ -14,6 +14,13 @@ import {
FormLabel,
FormMessage,
} from '@/components/ui/form'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
import { useCreateUser } from '../hooks/useCreateUser'
import { useRolesForSelect } from '../hooks/useRolesForSelect'
import type { CreatedUserDto } from '../api/createUser'
@@ -202,23 +209,26 @@ export function UserForm({ onSuccess }: UserFormProps) {
render={({ field }) => (
Rol
-
-
-
+
+
+
+
+
+
+
{rolOptions.map((r) => (
-
+
))}
-
-
+
+
)}
diff --git a/src/web/src/features/users/components/UsersFilters.tsx b/src/web/src/features/users/components/UsersFilters.tsx
index e21c187..f4c1f86 100644
--- a/src/web/src/features/users/components/UsersFilters.tsx
+++ b/src/web/src/features/users/components/UsersFilters.tsx
@@ -1,6 +1,13 @@
import { useState, useEffect } from 'react'
import { Input } from '@/components/ui/input'
import { useDebouncedValue } from '@/hooks/useDebouncedValue'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
interface UsersFiltersProps {
onRolChange: (rol: string) => void
@@ -38,32 +45,39 @@ export function UsersFilters({ onRolChange, onActivoChange, onSearchChange }: Us
/>
{/* Rol select */}
- onRolChange(e.target.value)}
- className="flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
+ onRolChange(v === '__all__' ? '' : v)}
>
- {ROL_OPTIONS.map((r) => (
-
- ))}
-
+
+
+
+
+ {ROL_OPTIONS.map((r) => (
+
+ {r.label}
+
+ ))}
+
+
{/* Activo filter */}
- {
- const v = e.target.value
- if (v === '') onActivoChange(undefined)
+ {
+ if (v === '__all__') onActivoChange(undefined)
else onActivoChange(v === 'true')
}}
- className="flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
>
-
-
-
-
+
+
+
+
+ Todos
+ Activos
+ Inactivos
+
+
)
}
diff --git a/src/web/src/features/users/pages/UserEditPage.tsx b/src/web/src/features/users/pages/UserEditPage.tsx
index 78605e7..85f1cfa 100644
--- a/src/web/src/features/users/pages/UserEditPage.tsx
+++ b/src/web/src/features/users/pages/UserEditPage.tsx
@@ -17,6 +17,13 @@ import {
FormLabel,
FormMessage,
} from '@/components/ui/form'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
import { useUser } from '../hooks/useUser'
import { useUpdateUser } from '../hooks/useUpdateUser'
import { ResetPasswordModal } from '../components/ResetPasswordModal'
@@ -199,18 +206,22 @@ export function UserEditPage() {
render={({ field }) => (
Rol
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ Admin
+ Cajero
+ Reportes
+
+
)}
diff --git a/src/web/src/tests/features/medios/CreateMedioPage.test.tsx b/src/web/src/tests/features/medios/CreateMedioPage.test.tsx
index 9045f61..d779ed3 100644
--- a/src/web/src/tests/features/medios/CreateMedioPage.test.tsx
+++ b/src/web/src/tests/features/medios/CreateMedioPage.test.tsx
@@ -61,7 +61,11 @@ describe('CreateMedioPage', () => {
await userEvent.type(screen.getByLabelText(/código/i), 'RAD01')
await userEvent.type(screen.getByLabelText(/nombre/i), 'Radio AM')
- await userEvent.selectOptions(screen.getByLabelText(/tipo/i), '2')
+
+ // Open Radix Select trigger and pick "Radio" (value=2)
+ await userEvent.click(screen.getByRole('combobox', { name: /tipo/i }))
+ await userEvent.click(screen.getByRole('option', { name: /^radio$/i }))
+
await userEvent.click(screen.getByRole('button', { name: /crear medio/i }))
await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith('/admin/medios'))
@@ -81,7 +85,11 @@ describe('CreateMedioPage', () => {
await userEvent.type(screen.getByLabelText(/código/i), 'DUP01')
await userEvent.type(screen.getByLabelText(/nombre/i), 'Duplicado')
- await userEvent.selectOptions(screen.getByLabelText(/tipo/i), '1')
+
+ // Open Radix Select trigger and pick "Diario" (value=1)
+ await userEvent.click(screen.getByRole('combobox', { name: /tipo/i }))
+ await userEvent.click(screen.getByRole('option', { name: /^diario$/i }))
+
await userEvent.click(screen.getByRole('button', { name: /crear medio/i }))
await waitFor(() =>
diff --git a/src/web/src/tests/features/medios/MedioForm.test.tsx b/src/web/src/tests/features/medios/MedioForm.test.tsx
index 8b8dc52..021ee0d 100644
--- a/src/web/src/tests/features/medios/MedioForm.test.tsx
+++ b/src/web/src/tests/features/medios/MedioForm.test.tsx
@@ -79,7 +79,11 @@ describe('MedioForm — create mode', () => {
await userEvent.type(screen.getByLabelText(/código/i), 'DIA99')
await userEvent.type(screen.getByLabelText(/nombre/i), 'Mi Diario')
- await userEvent.selectOptions(screen.getByLabelText(/tipo/i), '1')
+
+ // Open the Radix Select trigger and pick option
+ await userEvent.click(screen.getByRole('combobox', { name: /tipo/i }))
+ await userEvent.click(screen.getByRole('option', { name: /diario/i }))
+
await userEvent.click(screen.getByRole('button', { name: /crear medio/i }))
await waitFor(() => {
diff --git a/src/web/src/tests/features/medios/MediosListPage.test.tsx b/src/web/src/tests/features/medios/MediosListPage.test.tsx
index 6d48b92..34470ce 100644
--- a/src/web/src/tests/features/medios/MediosListPage.test.tsx
+++ b/src/web/src/tests/features/medios/MediosListPage.test.tsx
@@ -144,8 +144,9 @@ describe('MediosListPage', () => {
await waitFor(() => expect(requests.length).toBeGreaterThan(0))
- const tipoSelect = screen.getByRole('combobox', { name: /tipo/i })
- await userEvent.selectOptions(tipoSelect, '1')
+ // Open the Radix Select trigger and pick "Diario" (value=1)
+ await userEvent.click(screen.getByRole('combobox', { name: /tipo/i }))
+ await userEvent.click(screen.getByRole('option', { name: /^diario$/i }))
await waitFor(() => {
const filtered = requests.find((u) => u.includes('tipo=1'))
diff --git a/src/web/src/tests/features/secciones/SeccionForm.test.tsx b/src/web/src/tests/features/secciones/SeccionForm.test.tsx
index 04f0000..741f4bd 100644
--- a/src/web/src/tests/features/secciones/SeccionForm.test.tsx
+++ b/src/web/src/tests/features/secciones/SeccionForm.test.tsx
@@ -88,15 +88,25 @@ describe('SeccionForm — create mode', () => {
const onSubmit = vi.fn()
renderForm({ onSubmit })
- // Wait for medios to load
+ // Open Medio trigger, wait for medios to load, then pick one
+ const medioTrigger = screen.getByRole('combobox', { name: /medio/i })
+ await userEvent.click(medioTrigger)
await waitFor(() =>
expect(screen.getByRole('option', { name: 'Diario El Día' })).toBeInTheDocument(),
)
+ await userEvent.click(screen.getByRole('option', { name: 'Diario El Día' }))
- await userEvent.selectOptions(screen.getByLabelText(/medio/i), '1')
await userEvent.type(screen.getByLabelText(/código/i), 'CLAS99')
await userEvent.type(screen.getByLabelText(/nombre/i), 'Mi Sección')
- await userEvent.selectOptions(screen.getByLabelText(/tipo de sección/i), 'clasificados')
+
+ // Open Tipo trigger and pick Clasificados
+ const tipoTrigger = screen.getByRole('combobox', { name: /tipo de sección/i })
+ await userEvent.click(tipoTrigger)
+ await waitFor(() =>
+ expect(screen.getByRole('option', { name: 'Clasificados' })).toBeInTheDocument(),
+ )
+ await userEvent.click(screen.getByRole('option', { name: 'Clasificados' }))
+
await userEvent.click(screen.getByRole('button', { name: /crear sección/i }))
await waitFor(() => {
@@ -117,8 +127,9 @@ describe('SeccionForm — edit mode', () => {
renderForm({ initialData: sampleSeccion })
const codigoInput = screen.getByLabelText(/código/i) as HTMLInputElement
expect(codigoInput.disabled).toBe(true)
- const medioSelect = screen.getByLabelText(/medio/i) as HTMLSelectElement
- expect(medioSelect.disabled).toBe(true)
+ // Radix Select trigger is a