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 - - field.onChange(v === '' ? '' : Number(v))} + disabled={isPending} + > + + + + + + {TIPO_MEDIO_OPTIONS.map((o) => ( - + ))} - - + + )} 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(v === '__all__' ? '' : v)} > - - {TIPO_MEDIO_OPTIONS.map((o) => ( - - ))} - + + + + + Todos los tipos + {TIPO_MEDIO_OPTIONS.map((o) => ( + + {o.label} + + ))} + + - 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" /> - onMedioIdChange(v === '__all__' ? undefined : Number(v))} > - - {medios.map((m) => ( - - ))} - + + + + + Todos los medios + {medios.map((m) => ( + + {m.nombre} + + ))} + + - onTipoChange(v === '__all__' ? undefined : (v as TipoSeccion))} > - - {TIPO_SECCION_OPTIONS.map((o) => ( - - ))} - + + + + + Todos los tipos + {TIPO_SECCION_OPTIONS.map((o) => ( + + {o.label} + + ))} + + - { + 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(v === '__all__' ? '' : v)} > - {ROL_OPTIONS.map((r) => ( - - ))} - + + + + + {ROL_OPTIONS.map((r) => ( + + {r.label} + + ))} + + {/* Activo filter */} - { + 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 - - - + )} 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