Răsfoiți Sursa

(feat front) ajout des roles et des redirections a la connexion

Brin AMONKONAN 1 an în urmă
părinte
comite
cdc7c6ef0d

+ 1 - 0
app_transport_front/.env

@@ -0,0 +1 @@
+VITE_API_BASE_URL=http://localhost:3001/api

+ 1 - 0
app_transport_front/.env.local

@@ -0,0 +1 @@
+VITE_API_BASE_URL=http://localhost:3001/api

+ 8 - 0
app_transport_front/src/Enum/Role.ts

@@ -0,0 +1,8 @@
+export enum Role {
+  Admin = 'ADMIN',
+  User = 'USER',
+  Driver = 'DRIVER',
+  Manager= 'MANAGER',
+  Employee= 'EMPLOYEE',
+  Company = "Company",
+}

+ 48 - 0
app_transport_front/src/components/TopBar.vue

@@ -16,6 +16,9 @@
       </div>
       </div>
       <div class="user-dropdown" @click="toggleUserMenu">
       <div class="user-dropdown" @click="toggleUserMenu">
         <img :src="userAvatar" alt="User" />
         <img :src="userAvatar" alt="User" />
+        <div v-if="showUserMenu" class="dropdown-menu">
+          <button @click.stop="logout" class="dropdown-item">Déconnexion</button>
+        </div>
       </div>
       </div>
     </div>
     </div>
   </div>
   </div>
@@ -23,6 +26,7 @@
 
 
 <script setup lang="ts">
 <script setup lang="ts">
 import { ref } from 'vue'
 import { ref } from 'vue'
+import { useRouter } from 'vue-router'
 
 
 // Props pour personnaliser le composant
 // Props pour personnaliser le composant
 const props = defineProps({
 const props = defineProps({
@@ -59,9 +63,20 @@ const toggleMessages = () => {
   emit('toggle-messages')
   emit('toggle-messages')
 }
 }
 
 
+const showUserMenu = ref(false)
+const router = useRouter()
+
 const toggleUserMenu = () => {
 const toggleUserMenu = () => {
+  showUserMenu.value = !showUserMenu.value
   emit('toggle-user-menu')
   emit('toggle-user-menu')
 }
 }
+
+const logout = () => {
+  localStorage.removeItem('token')
+  localStorage.removeItem('role')
+  router.push('/')
+  showUserMenu.value = false
+}
 </script>
 </script>
 
 
 <style scoped>
 <style scoped>
@@ -132,6 +147,39 @@ const toggleUserMenu = () => {
   cursor: pointer;
   cursor: pointer;
 }
 }
 
 
+.user-dropdown {
+  position: relative;
+  display: inline-block;
+}
+
+.dropdown-menu {
+  position: absolute;
+  right: 0;
+  top: 40px;
+  background: #fff;
+  border: 1px solid #d1d3e2;
+  border-radius: 5px;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
+  min-width: 120px;
+  z-index: 100;
+}
+
+.dropdown-item {
+  width: 100%;
+  padding: 10px 15px;
+  background: none;
+  border: none;
+  text-align: left;
+  color: #333;
+  cursor: pointer;
+  font-size: 15px;
+  transition: background 0.2s;
+}
+
+.dropdown-item:hover {
+  background: #f8f9fc;
+}
+
 @media (max-width: 768px) {
 @media (max-width: 768px) {
   .search-box {
   .search-box {
     width: 200px;
     width: 200px;

+ 25 - 8
app_transport_front/src/router/index.ts

@@ -1,3 +1,4 @@
+import { Role } from '@/Enum/Role'
 import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
 import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
 
 
 const routes: Array<RouteRecordRaw> = [
 const routes: Array<RouteRecordRaw> = [
@@ -20,31 +21,37 @@ const routes: Array<RouteRecordRaw> = [
     path: '/dashboard',
     path: '/dashboard',
     name: 'dashboard',
     name: 'dashboard',
     component: () => import('../views/DashboardView.vue'),
     component: () => import('../views/DashboardView.vue'),
-    meta: { requiresAuth: true }
+    meta: { requiresAuth: true, roles: [Role.Admin] }
+  },
+  {
+    path: '/dashboard/:id',
+    name: 'dashboard company',
+    component: () => import('../views/DashboardView.vue'),
+    meta: { requiresAuth: true, roles: [Role.Admin, Role.Manager] }
   },
   },
   {
   {
     path: '/companies',
     path: '/companies',
     name: 'companies',
     name: 'companies',
     component: () => import('../views/CompanyView.vue'),
     component: () => import('../views/CompanyView.vue'),
-    meta: { requiresAuth: true }
+    meta: { requiresAuth: true, roles: [Role.Admin, Role.Manager] }
   },
   },
   {
   {
     path: '/employees',
     path: '/employees',
     name: 'employees',
     name: 'employees',
     component: () => import('../views/EmployeeView.vue'),
     component: () => import('../views/EmployeeView.vue'),
-    meta: { requiresAuth: true }
+    meta: { requiresAuth: true, roles: [Role.Admin, Role.Manager] }
   },
   },
   {
   {
     path: '/trips',
     path: '/trips',
     name: 'trips',
     name: 'trips',
     component: () => import('../views/TripView.vue'),
     component: () => import('../views/TripView.vue'),
-    meta: { requiresAuth: true }
+    meta: { requiresAuth: true, roles: [Role.Admin, Role.Manager, Role.Driver, Role.Employee, Role.User] }
   },
   },
   {
   {
     path: '/vehicles',
     path: '/vehicles',
     name: 'vehicles',
     name: 'vehicles',
     component: () => import('../views/VehicleView.vue'),
     component: () => import('../views/VehicleView.vue'),
-    meta: { requiresAuth: true }
+    meta: { requiresAuth: true, roles: [Role.Admin, Role.Manager, Role.Driver, Role.Employee] }
   },
   },
   // {
   // {
   //   path: '/budget',
   //   path: '/budget',
@@ -62,13 +69,13 @@ const routes: Array<RouteRecordRaw> = [
     path: '/drivers',
     path: '/drivers',
     name: 'drivers',
     name: 'drivers',
     component: () => import('../views/DriverView.vue'),
     component: () => import('../views/DriverView.vue'),
-    meta: { requiresAuth: true }
+    meta: { requiresAuth: true, roles: [Role.Admin, Role.Manager, Role.Driver, Role.Employee, Role.User]}
   },
   },
   {
   {
     path: '/verification-profil',
     path: '/verification-profil',
     name: 'profile-verification',
     name: 'profile-verification',
     component: () => import('../views/ProfileVerificationView.vue'),
     component: () => import('../views/ProfileVerificationView.vue'),
-    meta: { requiresAuth: true }
+    meta: { requiresAuth: true , roles: [Role.Admin, Role.Manager, Role.Driver, Role.Employee, Role.User] }
   },
   },
   // {
   // {
   //   path: '/company-setup',
   //   path: '/company-setup',
@@ -91,14 +98,24 @@ const routes: Array<RouteRecordRaw> = [
 ]
 ]
 
 
 const router = createRouter({
 const router = createRouter({
-  history: createWebHistory(import.meta.env.BASE_URL),
+  history: createWebHistory((import.meta as any).env.BASE_URL),
   routes
   routes
 })
 })
 
 
 router.beforeEach((to, from, next) => {
 router.beforeEach((to, from, next) => {
   const token = localStorage.getItem('token')
   const token = localStorage.getItem('token')
+  const userRole = localStorage.getItem('userRole')
   if (to.meta.requiresAuth && !token) {
   if (to.meta.requiresAuth && !token) {
     next('/login')
     next('/login')
+  } else if (to.meta.requiresAuth && token) {
+    const allowedRoles = to.meta.roles as string[] | undefined
+    if(allowedRoles && userRole && !allowedRoles.includes(userRole)) {
+      console.log('Access denied')
+      next('/login')
+    } else {
+      next()
+      return
+    }
   } else {
   } else {
     next()
     next()
   }
   }

+ 41 - 5
app_transport_front/src/views/LoginView.vue

@@ -49,6 +49,7 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
+import { Role } from '@/Enum/Role'
 import { ref, computed } from 'vue'
 import { ref, computed } from 'vue'
 import { useRouter } from 'vue-router'
 import { useRouter } from 'vue-router'
 
 
@@ -72,6 +73,36 @@ const goToHome = () => {
   router.push('/')
   router.push('/')
 }
 }
 
 
+const redirectionUser = async () => {
+  const userId = localStorage.getItem('userId')
+  const token = localStorage.getItem('token')
+  const userRole = localStorage.getItem('userRole')
+  if (userId) {
+    console.log('userId', userId)
+    //TODO:: a amélioré
+    const response = await fetch(`${(import.meta as any).env.VITE_API_BASE_URL}/companies/manager/${userId}`, {
+      method: 'GET',
+      headers: {
+        'Content-Type': 'application/json',
+        'Authorization': `Bearer ${token}`
+      }
+    })
+
+    const company = await response.json()
+    console.log('company', company)
+    if (response.ok) {
+      router.push('/dashboard/' + company.data.id)
+    } else if (response.status === 404 && userRole === Role.Admin ) {
+      router.push('/dashboard/')
+    } else if (response.status === 404) {
+     console.log('pas de conpagnie')
+    }
+    else {
+      router.push('/login')
+    }
+  }
+}
+
 const login = async () => {
 const login = async () => {
   if (!isFormValid.value) return
   if (!isFormValid.value) return
   
   
@@ -79,7 +110,7 @@ const login = async () => {
   errorMessage.value = ''
   errorMessage.value = ''
   
   
   try {
   try {
-    const response = await fetch('http://localhost:3001/api/auth/login', {
+    const response = await fetch(`${(import.meta as any).env.VITE_API_BASE_URL}/auth/login`, {
       method: 'POST',
       method: 'POST',
       headers: {
       headers: {
         'Content-Type': 'application/json'
         'Content-Type': 'application/json'
@@ -90,15 +121,20 @@ const login = async () => {
       })
       })
     })
     })
     
     
-    const data = await response.json()
     
     
+    const responseValue = await response.json()
+
     if (response.ok) {
     if (response.ok) {
+    
+      console.log('lala', responseValue.data)
       // Connexion réussie
       // Connexion réussie
-      localStorage.setItem('token', data.token)
-      router.push('/')
+      localStorage.setItem('token', responseValue.data.access_token)
+      localStorage.setItem('userId', responseValue.data.user.id)
+      localStorage.setItem('userRole', responseValue.data.user.role)
+      redirectionUser()
     } else {
     } else {
       // Erreur lors de la connexion
       // Erreur lors de la connexion
-      errorMessage.value = data.message || 'Email ou mot de passe incorrect'
+      errorMessage.value = responseValue.data.message || 'Email ou mot de passe incorrect'
     }
     }
   } catch (error) {
   } catch (error) {
     errorMessage.value = 'Erreur de connexion au serveur'
     errorMessage.value = 'Erreur de connexion au serveur'

+ 13 - 9
app_transport_front/src/views/ProfileVerificationView.vue

@@ -17,7 +17,7 @@
       <div class="profile-options">
       <div class="profile-options">
         <div 
         <div 
           class="profile-card" 
           class="profile-card" 
-          :class="{ 'selected': selectedProfile === 'company' }"
+          :class="{ 'selected': selectedProfile === Role.Company  }"
           @click="selectProfile('company')"
           @click="selectProfile('company')"
         >
         >
           <div class="icon-container">
           <div class="icon-container">
@@ -29,7 +29,7 @@
         
         
         <div 
         <div 
           class="profile-card" 
           class="profile-card" 
-          :class="{ 'selected': selectedProfile === 'driver' }"
+          :class="{ 'selected': selectedProfile === Role.Driver }"
           @click="selectProfile('driver')"
           @click="selectProfile('driver')"
         >
         >
           <div class="icon-container">
           <div class="icon-container">
@@ -41,7 +41,7 @@
         
         
         <div 
         <div 
           class="profile-card" 
           class="profile-card" 
-          :class="{ 'selected': selectedProfile === 'traveler' }"
+          :class="{ 'selected': selectedProfile === Role.User }"
           @click="selectProfile('traveler')"
           @click="selectProfile('traveler')"
         >
         >
           <div class="icon-container">
           <div class="icon-container">
@@ -65,6 +65,7 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
+import { Role } from '@/Enum/Role'
 import { ref } from 'vue'
 import { ref } from 'vue'
 import { useRouter } from 'vue-router'
 import { useRouter } from 'vue-router'
 
 
@@ -90,8 +91,8 @@ const continueSetup = async () => {
     }
     }
     
     
     // Envoyer le type de profil au serveur
     // Envoyer le type de profil au serveur
-    const response = await fetch(`http://localhost:3001/api/users/${userId}/profile-type`, {
-      method: 'PUT',
+    const response = await fetch(`${(import.meta as any).env.VITE_API_BASE_URL}/users/${userId}`, {
+      method: 'PATCH',
       headers: {
       headers: {
         'Content-Type': 'application/json',
         'Content-Type': 'application/json',
         'Authorization': `Bearer ${token}`
         'Authorization': `Bearer ${token}`
@@ -105,17 +106,20 @@ const continueSetup = async () => {
     
     
     // Rediriger vers la page appropriée en fonction du type de profil
     // Rediriger vers la page appropriée en fonction du type de profil
     switch (selectedProfile.value) {
     switch (selectedProfile.value) {
-      case 'company':
+      case Role.Company:
+        //Creation de la company
         router.push('/company-setup')
         router.push('/company-setup')
         break
         break
-      case 'driver':
+      case Role.Driver:
+        // Creation du driver
         router.push('/driver-setup')
         router.push('/driver-setup')
         break
         break
-      case 'traveler':
+        // information sur le voyageur vers son profil
+      case Role.User:
         router.push('/traveler-setup')
         router.push('/traveler-setup')
         break
         break
       default:
       default:
-        router.push('/dashboard')
+        router.push('/')
     }
     }
     
     
   } catch (error) {
   } catch (error) {

+ 1 - 1
app_transport_front/src/views/RegisterView.vue

@@ -103,7 +103,7 @@ const register = async () => {
   errorMessage.value = ''
   errorMessage.value = ''
   
   
   try {
   try {
-    const response = await fetch('http://localhost:3001/api/users', {
+    const response = await fetch(`${(import.meta as any).env.VITE_API_BASE_URL}/api/users`, {
       method: 'POST',
       method: 'POST',
       headers: {
       headers: {
         'Content-Type': 'application/json'
         'Content-Type': 'application/json'