parent
d3c427d01b
commit
8e8f6ac5c4
File diff suppressed because it is too large
Load Diff
@ -1,38 +1,46 @@ |
||||
.App { |
||||
text-align: center; |
||||
*{ |
||||
|
||||
padding: 0; |
||||
margin: 0; |
||||
box-sizing: border-box; |
||||
|
||||
} |
||||
|
||||
.App-logo { |
||||
height: 40vmin; |
||||
pointer-events: none; |
||||
html, body{ |
||||
background-color: white; |
||||
} |
||||
|
||||
@media (prefers-reduced-motion: no-preference) { |
||||
.App-logo { |
||||
animation: App-logo-spin infinite 20s linear; |
||||
} |
||||
.App { |
||||
position: relative; |
||||
height: 100vh; |
||||
width: 100vw; |
||||
background-image: url(${ImagenFondo}); |
||||
background-size: cover; |
||||
background-position: center; |
||||
background-repeat: no-repeat; |
||||
} |
||||
|
||||
.App-header { |
||||
background-color: #282c34; |
||||
min-height: 100vh; |
||||
display: flex; |
||||
|
||||
|
||||
.Formulario{ |
||||
height: 550px; |
||||
min-width: 600px; |
||||
display:flex; |
||||
flex-wrap: wrap; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: calc(10px + 2vmin); |
||||
color: white; |
||||
} |
||||
|
||||
.App-link { |
||||
color: #61dafb; |
||||
} |
||||
|
||||
@keyframes App-logo-spin { |
||||
from { |
||||
transform: rotate(0deg); |
||||
} |
||||
to { |
||||
transform: rotate(360deg); |
||||
} |
||||
|
||||
.Home{ |
||||
height: 550px; |
||||
min-width: 600px; |
||||
display:flex; |
||||
flex-wrap: wrap; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
} |
||||
|
||||
|
@ -1,26 +1,136 @@ |
||||
import React from 'react'; |
||||
import logo from './logo.svg'; |
||||
import './App.css'; |
||||
import React, { useEffect, useState } from 'react'; |
||||
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom'; |
||||
import axios from 'axios'; |
||||
import DTOLogin from './DTos/DTOLogin'; |
||||
import DTOLoginReset from './DTos/DTOLoginReset'; |
||||
import Home from './Componentes/Home'; |
||||
import Formulario from './Componentes/Formulario'; |
||||
import AmazonInvoice from './Componentes/AmazonInvoice'; |
||||
import ImagenLogo from './Imagenes/descarga.png'; |
||||
import ImagenFondo from './Imagenes/fondo.jpg'; |
||||
|
||||
axios.interceptors.response.use( |
||||
function (response) { |
||||
const newToken = response.data.token; |
||||
if (newToken) { |
||||
localStorage.setItem('jwtToken', newToken); |
||||
axios.defaults.headers.common['Authorization'] = `Bearer ${newToken}`; |
||||
} |
||||
return response; |
||||
}, |
||||
function (error) { |
||||
if (error.response && error.response.status === 401) { |
||||
window.location.href = '/login'; |
||||
} |
||||
return Promise.reject(error); |
||||
} |
||||
); |
||||
|
||||
const App: React.FC = () => { |
||||
const [user, setUser] = useState<any>(null); |
||||
const [isLoading, setIsLoading] = useState<boolean>(false); |
||||
|
||||
const handleLogin = async (Usuario: string, Contrasena: string) => { |
||||
setIsLoading(true); |
||||
try { |
||||
if (!Usuario || !Contrasena) { |
||||
alert('Ingrese un usuario y contraseña válidos'); |
||||
setIsLoading(false); |
||||
return; |
||||
} |
||||
|
||||
const data: DTOLogin = { usuario: Usuario, contrasena: Contrasena }; |
||||
const response = await axios.post("https://localhost:5051/api/Usuario/Loging", data); |
||||
if (response.status === 200) { |
||||
setUser(response.data); |
||||
alert('Inicio de sesión correcto'); |
||||
localStorage.setItem('jwtToken', response.data.token); |
||||
} |
||||
} catch (error) { |
||||
console.log(error); |
||||
} finally { |
||||
setIsLoading(false); |
||||
} |
||||
}; |
||||
|
||||
useEffect(() => { |
||||
const checkTokenValidity = async () => { |
||||
const token = localStorage.getItem('jwtToken'); |
||||
if (token) { |
||||
try { |
||||
const response = await axios.get('https://localhost:5051/api/Usuario/Validate', { |
||||
headers: { |
||||
Authorization: `Bearer ${token}`, |
||||
}, |
||||
}); |
||||
if (response.status === 200) { |
||||
setUser(response.data); |
||||
} |
||||
} catch (error) { |
||||
console.log(error); |
||||
handleLogout(); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
checkTokenValidity(); |
||||
}, []); |
||||
|
||||
const handleLogout = () => { |
||||
setUser(null); |
||||
localStorage.removeItem('jwtToken'); |
||||
}; |
||||
|
||||
const handlePasswordReset = async (Usuario: string, Contrasena: string, NuevaContrasena: string) => { |
||||
setIsLoading(true); |
||||
try { |
||||
const data1: DTOLoginReset = { usuario: Usuario, contrasena: Contrasena, nuevacontrasena: NuevaContrasena }; |
||||
const response = await axios.put("https://localhost:5051/api/Usuario/ResetPassword", data1); |
||||
if (response.status === 200) { |
||||
alert('Contraseña restablecida correctamente'); |
||||
} |
||||
} catch (error) { |
||||
console.log(error); |
||||
alert('Se ha producido un error al restablecer la contraseña.'); |
||||
} finally { |
||||
setIsLoading(false); |
||||
} |
||||
}; |
||||
|
||||
const handleLoginFormSubmit = (userObject: any) => { |
||||
handleLogin(userObject.usuario, userObject.contrasena); |
||||
}; |
||||
|
||||
function App() { |
||||
return ( |
||||
<div className="App"> |
||||
<header className="App-header"> |
||||
<img src={logo} className="App-logo" alt="logo" /> |
||||
<p> |
||||
Edit <code>src/App.tsx</code> and save to reload. |
||||
</p> |
||||
<a |
||||
className="App-link" |
||||
href="https://reactjs.org" |
||||
target="_blank" |
||||
rel="noopener noreferrer" |
||||
> |
||||
Learn React |
||||
</a> |
||||
</header> |
||||
<div className='App' style={{ backgroundImage: `url(${ImagenFondo})`, backgroundSize: 'cover', backgroundPosition: 'center', backgroundRepeat: 'no-repeat', height: '100vh' }}> |
||||
<Router> |
||||
{isLoading ? ( |
||||
<p>Loading...</p> |
||||
) : ( |
||||
<Routes> |
||||
<Route |
||||
path='/login' |
||||
element={ |
||||
!user ? ( |
||||
<Formulario handleLogin={handleLoginFormSubmit} handlePasswordReset={handlePasswordReset} /> |
||||
) : ( |
||||
<Navigate to='/home' /> |
||||
) |
||||
} |
||||
/> |
||||
<Route path='/home' element={user ? <Home user={user} handleLogout={handleLogout} /> : <Navigate to='/login' />} /> |
||||
<Route path='/amazon-invoice' element={user ? <AmazonInvoice /> : <Navigate to='/login' />} /> |
||||
<Route path='/*' element={<Navigate to='/login' />} /> |
||||
</Routes> |
||||
)} |
||||
{!user && ( |
||||
<div className='logo'> |
||||
<img className='ILogo' src={ImagenLogo} alt='Logo de Imagem' /> |
||||
</div> |
||||
)} |
||||
</Router> |
||||
</div> |
||||
); |
||||
} |
||||
}; |
||||
|
||||
export default App; |
||||
|
@ -0,0 +1,12 @@ |
||||
import React from 'react'; |
||||
|
||||
const AmazonInvoice: React.FC = () => { |
||||
return ( |
||||
<div> |
||||
<h1>Bienvenidos a Amazon Invoiceee</h1> |
||||
|
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
export default AmazonInvoice; |
@ -0,0 +1,86 @@ |
||||
import '../HojasDeEstilo/Formulario.css'; |
||||
import { useState } from 'react'; |
||||
|
||||
interface FormularioProps { |
||||
handleLogin: (userObject: any) => void; |
||||
handlePasswordReset: (usuario: string, contrasena: string, nuevaContrasena: string) => void; |
||||
} |
||||
|
||||
function Formulario({ handleLogin, handlePasswordReset }: FormularioProps) { |
||||
const [usuario, setUsuario] = useState(''); |
||||
const [contrasena, setContrasena] = useState(''); |
||||
const [resetMode, setResetMode] = useState(false); |
||||
const [resetError, setResetError] = useState(false); |
||||
const [nuevaContrasena, setNuevaContrasena] = useState(''); |
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { |
||||
e.preventDefault(); |
||||
|
||||
if (resetMode) { |
||||
if (usuario === '' || contrasena === '' || nuevaContrasena === '') { |
||||
setResetError(true); |
||||
alert('Todos los campos son obligatorios'); |
||||
return; |
||||
} |
||||
setResetError(false); |
||||
handlePasswordReset(usuario, contrasena, nuevaContrasena); |
||||
} else { |
||||
if (usuario === '' || contrasena === '') { |
||||
alert('Todos los campos son obligatorios'); |
||||
return; |
||||
} |
||||
const userObject = { |
||||
usuario, |
||||
contrasena |
||||
}; |
||||
|
||||
handleLogin(userObject); |
||||
} |
||||
}; |
||||
|
||||
return ( |
||||
<section> |
||||
<form className='Formulario' onSubmit={handleSubmit}> |
||||
<h2>Usuario</h2> |
||||
<input |
||||
type='text' |
||||
id='usuario-input' // ID para el cuadro de texto del usuario
|
||||
value={usuario} |
||||
onChange={(e) => setUsuario(e.target.value)} |
||||
/> |
||||
<h3>Contraseña</h3> |
||||
<input |
||||
type='password' |
||||
id='contrasena-input' // ID para el cuadro de texto de la contraseña
|
||||
value={contrasena} |
||||
onChange={(e) => setContrasena(e.target.value)} |
||||
/> |
||||
{resetMode && ( |
||||
<> |
||||
<h3>Nueva Contraseña</h3> |
||||
<input |
||||
type='password' |
||||
id='nuevaContrasena-input' // ID para el cuadro de texto de la nueva contraseña
|
||||
value={nuevaContrasena} |
||||
onChange={(e) => setNuevaContrasena(e.target.value)} |
||||
/> |
||||
<button type="submit" id='submit-reset-button' className='primary'> |
||||
Restablecer Contraseña |
||||
</button> |
||||
</> |
||||
)} |
||||
{!resetMode && ( |
||||
<button type="submit" id='submit-login-button' className='primary'> |
||||
Iniciar Sesión |
||||
</button> |
||||
)} |
||||
</form> |
||||
<button onClick={() => setResetMode(!resetMode)} id='reset-button'> |
||||
{resetMode ? 'Cancelar Restablecer Contraseña' : 'Restablecer Contraseña'} |
||||
</button> |
||||
{resetError && <p>Todos los campos son obligatorios para restablecer la contraseña</p>} |
||||
</section> |
||||
); |
||||
} |
||||
|
||||
export default Formulario; |
@ -0,0 +1,29 @@ |
||||
|
||||
import React from 'react'; |
||||
import { Navbar, Nav } from 'react-bootstrap'; |
||||
import { Link } from 'react-router-dom'; |
||||
import '../HojasDeEstilo/Navbar.css' |
||||
|
||||
interface HomeProps { |
||||
user: any; |
||||
handleLogout: () => void; |
||||
} |
||||
|
||||
const Home: React.FC<HomeProps> = ({ user, handleLogout }) => { |
||||
return ( |
||||
<div className="home-container"> |
||||
<h1>BIENVENIDOS AL HOME</h1> |
||||
<Navbar bg="dark" variant="dark" className="navbar-custom"> |
||||
<Nav.Link href="#amazon">No Le Click</Nav.Link> |
||||
<Nav className="ml-auto"> |
||||
<Nav.Link as={Link} to="/amazon-invoice"> |
||||
Amazon Invoice |
||||
</Nav.Link> |
||||
</Nav> |
||||
<Nav.Link onClick={handleLogout}>Cerrar Sesión</Nav.Link> |
||||
</Navbar> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
export default Home; |
@ -0,0 +1,4 @@ |
||||
declare module 'jsonwebtoken' { |
||||
export function decode(token: string): any; |
||||
} |
||||
|
@ -0,0 +1,38 @@ |
||||
import axios from 'axios'; |
||||
|
||||
axios.interceptors.response.use( |
||||
function (response) { |
||||
const newToken = response.data.token; |
||||
if (newToken) { |
||||
localStorage.setItem('jwtToken', newToken); // Guardar el token en el localStorage
|
||||
} |
||||
return response; |
||||
}, |
||||
function (error) { |
||||
// Manejar el error aquí
|
||||
if (error.response && error.response.status === 401) { |
||||
// Si el estado de respuesta es 401 (No autorizado), redirigir al formulario de inicio de sesión
|
||||
window.location.href = '/login'; |
||||
} |
||||
return Promise.reject(error); |
||||
} |
||||
); |
||||
|
||||
|
||||
// axios.interceptors.response.use(
|
||||
// function (response) {
|
||||
// const newToken = response.data.token;
|
||||
// if (newToken) {
|
||||
// localStorage.setItem('jwtToken', newToken);
|
||||
// }
|
||||
// return response;
|
||||
// },
|
||||
// function (error) {
|
||||
// // Manejar el error aquí
|
||||
// if (error.response && error.response.status === 401) {
|
||||
// // Si el estado de respuesta es 401 (No autorizado), redirigir al formulario de inicio de sesión
|
||||
// window.location.href = '/login';
|
||||
// }
|
||||
// return Promise.reject(error);
|
||||
// }
|
||||
// );
|
@ -0,0 +1,5 @@ |
||||
export default interface DTOLogin { |
||||
usuario: string, |
||||
contrasena: string,
|
||||
|
||||
} |
@ -0,0 +1,5 @@ |
||||
export default interface DTOLoginReset { |
||||
usuario: string, |
||||
contrasena: string,
|
||||
nuevacontrasena: string |
||||
} |
@ -0,0 +1,113 @@ |
||||
* { |
||||
padding: 0; |
||||
margin: 0; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.contenedor { |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
height: 100vh; |
||||
} |
||||
|
||||
|
||||
|
||||
.logo { |
||||
height: 100px; |
||||
min-width: 600px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
margin-bottom: 20px; /* Añade un margen inferior para separar el logotipo de los campos de entrada */ |
||||
} |
||||
|
||||
|
||||
|
||||
.Formulario { |
||||
position: relative; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
gap: 0rem; |
||||
padding: 1rem; |
||||
border-radius: 1rem; |
||||
margin-top: 5px; |
||||
} |
||||
|
||||
h2 { |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
flex-direction: column; |
||||
gap: 1rem; |
||||
font-size: 1rem; |
||||
color: white; |
||||
margin-top: 2rem; /* Ajusta el valor según tu necesidad */ |
||||
} |
||||
|
||||
h3 { |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
flex-direction: column; |
||||
gap: 1rem; |
||||
font-size: 1rem; |
||||
color: white; |
||||
} |
||||
|
||||
input { |
||||
padding: 12px 20px; |
||||
margin: 8px 0; |
||||
box-sizing: border-box; |
||||
border: 2px solid #ccc; |
||||
border-radius: 4px; |
||||
font-size: 16px; |
||||
font-family: Lato, sans-serif; |
||||
height: 50px; |
||||
} |
||||
|
||||
#submit-login-button { |
||||
background-color: greenyellow; |
||||
border: none; |
||||
color: #000000; |
||||
padding: 12px 24px; |
||||
text-align: center; |
||||
text-decoration: none; |
||||
display: inline-block; |
||||
font-size: 16px; |
||||
margin: 14px 0px; |
||||
cursor: pointer; |
||||
border-radius: 8px; |
||||
transition: background-color 0.3s ease; |
||||
height: 10%; |
||||
width: 237.5px; |
||||
} |
||||
|
||||
button { |
||||
background-color: rgb(132, 130, 238); |
||||
border: none; |
||||
color: white; |
||||
padding: 12px 24px; |
||||
text-align: center; |
||||
text-decoration: none; |
||||
display: inline-block; |
||||
font-size: 16px; |
||||
margin: 14px 0px; |
||||
cursor: pointer; |
||||
border-radius: 8px; |
||||
transition: background-color 0.3s ease; |
||||
height: 10%; |
||||
width: 237.5px; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,44 @@ |
||||
*{ |
||||
|
||||
padding: 0; |
||||
margin: 0; |
||||
box-sizing: border-box; |
||||
|
||||
} |
||||
|
||||
|
||||
.Home{ |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
flex-direction: column; |
||||
gap: 1rem; |
||||
background-color: green; |
||||
padding: 2rem; |
||||
border-radius: 1rem; |
||||
} |
||||
|
||||
|
||||
|
||||
h1{ |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
flex-direction: column; |
||||
gap: 1rem; |
||||
font-size: 3rem; |
||||
background-color: rgb(255, 255, 255); |
||||
text-shadow: 1px 1px #FFFFFF; |
||||
} |
||||
|
||||
button{ |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
flex-direction: column; |
||||
gap: 1rem; |
||||
font-size: 3rem; |
||||
background-color: rgb(255, 255, 255); |
||||
text-shadow: 1px 1px #FFFFFF; |
||||
|
||||
} |
@ -0,0 +1,26 @@ |
||||
.navbar-custom { |
||||
background-color: #4054bd; |
||||
color: #000; |
||||
position: fixed; |
||||
top: 0; |
||||
width: 100%; |
||||
z-index: 10; |
||||
border-bottom: 1px solid #4f3817; |
||||
border-radius: 0; |
||||
} |
||||
|
||||
.navbar-custom .navbar-brand { |
||||
font-weight: bold; |
||||
font-size: 24px; |
||||
} |
||||
|
||||
.navbar-custom .nav-link { |
||||
color: #f5f5f5; |
||||
font-weight: bold; |
||||
font-size: 18px; |
||||
margin-right: 15px; |
||||
} |
||||
|
||||
.navbar-custom .nav-link:hover { |
||||
color: #888888; |
||||
} |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 515 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Loading…
Reference in new issue