Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f695619
Se hace uso del estado global Auth para realizar el login, se hable u…
JMLTUnderCode Sep 27, 2025
028ea64
Se implementa una logica de proteccion de rutas en caso de que no se …
JMLTUnderCode Sep 27, 2025
b90ac7f
Actualizacion de nombre el custom hook useAuthentication
JMLTUnderCode Sep 27, 2025
e3ef8c2
Inclusion e instalacion de CORS para url de desarrollo
JMLTUnderCode Sep 27, 2025
24b1d5f
Se incluye context para Authenticacion. Se modifica el nombre del arc…
JMLTUnderCode Sep 27, 2025
d68bdf6
Actualizacion de nombre de context
JMLTUnderCode Sep 27, 2025
b86c6fc
Se incluye custom hooks para uso de provider de authenticacion
JMLTUnderCode Sep 27, 2025
5a3f633
Se incluye pagina web principal con un titulo, texto de verificacion …
JMLTUnderCode Sep 27, 2025
735890f
Actualizacion general de nombre de archivos. Cambio de sitio para log…
JMLTUnderCode Sep 27, 2025
476f22a
Actualizacion de tipos relacionado con LoginView y sus acciones. Incl…
JMLTUnderCode Sep 27, 2025
e6893f6
Se implementa React Router para navegacion entre componentes. Se prot…
JMLTUnderCode Sep 27, 2025
7222008
Se aplica provider de authenticacion a toda la aplicacion.
JMLTUnderCode Sep 27, 2025
f60ffac
Instalacion de react router dom para uso de React Router
JMLTUnderCode Sep 27, 2025
2aeb75b
Instalacion de CORS
JMLTUnderCode Sep 27, 2025
cb2ae3c
Inclusion de codigo comentado para el uso de prueba local de peticion…
JMLTUnderCode Sep 27, 2025
7d28e9d
Implementacion de reducer y provider para authenticacion de usuarios.…
JMLTUnderCode Sep 27, 2025
d8f1425
Se implementa handler de registro que de ser exitoso se reset estado …
JMLTUnderCode Sep 27, 2025
c96f67b
Se envuelve cada tests en su respectivo authentication provider y Mem…
JMLTUnderCode Sep 27, 2025
08a13d3
Se comenta que cors debe ir siempre primero en la lista de middleware
JMLTUnderCode Sep 27, 2025
1fea3e3
tab por spaces
JMLTUnderCode Sep 27, 2025
c9dcaa6
Manejo de catch por consola
JMLTUnderCode Sep 27, 2025
6baee63
Eliminacion de comentario de url antigua
JMLTUnderCode Sep 27, 2025
2a259c9
Elimnacion de comentario
JMLTUnderCode Sep 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'rest_framework',
'api',
]

MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # debe ir primero
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
Expand All @@ -58,6 +60,10 @@
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

CORS_ALLOWED_ORIGINS = [
"http://localhost:5173",
]

REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
Expand Down
64 changes: 59 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
},
"dependencies": {
"react": "19.1.1",
"react-dom": "19.1.1"
"react-dom": "19.1.1",
"react-router-dom": "7.9.3"
},
"devDependencies": {
"@eslint/js": "9.35.0",
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
asgiref==3.9.1
Django==5.2.6
django-cors-headers==4.9.0
djangorestframework==3.16.1
djangorestframework_simplejwt==5.5.1
gunicorn==23.0.0
Expand Down
22 changes: 17 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import './styles/App.css'
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { ProtectedRoute } from './components/ProtectedRoute';
import { StartPage } from './pages/StartPage';
import { MainPage } from './pages/MainPage';
import { Footer } from './components/Footer';

export function App() {
return (
<div className="App">
<StartPage />
<Footer />
</div>
return (
<BrowserRouter basename="/Clontube/">
<div className="App">
<Routes>
<Route path="/" element={<StartPage />} />
<Route path="/main/" element={
<ProtectedRoute>
<MainPage />
</ProtectedRoute>
} />
</Routes>
<Footer />
</div>
</BrowserRouter>
);
};
12 changes: 9 additions & 3 deletions src/components/FormLogin.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { FormLogin } from './FormLogin';
import { LoginViewProvider } from '../providers/LoginViewProvider';
import { AuthenticationProvider } from '../providers/AuthenticationProvider';
import { MemoryRouter } from 'react-router-dom';

describe('FormLogin component', () => {
function renderWithProvider() {
return render(
<LoginViewProvider>
<FormLogin />
</LoginViewProvider>
<AuthenticationProvider>
<MemoryRouter>
<LoginViewProvider>
<FormLogin />
</LoginViewProvider>
</MemoryRouter>
</AuthenticationProvider>
);
}

Expand Down
14 changes: 13 additions & 1 deletion src/components/FormLogin.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useLoginView } from '../hooks/useLoginView';
import { useAuthentication } from '../hooks/useAuthentication';
import { Input } from './Input';

export function FormLogin() {
const navigate = useNavigate();
const { LOGIN_VIEW_STATE, setLoginFields } = useLoginView();
const { login } = useAuthentication();

const [identifier, setIdentifier] = useState(LOGIN_VIEW_STATE.loginFields.identifier || '');
const [password, setPassword] = useState('');

const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
const success = await login(identifier, password);
if (success) {
navigate('/main/');
}
};

useEffect(() => {
setLoginFields({ identifier });
}, [setLoginFields, identifier]);

return (
<form className="login-form">
<form className="login-form" onSubmit={handleLogin}>
<h2>Iniciar Sesión</h2>
<Input type="USERNAME" label="Usuario / Correo Electrónico" field={identifier} onChange={setIdentifier} />
<Input type="PASSWORD" label="Contraseña" field={password} onChange={setPassword} />
Expand Down
29 changes: 27 additions & 2 deletions src/components/FormRegister.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useLoginView } from '../hooks/useLoginView';
import { Input } from './Input';

export function FormRegister() {
const { LOGIN_VIEW_STATE, setRegisterFields } = useLoginView();
const { LOGIN_VIEW_STATE, showLogin, setRegisterFields, clearFields } = useLoginView();

const [full_name, setFullName] = useState(LOGIN_VIEW_STATE.registerFields.full_name);
const [username, setUsername] = useState(LOGIN_VIEW_STATE.registerFields.username);
Expand All @@ -19,6 +19,31 @@ export function FormRegister() {
setRegisterFields({ full_name, username, email });
}, [setRegisterFields, full_name, username, email]);

async function handleRegister(e: React.FormEvent) {
if (emailError || passwordError) return;

e.preventDefault();

try {
const res = await fetch('https://backend-9tcm.onrender.com/api/users/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ full_name, username, email, password }),
});
const data = await res.json();
if (res.ok && data.success) {
clearFields();
// Registro exitoso, redirigir o mostrar mensaje
showLogin();

} else {
// Manejar error de registro
}
} catch {
// Manejar error de peticion
Comment on lines +40 to +43
Copy link

Copilot AI Sep 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty catch and error handling blocks provide no feedback to users. These should implement proper error handling with user-facing messages or logging.

Copilot uses AI. Check for mistakes.
}
}

function handleEmailBlur() {
if (email && confirmEmail && email !== confirmEmail) {
setEmailError(true);
Expand Down Expand Up @@ -52,7 +77,7 @@ export function FormRegister() {
}

return (
<form className="register-form">
<form className="register-form" onSubmit={handleRegister}>
<h2>Registrarse</h2>
<Input type="FULL_NAME" label="Nombre Completo" field={full_name} onChange={setFullName} />
<Input type="USERNAME" label="Usuario" field={username} onChange={setUsername} />
Expand Down
12 changes: 9 additions & 3 deletions src/components/LoginRegisterPanel.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { LoginRegisterPanel } from './LoginRegisterPanel';
import { LoginViewProvider } from '../providers/LoginViewProvider';
import { AuthenticationProvider } from '../providers/AuthenticationProvider';
import { MemoryRouter } from 'react-router-dom';

describe('LoginRegisterPanel component', () => {
function renderWithProvider() {
return render(
<LoginViewProvider>
<LoginRegisterPanel />
</LoginViewProvider>
<AuthenticationProvider>
<MemoryRouter>
<LoginViewProvider>
<LoginRegisterPanel />
</LoginViewProvider>
</MemoryRouter>
</AuthenticationProvider>
);
}

Expand Down
16 changes: 16 additions & 0 deletions src/components/ProtectedRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useNavigate } from "react-router-dom";
import React, { useEffect } from "react";
import { useAuthentication } from "../hooks/useAuthentication";

export function ProtectedRoute({ children }: { children: React.ReactNode }) {
const navigate = useNavigate();
const { AUTH_STATE } = useAuthentication();

useEffect(() => {
if (AUTH_STATE.isAuthenticated === false) {
navigate("/");
}
}, [AUTH_STATE.isAuthenticated, navigate]);

return <>{children}</>;
};
4 changes: 4 additions & 0 deletions src/contexts/AuthenticationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createContext } from 'react';
import type { AuthContextType } from '../utils/types';

export const AuthenticationContext = createContext<AuthContextType | undefined>(undefined);
File renamed without changes.
10 changes: 10 additions & 0 deletions src/hooks/useAuthentication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useContext } from 'react';
import { AuthenticationContext } from '../contexts/AuthenticationContext';

export function useAuthentication() {
const context = useContext(AuthenticationContext);
if (!context) {
throw new Error('useAuthentication must be used within a AuthenticationProvider');
}
return context;
}
2 changes: 1 addition & 1 deletion src/hooks/useLoginView.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useContext } from 'react';
import { LoginViewContext } from '../contexts/loginViewContext';
import { LoginViewContext } from '../contexts/LoginViewContext';

export function useLoginView() {
const context = useContext(LoginViewContext);
Expand Down
9 changes: 6 additions & 3 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './styles/index.css'
import { App } from './App.tsx'
import { AuthenticationProvider } from './providers/AuthenticationProvider.tsx'

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
<StrictMode>
<AuthenticationProvider>
<App />
</AuthenticationProvider>
</StrictMode>,
)
19 changes: 19 additions & 0 deletions src/pages/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useNavigate } from 'react-router-dom';
import { useAuthentication } from '../hooks/useAuthentication';

export function MainPage() {
const navigate = useNavigate();
const { AUTH_STATE, logout } = useAuthentication();

const handleLogout = () => {
logout();
navigate('/');
}
return (
<div>
<h2>Main Page</h2>
<p>Welcome, {AUTH_STATE.user ? AUTH_STATE.user.username : 'Guest'}!</p>
<button className="btn" onClick={handleLogout}>Logout</button>
</div>
)
}
Loading