diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 456012f..c5aa259 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -3,9 +3,18 @@ import { useAuthStore } from '../stores/auth'; import Swal from 'sweetalert2'; import { useI18n } from 'vue-i18n'; + import { useCompanyStore } from '../stores/company'; + import { useVehiclesStore } from '../stores/vehicles'; + import { useLoadsStore } from '../stores/loads'; + import { useNotificationsStore } from '../stores/notifications'; const route = useRoute(); const auth = useAuthStore(); + const company = useCompanyStore(); + const vehicles = useVehiclesStore(); + const loads = useLoadsStore(); + const noty = useNotificationsStore(); + const router = useRouter(); const { t } = useI18n() const handleLogout = () => { @@ -20,6 +29,11 @@ }).then(async(result) => { if(result.isConfirmed) { auth.logout(); + company.clear(); + vehicles.clear(); + loads.clear(); + noty.clear(); + router.push({name: 'login'}); } }); } diff --git a/src/main.js b/src/main.js index c934a84..0672e2c 100644 --- a/src/main.js +++ b/src/main.js @@ -6,10 +6,13 @@ import App from './App.vue' import router from './router' import i18n from './i18n/i18n' +const pinia = createPinia(); const app = createApp(App) -app.use(createPinia()) app.use(router) +app.use(pinia) + app.use(i18n) + app.mount('#app') diff --git a/src/router/index.js b/src/router/index.js index 4c9bd79..c4a40a0 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,6 +1,7 @@ import { createRouter, createWebHistory } from 'vue-router' import AuthLayout from '../layouts/AuthLayout.vue' import PublicLayout from '../layouts/PublicLayout.vue' +import { useAuthStore } from '../stores/auth'; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -30,6 +31,11 @@ const router = createRouter({ name: 'register-company', component: () => import('../views/CompleteRegisterView.vue') }, + { + path: '/:pathMatch(.*)*', + name: 'not-found', + component: () => import('../views/LoginView.vue'), + } ] }, { @@ -68,88 +74,121 @@ const router = createRouter({ path: '/dashboard', name: 'dashboard', component: () => import('../layouts/AdminLayout.vue'), - meta: { requiresAuth: true }, + meta: { + requiresAuth: true, + roles: ['manager', 'staff', 'owner'] + }, children: [ { path: 'inicio', name: 'home', + meta: { permissions: ['role_shipper', 'role_carrier'] }, component: () => import('../views/HomeView.vue'), }, { path: 'empresa', name: 'company', + meta: { permissions: ['role_shipper', 'role_carrier'] }, component: () => import('../views/MyCompanyView.vue'), }, { path: 'profile', name: 'profile', + meta: { permissions: ['role_shipper', 'role_carrier'] }, component: () => import('../views/EditProfileView.vue'), }, { path: 'empresa/:id', name: 'public-users', + meta: { permissions: ['role_shipper', 'role_carrier'] }, component: () => import('../views/PublicUsersCompanyView.vue'), }, { path: 'ubicaciones', name: 'locations', + meta: { permissions: ['role_shipper', 'role_carrier'] }, component: () => import('../views/LocationsView.vue'), }, { path: 'ofertas', name: 'published-trucks', + meta: { permissions: ['role_carrier'] }, component: () => import('../views/TrucksPublishedView.vue'), }, { path: 'usuarios', name: 'users', + meta: { permissions: ['role_shipper', 'role_carrier'] }, component: () => import('../views/UsersView.vue'), }, { path: 'calculadora', name: 'calculator', + meta: { permissions: ['role_carrier'] }, component: () => import('../views/CalculatorView.vue'), }, { path: 'reportes', name: 'reports', + meta: { permissions: ['role_shipper', 'role_carrier'] }, component: () => import('../views/ReportsView.vue'), }, { path: 'calendario', name: 'calendar', + meta: { + permissions: ['role_shipper', 'role_carrier'], + roles: ['staff', 'manager', 'owner', 'store'] + }, component: () => import('../views/CalendarView.vue'), }, { path: 'cargas', + meta: { permissions: ['role_shipper'] }, name: 'published-loads', component: () => import('../views/LoadsPublishedView.vue'), }, { path: 'vehiculos', name: 'vehicles', + meta: { permissions: ['role_carrier'] }, component: () => import('../views/VehiclesView.vue'), }, { path: 'transportistas', name: 'carriers', + meta: { permissions: ['role_shipper'] }, component: () => import('../views/CarriersView.vue'), }, { path: 'embarcadores', name: 'shippers', + meta: { permissions: ['role_carrier'] }, component: () => import('../views/ShippersView.vue'), }, { path: 'buscar-cargas', name: 'search-loads', + meta: { permissions: ['role_carrier'] }, component: () => import('../views/SearchLoadsView.vue'), }, { - path: 'buscar-vehiclulos', + path: 'buscar-vehiculos', name: 'search-vehicles', + meta: { permissions: ['role_shipper'] }, component: () => import('../views/SearchVehiclesView.vue'), }, + { + path: '403', + name: '403', + meta: { permissions: ['role_shipper', 'role_carrier'] }, + component: () => import('../views/NotFoundView.vue'), + }, + { + path: '/:pathMatch(.*)*', + name: 'not-found', + component: () => import('../views/HomeView.vue'), + } ] } ] @@ -158,16 +197,63 @@ const router = createRouter({ router.beforeEach( async(to, from, next) => { const requiresAuth = to.matched.some(url => url.meta.requiresAuth) if(requiresAuth === true) { + const auth = useAuthStore() const session = localStorage.getItem('session'); - //Comprobamos si el usuario esta authenticado + const permissions = to.meta.permissions; + const roles = to.meta.roles; + if(session) { + await auth.checkSession() + const permissionUser = auth?.user?.permissions; + const role = auth?.user?.job_role; + if (!permissionUser) { + return next({name: 'login'}); // Redirige al login si no está autenticado + } + + if (permissions && !permissions.includes(permissionUser)) { + if(role === 'store') { /// Check if user is store + return next({name: 'calendar'}); + } else { + return next({name: 'home'}); + } + } + + if(roles && !roles.includes(role)) { + return next({name: 'calendar'}); + } + next(); } else { - next({name: 'login'}) + return next({name: 'login'}) } } else { next(); } }); +// router.beforeEach( async(to, from, next) => { +// const requiresAuth = to.matched.some(url => url.meta.requiresAuth) +// if(requiresAuth === true) { +// const session = localStorage.getItem('session'); +// const role = localStorage.getItem('user'); +// const permissions = to.meta.permissions; +// const auth = useAuthStore() +// //Comprobamos si el usuario esta authenticado +// if(session) { +// if (!role) { +// return next({name: 'login'}); // Redirige al login si no está autenticado +// } + +// if (permissions && !permissions.includes(role)) { +// return next({name: 'home'}); // Redirige a una página de acceso denegado si no tiene permisos +// } +// next(); +// } else { +// return next({name: 'login'}) +// } +// } else { +// next(); +// } +// }); + export default router diff --git a/src/stores/auth.js b/src/stores/auth.js index 56e1093..95daecb 100644 --- a/src/stores/auth.js +++ b/src/stores/auth.js @@ -3,9 +3,7 @@ import { ref, onMounted } from "vue"; import { useRoute, useRouter } from 'vue-router'; import { renewToken } from '../services/auth'; import {useNotificationsStore} from './notifications'; -import {useCompanyStore} from './company'; import { useLoadsStore } from "./loads"; -import { useVehiclesStore } from "./vehicles"; import { updateMyUserProfile } from "../services/company"; export const useAuthStore = defineStore('auth', () => { @@ -13,16 +11,14 @@ export const useAuthStore = defineStore('auth', () => { const router = useRouter(); const route = useRoute(); const noty = useNotificationsStore(); - const company = useCompanyStore(); const loadStore = useLoadsStore(); - const vehiclesStore = useVehiclesStore(); - const notyStore = useNotificationsStore(); const sesion = ref('') const checking = ref(false); const authStatus = ref('checking'); const token = ref('') const lang = ref('es'); const user = ref(null); + const isAuthenticated = ref(false); const publicNames = [ 'terms-conditions', 'notice-privacy', @@ -34,15 +30,10 @@ export const useAuthStore = defineStore('auth', () => { 'register-company', ] - onMounted( async() => { - checkSession(); - }); - - const checkSession = async() => { const session = localStorage.getItem('session'); authStatus.value = 'checking'; - if(session && !publicNames.includes(route.name)) { + if((session && !publicNames.includes(route.name)) && isAuthenticated.value === false && checking.value === false) { checking.value = true; const resp = await renewToken(); if(resp.msg === 'success') { @@ -53,22 +44,24 @@ export const useAuthStore = defineStore('auth', () => { localStorage.setItem('access', resp.data.accessToken); localStorage.setItem('id', resp.data.user.company._id); checking.value = false; + isAuthenticated.value = true; } else { noty.show = true; noty.text = 'Sesión ha expirado, ingresa nuevamente'; noty.error = true; checking.value = false; + isAuthenticated.value = false; router.push({name: 'login'}); } - } + } authStatus.value = 'completed'; } - const authenticationPromise = new Promise((resolve) => { - onMounted(() => { - resolve('success'); - }); - }); + // const authenticationPromise = new Promise((resolve) => { + // onMounted(() => { + // resolve('success'); + // }); + // }); const updateProfile = async(data) => { const response = await updateMyUserProfile(data); @@ -90,17 +83,7 @@ export const useAuthStore = defineStore('auth', () => { user.value = null; checking.value = false; authStatus.value = 'checking' - notyStore.notifications = []; - notyStore.newNoty = false; - notyStore.show = false; - notyStore.openNotifications = false; - notyStore.toggleProfile = false; - - company.clear(); loadStore.clear(); - vehiclesStore.clear(); - - router.push({name: 'login'}); } return { @@ -111,8 +94,9 @@ export const useAuthStore = defineStore('auth', () => { checking, authStatus, checkSession, - authenticationPromise, + // authenticationPromise, updateProfile, - lang + lang, + isAuthenticated } }); \ No newline at end of file diff --git a/src/stores/notifications.js b/src/stores/notifications.js index a190601..d486e21 100644 --- a/src/stores/notifications.js +++ b/src/stores/notifications.js @@ -34,6 +34,15 @@ export const useNotificationsStore = defineStore('notifications', () => { return notifications.value = notifications.value.filter(noty => noty._id !== id); } + const clear = () => { + notifications.value = []; + newNoty.value = false; + show.value = false; + openNotifications.value = false; + toggleProfile.value = false; + } + + return { text, @@ -45,6 +54,7 @@ export const useNotificationsStore = defineStore('notifications', () => { removeNoty, toggleProfile, openNotifications, - toggleNotifications + toggleNotifications, + clear } }); \ No newline at end of file diff --git a/src/views/CompleteRegisterView.vue b/src/views/CompleteRegisterView.vue index e7f998f..6c30290 100644 --- a/src/views/CompleteRegisterView.vue +++ b/src/views/CompleteRegisterView.vue @@ -98,7 +98,7 @@ localStorage.setItem('id', result.data._id); localStorage.setItem('session', auth.sesion); - // localStorage.setItem('access', auth.token); + localStorage.setItem('access', auth.accessToken); const userData = { "first_name" : user.name, @@ -109,6 +109,7 @@ let respUser = await updateMyUserProfile( userData ); if(respUser.msg === 'success') { auth.user = respUser.data; + auth.isAuthenticated = true; } else { auth.user = userData; } diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index f60f260..fef0369 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -48,6 +48,7 @@ sesion: resp.data.session_token, token: resp.data.accessToken, user: resp.data.user, + isAuthenticated: true }) } else { // Completar registro auth.$patch({ diff --git a/src/views/MyCompanyView.vue b/src/views/MyCompanyView.vue index 7762bb2..3011154 100644 --- a/src/views/MyCompanyView.vue +++ b/src/views/MyCompanyView.vue @@ -27,7 +27,6 @@ }) const getInitialData = async() => { - await auth.authenticationPromise; await company.getCompanyData(); } diff --git a/src/views/NotFoundView.vue b/src/views/NotFoundView.vue new file mode 100644 index 0000000..b3a9d5a --- /dev/null +++ b/src/views/NotFoundView.vue @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file