From 0b3e9b26ea2911a769a43e2e754629397251bb6a Mon Sep 17 00:00:00 2001
From: VIktorGrev <viktog2210@gmail.com>
Date: Thu, 2 May 2024 15:22:48 +0200
Subject: [PATCH] feat: Adding badges and menu selected visual

---
 spec.json                                     | 465 +++++++++++++++++-
 src/components/BaseComponents/NavBar.vue      | 256 ++++++----
 src/components/Friends/UserFriends.vue        |   2 +-
 .../Leaderboard/LeaderboardRank.vue           |   7 +-
 src/components/Login/LoginForm.vue            |   2 +-
 src/components/Settings/SettingsProfile.vue   |  40 +-
 src/components/UserProfile/MyProfile.vue      |  73 ++-
 src/views/User/UserSettingsView.vue           |  13 +-
 8 files changed, 690 insertions(+), 168 deletions(-)

diff --git a/spec.json b/spec.json
index cf41850..0aab7ca 100644
--- a/spec.json
+++ b/spec.json
@@ -1,8 +1,8 @@
 {
   "openapi": "3.0.1",
   "info": {
-    "title": "SpareSti API",
-    "description": "The SpareSti API",
+    "title": "Sparesti API",
+    "description": "The Sparesti API",
     "version": "3.0"
   },
   "servers": [
@@ -349,6 +349,48 @@
         "security": []
       }
     },
+    "/api/notification/update": {
+      "post": {
+        "tags": [
+          "Notification"
+        ],
+        "summary": "Updates a notification",
+        "description": "Updates a notification based on the request",
+        "operationId": "updateNotification",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/NotificationDTO"
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "500": {
+            "description": "User is not found",
+            "content": {
+              "*/*": {
+                "schema": {
+                  "type": "object"
+                }
+              }
+            }
+          },
+          "200": {
+            "description": "Successfully updated notification",
+            "content": {
+              "*/*": {
+                "schema": {
+                  "type": "object"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "/api/item/{itemId}": {
       "post": {
         "tags": [
@@ -575,7 +617,7 @@
     "/api/budget/update/{budgetId}": {
       "post": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Updates a budget",
         "description": "Updates a budget based on the budget request",
@@ -628,7 +670,7 @@
     "/api/budget/update/expense/{budgetId}": {
       "post": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Created/Updates an expense",
         "description": "Creates/Updates a budget based on the budget request",
@@ -681,7 +723,7 @@
     "/api/budget/create": {
       "post": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Create a new budget",
         "description": "Create a new budget with based on the budget request",
@@ -849,6 +891,39 @@
         "security": []
       }
     },
+    "/api/auth/bank-id": {
+      "post": {
+        "tags": [
+          "Authentication"
+        ],
+        "summary": "Authenticate a BankID request",
+        "description": "Authenticate a BankID request",
+        "operationId": "bankIdAuthentication",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/BankIDRequest"
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "200": {
+            "description": "If the authentication is successful",
+            "content": {
+              "*/*": {
+                "schema": {
+                  "$ref": "#/components/schemas/AuthenticationResponse"
+                }
+              }
+            }
+          }
+        },
+        "security": []
+      }
+    },
     "/api/users": {
       "patch": {
         "tags": [
@@ -945,6 +1020,29 @@
         }
       }
     },
+    "/redirect": {
+      "get": {
+        "tags": [
+          "Redirect"
+        ],
+        "operationId": "consumeCallback",
+        "parameters": [
+          {
+            "name": "state",
+            "in": "query",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "OK"
+          }
+        }
+      }
+    },
     "/bank/v1/account/accounts/ssn/{ssn}": {
       "get": {
         "tags": [
@@ -1210,6 +1308,99 @@
         }
       }
     },
+    "/api/notification": {
+      "get": {
+        "tags": [
+          "Notification"
+        ],
+        "summary": "Get the list of notifications",
+        "description": "Get all notifications to a user",
+        "operationId": "getNotificationByUser",
+        "responses": {
+          "200": {
+            "description": "Successfully got notifications",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/NotificationDTO"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/notification/{notificationId}": {
+      "get": {
+        "tags": [
+          "Notification"
+        ],
+        "summary": "Get the notification",
+        "description": "Get notification by its id ",
+        "operationId": "getNotification",
+        "parameters": [
+          {
+            "name": "notificationId",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successfully got notification",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/NotificationDTO"
+                }
+              }
+            }
+          },
+          "500": {
+            "description": "Notification is not found",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/NotificationDTO"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/notification/unread": {
+      "get": {
+        "tags": [
+          "Notification"
+        ],
+        "summary": "Get the list of unread notifications",
+        "description": "Get all unread notifications to a user",
+        "operationId": "getUnreadNotificationByUser",
+        "responses": {
+          "200": {
+            "description": "Successfully got notifications",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/NotificationDTO"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "/api/leaderboard": {
       "get": {
         "tags": [
@@ -1258,6 +1449,29 @@
         }
       }
     },
+    "/api/leaderboard/total-points": {
+      "get": {
+        "tags": [
+          "Leaderboard"
+        ],
+        "summary": "Get sum of total points globally",
+        "description": "Get the sum of the total points of all users globally",
+        "operationId": "getTotalPoints",
+        "responses": {
+          "200": {
+            "description": "Successfully retrieved total points",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "integer",
+                  "format": "int64"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "/api/leaderboard/surrounding": {
       "get": {
         "tags": [
@@ -1401,6 +1615,37 @@
         "security": []
       }
     },
+    "/api/goals/{id}": {
+      "get": {
+        "tags": [
+          "Goal"
+        ],
+        "operationId": "getGoal",
+        "parameters": [
+          {
+            "name": "id",
+            "in": "query",
+            "required": true,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "OK",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GoalDTO"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "/api/friends": {
       "get": {
         "tags": [
@@ -1454,7 +1699,7 @@
     "/api/budget": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Get the list of budgets",
         "description": "Get all budgets related to the authenticated user",
@@ -1479,7 +1724,7 @@
     "/api/budget/{budgetId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Get the budget",
         "description": "Get budget by its id ",
@@ -1522,7 +1767,7 @@
     "/api/budget/expenses/{budgetId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Get the list of budgets",
         "description": "Get all budgets related to the authenticated user",
@@ -1558,7 +1803,7 @@
     "/api/budget/expense/{expenseId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Get the expense",
         "description": "Get expense by its id ",
@@ -1601,7 +1846,7 @@
     "/api/budget/delete/{budgetId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Deletes a budget",
         "description": "Deletes a budget based on provided budget id",
@@ -1644,7 +1889,7 @@
     "/api/budget/delete/expense/{expenseId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Deletes an expense",
         "description": "Deletes an expense based on provided expense id",
@@ -1683,6 +1928,146 @@
           }
         }
       }
+    },
+    "/api/badge": {
+      "get": {
+        "tags": [
+          "Badge"
+        ],
+        "summary": "Get the list of badges",
+        "description": "Get all badges stored in the database",
+        "operationId": "getAllBadges",
+        "responses": {
+          "200": {
+            "description": "Successfully got badges",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/BadgeDTO"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/badge/{badgeId}": {
+      "get": {
+        "tags": [
+          "Badge"
+        ],
+        "summary": "Get the budget",
+        "description": "Get budget by its id ",
+        "operationId": "getBadge",
+        "parameters": [
+          {
+            "name": "badgeId",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          }
+        ],
+        "responses": {
+          "500": {
+            "description": "Badge is not found",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/BadgeDTO"
+                }
+              }
+            }
+          },
+          "200": {
+            "description": "Successfully got budget",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/BadgeDTO"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/badge/update": {
+      "get": {
+        "tags": [
+          "Badge"
+        ],
+        "summary": "Updates unlocked badges",
+        "description": "Checks if a user has met the criteria for unlocking badges",
+        "operationId": "updateUnlockedBadges",
+        "responses": {
+          "200": {
+            "description": "Successfully updated badges",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "object"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/badge/unlocked": {
+      "get": {
+        "tags": [
+          "Badge"
+        ],
+        "summary": "Get the list of badges",
+        "description": "Get all badges unlocked by the user",
+        "operationId": "getBadgesUnlockedByUser",
+        "responses": {
+          "200": {
+            "description": "Successfully got badges",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/BadgeDTO"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/badge/locked": {
+      "get": {
+        "tags": [
+          "Badge"
+        ],
+        "summary": "Get the list of badges",
+        "description": "Get all badges not unlocked by the user",
+        "operationId": "getBadgesNotUnlockedByUser",
+        "responses": {
+          "200": {
+            "description": "Successfully got badges",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/BadgeDTO"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
     }
   },
   "components": {
@@ -1807,6 +2192,33 @@
           }
         }
       },
+      "NotificationDTO": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "message": {
+            "type": "string"
+          },
+          "unread": {
+            "type": "boolean"
+          },
+          "notificationType": {
+            "type": "string",
+            "enum": [
+              "BADGE",
+              "FRIEND_REQUEST",
+              "COMPLETED_GOAL"
+            ]
+          },
+          "createdAt": {
+            "type": "string",
+            "format": "date-time"
+          }
+        }
+      },
       "CreateGoalDTO": {
         "type": "object",
         "properties": {
@@ -2124,6 +2536,17 @@
           }
         }
       },
+      "BankIDRequest": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "string"
+          },
+          "state": {
+            "type": "string"
+          }
+        }
+      },
       "UserUpdateDTO": {
         "type": "object",
         "properties": {
@@ -2325,6 +2748,26 @@
             "type": "string"
           }
         }
+      },
+      "BadgeDTO": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "badgeName": {
+            "type": "string"
+          },
+          "criteria": {
+            "type": "integer",
+            "format": "int32"
+          },
+          "imageId": {
+            "type": "integer",
+            "format": "int64"
+          }
+        }
       }
     },
     "securitySchemes": {
diff --git a/src/components/BaseComponents/NavBar.vue b/src/components/BaseComponents/NavBar.vue
index a97684e..11a11f2 100644
--- a/src/components/BaseComponents/NavBar.vue
+++ b/src/components/BaseComponents/NavBar.vue
@@ -1,110 +1,144 @@
 <template>
-    <nav id="navBar" class="navbar navbar-expand-xl">
-        <div class="container-fluid">
-          <router-link class="navbar-brand" id="home" :to="toSavingGoals()">
-                <img id="logoImg" src="/src/assets/Sparesti-logo.png" alt="Sparesti-logo" width="60">
-                <span id="logo" class="text-white">SpareSti</span>
+  <nav id="navBar" class="navbar navbar-expand-xl">
+    <div class="container-fluid">
+      <router-link class="navbar-brand" id="home" :to="toSavingGoals()">
+        <img id="logoImg" src="/src/assets/Sparesti-logo.png" alt="Sparesti-logo" width="60">
+        <span id="logo" class="text-white">SpareSti</span>
+      </router-link>
+      <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
+        data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
+        aria-expanded="false" aria-label="Bytt navigasjon">
+        <span class="navbar-toggler-icon"></span>
+      </button>
+      <div class="collapse navbar-collapse" id="navbarSupportedContent">
+        <ul class="navbar-nav ms-auto mb-2 mb-lg-0 ui-menu">
+          <li class="nav-item">
+            <router-link data-cy="savingGoals" class="nav-link text-white"
+              :to="toSavingGoals()" exact-active-class="active-nav">
+              <img src="@/assets/icons/saving.svg">Sparemål
             </router-link>
-            <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
-                data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
-                aria-label="Bytt navigasjon">
-                <span class="navbar-toggler-icon"></span>
-            </button>
-            <div class="collapse navbar-collapse" id="navbarSupportedContent">
-                <ul class="navbar-nav ms-auto mb-2 mb-lg-0 ui-menu">
-                    <li class="nav-item">
-                      <router-link data-cy="savingGoals" class="nav-link text-white"
-                                   :to="toSavingGoals()"><img
-                                src="@/assets/icons/saving.svg">Sparemål</router-link>
-                    </li>
-                    <li class="nav-item">
-                      <router-link data-cy="leaderboard" class="nav-link text-white"
-                                   :to="toLeaderboard()"><img
-                                src="@/assets/icons/leaderboard.svg">Ledertavle</router-link>
-                    </li>
-                    <li class="nav-item">
-                      <router-link data-cy="news" class="nav-link text-white" :to="toNews()"><img
-                          src="@/assets/icons/newsletter.svg">Nyheter</router-link>
-                    </li>
-                    <li class="nav-item">
-                      <router-link data-cy="store" class="nav-link text-white" :to="toStore()"><img
-                          src="@/assets/icons/storefront.svg">Butikk</router-link>
-                    </li>
-                    <li class="nav-item dropdown">
-                        <a data-mdb-dropdown-init class=" nav-link dropdown-toggle hidden-arrow notification" href="#" id="navbarDropdownMenuLink"
-                           role="button" data-bs-toggle="dropdown" aria-expanded="false">
-                          <img src="/src/assets/icons/bell-white.svg">
-                          <span v-if="counter > 0" class="badge rounded-pill badge-notification bg-danger">{{counter}}</span>
-                        </a>
-                        <ul v-if="counter > 0" class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
-                          <li v-for="(array,key) in notifMap" :key="key" >
-                            <div class="d-flex align-items-center">
-                              <div v-if="array[1][0] === '1'" class="flex-shrink-0">
-                                <img src="/src/assets/icons/medal.png" alt="Varslingsikon" class="notification-icon">
-                              </div>
-                              <div v-if="array[1][0] === '2'" class="flex-shrink-0">
-                                <img src="/src/assets/userprofile.png" alt="Varslingsikon" class="notification-icon">
-                              </div>
-                              <div v-if="array[1][0] === '3'" class="flex-shrink-0">
-                                <img src="/src/assets/icons/piggybank.svg" alt="Varslingsikon" class="notification-icon">
-                              </div>
-                              <div class="flex-grow-1 ms-3">
-                                <router-link class="not-item dropdown-item"   :to="getPath(array[1][0])">{{array[1][1]}}</router-link>
-                              </div>
-                            </div>
-                          </li>
-                        </ul>
-                        <ul v-else class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
-                          <li>Ingen varslinger</li>
-                        </ul>
-                    </li>
-                    <li v-if="userStore.isLoggedIn" class="nav-item dropdown">
-                        <a data-cy="user"
-                           class="nav-link dropdown-toggle username-text text-white "
-                           href="#" role="button"
-                            data-bs-toggle="dropdown" aria-expanded="false">
-                            <img src="@/assets/icons/person.svg">{{useUserInfoStore().firstname }}
-                        </a>
-                        <ul class="dropdown-menu dropdown-username-content">
-                            <li><router-link data-cy="profile"
-                              class="dropdown-item dropdown-username-link" :to="toUserProfile()"><img
-                                  src="@/assets/icons/black_person.svg">Min profil</router-link></li>
-                            <li v-if="useUserInfoStore().isPremium"><router-link data-cy="budget"
-                              class="dropdown-item dropdown-username-link" :to="toBudget()"><img
-                              src="@/assets/icons/budget.svg">Budjsett</router-link></li>
-                            <li><router-link data-cy="friends"
-                              class="dropdown-item dropdown-username-link" :to="toFriends()"><img
-                                src="@/assets/icons/black_friends.svg">Venner</router-link></li>
-                            <li><router-link data-cy="settings"
-                              class="dropdown-item dropdown-username-link" :to="toSetting()"><img
-                                src="@/assets/icons/settings.svg">Innstillinger</router-link></li>
-                            <li><router-link data-cy="feedback"
-                              class="dropdown-item dropdown-username-link" :to="toFeedback()"><img
-                                src="@/assets/icons/feedback.svg">Tilbakemelding</router-link></li>
-                            <li><router-link data-cy="admin"
-                              class="dropdown-item dropdown-username-link" :to="toSetting()"><img
-                                src="@/assets/icons/admin.svg">Admin</router-link></li>
-                            <li style="cursor: pointer"><a data-testid="logout" class="dropdown-item dropdown-username-link" ref="#" @click="toLogout()"><img
-                                src="@/assets/icons/logout.svg">Logg ut</a></li>
-                        </ul>
-                    </li>
-                    <li v-else class="nav-item">
-                        <a class="nav-link" style="cursor: pointer;" href="#" @click="toLogout">Logg inn</a>
-                    </li>
-                </ul>
-            </div>
-        </div>
-    </nav>
+          </li>
+          <li class="nav-item">
+            <router-link data-cy="leaderboard" class="nav-link text-white"
+              :to="toLeaderboard()" exact-active-class="active-nav">
+              <img src="@/assets/icons/leaderboard.svg">Ledertavle
+            </router-link>
+          </li>
+          <li class="nav-item">
+            <router-link data-cy="news" class="nav-link text-white"
+              :to="toNews()" exact-active-class="active-nav">
+              <img src="@/assets/icons/newsletter.svg">Nyheter
+            </router-link>
+          </li>
+          <li class="nav-item">
+            <router-link data-cy="store" class="nav-link text-white"
+              :to="toStore()" exact-active-class="active-nav">
+              <img src="@/assets/icons/storefront.svg">Butikk
+            </router-link>
+          </li>
+          <li v-if="userStore.isLoggedIn" class="nav-item dropdown">
+
+
+            <a
+  data-cy="user"
+  :class="['nav-link', 'dropdown-toggle', 'username-text', 'text-white', { 'underline-active': !isAnyActivePage() }]"
+  href="#"
+  role="button"
+  data-bs-toggle="dropdown"
+  aria-expanded="false">
+  <img src="@/assets/icons/person.svg">{{ useUserInfoStore().firstname }}
+</a>
+
+            <ul class="dropdown-menu dropdown-username-content">
+
+
+              <li>
+                <router-link data-cy="profile"
+                  class="dropdown-item dropdown-username-link"
+                  :to="toUserProfile()"
+                  exact-active-class="active-link"
+                  @click="toggleDropdown">
+                  <img src="@/assets/icons/black_person.svg">Min profil
+                </router-link>
+              </li>
+              <li v-if="useUserInfoStore().isPremium">
+                <router-link data-cy="budget"
+                  class="dropdown-item dropdown-username-link"
+                  :to="toBudget()"
+                  exact-active-class="active-link"
+                  @click="toggleDropdown">
+                  <img src="@/assets/icons/budget.svg">Budjsett
+                </router-link>
+              </li>
+              <li>
+                <router-link data-cy="friends"
+                  class="dropdown-item dropdown-username-link"
+                  :to="toFriends()"
+                  exact-active-class="active-link"
+                  @click="toggleDropdown">
+                  <img src="@/assets/icons/black_friends.svg">Venner
+                </router-link>
+              </li>
+              <li>
+                <router-link data-cy="settings"
+                  class="dropdown-item dropdown-username-link"
+                  :to="toSetting()"
+                  exact-active-class="active-link"
+                  @click="toggleDropdown">
+                  <img src="@/assets/icons/settings.svg">Innstillinger
+                </router-link>
+              </li>
+              <li>
+                <router-link data-cy="feedback"
+                  class="dropdown-item dropdown-username-link"
+                  :to="toFeedback()"
+                  exact-active-class="active-link"
+                  @click="toggleDropdown">
+                  <img src="@/assets/icons/feedback.svg">Tilbakemelding
+                </router-link>
+              </li>
+              <li>
+                <router-link data-cy="admin"
+                  class="dropdown-item dropdown-username-link"
+                  :to="toSetting()"
+                  exact-active-class="active-link"
+                  @click="toggleDropdown">
+                  <img src="@/assets/icons/admin.svg">Admin
+                </router-link>
+              </li>
+              <li style="cursor: pointer">
+                <a data-testid="logout"
+                   class="dropdown-item dropdown-username-link"
+                   href="#"
+                   @click="() => { toggleDropdown(); toLogout(); }">
+                  <img src="@/assets/icons/logout.svg">Logg ut
+                </a>
+              </li>
+
+              
+            </ul>
+          </li>
+          <li v-else class="nav-item">
+            <a class="nav-link" style="cursor: pointer;" href="#"
+               @click="toLogout">Logg inn
+            </a>
+          </li>
+        </ul>
+      </div>
+    </div>
+  </nav>
 </template>
 
+
 <script setup lang="ts">
-import { useRouter } from "vue-router";
+import { useRouter, useRoute } from "vue-router";
 import { useUserInfoStore } from '@/stores/UserStore';
 import {onMounted, ref} from "vue";
 
 
 
 const router = useRouter();
+const route = useRoute();
 
 const userStore: any = useUserInfoStore();
 
@@ -132,7 +166,17 @@ let counter = ref(0)
    id: 2 -> /friend
  */
 
+ function isAnyActivePage() {
+  const activeRoutes = ['/roadmap', '/leaderboard', '/news', '/shop']; // Add other pages here
+  return activeRoutes.includes(route.path);
+}
 
+function toggleDropdown(event) {
+  const dropdownMenu = event.target.closest('.dropdown-menu');
+  if (dropdownMenu) {
+    dropdownMenu.classList.remove('show');
+  }
+}
 
 function getNotification(){
   //axios call
@@ -242,6 +286,26 @@ onMounted(() => {
     font-size: 1.7rem;
 }
 
+.active-nav {
+  border-radius: 0rem;
+  border-bottom: 4px solid #f3f3f3;
+}
+
+.active-link {
+  background-color: #f3f3f6;
+  border-bottom: 3px solid #01476b;
+}
+
+.underline-active {
+  border-bottom: 4px solid white;
+}
+
+.dropdown-item img {
+  height: 35px;
+  width: 35px;
+  margin-right: 5px;
+}
+
 .nav-item:hover {
     background-color: #01476b;
   border-radius: 1rem;
diff --git a/src/components/Friends/UserFriends.vue b/src/components/Friends/UserFriends.vue
index 1858195..d97189b 100644
--- a/src/components/Friends/UserFriends.vue
+++ b/src/components/Friends/UserFriends.vue
@@ -95,7 +95,7 @@
                                         </div>
                                         <div class="col-md-7 col-sm-7">
                                             <h5><a href="#" class="profile-link" @click="toUserProfile(user.id)">{{
-                user.firstName }}</a>
+                user.firstName }} {{ user.lastName }}</a>
                                             </h5>
                                         </div>
                                         <div class="col-md-3 col-sm-3">
diff --git a/src/components/Leaderboard/LeaderboardRank.vue b/src/components/Leaderboard/LeaderboardRank.vue
index 07f88f3..b3432f4 100644
--- a/src/components/Leaderboard/LeaderboardRank.vue
+++ b/src/components/Leaderboard/LeaderboardRank.vue
@@ -37,7 +37,7 @@
     </div>
     <div id="communityContainer">
         <h1>Totale poeng opptjent som et fellesskap</h1>
-        <h2>1000000 <img src="../../assets/items/v-buck.png" style="width: 2rem" alt="alt"></h2>
+        <h2>{{communityPoints}} <img src="../../assets/items/pigcoin.png" style="width: 2rem" alt="alt"></h2>
     </div>
 </template>
 
@@ -56,10 +56,15 @@ let streakLeaderboardDataExtra = ref([] as any);
 let currentLeaderboardDataExtra = ref([] as any);
 let pointsLeaderboardDataExtra = ref([] as any);
 
+let communityPoints = ref(0);
+
 const router = useRouter();
 
 async function fetchQuizData() {
     await global();
+
+    const response = await LeaderboardService.getTotalPoints();
+    communityPoints.value = response;
 }
 
 onMounted(() => {
diff --git a/src/components/Login/LoginForm.vue b/src/components/Login/LoginForm.vue
index 3b0518e..f0ca531 100644
--- a/src/components/Login/LoginForm.vue
+++ b/src/components/Login/LoginForm.vue
@@ -69,7 +69,7 @@ const handleSubmit = async () => {
 
     console.log(response.token)
 
-    await router.push({ name: 'home' });
+    await router.push({ name: 'roadmap' });
   } catch (error: any) {
     errorMsg.value = handleUnknownError(error);
     isSubmitting.value = false;
diff --git a/src/components/Settings/SettingsProfile.vue b/src/components/Settings/SettingsProfile.vue
index c45371b..6d083ff 100644
--- a/src/components/Settings/SettingsProfile.vue
+++ b/src/components/Settings/SettingsProfile.vue
@@ -12,6 +12,8 @@ const passwordRef = ref('')
 const formRef = ref()
 let samePasswords = ref(true)
 
+const imageRange = ref([10, 11, 12, 13, 14, 15]);
+
 const iconSrc = ref('../src/assets/userprofile.png');
 const fileInputRef = ref();
 
@@ -58,13 +60,11 @@ async function setupForm() {
   try {
     const response = await UserService.getUser();
     console.log(response.firstName)
-
     firstNameRef.value = response.firstName;
     if (response.lastName != null) {
       surnameRef.value = response.lastName;
     }
-    console.log(response.profileImage)
-    if(response.profileImage != null){
+    if (response.profileImage != null) {
       iconSrc.value = "http://localhost:8080/api/images/" + response.profileImage;
     } else {
       iconSrc.value = "../src/assets/userprofile.png";
@@ -107,31 +107,36 @@ onMounted(() => {
       <div class="user-avatar">
         <input type="file" ref="fileInputRef" @change="handleFileChange" accept=".jpg, .jpeg, .png"
           style="display: none;" />
-        <img :src="iconSrc" alt="Brukeravatar" style="width: 300px">
+        <img :src="iconSrc" alt="Brukeravatar" style="width: 200px; height: 200px;">
         <div class="mt-2">
           <button type="button" class="btn btn-primary" @click="triggerFileUpload"><img
               src="../../assets/icons/download.svg"> Last opp bilde</button>
         </div>
       </div>
       <div class="form-group">
-        <BaseInput data-cy="first-name" :model-value="firstNameRef"
-                   @input-change-event="handleFirstNameInputEvent" id="firstNameInputChange"
-                   input-id="first-name-new" type="text" label="Fornavn" placeholder="Skriv inn ditt fornavn"
-                   invalid-message="Vennligst skriv inn ditt fornavn" />
+        <BaseInput data-cy="first-name" :model-value="firstNameRef" @input-change-event="handleFirstNameInputEvent"
+          id="firstNameInputChange" input-id="first-name-new" type="text" label="Fornavn"
+          placeholder="Skriv inn ditt fornavn" invalid-message="Vennligst skriv inn ditt fornavn" />
       </div>
       <br>
       <div class="form-group">
-        <BaseInput data-cy="last-name" :model-value="surnameRef"
-                   @input-change-event="handleSurnameInputEvent"
-                    id="surnameInput-change"
-                   input-id="surname-new" type="text" label="Etternavn"
-                   placeholder="Skriv inn ditt etternavn"
-                   invalid-message="Vennligst skriv inn ditt etternavn" />
+        <BaseInput data-cy="last-name" :model-value="surnameRef" @input-change-event="handleSurnameInputEvent"
+          id="surnameInput-change" input-id="surname-new" type="text" label="Etternavn"
+          placeholder="Skriv inn ditt etternavn" invalid-message="Vennligst skriv inn ditt etternavn" />
       </div>
       <br>
       <button data-cy="profile-submit-btn" type="submit" class="btn btn-primary">Oppdater
         profil</button>
     </form>
+    <hr>
+    <div>
+      <h6>Stilsett din profil banner</h6>
+      <div class="bannerHolder">
+        <div v-for="x in imageRange" :key="x">
+          <img :src="'http://localhost:8080/api/images/' + x" style="width: 400px; height: 40px; margin: 10px">
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -144,4 +149,11 @@ onMounted(() => {
   -moz-border-radius: 100px;
   border-radius: 100px;
 }
+
+.bannerHolder {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  margin-top: 20px;
+}
 </style>
\ No newline at end of file
diff --git a/src/components/UserProfile/MyProfile.vue b/src/components/UserProfile/MyProfile.vue
index a1d386d..7a10b3e 100644
--- a/src/components/UserProfile/MyProfile.vue
+++ b/src/components/UserProfile/MyProfile.vue
@@ -2,7 +2,7 @@
 import { ref, onMounted } from "vue";
 import { useRouter } from "vue-router";
 import { useUserInfoStore } from "../../stores/UserStore";
-import { UserService } from "@/api";
+import { UserService, BadgeService } from "@/api";
 import { ItemService } from "@/api";
 
 let numberOfHistory = 6;
@@ -13,6 +13,7 @@ const imageUrl = ref(`../src/assets/userprofile.png`);
 
 const router = useRouter();
 const inventory = ref([] as any);
+const badges = ref([] as any);
 const backgroundName = ref("");
 
 async function setupForm() {
@@ -26,6 +27,7 @@ async function setupForm() {
       imageUrl.value = "http://localhost:8080/api/images/" + response.profileImage;
     }
     getInventory();
+    getBadges();
   } catch (err) {
     console.error(err)
   }
@@ -40,6 +42,15 @@ const getInventory = async () => {
   }
 }
 
+const getBadges = async () => {
+  try {
+    const responseBadge = await BadgeService.getBadgesUnlockedByUser();
+    badges.value = responseBadge;
+  } catch (error) {
+    console.log(error);
+  }
+}
+
 const selectItem = (item: any) => {
   backgroundName.value = item.itemName;
   useUserInfoStore().setUserInfo({
@@ -55,6 +66,8 @@ const toRoadmap = () => {
   router.push('/');
 };
 
+
+
 // Function to navigate to update user settings
 const toUpdateUserSettings = () => {
   router.push('/settings/profile');
@@ -80,7 +93,7 @@ const toUpdateUserSettings = () => {
                 data-mdb-ripple-color="dark" style="z-index: 1; height: 40px; margin-left: 17px" id="toUpdate" @click="toUpdateUserSettings">
                 Rediger profil
               </button>
-
+            
               </div>
               <div>
                 <p class="mb-1 h2" data-cy="points">253 <img src="@/assets/items/pigcoin.png" style="width: 4rem"></p>
@@ -92,12 +105,13 @@ const toUpdateUserSettings = () => {
               </div>
             </div>
           </div>
+          <hr>
           <div class="card-body p-1 text-black">
             <div class="row">
               <div class="col">
                 <div class="container-fluid">
-                  <h1 class="mt-5 text-start badges-text">Lageret ditt</h1>
-                  <div class="scrolling-wrapper-badges row flex-row flex-nowrap mt-4 pb-4 pt-2">
+                  <h1 class="mt-1 text-start badges-text">Lageret ditt</h1>
+                  <div class="scrolling-wrapper-badges row flex-row flex-nowrap mt-2 pb-2 pt-2">
                     <div v-for="product in inventory" :key="product.id" class="card text-center"
                         style="width: 12rem; border: none; cursor: pointer; margin: 1rem; border: 2px solid black" @click="selectItem(product)">
                         <img :src="`http://localhost:8080/api/images/${product.imageId}`" class="card-img-top"
@@ -112,52 +126,35 @@ const toUpdateUserSettings = () => {
               </div>
             </div>
           </div>
+          <hr>
           <div class="card-body p-1 text-black">
             <div class="row">
               <div class="col">
                 <div class="container-fluid">
-                  <h1 class="mt-5 text-start badges-text">Merker</h1>
-                  <div class="scrolling-wrapper-badges row flex-row flex-nowrap mt-4 pb-4 pt-2">
-
-                    <div class="col-5">
-                      <div class="card badges-block card-1"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-2"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-3"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-4"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-5"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-6"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-7"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-8"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-9"></div>
-                    </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-10"></div>
+                  <h1 class="mt-1 text-start badges-text">Merker</h1>
+                  <div class="scrolling-wrapper-badges row flex-row flex-nowrap mt-2 pb-2 pt-2">
+
+                    <div v-for="badge in badges" :key="badge.id" class="card text-center"
+                        style="width: 12rem; border: none; cursor: pointer; margin: 1rem; 
+                        border: 2px solid black" data-bs-toggle="tooltip" data-bs-placement="top" 
+                        data-bs-custom-class="custom-tooltip" :data-bs-title="badge.criteria">
+                        <img :src="`http://localhost:8080/api/images/${badge.imageId}`" class="card-img-top"
+                            alt="..." />
+                        <div class="card-body">
+                            <h5 class="card-title">{{ badge.badgeName }}</h5>
+                        </div>
                     </div>
+
                   </div>
                 </div>
               </div>
             </div>
+            <hr>
             <div class="row">
               <div class="col">
                 <!-- Her er historikken over lagrede mål -->
                 <div class="container-fluid mb-5">
-                  <h1 class="mt-5 text-start history-text">Historie</h1>
+                  <h1 class="mt-1 text-start history-text">Historie</h1>
                   <div class="row scrolling-wrapper-history">
                     <div v-for="index in numberOfHistory" :key="index"
                       class="col-md-4 col-sm-4 col-lg-4 col-xs-4 col-xl-4 control-label">
@@ -204,8 +201,6 @@ const toUpdateUserSettings = () => {
   overflow: auto;
 }
 
-
-
 .badges-text {
   font-weight: 500;
   font-size: 2.0em;
diff --git a/src/views/User/UserSettingsView.vue b/src/views/User/UserSettingsView.vue
index a190d10..485d8dd 100644
--- a/src/views/User/UserSettingsView.vue
+++ b/src/views/User/UserSettingsView.vue
@@ -1,9 +1,12 @@
 <script setup lang="ts">
 import { ref } from 'vue'
 import { useRouter } from 'vue-router'
+import {useRoute} from 'vue-router'
 
 const router = useRouter();
 
+const url = useRoute().path;
+
 const activeLink = ref('/settings/profile');  // Default active link
 
 function setActive(link: string) {
@@ -42,7 +45,7 @@ function toBilling() {
                         <nav class="nav flex-column nav-pills nav-gap-y-1">
 
                             <a @click.prevent="setActive('/settings/profile')" @click="toProfile"
-                                :class="['nav-item nav-link has-icon', { 'nav-link-faded': activeLink !== '/settings/profile', 'active': activeLink === '/settings/profile' }]">
+                                :class="['nav-item nav-link has-icon', { 'nav-link-faded': useRoute().path !== '/settings/profile', 'active': useRoute().path === '/settings/profile' }]">
                                 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                                     fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                                     stroke-linejoin="round" class="feather feather-user mr-2">
@@ -54,7 +57,7 @@ function toBilling() {
 
 
                             <a @click.prevent="setActive('/settings/account')" @click="toAccount"
-                                :class="['nav-item nav-link has-icon', { 'nav-link-faded': activeLink !== '/settings/account', 'active': activeLink === '/settings/account' }]">
+                                :class="['nav-item nav-link has-icon', { 'nav-link-faded': useRoute().path !== '/settings/account', 'active': useRoute().path === '/settings/account' }]">
                                 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                                     fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                                     stroke-linejoin="round" class="feather feather-settings mr-2">
@@ -68,7 +71,7 @@ function toBilling() {
 
 
                             <a @click.prevent="setActive('/settings/security')" @click="toSecurity"
-                                :class="['nav-item nav-link has-icon', { 'nav-link-faded': activeLink !== '/settings/security', 'active': activeLink === '/settings/security' }]">
+                                :class="['nav-item nav-link has-icon', { 'nav-link-faded': useRoute().path !== '/settings/security', 'active': useRoute().path === '/settings/security' }]">
                                 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                                     fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                                     stroke-linejoin="round" class="feather feather-shield mr-2">
@@ -79,7 +82,7 @@ function toBilling() {
 
 
                             <a @click.prevent="setActive('/settings/notification')" @click="toNotification"
-                                :class="['nav-item nav-link has-icon', { 'nav-link-faded': activeLink !== '/settings/notification', 'active': activeLink === '/settings/notification' }]">
+                                :class="['nav-item nav-link has-icon', { 'nav-link-faded': useRoute().path !== '/settings/notification', 'active': useRoute().path === '/settings/notification' }]">
                                 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                                     fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                                     stroke-linejoin="round" class="feather feather-bell mr-2">
@@ -89,7 +92,7 @@ function toBilling() {
                             </a>
                             <a>
                                 <a @click.prevent="setActive('/settings/bank')" @click="toBilling"
-                                    :class="['nav-item nav-link has-icon', { 'nav-link-faded': activeLink !== '/settings/bank', 'active': activeLink === '/settings/bank' }]">
+                                    :class="['nav-item nav-link has-icon', { 'nav-link-faded': useRoute().path !== '/settings/bank', 'active': useRoute().path === '/settings/bank' }]">
                                     <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                                         stroke-linejoin="round" class="feather feather-credit-card mr-2">
-- 
GitLab