fix(web): cablear ResetPasswordModal en UserDetailPage [UDT-008]

El componente ResetPasswordModal estaba implementado pero nunca montado en una pagina.
Ahora se renderiza en UserDetailPage, oculto cuando el target es el usuario logueado
(evita hit de cannot-self-reset en backend).
This commit is contained in:
2026-04-15 20:54:25 -03:00
parent 2e2d4543ad
commit 851fed8692
2 changed files with 83 additions and 0 deletions

View File

@@ -4,11 +4,14 @@ import { Badge } from '@/components/ui/badge'
import { useUser } from '../hooks/useUser'
import { useDeactivateUser } from '../hooks/useDeactivateUser'
import { useReactivateUser } from '../hooks/useReactivateUser'
import { ResetPasswordModal } from '../components/ResetPasswordModal'
import { useAuthStore } from '@/stores/authStore'
export function UserDetailPage() {
const { id } = useParams<{ id: string }>()
const userId = Number(id)
const navigate = useNavigate()
const loggedUserId = useAuthStore((s) => s.user?.id)
const { data: user, isLoading } = useUser(userId)
const { mutate: deactivate, isPending: deactivating } = useDeactivateUser()
@@ -90,6 +93,8 @@ export function UserDetailPage() {
{reactivating ? 'Reactivando...' : 'Reactivar'}
</Button>
)}
{loggedUserId !== userId && <ResetPasswordModal userId={userId} />}
</div>
</div>
)

View File

@@ -0,0 +1,78 @@
import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { MemoryRouter, Routes, Route } from 'react-router-dom'
import { UserDetailPage } from '../../../features/users/pages/UserDetailPage'
import { useAuthStore } from '../../../stores/authStore'
const API_URL = 'http://localhost:5000'
const adminUser = {
id: 1, username: 'admin', nombre: 'Admin', rol: 'admin',
permisos: ['administracion:usuarios:gestionar'],
mustChangePassword: false,
}
const target = {
id: 5,
username: 'cajero1',
nombre: 'Juan',
apellido: 'Perez',
email: 'juan@test.com',
rol: 'cajero',
activo: true,
permisosJson: '[]',
fechaModificacion: null,
ultimoLogin: null,
}
const server = setupServer()
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
afterEach(() => {
server.resetHandlers()
useAuthStore.getState().clearAuth()
})
afterAll(() => server.close())
function renderDetail(userId: number) {
useAuthStore.setState({ user: adminUser })
const qc = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } } })
return render(
<QueryClientProvider client={qc}>
<MemoryRouter initialEntries={[`/usuarios/${userId}`]}>
<Routes>
<Route path="/usuarios/:id" element={<UserDetailPage />} />
</Routes>
</MemoryRouter>
</QueryClientProvider>,
)
}
describe('UserDetailPage — reset password wiring', () => {
it('shows "Resetear contraseña" button when viewing another user', async () => {
server.use(
http.get(`${API_URL}/api/v1/users/5`, () => HttpResponse.json(target)),
)
renderDetail(5)
await waitFor(() => expect(screen.getByText('Juan Perez')).toBeInTheDocument())
expect(screen.getByRole('button', { name: /resetear contraseña/i })).toBeInTheDocument()
})
it('hides "Resetear contraseña" button when viewing own profile (prevent cannot-self-reset)', async () => {
server.use(
http.get(`${API_URL}/api/v1/users/1`, () =>
HttpResponse.json({ ...target, id: 1, username: 'admin', nombre: 'Admin', apellido: 'Root', rol: 'admin' }),
),
)
renderDetail(1)
await waitFor(() => expect(screen.getByText('Admin Root')).toBeInTheDocument())
expect(screen.queryByRole('button', { name: /resetear contraseña/i })).not.toBeInTheDocument()
})
})