#28 feat(api): add logout.

This commit is contained in:
2026-02-14 18:55:26 -05:00
parent 4a67f85dcb
commit 4e79ecd56b
5 changed files with 45 additions and 35 deletions

View File

@@ -1,3 +1,12 @@
<template>
<h1>Login</h1>
<v-form @submit.prevent="login">
<v-text-field v-model="username" label="Usuario" required />
<v-text-field v-model="password" label="Contraseña" type="password" required />
<v-btn type="submit">Entrar</v-btn>
<v-alert v-if="error" type="error">{{ error }}</v-alert>
</v-form>
</template>
<script setup>
import { ref } from 'vue';
import AuthService from '@/services/auth';
@@ -10,33 +19,8 @@
async function login() {
try {
await AuthService.login({ username: username.value, password: password.value });
// opcional: redirigir al dashboard
} catch (e) {
error.value = e.message;
}
}
// ejemplo de llamada a clientes (requiere token)
const api = inject('api');
async function loadCustomers() {
try {
const data = await api.getCustomers();
console.log(data);
} catch (e) {
console.error(e);
}
}
</script>
<template>
<h1>Login</h1>
<v-form @submit.prevent="login">
<v-text-field v-model="username" label="Usuario" required />
<v-text-field v-model="password" label="Contraseña" type="password" required />
<v-btn type="submit">Entrar</v-btn>
<v-alert v-if="error" type="error">{{ error }}</v-alert>
</v-form>
<v-btn @click="loadCustomers">Cargar clientes</v-btn>
</template>

29
src/components/Logout.vue Normal file
View File

@@ -0,0 +1,29 @@
<style scoped>
p {
font-size: 1.1rem;
color: #555;
}
</style>
<template>
<v-container class="d-flex flex-column align-center justify-center" style="height: 100vh;">
<v-progress-circular indeterminate color="primary" />
<p class="mt-4">Cerrando sesión</p>
</v-container>
</template>
<script>
import AuthService from '@/services/auth';
export default {
name: 'DonConfiao',
mounted() {
this.logout();
},
methods: {
logout() {
AuthService.logout();
this.$router.push({
path: "/autenticarse"
});
},
},
};
</script>

View File

@@ -50,6 +50,7 @@
menuItems: [
{ title: 'Inicio', route: '/', icon: 'mdi-home'},
{ title: 'Comprar', route:'/comprar', icon: 'mdi-cart'},
{ title: 'Salir', route:'/salir', icon: 'mdi-cart'},
],
menuAdminItems: [
{ title: 'Cuadrar tarro', route: '/cuadrar_tarro', icon: 'mdi-calculator'},

View File

@@ -1,5 +1,5 @@
<template>
<Login />
<Logout />
</template>
<script setup>

View File

@@ -2,7 +2,7 @@ import axios from 'axios';
import AuthService from '@/services/auth';
const http = axios.create({
baseURL: import.meta.env.VITE_DJANGO_BASE_URL, // ← raíz del API
baseURL: import.meta.env.VITE_DJANGO_BASE_URL,
headers: {
'Content-Type': 'application/json',
},
@@ -20,23 +20,19 @@ http.interceptors.request.use(
);
http.interceptors.response.use(
response => response, // paso directo si todo está OK
response => response,
async error => {
const originalRequest = error.config;
// Sólo intentamos refrescar una vez
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const newAccess = await AuthService.refresh(); // guarda el nuevo token
// vuelve a colocar el header actualizado
const newAccess = await AuthService.refresh();
originalRequest.headers.Authorization = `Bearer ${newAccess}`;
return http.request(originalRequest); // reintenta la petición
return http.request(originalRequest);
} catch (refreshError) {
// Si el refresh falla, forzamos logout
AuthService.logout();
// opcional: redirigir al login
window.location.href = '/login';
window.location.href = '/autenticarse';
return Promise.reject(refreshError);
}
}