Fase 2: Creatción de la UI (React + Vite). Implementación de Log In reemplazando texto plano. Y creación de tool para migrar contraseñas.
This commit is contained in:
23
Frontend/src/pages/ChangePasswordPage.tsx
Normal file
23
Frontend/src/pages/ChangePasswordPage.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import { Typography, Container } from '@mui/material';
|
||||
// import { useLocation } from 'react-router-dom'; // Para obtener el estado 'firstLogin'
|
||||
|
||||
const ChangePasswordPage: React.FC = () => {
|
||||
// const location = useLocation();
|
||||
// const isFirstLogin = location.state?.firstLogin;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Typography variant="h4" component="h1" gutterBottom>
|
||||
Cambiar Contraseña
|
||||
</Typography>
|
||||
{/* {isFirstLogin && <Alert severity="warning">Debes cambiar tu contraseña inicial.</Alert>} */}
|
||||
{/* Aquí irá el formulario de cambio de contraseña */}
|
||||
<Typography variant="body1">
|
||||
Formulario de cambio de contraseña irá aquí...
|
||||
</Typography>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangePasswordPage;
|
||||
17
Frontend/src/pages/HomePage.tsx
Normal file
17
Frontend/src/pages/HomePage.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { Typography, Container } from '@mui/material';
|
||||
|
||||
const HomePage: React.FC = () => {
|
||||
return (
|
||||
<Container>
|
||||
<Typography variant="h4" component="h1" gutterBottom>
|
||||
Bienvenido al Sistema
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
Seleccione una opción del menú principal para comenzar.
|
||||
</Typography>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomePage;
|
||||
112
Frontend/src/pages/LoginPage.tsx
Normal file
112
Frontend/src/pages/LoginPage.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import React, { useState } from 'react';
|
||||
import axios from 'axios'; // Importar axios
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import apiClient from '../services/apiClient'; // Nuestro cliente axios
|
||||
import type { LoginRequestDto } from '../models/dtos/LoginRequestDto'; // Usar type
|
||||
import type { LoginResponseDto } from '../models/dtos/LoginResponseDto'; // Usar type
|
||||
|
||||
// Importaciones de Material UI
|
||||
import { Container, TextField, Button, Typography, Box, Alert } from '@mui/material';
|
||||
|
||||
const LoginPage: React.FC = () => {
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { login } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
setLoading(true);
|
||||
|
||||
const loginData: LoginRequestDto = { Username: username, Password: password };
|
||||
|
||||
try {
|
||||
const response = await apiClient.post<LoginResponseDto>('/auth/login', loginData);
|
||||
login(response.data); // Guardar token y estado de usuario en el contexto
|
||||
|
||||
// TODO: Verificar si response.data.DebeCambiarClave es true y redirigir
|
||||
// a '/change-password' si es necesario.
|
||||
// if (response.data.DebeCambiarClave) {
|
||||
// navigate('/change-password', { state: { firstLogin: true } }); // Pasar estado si es necesario
|
||||
// } else {
|
||||
navigate('/'); // Redirigir a la página principal
|
||||
// }
|
||||
|
||||
} catch (err: any) {
|
||||
console.error("Login error:", err);
|
||||
if (axios.isAxiosError(err) && err.response) {
|
||||
// Intenta obtener el mensaje de error de la API, si no, usa uno genérico
|
||||
setError(err.response.data?.message || 'Error al iniciar sesión. Verifique sus credenciales.');
|
||||
} else {
|
||||
setError('Ocurrió un error inesperado.');
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Container component="main" maxWidth="xs">
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Typography component="h1" variant="h5">
|
||||
Iniciar Sesión
|
||||
</Typography>
|
||||
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
|
||||
<TextField
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
id="username"
|
||||
label="Usuario"
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
autoFocus
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
disabled={loading}
|
||||
/>
|
||||
<TextField
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
name="password"
|
||||
label="Contraseña"
|
||||
type="password"
|
||||
id="password"
|
||||
autoComplete="current-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
disabled={loading}
|
||||
/>
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mt: 2, width: '100%' }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
sx={{ mt: 3, mb: 2 }}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? 'Ingresando...' : 'Ingresar'}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
Reference in New Issue
Block a user