diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9545d594d76df2d8590c4404490263348b0993fd..15f8cb88f85dce50bd57b63701defaf3edcbc4d6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -24,44 +24,47 @@ install_dependencies:
 
 build_project:
   stage: build
-  script:
-    - npm ci
-    - npm run build
-  dependencies:
-    - install_dependencies
   cache:
     key: "${CI_COMMIT_REF_SLUG}"
     paths:
       - node_modules/
     policy: pull
-
-vitest_unit-tests:
-  stage: test
   script:
     - npm ci
-    - npm run test:unit
+    - npm run build
   dependencies:
     - install_dependencies
+
+vitest_unit-tests:
+  stage: test
   cache:
     key: ${CI_COMMIT_REF_SLUG}
     paths:
         - node_modules/
     policy: pull
-
-eslint_run-lint:
-  stage: lint
   script:
     - npm ci
-    - npm run lint
+    - npm run test:unit
   dependencies:
     - install_dependencies
+
+eslint_run-lint:
+  stage: lint
   cache:
     key: ${CI_COMMIT_REF_SLUG}
     paths:
         - node_modules/
     policy: pull
+  script:
+    - npm ci
+    - npm run lint
+  dependencies:
+    - install_dependencies
   allow_failure: true  
 
 
 
     
+
+
+    
diff --git a/README.md b/README.md
index f236c043b819737dbf60da74993a455b05431796..3d0d9717bfe338b96bec22f8fce822b6e760df6a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,11 @@
-# frontend
+# SpareSti
 
-This template should help get you started developing with Vue 3 in Vite.
+## Description
+The frontend of sparesti.app. SpareSti is designed to make saving fun. The app is integrated with your online bank, therefore it has an overview of what your money is being spent on and can provide you with personalized saving tips based on this information. The app is suitable for all saving goals and offers motivation and tips tailored to your desires. Since we know that saving money can be difficult, SpareSti automatically deposits money into your savings account when you complete challenges. Based on your saved funds, the feed will give you personalized tips on how your money can be invested, and you will be able to set up a budget that provides you with the overview you need to make informed choices.
+
+## Links
+
+- **Backend**: [https://gitlab.stud.idi.ntnu.no/idatt2106-2024-07/backend](https://gitlab.stud.idi.ntnu.no/idatt2106-2024-07/backend)
 
 ## Recommended IDE Setup
 
@@ -14,7 +19,7 @@ TypeScript cannot handle type information for `.vue` imports by default, so we r
 
 See [Vite Configuration Reference](https://vitejs.dev/config/).
 
-## Project Setup
+## Getting Started
 
 ```sh
 npm install
@@ -59,3 +64,48 @@ npm run test:e2e
 ```sh
 npm run lint
 ```
+
+## Using test data
+For easy use of the web application we have provided a set of test users that can be used.
+
+#### Regular user
+- **Email**
+    ```sh
+    user@example.com
+    ```
+- **Password**
+    ```sh
+    John1
+    ```
+#### Admin user
+- **Email**
+    ```sh
+    admin@example.com
+    ```
+- **Password**
+    ```sh
+    John1
+    ```
+#### BankID user
+The BankID service uses a set of pre-generated test users provided by Signicat. Make sure you have the updated test-users [here](https://developer.signicat.com/identity-methods/nbid/test.html#test-norwegian-bankid).
+- **Social Security Number**
+    ```sh
+    29090816894
+    ```
+- **One time password**
+    ```sh
+    otp
+    ```
+- **Password**
+    ```sh
+    qwer1234
+    ```
+## Contributors
+The individuals who contributed to the project:
+- Anders Høvik
+- Andreas Kluge Svendsrud 
+- Henrik Dybdahl Berg
+- Henrik Teksle Sandok 
+- Jens Christian Aanestad 
+- Victor Kaste 
+- Viktor Grevskott
diff --git a/cypress/e2e/Exception/NotFoundView.cy.ts b/cypress/e2e/Exception/NotFoundView.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9f8515e8250d43784702ed3e645e08976a70b43a
--- /dev/null
+++ b/cypress/e2e/Exception/NotFoundView.cy.ts
@@ -0,0 +1,17 @@
+describe('NotFound Test', () => {
+  beforeEach(() => {
+    cy.visit('/login');
+    cy.get('#emailInput input').type('user@example.com');
+    cy.get('#passwordInput input').type('John1');
+    cy.get('form').submit();
+    cy.wait(1000);
+    cy.visit('/')
+  })
+  it('redirects user when page is not found, then go home', () => {
+    cy.visit('/non-existent-page')
+    cy.get('[data-cy="404-error"]').should('exist')
+    cy.get('[data-cy="to-home"]').click()
+    cy.url().should('include', '/')
+  })
+
+})
\ No newline at end of file
diff --git a/cypress/e2e/Leaderboard/LeaderboardView.cy.ts b/cypress/e2e/Leaderboard/LeaderboardView.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cf4eb93ae22801101d7beded40ef13f1b5531cf8
--- /dev/null
+++ b/cypress/e2e/Leaderboard/LeaderboardView.cy.ts
@@ -0,0 +1,57 @@
+describe("Leaderboard Test", () => {
+  beforeEach(() => {
+    cy.visit('/login');
+    cy.get('#emailInput input').type('user@example.com');
+    cy.get('#passwordInput input').type('John1');
+    cy.get('form').submit();
+    cy.wait(1000);
+    cy.visit('/leaderboard')
+  });
+
+  it('loads global leaderboards', () => {
+    cy.wait(5000)
+    cy.get('[data-cy="total-points-board"]')
+    .find('[data-cy="top-leaderboard-tablerow"]')
+    .should('have.length', 10);
+
+    cy.get('[data-cy="total-points-board"]')
+    .find('[data-cy="surrounding-user-leaderboard-tablerow"]')
+    .should('have.length', 4);
+
+    cy.get('[data-cy="current-points-board"]')
+    .find('[data-cy="top-leaderboard-tablerow"]')
+    .should('have.length', 10);
+
+    cy.get('[data-cy="streak-board"]')
+    .find('[data-cy="top-leaderboard-tablerow"]')
+    .should('have.length', 10);
+  })
+
+  it('loads friends leaderboards', () => {
+    cy.get('[data-cy="friends-leaderboard-btn"]').click()
+
+    cy.get('[data-cy="total-points-board"]')
+    .find('[data-cy="top-leaderboard-tablerow"]')
+    .should('have.length', 3);
+
+    cy.get('[data-cy="current-points-board"]')
+    .find('[data-cy="top-leaderboard-tablerow"]')
+    .should('have.length', 3);
+
+    cy.get('[data-cy="streak-board"]')
+    .find('[data-cy="top-leaderboard-tablerow"]')
+    .should('have.length', 3);
+  })
+
+  it('redirects to profile-page when clicking user', () => {
+    cy.get('[data-cy="total-points-board"]')
+    .find('[data-cy="top-leaderboard-tablerow"]')
+    .first()
+    .within(() => {
+      cy.get('td:nth-child(2)').click();
+    })
+    cy.wait(1000);
+    cy.url().should('include', '/profile/15');
+  })
+
+})
\ No newline at end of file
diff --git a/cypress/e2e/Settings/SettingsAccountView.cy.ts b/cypress/e2e/Settings/SettingsAccountView.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..424675017e5013a5a45ed89037e2f25728340785
--- /dev/null
+++ b/cypress/e2e/Settings/SettingsAccountView.cy.ts
@@ -0,0 +1,35 @@
+describe('SettingsAccount Test', () => {
+  beforeEach(() => {
+    cy.visit('/login');
+    cy.get('#emailInput input').type('user@example.com');
+    cy.get('#passwordInput input').type('John1');
+    cy.get('form').submit();
+    cy.wait(1000);
+    cy.visit('/settings/account')
+    cy.wait(1000)
+  });
+
+  it('updates email of user', () => {
+    cy.get('[data-cy="email-input"]').find('[data-cy="bi-input"]')
+    .should('have.value','user@example.com')
+    cy.get('[data-cy="email-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="email-input"]').find('[data-cy="bi-input"]').type('NewEmailforUser@NewExample.com')
+    cy.get('[data-cy="change-email-btn"]').click()
+    cy.wait(1000)
+    cy.get('[data-cy="change-email-msg-confirm"]').should('include.text', 'Email updated successfully!')
+
+    cy.get('[data-cy="menu"]').get('[data-cy="user"]').click();
+    cy.get('[data-testid="logout"]').click();
+
+    cy.get('#emailInput input').type('NewEmailforUser@NewExample.com');
+    cy.get('#passwordInput input').type('John1');
+    cy.get('form').submit();
+    cy.wait(1000);
+    cy.visit('/settings/account')
+    cy.wait(1000)
+
+    cy.get('[data-cy="email-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="email-input"]').find('[data-cy="bi-input"]').type('user@example.com')
+    cy.get('[data-cy="change-email-btn"]').click()
+  })
+})
\ No newline at end of file
diff --git a/cypress/e2e/Settings/SettingsBankView.cy.ts b/cypress/e2e/Settings/SettingsBankView.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8bd0d1468aa10b8b002180ff9562660ee927b85a
--- /dev/null
+++ b/cypress/e2e/Settings/SettingsBankView.cy.ts
@@ -0,0 +1,25 @@
+describe('SettingsBank Test', () => {
+  beforeEach(() => {
+    cy.visit('/login');
+    cy.get('#emailInput input').type('user@example.com');
+    cy.get('#passwordInput input').type('John1');
+    cy.get('form').submit();
+    cy.wait(1000);
+    cy.visit('/settings/bank')
+    cy.wait(1000)
+  });
+
+  it('updates spendings account of user', () => {
+    cy.get('[data-cy="spending-account-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="spending-account-input"]').find('[data-cy="bi-input"]').type('12073650567');
+    cy.get('[data-cy="update-spending-btn"]').click()
+  })
+
+  it('updates savings account of user', () => {
+    cy.get('[data-cy="savings-account-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="savings-account-input"]').find('[data-cy="bi-input"]').type('12061174077');
+    cy.get('[data-cy="update-savings-btn"]').click()
+  })
+
+
+})
\ No newline at end of file
diff --git a/cypress/e2e/Settings/SettingsProfileView.cy.ts b/cypress/e2e/Settings/SettingsProfileView.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b6e1fd576e06eddfcf31fb7affddd7b32f9f001
--- /dev/null
+++ b/cypress/e2e/Settings/SettingsProfileView.cy.ts
@@ -0,0 +1,29 @@
+describe('SettingsProfile Test', () => {
+  beforeEach(() => {
+    cy.visit('/login');
+    cy.get('#emailInput input').type('user@example.com');
+    cy.get('#passwordInput input').type('John1');
+    cy.get('form').submit();
+    cy.wait(1000);
+    cy.visit('/settings/profile')
+    cy.wait(1000)
+  });
+
+  it('updates first and last name', () => {
+    cy.get('[data-cy="first-name"]').find('[data-cy="bi-input"]').should('have.value','User')
+    cy.get('[data-cy="last-name"]').find('[data-cy="bi-input"]').should( 'have.value','User')
+    cy.get('[data-cy="first-name"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="first-name"]').find('[data-cy="bi-input"]').type('NewFirstName')
+    cy.get('[data-cy="last-name"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="last-name"]').find('[data-cy="bi-input"]').type('NewLastName')
+
+    cy.get('[data-cy="profile-submit-btn"]').click()
+    cy.get('[data-cy="menu"]').get('[data-cy="user"]').should('include.text', 'NewFirstName')
+    //update the user back to its original state
+    cy.get('[data-cy="first-name"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="first-name"]').find('[data-cy="bi-input"]').type('User')
+    cy.get('[data-cy="last-name"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="last-name"]').find('[data-cy="bi-input"]').type('User')
+    cy.get('[data-cy="profile-submit-btn"]').click()
+  })
+})
\ No newline at end of file
diff --git a/cypress/e2e/Settings/SettingsSecurityView.cy.ts b/cypress/e2e/Settings/SettingsSecurityView.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ae2601a479337a887400c31c86cdf121d0cd843
--- /dev/null
+++ b/cypress/e2e/Settings/SettingsSecurityView.cy.ts
@@ -0,0 +1,46 @@
+describe('SettingsSecurity Test', () => {
+  beforeEach(() => {
+    cy.visit('/login');
+    cy.get('#emailInput input').type('user@example.com');
+    cy.get('#passwordInput input').type('John1');
+    cy.get('form').submit();
+    cy.wait(1000);
+    cy.visit('/settings/security')
+    cy.wait(1000)
+  });
+
+  it('updates password of user', () => {
+    cy.get('[data-cy="old-password-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="old-password-input"]').find('[data-cy="bi-input"]').type('John1')
+
+    cy.get('[data-cy="new-password-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="new-password-input"]').find('[data-cy="bi-input"]').type('NewJohn1Password')
+
+    cy.get('[data-cy="confirm-password-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="confirm-password-input"]').find('[data-cy="bi-input"]').type('NewJohn1Password')
+    cy.get('[data-cy="update-password-btn"]').click()
+
+    cy.get('[data-cy="menu"]').get('[data-cy="user"]').click();
+    cy.get('[data-testid="logout"]').click();
+
+    // reset all changes made to the user
+    cy.get('#emailInput input').type('user@example.com');
+    cy.get('#passwordInput input').type('NewJohn1Password');
+    cy.get('form').submit();
+    cy.wait(1000);
+    cy.visit('/settings/security')
+    cy.wait(1000)
+
+    cy.get('[data-cy="old-password-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="old-password-input"]').find('[data-cy="bi-input"]').type('NewJohn1Password')
+
+    cy.get('[data-cy="new-password-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="new-password-input"]').find('[data-cy="bi-input"]').type('John1')
+
+    cy.get('[data-cy="confirm-password-input"]').find('[data-cy="bi-input"]').clear()
+    cy.get('[data-cy="confirm-password-input"]').find('[data-cy="bi-input"]').type('John1')
+    cy.get('[data-cy="update-password-btn"]').click()
+
+
+  })
+})
\ No newline at end of file
diff --git a/cypress/e2e/User/UserFriendsView.cy.ts b/cypress/e2e/User/UserFriendsView.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2e8eec5dbc0068f7d0ab1388a55ebcb6ea537406
--- /dev/null
+++ b/cypress/e2e/User/UserFriendsView.cy.ts
@@ -0,0 +1,44 @@
+describe('Friend Management View', () => {
+    beforeEach(() => {
+        cy.visit('/login');
+        cy.get('#emailInput input').type('user@example.com');
+        cy.get('#passwordInput input').type('John1');
+        cy.get('form').submit();
+        cy.wait(1000);
+        cy.visit('/friends')
+      });
+  
+    it('should display friend management UI elements', () => {
+      cy.contains('Dine venner')
+      cy.get('.container').within(() => {
+        cy.contains('+ Legg til venn')
+      })
+    })
+  
+    it('should navigate between friend management sections', () => {
+        cy.wait(1000);
+        cy.get('[data-cy="navigateToFriend"]').first().click();
+        cy.wait(1000);
+        cy.url().should('include', '/profile');
+
+    })
+  
+    it('should search and add friends', () => {
+      cy.contains('+ Legg til venn').click()
+      cy.get('.modal-title').should('contain', 'Legg til venn')
+      cy.get('input[type="search"]').type('TestUser1')
+      cy.contains('Søk').click()
+      cy.wait(1000);
+      cy.get('.people-nearby').within(() => {
+        cy.contains('TestUser1')
+      })
+    })
+
+    it('should display no friend requests when there is no friend requests', () => {
+        cy.contains('Venneforespørsler').click()
+        cy.get('.container').within(() => {
+          cy.contains('Ingen venneforespørsler')
+        })
+      })
+  })
+  
\ No newline at end of file
diff --git a/cypress/e2e/User/UserProfileView.cy.ts b/cypress/e2e/User/UserProfileView.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f29ecab62af4df5ec5d07924f99751c65df63e9e
--- /dev/null
+++ b/cypress/e2e/User/UserProfileView.cy.ts
@@ -0,0 +1,23 @@
+describe('User Profile Page', () => {
+    beforeEach(() => {
+        cy.visit('/login');
+        cy.get('#emailInput input').type('user@example.com');
+        cy.get('#passwordInput input').type('John1');
+        cy.get('form').submit();
+        cy.wait(1000);
+        cy.visit('/profile')
+      });
+  
+    it('displays user information', () => {
+      cy.get('[data-cy="firstname"]').should('contain.text', 'MrSlave');
+      cy.get('[data-cy="firstname"]').should('contain.text', 'Swift');
+      cy.get('[data-cy="points"]').should('contain.text', '253'); 
+      cy.get('[data-cy="streak"]').should('contain.text', '1026'); 
+    });
+  
+    it('navigates to update user settings', () => {
+      cy.get('[data-cy="toUpdate"]').click();
+      cy.url().should('include', '/settings/profile');
+    });
+  });
+  
\ No newline at end of file
diff --git a/cypress/e2e/example.cy.ts b/cypress/e2e/example.cy.ts
deleted file mode 100644
index 7554c35d8d0ff1412457a5ae7f8649a9871cc21b..0000000000000000000000000000000000000000
--- a/cypress/e2e/example.cy.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-// https://on.cypress.io/api
-
-describe('My First Test', () => {
-  it('visits the app root url', () => {
-    cy.visit('/')
-    cy.contains('h1', 'You did it!')
-  })
-})
diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json
deleted file mode 100644
index 02e4254378e9785f013be7cc8d94a8229dcbcbb7..0000000000000000000000000000000000000000
--- a/cypress/fixtures/example.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "name": "Using fixtures to represent data",
-  "email": "hello@cypress.io",
-  "body": "Fixtures are a great way to mock data for responses to routes"
-}
diff --git a/index.html b/index.html
index 48d04d242838a0af8891ee79b127695b46798079..2ca1ae971289de4d6fec571d55a0c8172048dff3 100644
--- a/index.html
+++ b/index.html
@@ -4,7 +4,7 @@
     <meta charset="UTF-8">
     <link rel="icon" href="/src/assets/Sparesti-logo.png">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Sparesti</title>
+    <title>SpareSti</title>
   </head>
   <body>
     <div id="app"></div>
diff --git a/package-lock.json b/package-lock.json
index 0c20a4e80edf18722c3f5638926a2d348f1a1517..a60b61f67195e50b022320405733b0e6d6f4e206 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
         "@popperjs/core": "^2.11.8",
         "axios": "^1.6.8",
         "bootstrap": "^5.3.3",
+        "chart.js": "^4.4.2",
         "install": "^0.13.0",
         "jQuery": "^1.7.4",
         "js-cookie": "^3.0.5",
@@ -21,10 +22,12 @@
         "pinia-plugin-persist": "^1.0.0",
         "pinia-plugin-persistedstate": "^3.2.1",
         "vue": "^3.4.21",
+        "vue-chartjs": "^5.3.1",
         "vue-router": "^4.3.0",
         "xml2js": "^0.6.2"
       },
       "devDependencies": {
+        "@cypress/code-coverage": "^3.12.38",
         "@rushstack/eslint-patch": "^1.8.0",
         "@testing-library/user-event": "^14.5.2",
         "@testing-library/vue": "^8.0.3",
@@ -40,6 +43,8 @@
         "@vue/eslint-config-typescript": "^13.0.0",
         "@vue/test-utils": "^2.4.5",
         "@vue/tsconfig": "^0.5.1",
+        "babel-loader": "^9.1.3",
+        "babel-plugin-istanbul": "^6.1.1",
         "cypress": "^13.7.2",
         "eslint": "^8.57.0",
         "eslint-plugin-cypress": "^2.15.1",
@@ -185,6 +190,19 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz",
+      "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/types": "^7.22.15"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
     "node_modules/@babel/helper-compilation-targets": {
       "version": "7.23.6",
       "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz",
@@ -202,19 +220,37 @@
       }
     },
     "node_modules/@babel/helper-create-class-features-plugin": {
-      "version": "7.24.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz",
-      "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==",
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.5.tgz",
+      "integrity": "sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==",
       "dev": true,
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.22.5",
         "@babel/helper-environment-visitor": "^7.22.20",
         "@babel/helper-function-name": "^7.23.0",
-        "@babel/helper-member-expression-to-functions": "^7.23.0",
+        "@babel/helper-member-expression-to-functions": "^7.24.5",
         "@babel/helper-optimise-call-expression": "^7.22.5",
         "@babel/helper-replace-supers": "^7.24.1",
         "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
-        "@babel/helper-split-export-declaration": "^7.22.6",
+        "@babel/helper-split-export-declaration": "^7.24.5",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-create-regexp-features-plugin": {
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz",
+      "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.22.5",
+        "regexpu-core": "^5.3.1",
         "semver": "^6.3.1"
       },
       "engines": {
@@ -224,6 +260,23 @@
         "@babel/core": "^7.0.0"
       }
     },
+    "node_modules/@babel/helper-define-polyfill-provider": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz",
+      "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-compilation-targets": "^7.22.6",
+        "@babel/helper-plugin-utils": "^7.22.5",
+        "debug": "^4.1.1",
+        "lodash.debounce": "^4.0.8",
+        "resolve": "^1.14.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+      }
+    },
     "node_modules/@babel/helper-environment-visitor": {
       "version": "7.22.20",
       "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
@@ -259,12 +312,12 @@
       }
     },
     "node_modules/@babel/helper-member-expression-to-functions": {
-      "version": "7.23.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
-      "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.5.tgz",
+      "integrity": "sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.23.0"
+        "@babel/types": "^7.24.5"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -314,14 +367,32 @@
       }
     },
     "node_modules/@babel/helper-plugin-utils": {
-      "version": "7.24.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
-      "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz",
+      "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babel/helper-remap-async-to-generator": {
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz",
+      "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.22.5",
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-wrap-function": "^7.22.20"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
     "node_modules/@babel/helper-replace-supers": {
       "version": "7.24.1",
       "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz",
@@ -364,12 +435,12 @@
       }
     },
     "node_modules/@babel/helper-split-export-declaration": {
-      "version": "7.22.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
-      "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz",
+      "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.22.5"
+        "@babel/types": "^7.24.5"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -385,9 +456,9 @@
       }
     },
     "node_modules/@babel/helper-validator-identifier": {
-      "version": "7.22.20",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
-      "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
+      "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
@@ -402,6 +473,21 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babel/helper-wrap-function": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.5.tgz",
+      "integrity": "sha512-/xxzuNvgRl4/HLNKvnFwdhdgN3cpLxgLROeLDl83Yx0AJ1SGvq1ak0OszTOjDfiB8Vx03eJbeDWh9r+jCCWttw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-function-name": "^7.23.0",
+        "@babel/template": "^7.24.0",
+        "@babel/types": "^7.24.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
     "node_modules/@babel/helpers": {
       "version": "7.24.4",
       "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz",
@@ -510,18 +596,1147 @@
         "parser": "bin/babel-parser.js"
       },
       "engines": {
-        "node": ">=6.0.0"
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.5.tgz",
+      "integrity": "sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-plugin-utils": "^7.24.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz",
+      "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz",
+      "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
+        "@babel/plugin-transform-optional-chaining": "^7.24.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.13.0"
+      }
+    },
+    "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz",
+      "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-decorators": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.1.tgz",
+      "integrity": "sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.24.1",
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-decorators": "^7.24.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-private-property-in-object": {
+      "version": "7.21.0-placeholder-for-preset-env.2",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
+      "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-properties": {
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.12.13"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-static-block": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
+      "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-decorators": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.1.tgz",
+      "integrity": "sha512-05RJdO/cCrtVWuAaSn1tS3bH8jbsJa/Y1uD186u6J4C/1mnHFxseeuWpsqr9anvo7TUulev7tm7GDwRV+VuhDw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-dynamic-import": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
+      "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-export-namespace-from": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
+      "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-assertions": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz",
+      "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-attributes": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz",
+      "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz",
+      "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-private-property-in-object": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
+      "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz",
+      "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-unicode-sets-regex": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
+      "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-arrow-functions": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz",
+      "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-async-generator-functions": {
+      "version": "7.24.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz",
+      "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/helper-remap-async-to-generator": "^7.22.20",
+        "@babel/plugin-syntax-async-generators": "^7.8.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-async-to-generator": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz",
+      "integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.24.1",
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/helper-remap-async-to-generator": "^7.22.20"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-block-scoped-functions": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz",
+      "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-block-scoping": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.5.tgz",
+      "integrity": "sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-class-properties": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz",
+      "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.24.1",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-class-static-block": {
+      "version": "7.24.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz",
+      "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.24.4",
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-class-static-block": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.12.0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-classes": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.5.tgz",
+      "integrity": "sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.22.5",
+        "@babel/helper-compilation-targets": "^7.23.6",
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-function-name": "^7.23.0",
+        "@babel/helper-plugin-utils": "^7.24.5",
+        "@babel/helper-replace-supers": "^7.24.1",
+        "@babel/helper-split-export-declaration": "^7.24.5",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-computed-properties": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz",
+      "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/template": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-destructuring": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.5.tgz",
+      "integrity": "sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-dotall-regex": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz",
+      "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.22.15",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-duplicate-keys": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz",
+      "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-dynamic-import": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz",
+      "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-exponentiation-operator": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz",
+      "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-export-namespace-from": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz",
+      "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-for-of": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz",
+      "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-function-name": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz",
+      "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-compilation-targets": "^7.23.6",
+        "@babel/helper-function-name": "^7.23.0",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-json-strings": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz",
+      "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-json-strings": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-literals": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz",
+      "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-logical-assignment-operators": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz",
+      "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-member-expression-literals": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz",
+      "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-amd": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz",
+      "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.23.3",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-commonjs": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz",
+      "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.23.3",
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/helper-simple-access": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-systemjs": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz",
+      "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-hoist-variables": "^7.22.5",
+        "@babel/helper-module-transforms": "^7.23.3",
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/helper-validator-identifier": "^7.22.20"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-umd": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz",
+      "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.23.3",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz",
+      "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.22.5",
+        "@babel/helper-plugin-utils": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-new-target": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz",
+      "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz",
+      "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-numeric-separator": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz",
+      "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-numeric-separator": "^7.10.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-object-rest-spread": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.5.tgz",
+      "integrity": "sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-compilation-targets": "^7.23.6",
+        "@babel/helper-plugin-utils": "^7.24.5",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-transform-parameters": "^7.24.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-object-super": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz",
+      "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/helper-replace-supers": "^7.24.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-optional-catch-binding": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz",
+      "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-optional-chaining": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.5.tgz",
+      "integrity": "sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.5",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-parameters": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.5.tgz",
+      "integrity": "sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-private-methods": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz",
+      "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.24.1",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-private-property-in-object": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.5.tgz",
+      "integrity": "sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.22.5",
+        "@babel/helper-create-class-features-plugin": "^7.24.5",
+        "@babel/helper-plugin-utils": "^7.24.5",
+        "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-property-literals": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz",
+      "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-regenerator": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz",
+      "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "regenerator-transform": "^0.15.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-reserved-words": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz",
+      "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-shorthand-properties": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz",
+      "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-spread": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz",
+      "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-sticky-regex": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz",
+      "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-template-literals": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz",
+      "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
       }
     },
-    "node_modules/@babel/plugin-proposal-decorators": {
-      "version": "7.24.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.1.tgz",
-      "integrity": "sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA==",
+    "node_modules/@babel/plugin-transform-typeof-symbol": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.5.tgz",
+      "integrity": "sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@babel/helper-create-class-features-plugin": "^7.24.1",
-        "@babel/helper-plugin-utils": "^7.24.0",
-        "@babel/plugin-syntax-decorators": "^7.24.1"
+        "@babel/helper-plugin-utils": "^7.24.5"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -530,13 +1745,16 @@
         "@babel/core": "^7.0.0-0"
       }
     },
-    "node_modules/@babel/plugin-syntax-decorators": {
-      "version": "7.24.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.1.tgz",
-      "integrity": "sha512-05RJdO/cCrtVWuAaSn1tS3bH8jbsJa/Y1uD186u6J4C/1mnHFxseeuWpsqr9anvo7TUulev7tm7GDwRV+VuhDw==",
+    "node_modules/@babel/plugin-transform-typescript": {
+      "version": "7.24.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz",
+      "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.24.0"
+        "@babel/helper-annotate-as-pure": "^7.22.5",
+        "@babel/helper-create-class-features-plugin": "^7.24.4",
+        "@babel/helper-plugin-utils": "^7.24.0",
+        "@babel/plugin-syntax-typescript": "^7.24.1"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -545,11 +1763,12 @@
         "@babel/core": "^7.0.0-0"
       }
     },
-    "node_modules/@babel/plugin-syntax-import-attributes": {
+    "node_modules/@babel/plugin-transform-unicode-escapes": {
       "version": "7.24.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz",
-      "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz",
+      "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "@babel/helper-plugin-utils": "^7.24.0"
       },
@@ -560,24 +1779,31 @@
         "@babel/core": "^7.0.0-0"
       }
     },
-    "node_modules/@babel/plugin-syntax-import-meta": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
-      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+    "node_modules/@babel/plugin-transform-unicode-property-regex": {
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz",
+      "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-create-regexp-features-plugin": "^7.22.15",
+        "@babel/helper-plugin-utils": "^7.24.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
       },
       "peerDependencies": {
         "@babel/core": "^7.0.0-0"
       }
     },
-    "node_modules/@babel/plugin-syntax-jsx": {
+    "node_modules/@babel/plugin-transform-unicode-regex": {
       "version": "7.24.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz",
-      "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz",
+      "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==",
       "dev": true,
+      "peer": true,
       "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.22.15",
         "@babel/helper-plugin-utils": "^7.24.0"
       },
       "engines": {
@@ -587,31 +1813,111 @@
         "@babel/core": "^7.0.0-0"
       }
     },
-    "node_modules/@babel/plugin-syntax-typescript": {
+    "node_modules/@babel/plugin-transform-unicode-sets-regex": {
       "version": "7.24.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz",
-      "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz",
+      "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.22.15",
         "@babel/helper-plugin-utils": "^7.24.0"
       },
       "engines": {
         "node": ">=6.9.0"
       },
       "peerDependencies": {
-        "@babel/core": "^7.0.0-0"
+        "@babel/core": "^7.0.0"
       }
     },
-    "node_modules/@babel/plugin-transform-typescript": {
-      "version": "7.24.4",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz",
-      "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==",
+    "node_modules/@babel/preset-env": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.5.tgz",
+      "integrity": "sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@babel/helper-annotate-as-pure": "^7.22.5",
-        "@babel/helper-create-class-features-plugin": "^7.24.4",
-        "@babel/helper-plugin-utils": "^7.24.0",
-        "@babel/plugin-syntax-typescript": "^7.24.1"
+        "@babel/compat-data": "^7.24.4",
+        "@babel/helper-compilation-targets": "^7.23.6",
+        "@babel/helper-plugin-utils": "^7.24.5",
+        "@babel/helper-validator-option": "^7.23.5",
+        "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.5",
+        "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1",
+        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1",
+        "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1",
+        "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-class-properties": "^7.12.13",
+        "@babel/plugin-syntax-class-static-block": "^7.14.5",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.3",
+        "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
+        "@babel/plugin-syntax-import-assertions": "^7.24.1",
+        "@babel/plugin-syntax-import-attributes": "^7.24.1",
+        "@babel/plugin-syntax-import-meta": "^7.10.4",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.10.4",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
+        "@babel/plugin-syntax-top-level-await": "^7.14.5",
+        "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
+        "@babel/plugin-transform-arrow-functions": "^7.24.1",
+        "@babel/plugin-transform-async-generator-functions": "^7.24.3",
+        "@babel/plugin-transform-async-to-generator": "^7.24.1",
+        "@babel/plugin-transform-block-scoped-functions": "^7.24.1",
+        "@babel/plugin-transform-block-scoping": "^7.24.5",
+        "@babel/plugin-transform-class-properties": "^7.24.1",
+        "@babel/plugin-transform-class-static-block": "^7.24.4",
+        "@babel/plugin-transform-classes": "^7.24.5",
+        "@babel/plugin-transform-computed-properties": "^7.24.1",
+        "@babel/plugin-transform-destructuring": "^7.24.5",
+        "@babel/plugin-transform-dotall-regex": "^7.24.1",
+        "@babel/plugin-transform-duplicate-keys": "^7.24.1",
+        "@babel/plugin-transform-dynamic-import": "^7.24.1",
+        "@babel/plugin-transform-exponentiation-operator": "^7.24.1",
+        "@babel/plugin-transform-export-namespace-from": "^7.24.1",
+        "@babel/plugin-transform-for-of": "^7.24.1",
+        "@babel/plugin-transform-function-name": "^7.24.1",
+        "@babel/plugin-transform-json-strings": "^7.24.1",
+        "@babel/plugin-transform-literals": "^7.24.1",
+        "@babel/plugin-transform-logical-assignment-operators": "^7.24.1",
+        "@babel/plugin-transform-member-expression-literals": "^7.24.1",
+        "@babel/plugin-transform-modules-amd": "^7.24.1",
+        "@babel/plugin-transform-modules-commonjs": "^7.24.1",
+        "@babel/plugin-transform-modules-systemjs": "^7.24.1",
+        "@babel/plugin-transform-modules-umd": "^7.24.1",
+        "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5",
+        "@babel/plugin-transform-new-target": "^7.24.1",
+        "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1",
+        "@babel/plugin-transform-numeric-separator": "^7.24.1",
+        "@babel/plugin-transform-object-rest-spread": "^7.24.5",
+        "@babel/plugin-transform-object-super": "^7.24.1",
+        "@babel/plugin-transform-optional-catch-binding": "^7.24.1",
+        "@babel/plugin-transform-optional-chaining": "^7.24.5",
+        "@babel/plugin-transform-parameters": "^7.24.5",
+        "@babel/plugin-transform-private-methods": "^7.24.1",
+        "@babel/plugin-transform-private-property-in-object": "^7.24.5",
+        "@babel/plugin-transform-property-literals": "^7.24.1",
+        "@babel/plugin-transform-regenerator": "^7.24.1",
+        "@babel/plugin-transform-reserved-words": "^7.24.1",
+        "@babel/plugin-transform-shorthand-properties": "^7.24.1",
+        "@babel/plugin-transform-spread": "^7.24.1",
+        "@babel/plugin-transform-sticky-regex": "^7.24.1",
+        "@babel/plugin-transform-template-literals": "^7.24.1",
+        "@babel/plugin-transform-typeof-symbol": "^7.24.5",
+        "@babel/plugin-transform-unicode-escapes": "^7.24.1",
+        "@babel/plugin-transform-unicode-property-regex": "^7.24.1",
+        "@babel/plugin-transform-unicode-regex": "^7.24.1",
+        "@babel/plugin-transform-unicode-sets-regex": "^7.24.1",
+        "@babel/preset-modules": "0.1.6-no-external-plugins",
+        "babel-plugin-polyfill-corejs2": "^0.4.10",
+        "babel-plugin-polyfill-corejs3": "^0.10.4",
+        "babel-plugin-polyfill-regenerator": "^0.6.1",
+        "core-js-compat": "^3.31.0",
+        "semver": "^6.3.1"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -620,6 +1926,28 @@
         "@babel/core": "^7.0.0-0"
       }
     },
+    "node_modules/@babel/preset-modules": {
+      "version": "0.1.6-no-external-plugins",
+      "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
+      "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@babel/types": "^7.4.4",
+        "esutils": "^2.0.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0"
+      }
+    },
+    "node_modules/@babel/regjsgen": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz",
+      "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/@babel/runtime": {
       "version": "7.24.4",
       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
@@ -668,13 +1996,13 @@
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.24.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
-      "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
+      "version": "7.24.5",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz",
+      "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-string-parser": "^7.23.4",
-        "@babel/helper-validator-identifier": "^7.22.20",
+        "@babel/helper-string-parser": "^7.24.1",
+        "@babel/helper-validator-identifier": "^7.24.5",
         "to-fast-properties": "^2.0.0"
       },
       "engines": {
@@ -697,6 +2025,30 @@
         "node": ">=0.1.90"
       }
     },
+    "node_modules/@cypress/code-coverage": {
+      "version": "3.12.38",
+      "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.12.38.tgz",
+      "integrity": "sha512-1jYHxAeweMBD5hvrHdzpwmS0yHQ/AKHC1BsoAgYtvYYRe/aOkAeWUwy3CaOTQzyVOMa+cWFElPYYusf1WiW85A==",
+      "dev": true,
+      "dependencies": {
+        "@cypress/webpack-preprocessor": "^6.0.0",
+        "chalk": "4.1.2",
+        "dayjs": "1.11.10",
+        "debug": "4.3.4",
+        "execa": "4.1.0",
+        "globby": "11.1.0",
+        "istanbul-lib-coverage": "^3.0.0",
+        "js-yaml": "4.1.0",
+        "nyc": "15.1.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.1",
+        "@babel/preset-env": "^7.0.0",
+        "babel-loader": "^8.3 || ^9",
+        "cypress": "*",
+        "webpack": "^4 || ^5"
+      }
+    },
     "node_modules/@cypress/request": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz",
@@ -740,6 +2092,29 @@
         "node": ">= 0.12"
       }
     },
+    "node_modules/@cypress/webpack-preprocessor": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/@cypress/webpack-preprocessor/-/webpack-preprocessor-6.0.1.tgz",
+      "integrity": "sha512-WVNeFVSnFKxE3WZNRIriduTgqJRpevaiJIPlfqYTTzfXRD7X1Pv4woDE+G4caPV9bJqVKmVFiwzrXMRNeJxpxA==",
+      "dev": true,
+      "dependencies": {
+        "bluebird": "3.7.1",
+        "debug": "^4.3.4",
+        "lodash": "^4.17.20"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.1",
+        "@babel/preset-env": "^7.0.0",
+        "babel-loader": "^8.3 || ^9",
+        "webpack": "^4 || ^5"
+      }
+    },
+    "node_modules/@cypress/webpack-preprocessor/node_modules/bluebird": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
+      "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==",
+      "dev": true
+    },
     "node_modules/@cypress/xvfb": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
@@ -1378,6 +2753,114 @@
         "url": "https://github.com/chalk/strip-ansi?sponsor=1"
       }
     },
+    "node_modules/@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/@istanbuljs/schema": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
@@ -1431,6 +2914,17 @@
         "node": ">=6.0.0"
       }
     },
+    "node_modules/@jridgewell/source-map": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
+      "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.25"
+      }
+    },
     "node_modules/@jridgewell/sourcemap-codec": {
       "version": "1.4.15",
       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
@@ -1451,6 +2945,11 @@
       "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
       "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="
     },
+    "node_modules/@kurkle/color": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
+      "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
+    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1888,6 +3387,28 @@
       "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
       "dev": true
     },
+    "node_modules/@types/eslint": {
+      "version": "8.56.10",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
+      "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/estree": "*",
+        "@types/json-schema": "*"
+      }
+    },
+    "node_modules/@types/eslint-scope": {
+      "version": "3.7.7",
+      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+      "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/eslint": "*",
+        "@types/estree": "*"
+      }
+    },
     "node_modules/@types/estree": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
@@ -2803,6 +4324,181 @@
       "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==",
       "dev": true
     },
+    "node_modules/@webassemblyjs/ast": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
+      "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@webassemblyjs/helper-numbers": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/floating-point-hex-parser": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
+      "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@webassemblyjs/helper-api-error": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
+      "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@webassemblyjs/helper-buffer": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
+      "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@webassemblyjs/helper-numbers": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
+      "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@webassemblyjs/floating-point-hex-parser": "1.11.6",
+        "@webassemblyjs/helper-api-error": "1.11.6",
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@webassemblyjs/helper-wasm-bytecode": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
+      "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@webassemblyjs/helper-wasm-section": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
+      "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/wasm-gen": "1.12.1"
+      }
+    },
+    "node_modules/@webassemblyjs/ieee754": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
+      "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@xtuc/ieee754": "^1.2.0"
+      }
+    },
+    "node_modules/@webassemblyjs/leb128": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
+      "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@webassemblyjs/utf8": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
+      "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@webassemblyjs/wasm-edit": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
+      "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/helper-wasm-section": "1.12.1",
+        "@webassemblyjs/wasm-gen": "1.12.1",
+        "@webassemblyjs/wasm-opt": "1.12.1",
+        "@webassemblyjs/wasm-parser": "1.12.1",
+        "@webassemblyjs/wast-printer": "1.12.1"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-gen": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
+      "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/ieee754": "1.11.6",
+        "@webassemblyjs/leb128": "1.11.6",
+        "@webassemblyjs/utf8": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-opt": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
+      "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-buffer": "1.12.1",
+        "@webassemblyjs/wasm-gen": "1.12.1",
+        "@webassemblyjs/wasm-parser": "1.12.1"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-parser": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
+      "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.12.1",
+        "@webassemblyjs/helper-api-error": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/ieee754": "1.11.6",
+        "@webassemblyjs/leb128": "1.11.6",
+        "@webassemblyjs/utf8": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/wast-printer": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
+      "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.12.1",
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@xtuc/ieee754": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+      "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@xtuc/long": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+      "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/abbrev": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
@@ -2824,6 +4520,16 @@
         "node": ">=0.4.0"
       }
     },
+    "node_modules/acorn-import-assertions": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
+      "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "acorn": "^8"
+      }
+    },
     "node_modules/acorn-jsx": {
       "version": "5.3.2",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
@@ -2883,6 +4589,55 @@
         "url": "https://github.com/sponsors/epoberezkin"
       }
     },
+    "node_modules/ajv-formats": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+      "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "ajv": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/ajv-formats/node_modules/ajv": {
+      "version": "8.13.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
+      "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.4.1"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
+    "node_modules/ajv-keywords": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+      "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "ajv": "^6.9.1"
+      }
+    },
     "node_modules/ansi-colors": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@@ -2931,6 +4686,18 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
+    "node_modules/append-transform": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
+      "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
+      "dev": true,
+      "dependencies": {
+        "default-require-extensions": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/arch": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
@@ -2951,6 +4718,12 @@
         }
       ]
     },
+    "node_modules/archy": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+      "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==",
+      "dev": true
+    },
     "node_modules/arg": {
       "version": "5.0.2",
       "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
@@ -3115,6 +4888,81 @@
         "proxy-from-env": "^1.1.0"
       }
     },
+    "node_modules/babel-loader": {
+      "version": "9.1.3",
+      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz",
+      "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==",
+      "dev": true,
+      "dependencies": {
+        "find-cache-dir": "^4.0.0",
+        "schema-utils": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.12.0",
+        "webpack": ">=5"
+      }
+    },
+    "node_modules/babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+      "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-plugin-polyfill-corejs2": {
+      "version": "0.4.11",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz",
+      "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.22.6",
+        "@babel/helper-define-polyfill-provider": "^0.6.2",
+        "semver": "^6.3.1"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+      }
+    },
+    "node_modules/babel-plugin-polyfill-corejs3": {
+      "version": "0.10.4",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz",
+      "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-define-polyfill-provider": "^0.6.1",
+        "core-js-compat": "^3.36.1"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+      }
+    },
+    "node_modules/babel-plugin-polyfill-regenerator": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz",
+      "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/helper-define-polyfill-provider": "^0.6.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+      }
+    },
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -3272,6 +5120,13 @@
         "node": "*"
       }
     },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/builtin-modules": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
@@ -3314,6 +5169,36 @@
         "node": ">=6"
       }
     },
+    "node_modules/caching-transform": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
+      "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
+      "dev": true,
+      "dependencies": {
+        "hasha": "^5.0.0",
+        "make-dir": "^3.0.0",
+        "package-hash": "^4.0.0",
+        "write-file-atomic": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/caching-transform/node_modules/make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/call-bind": {
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
@@ -3413,6 +5298,17 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
     },
+    "node_modules/chart.js": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz",
+      "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==",
+      "dependencies": {
+        "@kurkle/color": "^0.3.0"
+      },
+      "engines": {
+        "pnpm": ">=8"
+      }
+    },
     "node_modules/check-error": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
@@ -3434,6 +5330,16 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/chrome-trace-event": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+      "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6.0"
+      }
+    },
     "node_modules/ci-info": {
       "version": "3.9.0",
       "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
@@ -3501,6 +5407,31 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      }
+    },
+    "node_modules/cliui/node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -3545,6 +5476,12 @@
         "node": ">= 6"
       }
     },
+    "node_modules/common-path-prefix": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz",
+      "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==",
+      "dev": true
+    },
     "node_modules/common-tags": {
       "version": "1.8.2",
       "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz",
@@ -3554,6 +5491,12 @@
         "node": ">=4.0.0"
       }
     },
+    "node_modules/commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+      "dev": true
+    },
     "node_modules/computeds": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz",
@@ -3594,6 +5537,20 @@
       "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
       "dev": true
     },
+    "node_modules/core-js-compat": {
+      "version": "3.37.0",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz",
+      "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.23.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
     "node_modules/core-util-is": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -3859,6 +5816,15 @@
         }
       }
     },
+    "node_modules/decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/decimal.js": {
       "version": "10.4.3",
       "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
@@ -3943,6 +5909,30 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/default-require-extensions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz",
+      "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==",
+      "dev": true,
+      "dependencies": {
+        "strip-bom": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/default-require-extensions/node_modules/strip-bom": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/define-data-property": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@@ -4173,6 +6163,20 @@
         "once": "^1.4.0"
       }
     },
+    "node_modules/enhanced-resolve": {
+      "version": "5.16.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
+      "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/enquirer": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
@@ -4316,6 +6320,13 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/es-module-lexer": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.2.tgz",
+      "integrity": "sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/es-object-atoms": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
@@ -4359,6 +6370,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/es6-error": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+      "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+      "dev": true
+    },
     "node_modules/esbuild": {
       "version": "0.20.2",
       "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
@@ -4811,6 +6828,16 @@
       "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
       "dev": true
     },
+    "node_modules/events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.8.x"
+      }
+    },
     "node_modules/execa": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
@@ -4999,6 +7026,22 @@
         "node": ">=8"
       }
     },
+    "node_modules/find-cache-dir": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz",
+      "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==",
+      "dev": true,
+      "dependencies": {
+        "common-path-prefix": "^3.0.0",
+        "pkg-dir": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/find-up": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -5119,6 +7162,26 @@
       "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
       "dev": true
     },
+    "node_modules/fromentries": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
+      "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
     "node_modules/fs-extra": {
       "version": "9.1.0",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
@@ -5199,6 +7262,15 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
     "node_modules/get-func-name": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
@@ -5227,6 +7299,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
     "node_modules/get-stream": {
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
@@ -5311,6 +7392,13 @@
         "node": ">=10.13.0"
       }
     },
+    "node_modules/glob-to-regexp": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+      "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/global-dirs": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
@@ -5482,6 +7570,31 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/hasha": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
+      "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
+      "dev": true,
+      "dependencies": {
+        "is-stream": "^2.0.0",
+        "type-fest": "^0.8.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/hasha/node_modules/type-fest": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/hasown": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
@@ -6148,6 +8261,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/is-wsl": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
@@ -6190,6 +8312,63 @@
         "node": ">=8"
       }
     },
+    "node_modules/istanbul-lib-hook": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
+      "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
+      "dev": true,
+      "dependencies": {
+        "append-transform": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+      "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-processinfo": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
+      "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==",
+      "dev": true,
+      "dependencies": {
+        "archy": "^1.0.0",
+        "cross-spawn": "^7.0.3",
+        "istanbul-lib-coverage": "^3.2.0",
+        "p-map": "^3.0.0",
+        "rimraf": "^3.0.0",
+        "uuid": "^8.3.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-processinfo/node_modules/p-map": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+      "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+      "dev": true,
+      "dependencies": {
+        "aggregate-error": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/istanbul-lib-report": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
@@ -6249,6 +8428,37 @@
         "@pkgjs/parseargs": "^0.11.0"
       }
     },
+    "node_modules/jest-worker": {
+      "version": "27.5.1",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+      "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/node": "*",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^8.0.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      }
+    },
+    "node_modules/jest-worker/node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
     "node_modules/joi": {
       "version": "17.13.0",
       "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.0.tgz",
@@ -6572,6 +8782,16 @@
         "node": ">=4"
       }
     },
+    "node_modules/loader-runner": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
+      "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6.11.5"
+      }
+    },
     "node_modules/local-pkg": {
       "version": "0.5.0",
       "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
@@ -6609,6 +8829,19 @@
       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
       "dev": true
     },
+    "node_modules/lodash.debounce": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+      "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/lodash.flattendeep": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+      "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
+      "dev": true
+    },
     "node_modules/lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -6968,6 +9201,18 @@
       "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
       "dev": true
     },
+    "node_modules/node-preload": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
+      "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
+      "dev": true,
+      "dependencies": {
+        "process-on-spawn": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/node-releases": {
       "version": "2.0.14",
       "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
@@ -7250,38 +9495,286 @@
         "pidtree": "bin/pidtree.js"
       },
       "engines": {
-        "node": ">=0.10"
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/npm-run-path": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/nwsapi": {
+      "version": "2.2.9",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz",
+      "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==",
+      "dev": true
+    },
+    "node_modules/nyc": {
+      "version": "15.1.0",
+      "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
+      "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
+      "dev": true,
+      "dependencies": {
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "caching-transform": "^4.0.0",
+        "convert-source-map": "^1.7.0",
+        "decamelize": "^1.2.0",
+        "find-cache-dir": "^3.2.0",
+        "find-up": "^4.1.0",
+        "foreground-child": "^2.0.0",
+        "get-package-type": "^0.1.0",
+        "glob": "^7.1.6",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-hook": "^3.0.0",
+        "istanbul-lib-instrument": "^4.0.0",
+        "istanbul-lib-processinfo": "^2.0.2",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.0.2",
+        "make-dir": "^3.0.0",
+        "node-preload": "^0.2.1",
+        "p-map": "^3.0.0",
+        "process-on-spawn": "^1.0.0",
+        "resolve-from": "^5.0.0",
+        "rimraf": "^3.0.0",
+        "signal-exit": "^3.0.2",
+        "spawn-wrap": "^2.0.0",
+        "test-exclude": "^6.0.0",
+        "yargs": "^15.0.2"
+      },
+      "bin": {
+        "nyc": "bin/nyc.js"
+      },
+      "engines": {
+        "node": ">=8.9"
+      }
+    },
+    "node_modules/nyc/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/nyc/node_modules/convert-source-map": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+      "dev": true
+    },
+    "node_modules/nyc/node_modules/find-cache-dir": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+      "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+      "dev": true,
+      "dependencies": {
+        "commondir": "^1.0.1",
+        "make-dir": "^3.0.2",
+        "pkg-dir": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
+      }
+    },
+    "node_modules/nyc/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/foreground-child": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
+      "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.0",
+        "signal-exit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/nyc/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/nyc/node_modules/istanbul-lib-instrument": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
+      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "^7.7.5",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.0.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/nyc/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/nyc/node_modules/make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/nyc/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/nyc/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/nyc/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/npm-run-path": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+    "node_modules/nyc/node_modules/p-map": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+      "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
       "dev": true,
       "dependencies": {
-        "path-key": "^3.0.0"
+        "aggregate-error": "^3.0.0"
       },
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/nth-check": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
-      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+    "node_modules/nyc/node_modules/pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
       "dev": true,
       "dependencies": {
-        "boolbase": "^1.0.0"
+        "find-up": "^4.0.0"
       },
-      "funding": {
-        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/nwsapi": {
-      "version": "2.2.9",
-      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz",
-      "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==",
-      "dev": true
+    "node_modules/nyc/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
     },
     "node_modules/object-inspect": {
       "version": "1.13.1",
@@ -7523,6 +10016,30 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/package-hash": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
+      "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.15",
+        "hasha": "^5.0.0",
+        "lodash.flattendeep": "^4.4.0",
+        "release-zalgo": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/parent-module": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -7814,6 +10331,103 @@
         }
       }
     },
+    "node_modules/pkg-dir": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz",
+      "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/find-up": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
+      "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^7.1.0",
+        "path-exists": "^5.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/locate-path": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
+      "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^6.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-limit": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+      "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+      "dev": true,
+      "dependencies": {
+        "yocto-queue": "^1.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-locate": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
+      "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/path-exists": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
+      "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
+      "dev": true,
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/yocto-queue": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
+      "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+      "dev": true,
+      "engines": {
+        "node": ">=12.20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/pkg-types": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.0.tgz",
@@ -7957,6 +10571,18 @@
         "node": ">= 0.6.0"
       }
     },
+    "node_modules/process-on-spawn": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
+      "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
+      "dev": true,
+      "dependencies": {
+        "fromentries": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/proto-list": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -8049,6 +10675,16 @@
         }
       ]
     },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
     "node_modules/react-is": {
       "version": "17.0.2",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -8103,12 +10739,42 @@
         "node": ">=4"
       }
     },
+    "node_modules/regenerate": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+      "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/regenerate-unicode-properties": {
+      "version": "10.1.1",
+      "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz",
+      "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "regenerate": "^1.4.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/regenerator-runtime": {
       "version": "0.14.1",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
       "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
       "dev": true
     },
+    "node_modules/regenerator-transform": {
+      "version": "0.15.2",
+      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
+      "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/runtime": "^7.8.4"
+      }
+    },
     "node_modules/regexp.prototype.flags": {
       "version": "1.5.2",
       "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
@@ -8127,6 +10793,59 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/regexpu-core": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz",
+      "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@babel/regjsgen": "^0.8.0",
+        "regenerate": "^1.4.2",
+        "regenerate-unicode-properties": "^10.1.0",
+        "regjsparser": "^0.9.1",
+        "unicode-match-property-ecmascript": "^2.0.0",
+        "unicode-match-property-value-ecmascript": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/regjsparser": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
+      "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "jsesc": "~0.5.0"
+      },
+      "bin": {
+        "regjsparser": "bin/parser"
+      }
+    },
+    "node_modules/regjsparser/node_modules/jsesc": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+      "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "jsesc": "bin/jsesc"
+      }
+    },
+    "node_modules/release-zalgo": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
+      "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==",
+      "dev": true,
+      "dependencies": {
+        "es6-error": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/request-progress": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz",
@@ -8136,6 +10855,30 @@
         "throttleit": "^1.0.0"
       }
     },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "dev": true
+    },
     "node_modules/requires-port": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -8417,6 +11160,59 @@
         "node": ">=v12.22.7"
       }
     },
+    "node_modules/schema-utils": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+      "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.9",
+        "ajv": "^8.9.0",
+        "ajv-formats": "^2.1.1",
+        "ajv-keywords": "^5.1.0"
+      },
+      "engines": {
+        "node": ">= 12.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
+    "node_modules/schema-utils/node_modules/ajv": {
+      "version": "8.13.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
+      "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.4.1"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/schema-utils/node_modules/ajv-keywords": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+      "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3"
+      },
+      "peerDependencies": {
+        "ajv": "^8.8.2"
+      }
+    },
+    "node_modules/schema-utils/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
     "node_modules/semver": {
       "version": "6.3.1",
       "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -8426,6 +11222,22 @@
         "semver": "bin/semver.js"
       }
     },
+    "node_modules/serialize-javascript": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+      "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "randombytes": "^2.1.0"
+      }
+    },
+    "node_modules/set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+      "dev": true
+    },
     "node_modules/set-function-length": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -8547,28 +11359,84 @@
       "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
       "dev": true,
       "dependencies": {
-        "ansi-styles": "^4.0.0",
-        "astral-regex": "^2.0.0",
-        "is-fullwidth-code-point": "^3.0.0"
+        "ansi-styles": "^4.0.0",
+        "astral-regex": "^2.0.0",
+        "is-fullwidth-code-point": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/spawn-wrap": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
+      "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
+      "dev": true,
+      "dependencies": {
+        "foreground-child": "^2.0.0",
+        "is-windows": "^1.0.2",
+        "make-dir": "^3.0.0",
+        "rimraf": "^3.0.0",
+        "signal-exit": "^3.0.2",
+        "which": "^2.0.1"
       },
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+    "node_modules/spawn-wrap/node_modules/foreground-child": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
+      "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.0",
+        "signal-exit": "^3.0.2"
+      },
       "engines": {
-        "node": ">=0.10.0"
+        "node": ">=8.0.0"
       }
     },
-    "node_modules/source-map-js": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
-      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+    "node_modules/spawn-wrap/node_modules/make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
       "engines": {
-        "node": ">=0.10.0"
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/spdx-correct": {
@@ -8977,6 +11845,96 @@
         "url": "https://opencollective.com/unts"
       }
     },
+    "node_modules/tapable": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/terser": {
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz",
+      "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/source-map": "^0.3.3",
+        "acorn": "^8.8.2",
+        "commander": "^2.20.0",
+        "source-map-support": "~0.5.20"
+      },
+      "bin": {
+        "terser": "bin/terser"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/terser-webpack-plugin": {
+      "version": "5.3.10",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
+      "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.20",
+        "jest-worker": "^27.4.5",
+        "schema-utils": "^3.1.1",
+        "serialize-javascript": "^6.0.1",
+        "terser": "^5.26.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^5.1.0"
+      },
+      "peerDependenciesMeta": {
+        "@swc/core": {
+          "optional": true
+        },
+        "esbuild": {
+          "optional": true
+        },
+        "uglify-js": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+      "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.8",
+        "ajv": "^6.12.5",
+        "ajv-keywords": "^3.5.2"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
+    "node_modules/terser/node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/test-exclude": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
@@ -9500,6 +12458,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "dev": true,
+      "dependencies": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
     "node_modules/typescript": {
       "version": "5.4.5",
       "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
@@ -9552,6 +12519,50 @@
       "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
       "dev": true
     },
+    "node_modules/unicode-canonical-property-names-ecmascript": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
+      "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/unicode-match-property-ecmascript": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
+      "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "unicode-canonical-property-names-ecmascript": "^2.0.0",
+        "unicode-property-aliases-ecmascript": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/unicode-match-property-value-ecmascript": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
+      "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/unicode-property-aliases-ecmascript": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
+      "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/universalify": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
@@ -10192,6 +13203,15 @@
         }
       }
     },
+    "node_modules/vue-chartjs": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.1.tgz",
+      "integrity": "sha512-rZjqcHBxKiHrBl0CIvcOlVEBwRhpWAVf6rDU3vUfa7HuSRmGtCslc0Oc8m16oAVuk0erzc1FCtH1VCriHsrz+A==",
+      "peerDependencies": {
+        "chart.js": "^4.1.1",
+        "vue": "^3.0.0-0 || ^2.7.0"
+      }
+    },
     "node_modules/vue-component-type-helpers": {
       "version": "2.0.14",
       "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.0.14.tgz",
@@ -10379,6 +13399,20 @@
         "node": ">=12.0.0"
       }
     },
+    "node_modules/watchpack": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
+      "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.1.2"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/webidl-conversions": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -10388,6 +13422,114 @@
         "node": ">=12"
       }
     },
+    "node_modules/webpack": {
+      "version": "5.91.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz",
+      "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/eslint-scope": "^3.7.3",
+        "@types/estree": "^1.0.5",
+        "@webassemblyjs/ast": "^1.12.1",
+        "@webassemblyjs/wasm-edit": "^1.12.1",
+        "@webassemblyjs/wasm-parser": "^1.12.1",
+        "acorn": "^8.7.1",
+        "acorn-import-assertions": "^1.9.0",
+        "browserslist": "^4.21.10",
+        "chrome-trace-event": "^1.0.2",
+        "enhanced-resolve": "^5.16.0",
+        "es-module-lexer": "^1.2.1",
+        "eslint-scope": "5.1.1",
+        "events": "^3.2.0",
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.2.11",
+        "json-parse-even-better-errors": "^2.3.1",
+        "loader-runner": "^4.2.0",
+        "mime-types": "^2.1.27",
+        "neo-async": "^2.6.2",
+        "schema-utils": "^3.2.0",
+        "tapable": "^2.1.1",
+        "terser-webpack-plugin": "^5.3.10",
+        "watchpack": "^2.4.1",
+        "webpack-sources": "^3.2.3"
+      },
+      "bin": {
+        "webpack": "bin/webpack.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependenciesMeta": {
+        "webpack-cli": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/webpack-sources": {
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
+      "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/webpack/node_modules/eslint-scope": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^4.1.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/webpack/node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/webpack/node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/webpack/node_modules/schema-utils": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+      "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.8",
+        "ajv": "^6.12.5",
+        "ajv-keywords": "^3.5.2"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
     "node_modules/whatwg-encoding": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
@@ -10471,6 +13613,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/which-module": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
+      "dev": true
+    },
     "node_modules/which-typed-array": {
       "version": "1.1.15",
       "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
@@ -10614,6 +13762,18 @@
       "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
       "dev": true
     },
+    "node_modules/write-file-atomic": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+      "dev": true,
+      "dependencies": {
+        "imurmurhash": "^0.1.4",
+        "is-typedarray": "^1.0.0",
+        "signal-exit": "^3.0.2",
+        "typedarray-to-buffer": "^3.1.5"
+      }
+    },
     "node_modules/ws": {
       "version": "8.16.0",
       "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
@@ -10670,12 +13830,114 @@
       "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
       "dev": true
     },
+    "node_modules/y18n": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+      "dev": true
+    },
     "node_modules/yallist": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
       "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
       "dev": true
     },
+    "node_modules/yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "dev": true,
+      "dependencies": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/yargs-parser/node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/yargs/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/yargs/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/yauzl": {
       "version": "2.10.0",
       "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
diff --git a/package.json b/package.json
index 7451ccd606573141e0942ce9e76b9b6dfca81901..c5fee03be5ba0bd83eac108d176d78c6812cec66 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
     "@popperjs/core": "^2.11.8",
     "axios": "^1.6.8",
     "bootstrap": "^5.3.3",
+    "chart.js": "^4.4.2",
     "install": "^0.13.0",
     "jQuery": "^1.7.4",
     "js-cookie": "^3.0.5",
@@ -29,10 +30,12 @@
     "pinia-plugin-persist": "^1.0.0",
     "pinia-plugin-persistedstate": "^3.2.1",
     "vue": "^3.4.21",
+    "vue-chartjs": "^5.3.1",
     "vue-router": "^4.3.0",
     "xml2js": "^0.6.2"
   },
   "devDependencies": {
+    "@cypress/code-coverage": "^3.12.38",
     "@rushstack/eslint-patch": "^1.8.0",
     "@testing-library/user-event": "^14.5.2",
     "@testing-library/vue": "^8.0.3",
@@ -48,6 +51,8 @@
     "@vue/eslint-config-typescript": "^13.0.0",
     "@vue/test-utils": "^2.4.5",
     "@vue/tsconfig": "^0.5.1",
+    "babel-loader": "^9.1.3",
+    "babel-plugin-istanbul": "^6.1.1",
     "cypress": "^13.7.2",
     "eslint": "^8.57.0",
     "eslint-plugin-cypress": "^2.15.1",
diff --git a/spec.json b/spec.json
index e6566e8325cdbf7dd17a2bb0286b7fe42273b085..d22821d7fd6ecd38fdd014cc2859ec7fcbe472f1 100644
--- a/spec.json
+++ b/spec.json
@@ -17,6 +17,10 @@
     }
   ],
   "tags": [
+    {
+      "name": "Item",
+      "description": "Endpoints for managing store and user inventory."
+    },
     {
       "name": "Friend",
       "description": "API for managing friend relationships"
@@ -75,8 +79,8 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Friend request not found",
+          "200": {
+            "description": "Friend request successfully accepted",
             "content": {
               "*/*": {
                 "schema": {
@@ -85,8 +89,8 @@
               }
             }
           },
-          "200": {
-            "description": "Friend request successfully accepted",
+          "404": {
+            "description": "Friend request not found",
             "content": {
               "*/*": {
                 "schema": {
@@ -116,8 +120,8 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Friend or friend request not found",
+          "200": {
+            "description": "Friend successfully deleted or friend request cancelled",
             "content": {
               "*/*": {
                 "schema": {
@@ -126,8 +130,8 @@
               }
             }
           },
-          "200": {
-            "description": "Friend successfully deleted or friend request cancelled",
+          "404": {
+            "description": "Friend or friend request not found",
             "content": {
               "*/*": {
                 "schema": {
@@ -158,8 +162,8 @@
           "required": true
         },
         "responses": {
-          "404": {
-            "description": "Bank profile id does not exist",
+          "200": {
+            "description": "No accounts associated with a bank user",
             "content": {
               "*/*": {
                 "schema": {
@@ -168,8 +172,8 @@
               }
             }
           },
-          "200": {
-            "description": "No accounts associated with a bank user",
+          "404": {
+            "description": "Bank profile id does not exist",
             "content": {
               "*/*": {
                 "schema": {
@@ -200,8 +204,8 @@
           "required": true
         },
         "responses": {
-          "400": {
-            "description": "Could not create profile",
+          "200": {
+            "description": "Successfully created a bank profile",
             "content": {
               "*/*": {
                 "schema": {
@@ -210,8 +214,8 @@
               }
             }
           },
-          "200": {
-            "description": "Successfully created a bank profile",
+          "400": {
+            "description": "Could not create profile",
             "content": {
               "*/*": {
                 "schema": {
@@ -242,8 +246,8 @@
           "required": true
         },
         "responses": {
-          "404": {
-            "description": "Provided bank profile id could not be found",
+          "200": {
+            "description": "Successfully created account",
             "content": {
               "*/*": {
                 "schema": {
@@ -252,8 +256,8 @@
               }
             }
           },
-          "200": {
-            "description": "Successfully created account",
+          "404": {
+            "description": "Provided bank profile id could not be found",
             "content": {
               "*/*": {
                 "schema": {
@@ -335,16 +339,97 @@
           "required": true
         },
         "responses": {
-          "403": {
-            "description": "Invalid token"
-          },
           "204": {
             "description": "Password was reset successfully"
+          },
+          "403": {
+            "description": "Invalid token"
           }
         },
         "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": {
+          "200": {
+            "description": "Successfully updated notification",
+            "content": {
+              "*/*": {
+                "schema": {
+                  "type": "object"
+                }
+              }
+            }
+          },
+          "500": {
+            "description": "User is not found",
+            "content": {
+              "*/*": {
+                "schema": {
+                  "type": "object"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/item/{itemId}": {
+      "post": {
+        "tags": [
+          "Item"
+        ],
+        "summary": "Purchase an item",
+        "description": "Performs a purchase of the item by the user. Points will be deducted from the user.",
+        "operationId": "buyItem",
+        "parameters": [
+          {
+            "name": "itemId",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          }
+        ],
+        "responses": {
+          "201": {
+            "description": "Item purchased and added to inventory successfully",
+            "content": {
+              "application/json": {}
+            }
+          },
+          "403": {
+            "description": "Insufficient points to purchase the item",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "/api/images": {
       "post": {
         "tags": [
@@ -386,11 +471,36 @@
         }
       }
     },
-    "/api/goal/createGoal": {
+    "/api/goals": {
+      "get": {
+        "tags": [
+          "Goal"
+        ],
+        "summary": "Get goals",
+        "description": "Get the goals of the authenticated user",
+        "operationId": "getGoals",
+        "responses": {
+          "200": {
+            "description": "Successfully retrieved the goals",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/GoalDTO"
+                  }
+                }
+              }
+            }
+          }
+        }
+      },
       "post": {
         "tags": [
-          "goal"
+          "Goal"
         ],
+        "summary": "Create a goal",
+        "description": "Create a new goal",
         "operationId": "createGoal",
         "requestBody": {
           "content": {
@@ -402,13 +512,48 @@
           },
           "required": true
         },
+        "responses": {
+          "201": {
+            "description": "Successfully created a goal",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GoalDTO"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/goals/update-challenge": {
+      "post": {
+        "tags": [
+          "Goal"
+        ],
+        "summary": "Update a challenge",
+        "description": "Update a challenge day as completed",
+        "operationId": "updateChallenge",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/MarkChallengeDTO"
+              }
+            }
+          },
+          "required": true
+        },
         "responses": {
           "200": {
-            "description": "OK",
+            "description": "Successfully updated the challenge"
+          },
+          "401": {
+            "description": "Day is already completed or day outside of range",
             "content": {
               "*/*": {
                 "schema": {
-                  "$ref": "#/components/schemas/GoalDTO"
+                  "$ref": "#/components/schemas/ExceptionResponse"
                 }
               }
             }
@@ -416,13 +561,38 @@
         }
       }
     },
+    "/api/goals/update-challenge-amount": {
+      "post": {
+        "tags": [
+          "Goal"
+        ],
+        "summary": "Update challenge saving amount",
+        "description": "Update the challenge saving amount",
+        "operationId": "updateChallengeAmount",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/MarkChallengeDTO"
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "200": {
+            "description": "Successfully updated the challenge"
+          }
+        }
+      }
+    },
     "/api/friends/{userId}": {
       "post": {
         "tags": [
           "Friend"
         ],
         "summary": "Send a friend request",
-        "description": "Sends a new friend request to another user.",
+        "description": "Sends a new friend request to another user. A notification is sent to this user",
         "operationId": "addFriendRequest",
         "parameters": [
           {
@@ -445,7 +615,7 @@
     "/api/budget/update/{budgetId}": {
       "post": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Updates a budget",
         "description": "Updates a budget based on the budget request",
@@ -472,8 +642,8 @@
           "required": true
         },
         "responses": {
-          "500": {
-            "description": "Budget is not found",
+          "200": {
+            "description": "Successfully updated budget",
             "content": {
               "application/json": {
                 "schema": {
@@ -482,8 +652,8 @@
               }
             }
           },
-          "200": {
-            "description": "Successfully updated budget",
+          "500": {
+            "description": "Budget is not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -498,7 +668,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",
@@ -525,8 +695,8 @@
           "required": true
         },
         "responses": {
-          "500": {
-            "description": "Error updating expense",
+          "200": {
+            "description": "Successfully updated budget",
             "content": {
               "application/json": {
                 "schema": {
@@ -535,8 +705,8 @@
               }
             }
           },
-          "200": {
-            "description": "Successfully updated budget",
+          "500": {
+            "description": "Error updating expense",
             "content": {
               "application/json": {
                 "schema": {
@@ -551,7 +721,7 @@
     "/api/budget/create": {
       "post": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Create a new budget",
         "description": "Create a new budget with based on the budget request",
@@ -695,8 +865,8 @@
               }
             }
           },
-          "404": {
-            "description": "User not found",
+          "401": {
+            "description": "Invalid credentials",
             "content": {
               "application/json": {
                 "schema": {
@@ -705,8 +875,8 @@
               }
             }
           },
-          "401": {
-            "description": "Invalid credentials",
+          "404": {
+            "description": "User not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -719,6 +889,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": [
@@ -815,6 +1018,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": [
@@ -884,8 +1110,8 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Bank profile id does not exist",
+          "200": {
+            "description": "No accounts associated with a bank user",
             "content": {
               "*/*": {
                 "schema": {
@@ -897,8 +1123,8 @@
               }
             }
           },
-          "200": {
-            "description": "No accounts associated with a bank user",
+          "404": {
+            "description": "Bank profile id does not exist",
             "content": {
               "*/*": {
                 "schema": {
@@ -1080,6 +1306,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": [
@@ -1128,6 +1447,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": [
@@ -1176,6 +1518,56 @@
         }
       }
     },
+    "/api/item/store": {
+      "get": {
+        "tags": [
+          "Item"
+        ],
+        "summary": "Get available store items",
+        "description": "Retrieves all items available in the store and a flag indicating whether the user has purchased each item.",
+        "operationId": "getStore",
+        "responses": {
+          "200": {
+            "description": "List of store items fetched successfully",
+            "content": {
+              "*/*": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/ItemDTO"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/item/inventory": {
+      "get": {
+        "tags": [
+          "Item"
+        ],
+        "summary": "Get user inventory items",
+        "description": "Retrieves a list of all items currently in the inventory of the user.",
+        "operationId": "getInventory",
+        "responses": {
+          "200": {
+            "description": "List of inventory items fetched successfully",
+            "content": {
+              "*/*": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/InventoryDTO"
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "/api/images/{id}": {
       "get": {
         "tags": [
@@ -1196,23 +1588,23 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Image not found",
+          "200": {
+            "description": "Successfully retrieved the image",
             "content": {
               "*/*": {
                 "schema": {
-                  "$ref": "#/components/schemas/ExceptionResponse"
+                  "type": "string",
+                  "format": "binary"
                 }
               }
             }
           },
-          "200": {
-            "description": "Successfully retrieved the image",
+          "404": {
+            "description": "Image not found",
             "content": {
               "*/*": {
                 "schema": {
-                  "type": "string",
-                  "format": "binary"
+                  "$ref": "#/components/schemas/ExceptionResponse"
                 }
               }
             }
@@ -1221,40 +1613,28 @@
         "security": []
       }
     },
-    "/api/goal/getGoals": {
+    "/api/goals/{id}": {
       "get": {
         "tags": [
-          "goal"
+          "Goal"
         ],
-        "operationId": "getGoals",
-        "responses": {
-          "200": {
-            "description": "OK",
-            "content": {
-              "*/*": {
-                "schema": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/components/schemas/GoalDTO"
-                  }
-                }
-              }
+        "operationId": "getGoal",
+        "parameters": [
+          {
+            "name": "id",
+            "in": "query",
+            "required": true,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
             }
           }
-        }
-      }
-    },
-    "/api/goal/getGoal": {
-      "get": {
-        "tags": [
-          "goal"
         ],
-        "operationId": "getGoal",
         "responses": {
           "200": {
             "description": "OK",
             "content": {
-              "*/*": {
+              "application/json": {
                 "schema": {
                   "$ref": "#/components/schemas/GoalDTO"
                 }
@@ -1317,7 +1697,7 @@
     "/api/budget": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Get the list of budgets",
         "description": "Get all budgets related to the authenticated user",
@@ -1342,7 +1722,7 @@
     "/api/budget/{budgetId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Get the budget",
         "description": "Get budget by its id ",
@@ -1359,8 +1739,8 @@
           }
         ],
         "responses": {
-          "500": {
-            "description": "Budget is not found",
+          "200": {
+            "description": "Successfully got budget",
             "content": {
               "application/json": {
                 "schema": {
@@ -1369,8 +1749,8 @@
               }
             }
           },
-          "200": {
-            "description": "Successfully got budget",
+          "500": {
+            "description": "Budget is not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -1385,7 +1765,7 @@
     "/api/budget/expenses/{budgetId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Get the list of budgets",
         "description": "Get all budgets related to the authenticated user",
@@ -1421,7 +1801,7 @@
     "/api/budget/expense/{expenseId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Get the expense",
         "description": "Get expense by its id ",
@@ -1464,7 +1844,7 @@
     "/api/budget/delete/{budgetId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Deletes a budget",
         "description": "Deletes a budget based on provided budget id",
@@ -1481,8 +1861,8 @@
           }
         ],
         "responses": {
-          "500": {
-            "description": "Budget is not found",
+          "200": {
+            "description": "Successfully deleted budget",
             "content": {
               "application/json": {
                 "schema": {
@@ -1491,8 +1871,8 @@
               }
             }
           },
-          "200": {
-            "description": "Successfully deleted budget",
+          "500": {
+            "description": "Budget is not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -1507,7 +1887,7 @@
     "/api/budget/delete/expense/{expenseId}": {
       "get": {
         "tags": [
-          "User"
+          "Budget"
         ],
         "summary": "Deletes an expense",
         "description": "Deletes an expense based on provided expense id",
@@ -1546,44 +1926,184 @@
           }
         }
       }
-    }
-  },
-  "components": {
-    "schemas": {
-      "TransactionDTO": {
-        "type": "object",
-        "properties": {
-          "debtorBBAN": {
-            "type": "integer",
-            "format": "int64"
-          },
-          "creditorBBAN": {
-            "type": "integer",
-            "format": "int64"
-          },
-          "amount": {
-            "type": "number"
+    },
+    "/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"
+                  }
+                }
+              }
+            }
           }
         }
-      },
-      "BankProfileDTO": {
-        "type": "object",
-        "properties": {
-          "ssn": {
-            "type": "integer",
-            "format": "int64"
+      }
+    },
+    "/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"
+            }
           }
-        }
-      },
-      "Account": {
-        "type": "object",
-        "properties": {
-          "bban": {
-            "type": "integer",
-            "format": "int64"
-          },
-          "balance": {
-            "type": "number"
+        ],
+        "responses": {
+          "200": {
+            "description": "Successfully got budget",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/BadgeDTO"
+                }
+              }
+            }
+          },
+          "500": {
+            "description": "Badge is not found",
+            "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": {
+    "schemas": {
+      "TransactionDTO": {
+        "type": "object",
+        "properties": {
+          "debtorBBAN": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "creditorBBAN": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "amount": {
+            "type": "number"
+          }
+        }
+      },
+      "BankProfileDTO": {
+        "type": "object",
+        "properties": {
+          "ssn": {
+            "type": "integer",
+            "format": "int64"
+          }
+        }
+      },
+      "Account": {
+        "type": "object",
+        "properties": {
+          "bban": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "balance": {
+            "type": "number"
           },
           "bankProfile": {
             "$ref": "#/components/schemas/BankProfile"
@@ -1670,22 +2190,47 @@
           }
         }
       },
+      "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": {
-          "goalName": {
+          "name": {
             "type": "string"
           },
           "description": {
             "type": "string"
           },
           "targetAmount": {
-            "type": "integer",
-            "format": "int32"
+            "type": "number"
           },
           "targetDate": {
-            "type": "string",
-            "format": "date-time"
+            "type": "string"
           }
         }
       },
@@ -1696,44 +2241,73 @@
             "type": "integer",
             "format": "int64"
           },
-          "potentialSavingAmount": {
+          "amount": {
+            "type": "number"
+          },
+          "points": {
             "type": "integer",
             "format": "int32"
           },
-          "points": {
+          "checkDays": {
             "type": "integer",
             "format": "int32"
           },
-          "days": {
+          "totalDays": {
             "type": "integer",
             "format": "int32"
           },
-          "createdAt": {
+          "startDate": {
+            "type": "string",
+            "format": "date-time"
+          },
+          "endDate": {
             "type": "string",
             "format": "date-time"
           },
-          "dailyChallengeProgressList": {
+          "challengeTemplate": {
+            "$ref": "#/components/schemas/ChallengeTemplateDTO"
+          },
+          "progressList": {
             "type": "array",
             "items": {
-              "$ref": "#/components/schemas/DailyChallengeProgressDTO"
+              "$ref": "#/components/schemas/ProgressDTO"
             }
           }
         }
       },
-      "DailyChallengeProgressDTO": {
+      "ChallengeTemplateDTO": {
         "type": "object",
         "properties": {
           "id": {
             "type": "integer",
             "format": "int64"
           },
-          "challengeDay": {
-            "type": "integer",
-            "format": "int32"
+          "text": {
+            "type": "string"
           },
-          "completedAt": {
+          "amount": {
+            "type": "number"
+          },
+          "type": {
             "type": "string",
-            "format": "date-time"
+            "enum": [
+              "NO_COFFEE",
+              "NO_CAR",
+              "SHORTER_SHOWER",
+              "SPEND_LESS_ON_FOOD",
+              "BUY_USED_CLOTHES",
+              "LESS_SHOPPING",
+              "DROP_SUBSCRIPTION",
+              "SELL_SOMETHING",
+              "BUY_USED",
+              "EAT_PACKED_LUNCH",
+              "STOP_SHOPPING",
+              "ZERO_SPENDING",
+              "RENT_YOUR_STUFF",
+              "MEATLESS",
+              "SCREEN_TIME_LIMIT",
+              "UNPLUGGED_ENTERTAINMENT"
+            ]
           }
         }
       },
@@ -1744,24 +2318,19 @@
             "type": "integer",
             "format": "int64"
           },
-          "goalName": {
+          "name": {
             "type": "string"
           },
           "description": {
             "type": "string"
           },
           "targetAmount": {
-            "type": "integer",
-            "format": "int32"
+            "type": "number"
           },
           "targetDate": {
             "type": "string",
             "format": "date-time"
           },
-          "completedAt": {
-            "type": "string",
-            "format": "date-time"
-          },
           "createdAt": {
             "type": "string",
             "format": "date-time"
@@ -1772,37 +2341,88 @@
               "$ref": "#/components/schemas/ChallengeDTO"
             }
           },
-          "participants": {
-            "type": "array",
-            "items": {
-              "$ref": "#/components/schemas/ParticipantDTO"
-            }
+          "user": {
+            "$ref": "#/components/schemas/UserDTO"
           }
         }
       },
-      "ParticipantDTO": {
+      "ProgressDTO": {
         "type": "object",
         "properties": {
-          "role": {
-            "type": "string",
-            "enum": [
-              "CREATOR",
-              "CONTRIBUTOR"
-            ]
+          "id": {
+            "type": "integer",
+            "format": "int64"
           },
-          "user": {
-            "$ref": "#/components/schemas/ParticipantUserDTO"
+          "day": {
+            "type": "integer",
+            "format": "int32"
+          },
+          "amount": {
+            "type": "number"
+          },
+          "completedAt": {
+            "type": "string",
+            "format": "date-time"
           }
         }
       },
-      "ParticipantUserDTO": {
+      "UserDTO": {
         "type": "object",
         "properties": {
+          "id": {
+            "type": "integer",
+            "format": "int64"
+          },
           "firstName": {
             "type": "string"
           },
           "lastName": {
             "type": "string"
+          },
+          "profileImage": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "email": {
+            "type": "string"
+          },
+          "createdAt": {
+            "type": "string",
+            "format": "date-time"
+          },
+          "role": {
+            "type": "string"
+          },
+          "subscriptionLevel": {
+            "type": "string"
+          }
+        }
+      },
+      "MarkChallengeDTO": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "day": {
+            "type": "integer",
+            "format": "int32"
+          },
+          "amount": {
+            "type": "number"
+          }
+        }
+      },
+      "ExceptionResponse": {
+        "type": "object",
+        "properties": {
+          "status": {
+            "type": "integer",
+            "format": "int32"
+          },
+          "message": {
+            "type": "string"
           }
         }
       },
@@ -1835,18 +2455,6 @@
           }
         }
       },
-      "ExceptionResponse": {
-        "type": "object",
-        "properties": {
-          "status": {
-            "type": "integer",
-            "format": "int32"
-          },
-          "message": {
-            "type": "string"
-          }
-        }
-      },
       "ConfigurationDTO": {
         "type": "object",
         "properties": {
@@ -1926,56 +2534,35 @@
           }
         }
       },
-      "UserUpdateDTO": {
+      "BankIDRequest": {
         "type": "object",
         "properties": {
-          "firstName": {
+          "code": {
             "type": "string"
           },
-          "lastName": {
-            "type": "string"
-          },
-          "email": {
+          "state": {
             "type": "string"
-          },
-          "profileImage": {
-            "type": "integer",
-            "format": "int64"
-          },
-          "configuration": {
-            "$ref": "#/components/schemas/ConfigurationDTO"
           }
         }
       },
-      "UserDTO": {
+      "UserUpdateDTO": {
         "type": "object",
         "properties": {
-          "id": {
-            "type": "integer",
-            "format": "int64"
-          },
           "firstName": {
             "type": "string"
           },
           "lastName": {
             "type": "string"
           },
-          "profileImage": {
-            "type": "integer",
-            "format": "int64"
-          },
           "email": {
             "type": "string"
           },
-          "createdAt": {
-            "type": "string",
-            "format": "date-time"
-          },
-          "role": {
-            "type": "string"
+          "profileImage": {
+            "type": "integer",
+            "format": "int64"
           },
-          "subscriptionLevel": {
-            "type": "string"
+          "configuration": {
+            "$ref": "#/components/schemas/ConfigurationDTO"
           }
         }
       },
@@ -2076,6 +2663,49 @@
           }
         }
       },
+      "ItemDTO": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "itemName": {
+            "type": "string"
+          },
+          "price": {
+            "type": "integer",
+            "format": "int32"
+          },
+          "imageId": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "alreadyBought": {
+            "type": "boolean"
+          }
+        }
+      },
+      "InventoryDTO": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "itemName": {
+            "type": "string"
+          },
+          "imageId": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "boughtAt": {
+            "type": "string",
+            "format": "date-time"
+          }
+        }
+      },
       "BudgetResponseDTO": {
         "type": "object",
         "properties": {
@@ -2116,6 +2746,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/api/index.ts b/src/api/index.ts
index 0a46cc0e4ddd97a94230ae6cffde43965f222b93..4ab22c2112459939cb385110bf7011d567d948a2 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -11,30 +11,35 @@ export type { Account } from './models/Account';
 export type { AccountRequestDTO } from './models/AccountRequestDTO';
 export type { AccountResponseDTO } from './models/AccountResponseDTO';
 export type { AuthenticationResponse } from './models/AuthenticationResponse';
+export type { BadgeDTO } from './models/BadgeDTO';
 export type { BankAccountDTO } from './models/BankAccountDTO';
+export type { BankIDRequest } from './models/BankIDRequest';
 export type { BankProfile } from './models/BankProfile';
 export type { BankProfileDTO } from './models/BankProfileDTO';
 export type { BankProfileResponseDTO } from './models/BankProfileResponseDTO';
 export type { BudgetRequestDTO } from './models/BudgetRequestDTO';
 export type { BudgetResponseDTO } from './models/BudgetResponseDTO';
 export type { ChallengeDTO } from './models/ChallengeDTO';
+export { ChallengeTemplateDTO } from './models/ChallengeTemplateDTO';
 export type { ConfigurationDTO } from './models/ConfigurationDTO';
 export type { CreateGoalDTO } from './models/CreateGoalDTO';
-export type { DailyChallengeProgressDTO } from './models/DailyChallengeProgressDTO';
 export type { ExceptionResponse } from './models/ExceptionResponse';
 export type { ExpenseRequestDTO } from './models/ExpenseRequestDTO';
 export type { ExpenseResponseDTO } from './models/ExpenseResponseDTO';
 export type { FeedbackRequestDTO } from './models/FeedbackRequestDTO';
 export type { FeedbackResponseDTO } from './models/FeedbackResponseDTO';
 export type { GoalDTO } from './models/GoalDTO';
+export type { InventoryDTO } from './models/InventoryDTO';
+export type { ItemDTO } from './models/ItemDTO';
 export type { LeaderboardDTO } from './models/LeaderboardDTO';
 export type { LeaderboardEntryDTO } from './models/LeaderboardEntryDTO';
 export type { LoginRequest } from './models/LoginRequest';
-export { ParticipantDTO } from './models/ParticipantDTO';
-export type { ParticipantUserDTO } from './models/ParticipantUserDTO';
+export type { MarkChallengeDTO } from './models/MarkChallengeDTO';
+export { NotificationDTO } from './models/NotificationDTO';
 export type { PasswordResetDTO } from './models/PasswordResetDTO';
 export type { PasswordUpdateDTO } from './models/PasswordUpdateDTO';
 export type { ProfileDTO } from './models/ProfileDTO';
+export type { ProgressDTO } from './models/ProgressDTO';
 export type { SignUpRequest } from './models/SignUpRequest';
 export type { TransactionDTO } from './models/TransactionDTO';
 export type { UserDTO } from './models/UserDTO';
@@ -42,10 +47,15 @@ export type { UserUpdateDTO } from './models/UserUpdateDTO';
 
 export { AccountControllerService } from './services/AccountControllerService';
 export { AuthenticationService } from './services/AuthenticationService';
+export { BadgeService } from './services/BadgeService';
 export { BankProfileControllerService } from './services/BankProfileControllerService';
+export { BudgetService } from './services/BudgetService';
 export { FriendService } from './services/FriendService';
 export { GoalService } from './services/GoalService';
 export { ImageService } from './services/ImageService';
+export { ItemService } from './services/ItemService';
 export { LeaderboardService } from './services/LeaderboardService';
+export { NotificationService } from './services/NotificationService';
+export { RedirectService } from './services/RedirectService';
 export { TransactionControllerService } from './services/TransactionControllerService';
 export { UserService } from './services/UserService';
diff --git a/src/api/models/BadgeDTO.ts b/src/api/models/BadgeDTO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9fd3d054da77c4e8adcef24d0a2853b0bba641f5
--- /dev/null
+++ b/src/api/models/BadgeDTO.ts
@@ -0,0 +1,11 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+export type BadgeDTO = {
+    id?: number;
+    badgeName?: string;
+    criteria?: number;
+    imageId?: number;
+};
+
diff --git a/src/api/models/ParticipantUserDTO.ts b/src/api/models/BankIDRequest.ts
similarity index 62%
rename from src/api/models/ParticipantUserDTO.ts
rename to src/api/models/BankIDRequest.ts
index 5499c09f765c2b01e58efea75581a8f14d3f9e40..225dc8bb202284c5438e1a0f8d01bdd9d85a2231 100644
--- a/src/api/models/ParticipantUserDTO.ts
+++ b/src/api/models/BankIDRequest.ts
@@ -2,8 +2,8 @@
 /* istanbul ignore file */
 /* tslint:disable */
 /* eslint-disable */
-export type ParticipantUserDTO = {
-    firstName?: string;
-    lastName?: string;
+export type BankIDRequest = {
+    code?: string;
+    state?: string;
 };
 
diff --git a/src/api/models/ChallengeDTO.ts b/src/api/models/ChallengeDTO.ts
index f5bd38d483c363d921274e9ed77dbd5e6d4aef75..3ccf0f055c0ffb92c2f2612a02aaf5e25d3c856b 100644
--- a/src/api/models/ChallengeDTO.ts
+++ b/src/api/models/ChallengeDTO.ts
@@ -2,13 +2,17 @@
 /* istanbul ignore file */
 /* tslint:disable */
 /* eslint-disable */
-import type { DailyChallengeProgressDTO } from './DailyChallengeProgressDTO';
+import type { ChallengeTemplateDTO } from './ChallengeTemplateDTO';
+import type { ProgressDTO } from './ProgressDTO';
 export type ChallengeDTO = {
     id?: number;
-    potentialSavingAmount?: number;
+    amount?: number;
     points?: number;
-    days?: number;
-    createdAt?: string;
-    dailyChallengeProgressList?: Array<DailyChallengeProgressDTO>;
+    checkDays?: number;
+    totalDays?: number;
+    startDate?: string;
+    endDate?: string;
+    challengeTemplate?: ChallengeTemplateDTO;
+    progressList?: Array<ProgressDTO>;
 };
 
diff --git a/src/api/models/ChallengeTemplateDTO.ts b/src/api/models/ChallengeTemplateDTO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..323e64de48b8a201d3c4da78e5de83a904b0b0b1
--- /dev/null
+++ b/src/api/models/ChallengeTemplateDTO.ts
@@ -0,0 +1,31 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+export type ChallengeTemplateDTO = {
+    id?: number;
+    text?: string;
+    amount?: number;
+    type?: ChallengeTemplateDTO.type;
+};
+export namespace ChallengeTemplateDTO {
+    export enum type {
+        NO_COFFEE = 'NO_COFFEE',
+        NO_CAR = 'NO_CAR',
+        SHORTER_SHOWER = 'SHORTER_SHOWER',
+        SPEND_LESS_ON_FOOD = 'SPEND_LESS_ON_FOOD',
+        BUY_USED_CLOTHES = 'BUY_USED_CLOTHES',
+        LESS_SHOPPING = 'LESS_SHOPPING',
+        DROP_SUBSCRIPTION = 'DROP_SUBSCRIPTION',
+        SELL_SOMETHING = 'SELL_SOMETHING',
+        BUY_USED = 'BUY_USED',
+        EAT_PACKED_LUNCH = 'EAT_PACKED_LUNCH',
+        STOP_SHOPPING = 'STOP_SHOPPING',
+        ZERO_SPENDING = 'ZERO_SPENDING',
+        RENT_YOUR_STUFF = 'RENT_YOUR_STUFF',
+        MEATLESS = 'MEATLESS',
+        SCREEN_TIME_LIMIT = 'SCREEN_TIME_LIMIT',
+        UNPLUGGED_ENTERTAINMENT = 'UNPLUGGED_ENTERTAINMENT',
+    }
+}
+
diff --git a/src/api/models/CreateGoalDTO.ts b/src/api/models/CreateGoalDTO.ts
index 61eb0457b42b2aebf8be3c560bcd62d2346648e4..2e6e535f0b0a2317ef26e76c8db8f53572cbcd8d 100644
--- a/src/api/models/CreateGoalDTO.ts
+++ b/src/api/models/CreateGoalDTO.ts
@@ -3,7 +3,7 @@
 /* tslint:disable */
 /* eslint-disable */
 export type CreateGoalDTO = {
-    goalName?: string;
+    name?: string;
     description?: string;
     targetAmount?: number;
     targetDate?: string;
diff --git a/src/api/models/GoalDTO.ts b/src/api/models/GoalDTO.ts
index 004eb49fd0bec010a1d4227bac6ec6bbc3daea50..c24e9abfb1d37acc49db64803d4da80a901960ce 100644
--- a/src/api/models/GoalDTO.ts
+++ b/src/api/models/GoalDTO.ts
@@ -3,16 +3,15 @@
 /* tslint:disable */
 /* eslint-disable */
 import type { ChallengeDTO } from './ChallengeDTO';
-import type { ParticipantDTO } from './ParticipantDTO';
+import type { UserDTO } from './UserDTO';
 export type GoalDTO = {
     id?: number;
-    goalName?: string;
+    name?: string;
     description?: string;
     targetAmount?: number;
     targetDate?: string;
-    completedAt?: string;
     createdAt?: string;
     challenges?: Array<ChallengeDTO>;
-    participants?: Array<ParticipantDTO>;
+    user?: UserDTO;
 };
 
diff --git a/src/api/models/InventoryDTO.ts b/src/api/models/InventoryDTO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..826a6b61da10137a07982263be585d3be2571bfa
--- /dev/null
+++ b/src/api/models/InventoryDTO.ts
@@ -0,0 +1,11 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+export type InventoryDTO = {
+    id?: number;
+    itemName?: string;
+    imageId?: number;
+    boughtAt?: string;
+};
+
diff --git a/src/api/models/ItemDTO.ts b/src/api/models/ItemDTO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b2c65c3135bb7307dd11c25a5c4defe7781af209
--- /dev/null
+++ b/src/api/models/ItemDTO.ts
@@ -0,0 +1,12 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+export type ItemDTO = {
+    id?: number;
+    itemName?: string;
+    price?: number;
+    imageId?: number;
+    alreadyBought?: boolean;
+};
+
diff --git a/src/api/models/MarkChallengeDTO.ts b/src/api/models/MarkChallengeDTO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..09c06b8a91f40448ceb2fe25867da13de7f713cb
--- /dev/null
+++ b/src/api/models/MarkChallengeDTO.ts
@@ -0,0 +1,10 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+export type MarkChallengeDTO = {
+    id?: number;
+    day?: number;
+    amount?: number;
+};
+
diff --git a/src/api/models/NotificationDTO.ts b/src/api/models/NotificationDTO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2834bf8466bb776108d1054e1278c96a6ce69636
--- /dev/null
+++ b/src/api/models/NotificationDTO.ts
@@ -0,0 +1,19 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+export type NotificationDTO = {
+    id?: number;
+    message?: string;
+    unread?: boolean;
+    notificationType?: NotificationDTO.notificationType;
+    createdAt?: string;
+};
+export namespace NotificationDTO {
+    export enum notificationType {
+        BADGE = 'BADGE',
+        FRIEND_REQUEST = 'FRIEND_REQUEST',
+        COMPLETED_GOAL = 'COMPLETED_GOAL',
+    }
+}
+
diff --git a/src/api/models/ParticipantDTO.ts b/src/api/models/ParticipantDTO.ts
deleted file mode 100644
index 0615b50834924e46416818dffbb00718b3607bab..0000000000000000000000000000000000000000
--- a/src/api/models/ParticipantDTO.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/* generated using openapi-typescript-codegen -- do not edit */
-/* istanbul ignore file */
-/* tslint:disable */
-/* eslint-disable */
-import type { ParticipantUserDTO } from './ParticipantUserDTO';
-export type ParticipantDTO = {
-    role?: ParticipantDTO.role;
-    user?: ParticipantUserDTO;
-};
-export namespace ParticipantDTO {
-    export enum role {
-        CREATOR = 'CREATOR',
-        CONTRIBUTOR = 'CONTRIBUTOR',
-    }
-}
-
diff --git a/src/api/models/DailyChallengeProgressDTO.ts b/src/api/models/ProgressDTO.ts
similarity index 72%
rename from src/api/models/DailyChallengeProgressDTO.ts
rename to src/api/models/ProgressDTO.ts
index c7bda736cefef3aebff0533272807cde205e16ee..cb6f11746458912e9efef6438bb3278ff585c2d6 100644
--- a/src/api/models/DailyChallengeProgressDTO.ts
+++ b/src/api/models/ProgressDTO.ts
@@ -2,9 +2,10 @@
 /* istanbul ignore file */
 /* tslint:disable */
 /* eslint-disable */
-export type DailyChallengeProgressDTO = {
+export type ProgressDTO = {
     id?: number;
-    challengeDay?: number;
+    day?: number;
+    amount?: number;
     completedAt?: string;
 };
 
diff --git a/src/api/services/AuthenticationService.ts b/src/api/services/AuthenticationService.ts
index 48c819ab0a448c84d87fce77baf7d9b54b49dc51..ac619756c90377b2090d430cbcd47e746eb52af9 100644
--- a/src/api/services/AuthenticationService.ts
+++ b/src/api/services/AuthenticationService.ts
@@ -3,6 +3,7 @@
 /* tslint:disable */
 /* eslint-disable */
 import type { AuthenticationResponse } from '../models/AuthenticationResponse';
+import type { BankIDRequest } from '../models/BankIDRequest';
 import type { LoginRequest } from '../models/LoginRequest';
 import type { SignUpRequest } from '../models/SignUpRequest';
 import type { CancelablePromise } from '../core/CancelablePromise';
@@ -74,4 +75,22 @@ export class AuthenticationService {
             },
         });
     }
+    /**
+     * Authenticate a BankID request
+     * Authenticate a BankID request
+     * @returns AuthenticationResponse If the authentication is successful
+     * @throws ApiError
+     */
+    public static bankIdAuthentication({
+        requestBody,
+    }: {
+        requestBody: BankIDRequest,
+    }): CancelablePromise<AuthenticationResponse> {
+        return __request(OpenAPI, {
+            method: 'POST',
+            url: '/api/auth/bank-id',
+            body: requestBody,
+            mediaType: 'application/json',
+        });
+    }
 }
diff --git a/src/api/services/BadgeService.ts b/src/api/services/BadgeService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f014b589ece802008c9e9da2669308001665c046
--- /dev/null
+++ b/src/api/services/BadgeService.ts
@@ -0,0 +1,80 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+import type { BadgeDTO } from '../models/BadgeDTO';
+import type { CancelablePromise } from '../core/CancelablePromise';
+import { OpenAPI } from '../core/OpenAPI';
+import { request as __request } from '../core/request';
+export class BadgeService {
+    /**
+     * Get the list of badges
+     * Get all badges stored in the database
+     * @returns BadgeDTO Successfully got badges
+     * @throws ApiError
+     */
+    public static getAllBadges(): CancelablePromise<Array<BadgeDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/badge',
+        });
+    }
+    /**
+     * Get the budget
+     * Get budget by its id
+     * @returns BadgeDTO Successfully got budget
+     * @throws ApiError
+     */
+    public static getBadge({
+        badgeId,
+    }: {
+        badgeId: number,
+    }): CancelablePromise<BadgeDTO> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/badge/{badgeId}',
+            path: {
+                'badgeId': badgeId,
+            },
+            errors: {
+                500: `Badge is not found`,
+            },
+        });
+    }
+    /**
+     * Updates unlocked badges
+     * Checks if a user has met the criteria for unlocking badges
+     * @returns any Successfully updated badges
+     * @throws ApiError
+     */
+    public static updateUnlockedBadges(): CancelablePromise<Record<string, any>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/badge/update',
+        });
+    }
+    /**
+     * Get the list of badges
+     * Get all badges unlocked by the user
+     * @returns BadgeDTO Successfully got badges
+     * @throws ApiError
+     */
+    public static getBadgesUnlockedByUser(): CancelablePromise<Array<BadgeDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/badge/unlocked',
+        });
+    }
+    /**
+     * Get the list of badges
+     * Get all badges not unlocked by the user
+     * @returns BadgeDTO Successfully got badges
+     * @throws ApiError
+     */
+    public static getBadgesNotUnlockedByUser(): CancelablePromise<Array<BadgeDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/badge/locked',
+        });
+    }
+}
diff --git a/src/api/services/BudgetService.ts b/src/api/services/BudgetService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..219c866aa5f4ed51c86e3d10404e1e197898be1d
--- /dev/null
+++ b/src/api/services/BudgetService.ts
@@ -0,0 +1,202 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+import type { BudgetRequestDTO } from '../models/BudgetRequestDTO';
+import type { BudgetResponseDTO } from '../models/BudgetResponseDTO';
+import type { ExpenseRequestDTO } from '../models/ExpenseRequestDTO';
+import type { ExpenseResponseDTO } from '../models/ExpenseResponseDTO';
+import type { CancelablePromise } from '../core/CancelablePromise';
+import { OpenAPI } from '../core/OpenAPI';
+import { request as __request } from '../core/request';
+export class BudgetService {
+    /**
+     * Updates a budget
+     * Updates a budget based on the budget request
+     * @returns any Successfully updated budget
+     * @throws ApiError
+     */
+    public static updateBudget({
+        budgetId,
+        requestBody,
+    }: {
+        budgetId: number,
+        requestBody: BudgetRequestDTO,
+    }): CancelablePromise<Record<string, any>> {
+        return __request(OpenAPI, {
+            method: 'POST',
+            url: '/api/budget/update/{budgetId}',
+            path: {
+                'budgetId': budgetId,
+            },
+            body: requestBody,
+            mediaType: 'application/json',
+            errors: {
+                500: `Budget is not found`,
+            },
+        });
+    }
+    /**
+     * Created/Updates an expense
+     * Creates/Updates a budget based on the budget request
+     * @returns any Successfully updated budget
+     * @throws ApiError
+     */
+    public static updateExpense({
+        budgetId,
+        requestBody,
+    }: {
+        budgetId: number,
+        requestBody: ExpenseRequestDTO,
+    }): CancelablePromise<Record<string, any>> {
+        return __request(OpenAPI, {
+            method: 'POST',
+            url: '/api/budget/update/expense/{budgetId}',
+            path: {
+                'budgetId': budgetId,
+            },
+            body: requestBody,
+            mediaType: 'application/json',
+            errors: {
+                500: `Error updating expense`,
+            },
+        });
+    }
+    /**
+     * Create a new budget
+     * Create a new budget with based on the budget request
+     * @returns any Successfully created new budget
+     * @throws ApiError
+     */
+    public static createBudget({
+        requestBody,
+    }: {
+        requestBody: BudgetRequestDTO,
+    }): CancelablePromise<Record<string, any>> {
+        return __request(OpenAPI, {
+            method: 'POST',
+            url: '/api/budget/create',
+            body: requestBody,
+            mediaType: 'application/json',
+        });
+    }
+    /**
+     * Get the list of budgets
+     * Get all budgets related to the authenticated user
+     * @returns BudgetResponseDTO Successfully got budgets
+     * @throws ApiError
+     */
+    public static getBudgetsByUser(): CancelablePromise<Array<BudgetResponseDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/budget',
+        });
+    }
+    /**
+     * Get the budget
+     * Get budget by its id
+     * @returns BudgetResponseDTO Successfully got budget
+     * @throws ApiError
+     */
+    public static getBudget({
+        budgetId,
+    }: {
+        budgetId: number,
+    }): CancelablePromise<BudgetResponseDTO> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/budget/{budgetId}',
+            path: {
+                'budgetId': budgetId,
+            },
+            errors: {
+                500: `Budget is not found`,
+            },
+        });
+    }
+    /**
+     * Get the list of budgets
+     * Get all budgets related to the authenticated user
+     * @returns ExpenseResponseDTO Successfully got expenses
+     * @throws ApiError
+     */
+    public static getExpenses({
+        budgetId,
+    }: {
+        budgetId: number,
+    }): CancelablePromise<Array<ExpenseResponseDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/budget/expenses/{budgetId}',
+            path: {
+                'budgetId': budgetId,
+            },
+        });
+    }
+    /**
+     * Get the expense
+     * Get expense by its id
+     * @returns ExpenseResponseDTO Successfully got expense
+     * @throws ApiError
+     */
+    public static getExpense({
+        expenseId,
+    }: {
+        expenseId: number,
+    }): CancelablePromise<ExpenseResponseDTO> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/budget/expense/{expenseId}',
+            path: {
+                'expenseId': expenseId,
+            },
+            errors: {
+                500: `Expense is not found`,
+            },
+        });
+    }
+    /**
+     * Deletes a budget
+     * Deletes a budget based on provided budget id
+     * @returns any Successfully deleted budget
+     * @throws ApiError
+     */
+    public static deleteBudget({
+        budgetId,
+    }: {
+        budgetId: number,
+    }): CancelablePromise<Record<string, any>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/budget/delete/{budgetId}',
+            path: {
+                'budgetId': budgetId,
+            },
+            errors: {
+                500: `Budget is not found`,
+            },
+        });
+    }
+    /**
+     * Deletes an expense
+     * Deletes an expense based on provided expense id
+     * @returns any Successfully deleted expense
+     * @throws ApiError
+     */
+    public static deleteExpense({
+        expenseId,
+    }: {
+        expenseId: number,
+    }): CancelablePromise<Record<string, any>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/budget/delete/expense/{expenseId}',
+            path: {
+                'expenseId': expenseId,
+            },
+            errors: {
+                500: `Expense is not found`,
+            },
+        });
+    }
+}
diff --git a/src/api/services/FriendService.ts b/src/api/services/FriendService.ts
index 027c6a7e55949b0ab3663cea767d451121593f3d..70b531d682d20c95dc134b4f0d694df49fb548fb 100644
--- a/src/api/services/FriendService.ts
+++ b/src/api/services/FriendService.ts
@@ -53,7 +53,7 @@ export class FriendService {
     }
     /**
      * Send a friend request
-     * Sends a new friend request to another user.
+     * Sends a new friend request to another user. A notification is sent to this user
      * @returns any Friend request successfully created
      * @throws ApiError
      */
diff --git a/src/api/services/GoalService.ts b/src/api/services/GoalService.ts
index 28ae857fcaf1e5268dc6aefc5ba9c9e0d27398f2..b3bfa72d953cab2252919fc7ab21566db845e51f 100644
--- a/src/api/services/GoalService.ts
+++ b/src/api/services/GoalService.ts
@@ -4,12 +4,27 @@
 /* eslint-disable */
 import type { CreateGoalDTO } from '../models/CreateGoalDTO';
 import type { GoalDTO } from '../models/GoalDTO';
+import type { MarkChallengeDTO } from '../models/MarkChallengeDTO';
 import type { CancelablePromise } from '../core/CancelablePromise';
 import { OpenAPI } from '../core/OpenAPI';
 import { request as __request } from '../core/request';
 export class GoalService {
     /**
-     * @returns GoalDTO OK
+     * Get goals
+     * Get the goals of the authenticated user
+     * @returns GoalDTO Successfully retrieved the goals
+     * @throws ApiError
+     */
+    public static getGoals(): CancelablePromise<Array<GoalDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/goals',
+        });
+    }
+    /**
+     * Create a goal
+     * Create a new goal
+     * @returns GoalDTO Successfully created a goal
      * @throws ApiError
      */
     public static createGoal({
@@ -19,29 +34,65 @@ export class GoalService {
     }): CancelablePromise<GoalDTO> {
         return __request(OpenAPI, {
             method: 'POST',
-            url: '/api/goal/createGoal',
+            url: '/api/goals',
             body: requestBody,
             mediaType: 'application/json',
         });
     }
     /**
-     * @returns GoalDTO OK
+     * Update a challenge
+     * Update a challenge day as completed
+     * @returns any Successfully updated the challenge
      * @throws ApiError
      */
-    public static getGoals(): CancelablePromise<Array<GoalDTO>> {
+    public static updateChallenge({
+        requestBody,
+    }: {
+        requestBody: MarkChallengeDTO,
+    }): CancelablePromise<any> {
         return __request(OpenAPI, {
-            method: 'GET',
-            url: '/api/goal/getGoals',
+            method: 'POST',
+            url: '/api/goals/update-challenge',
+            body: requestBody,
+            mediaType: 'application/json',
+            errors: {
+                401: `Day is already completed or day outside of range`,
+            },
+        });
+    }
+    /**
+     * Update challenge saving amount
+     * Update the challenge saving amount
+     * @returns any Successfully updated the challenge
+     * @throws ApiError
+     */
+    public static updateChallengeAmount({
+        requestBody,
+    }: {
+        requestBody: MarkChallengeDTO,
+    }): CancelablePromise<any> {
+        return __request(OpenAPI, {
+            method: 'POST',
+            url: '/api/goals/update-challenge-amount',
+            body: requestBody,
+            mediaType: 'application/json',
         });
     }
     /**
      * @returns GoalDTO OK
      * @throws ApiError
      */
-    public static getGoal(): CancelablePromise<GoalDTO> {
+    public static getGoal({
+        id,
+    }: {
+        id: number,
+    }): CancelablePromise<GoalDTO> {
         return __request(OpenAPI, {
             method: 'GET',
-            url: '/api/goal/getGoal',
+            url: '/api/goals/{id}',
+            query: {
+                'id': id,
+            },
         });
     }
 }
diff --git a/src/api/services/ItemService.ts b/src/api/services/ItemService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ae2a3a8997ee79ac0fd22e289c153666a79b7396
--- /dev/null
+++ b/src/api/services/ItemService.ts
@@ -0,0 +1,57 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+import type { InventoryDTO } from '../models/InventoryDTO';
+import type { ItemDTO } from '../models/ItemDTO';
+import type { CancelablePromise } from '../core/CancelablePromise';
+import { OpenAPI } from '../core/OpenAPI';
+import { request as __request } from '../core/request';
+export class ItemService {
+    /**
+     * Purchase an item
+     * Performs a purchase of the item by the user. Points will be deducted from the user.
+     * @returns any Item purchased and added to inventory successfully
+     * @throws ApiError
+     */
+    public static buyItem({
+        itemId,
+    }: {
+        itemId: number,
+    }): CancelablePromise<any> {
+        return __request(OpenAPI, {
+            method: 'POST',
+            url: '/api/item/{itemId}',
+            path: {
+                'itemId': itemId,
+            },
+            errors: {
+                403: `Insufficient points to purchase the item`,
+            },
+        });
+    }
+    /**
+     * Get available store items
+     * Retrieves all items available in the store and a flag indicating whether the user has purchased each item.
+     * @returns ItemDTO List of store items fetched successfully
+     * @throws ApiError
+     */
+    public static getStore(): CancelablePromise<Array<ItemDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/item/store',
+        });
+    }
+    /**
+     * Get user inventory items
+     * Retrieves a list of all items currently in the inventory of the user.
+     * @returns InventoryDTO List of inventory items fetched successfully
+     * @throws ApiError
+     */
+    public static getInventory(): CancelablePromise<Array<InventoryDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/item/inventory',
+        });
+    }
+}
diff --git a/src/api/services/LeaderboardService.ts b/src/api/services/LeaderboardService.ts
index f77a3cc9b2e67de48357385ed47ae8c523b2c0e0..8a38209a1808d6879f636efd4613b5f53b65f23c 100644
--- a/src/api/services/LeaderboardService.ts
+++ b/src/api/services/LeaderboardService.ts
@@ -30,6 +30,18 @@ export class LeaderboardService {
             },
         });
     }
+    /**
+     * Get sum of total points globally
+     * Get the sum of the total points of all users globally
+     * @returns number Successfully retrieved total points
+     * @throws ApiError
+     */
+    public static getTotalPoints(): CancelablePromise<number> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/leaderboard/total-points',
+        });
+    }
     /**
      * @returns LeaderboardDTO OK
      * @throws ApiError
diff --git a/src/api/services/NotificationService.ts b/src/api/services/NotificationService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..331fc68ba61a26c7fd8b51972a2b2e0de381ce45
--- /dev/null
+++ b/src/api/services/NotificationService.ts
@@ -0,0 +1,77 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+import type { NotificationDTO } from '../models/NotificationDTO';
+import type { CancelablePromise } from '../core/CancelablePromise';
+import { OpenAPI } from '../core/OpenAPI';
+import { request as __request } from '../core/request';
+export class NotificationService {
+    /**
+     * Updates a notification
+     * Updates a notification based on the request
+     * @returns any Successfully updated notification
+     * @throws ApiError
+     */
+    public static updateNotification({
+        requestBody,
+    }: {
+        requestBody: NotificationDTO,
+    }): CancelablePromise<Record<string, any>> {
+        return __request(OpenAPI, {
+            method: 'POST',
+            url: '/api/notification/update',
+            body: requestBody,
+            mediaType: 'application/json',
+            errors: {
+                500: `User is not found`,
+            },
+        });
+    }
+    /**
+     * Get the list of notifications
+     * Get all notifications to a user
+     * @returns NotificationDTO Successfully got notifications
+     * @throws ApiError
+     */
+    public static getNotificationByUser(): CancelablePromise<Array<NotificationDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/notification',
+        });
+    }
+    /**
+     * Get the notification
+     * Get notification by its id
+     * @returns NotificationDTO Successfully got notification
+     * @throws ApiError
+     */
+    public static getNotification({
+        notificationId,
+    }: {
+        notificationId: number,
+    }): CancelablePromise<NotificationDTO> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/notification/{notificationId}',
+            path: {
+                'notificationId': notificationId,
+            },
+            errors: {
+                500: `Notification is not found`,
+            },
+        });
+    }
+    /**
+     * Get the list of unread notifications
+     * Get all unread notifications to a user
+     * @returns NotificationDTO Successfully got notifications
+     * @throws ApiError
+     */
+    public static getUnreadNotificationByUser(): CancelablePromise<Array<NotificationDTO>> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/api/notification/unread',
+        });
+    }
+}
diff --git a/src/api/services/RedirectService.ts b/src/api/services/RedirectService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1dbf1cfac5dedad6ccd91c038991c0cb961ed24e
--- /dev/null
+++ b/src/api/services/RedirectService.ts
@@ -0,0 +1,26 @@
+/* generated using openapi-typescript-codegen -- do not edit */
+/* istanbul ignore file */
+/* tslint:disable */
+/* eslint-disable */
+import type { CancelablePromise } from '../core/CancelablePromise';
+import { OpenAPI } from '../core/OpenAPI';
+import { request as __request } from '../core/request';
+export class RedirectService {
+    /**
+     * @returns any OK
+     * @throws ApiError
+     */
+    public static consumeCallback({
+        state,
+    }: {
+        state: string,
+    }): CancelablePromise<any> {
+        return __request(OpenAPI, {
+            method: 'GET',
+            url: '/redirect',
+            query: {
+                'state': state,
+            },
+        });
+    }
+}
diff --git a/src/api/services/UserService.ts b/src/api/services/UserService.ts
index 593418a27bb5f5beb68aa4d7d017da91be1df7a3..51df6e46b965ecbb438f7dcfb68258422e13d22e 100644
--- a/src/api/services/UserService.ts
+++ b/src/api/services/UserService.ts
@@ -4,10 +4,6 @@
 /* eslint-disable */
 import type { Account } from '../models/Account';
 import type { BankAccountDTO } from '../models/BankAccountDTO';
-import type { BudgetRequestDTO } from '../models/BudgetRequestDTO';
-import type { BudgetResponseDTO } from '../models/BudgetResponseDTO';
-import type { ExpenseRequestDTO } from '../models/ExpenseRequestDTO';
-import type { ExpenseResponseDTO } from '../models/ExpenseResponseDTO';
 import type { FeedbackRequestDTO } from '../models/FeedbackRequestDTO';
 import type { FeedbackResponseDTO } from '../models/FeedbackResponseDTO';
 import type { PasswordResetDTO } from '../models/PasswordResetDTO';
@@ -95,76 +91,6 @@ export class UserService {
             },
         });
     }
-    /**
-     * Updates a budget
-     * Updates a budget based on the budget request
-     * @returns any Successfully updated budget
-     * @throws ApiError
-     */
-    public static updateBudget({
-        budgetId,
-        requestBody,
-    }: {
-        budgetId: number,
-        requestBody: BudgetRequestDTO,
-    }): CancelablePromise<Record<string, any>> {
-        return __request(OpenAPI, {
-            method: 'POST',
-            url: '/api/budget/update/{budgetId}',
-            path: {
-                'budgetId': budgetId,
-            },
-            body: requestBody,
-            mediaType: 'application/json',
-            errors: {
-                500: `Budget is not found`,
-            },
-        });
-    }
-    /**
-     * Created/Updates an expense
-     * Creates/Updates a budget based on the budget request
-     * @returns any Successfully updated budget
-     * @throws ApiError
-     */
-    public static updateExpense({
-        budgetId,
-        requestBody,
-    }: {
-        budgetId: number,
-        requestBody: ExpenseRequestDTO,
-    }): CancelablePromise<Record<string, any>> {
-        return __request(OpenAPI, {
-            method: 'POST',
-            url: '/api/budget/update/expense/{budgetId}',
-            path: {
-                'budgetId': budgetId,
-            },
-            body: requestBody,
-            mediaType: 'application/json',
-            errors: {
-                500: `Error updating expense`,
-            },
-        });
-    }
-    /**
-     * Create a new budget
-     * Create a new budget with based on the budget request
-     * @returns any Successfully created new budget
-     * @throws ApiError
-     */
-    public static createBudget({
-        requestBody,
-    }: {
-        requestBody: BudgetRequestDTO,
-    }): CancelablePromise<Record<string, any>> {
-        return __request(OpenAPI, {
-            method: 'POST',
-            url: '/api/budget/create',
-            body: requestBody,
-            mediaType: 'application/json',
-        });
-    }
     /**
      * Update a profile
      * Update the profile of the authenticated user
@@ -306,123 +232,4 @@ export class UserService {
             url: '/api/users/get-feedback',
         });
     }
-    /**
-     * Get the list of budgets
-     * Get all budgets related to the authenticated user
-     * @returns BudgetResponseDTO Successfully got budgets
-     * @throws ApiError
-     */
-    public static getBudgetsByUser(): CancelablePromise<Array<BudgetResponseDTO>> {
-        return __request(OpenAPI, {
-            method: 'GET',
-            url: '/api/budget',
-        });
-    }
-    /**
-     * Get the budget
-     * Get budget by its id
-     * @returns BudgetResponseDTO Successfully got budget
-     * @throws ApiError
-     */
-    public static getBudget({
-        budgetId,
-    }: {
-        budgetId: number,
-    }): CancelablePromise<BudgetResponseDTO> {
-        return __request(OpenAPI, {
-            method: 'GET',
-            url: '/api/budget/{budgetId}',
-            path: {
-                'budgetId': budgetId,
-            },
-            errors: {
-                500: `Budget is not found`,
-            },
-        });
-    }
-    /**
-     * Get the list of budgets
-     * Get all budgets related to the authenticated user
-     * @returns ExpenseResponseDTO Successfully got expenses
-     * @throws ApiError
-     */
-    public static getExpenses({
-        budgetId,
-    }: {
-        budgetId: number,
-    }): CancelablePromise<Array<ExpenseResponseDTO>> {
-        return __request(OpenAPI, {
-            method: 'GET',
-            url: '/api/budget/expenses/{budgetId}',
-            path: {
-                'budgetId': budgetId,
-            },
-        });
-    }
-    /**
-     * Get the expense
-     * Get expense by its id
-     * @returns ExpenseResponseDTO Successfully got expense
-     * @throws ApiError
-     */
-    public static getExpense({
-        expenseId,
-    }: {
-        expenseId: number,
-    }): CancelablePromise<ExpenseResponseDTO> {
-        return __request(OpenAPI, {
-            method: 'GET',
-            url: '/api/budget/expense/{expenseId}',
-            path: {
-                'expenseId': expenseId,
-            },
-            errors: {
-                500: `Expense is not found`,
-            },
-        });
-    }
-    /**
-     * Deletes a budget
-     * Deletes a budget based on provided budget id
-     * @returns any Successfully deleted budget
-     * @throws ApiError
-     */
-    public static deleteBudget({
-        budgetId,
-    }: {
-        budgetId: number,
-    }): CancelablePromise<Record<string, any>> {
-        return __request(OpenAPI, {
-            method: 'GET',
-            url: '/api/budget/delete/{budgetId}',
-            path: {
-                'budgetId': budgetId,
-            },
-            errors: {
-                500: `Budget is not found`,
-            },
-        });
-    }
-    /**
-     * Deletes an expense
-     * Deletes an expense based on provided expense id
-     * @returns any Successfully deleted expense
-     * @throws ApiError
-     */
-    public static deleteExpense({
-        expenseId,
-    }: {
-        expenseId: number,
-    }): CancelablePromise<Record<string, any>> {
-        return __request(OpenAPI, {
-            method: 'GET',
-            url: '/api/budget/delete/expense/{expenseId}',
-            path: {
-                'expenseId': expenseId,
-            },
-            errors: {
-                500: `Expense is not found`,
-            },
-        });
-    }
 }
diff --git a/src/assets/background-shop.svg b/src/assets/background-shop.svg
new file mode 100644
index 0000000000000000000000000000000000000000..c88214b9025323f349cab7b68e80a5345f2e0a17
--- /dev/null
+++ b/src/assets/background-shop.svg
@@ -0,0 +1 @@
+<svg id="visual" viewBox="0 0 1500 4000" width="1500" height="4000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><rect x="0" y="0" width="1500" height="4000" fill="#dfe7ec"></rect><defs><linearGradient id="grad1_0" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="30%" stop-color="#dfe7ec" stop-opacity="1"></stop><stop offset="70%" stop-color="#dfe7ec" stop-opacity="1"></stop></linearGradient></defs><defs><linearGradient id="grad2_0" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="30%" stop-color="#dfe7ec" stop-opacity="1"></stop><stop offset="70%" stop-color="#dfe7ec" stop-opacity="1"></stop></linearGradient></defs><g transform="translate(1500, 0)"><path d="M0 1350C-182.1 1338.4 -364.1 1326.7 -516.6 1247.2C-669.1 1167.8 -792 1020.4 -876.8 876.8C-961.6 733.2 -1008.4 593.3 -1080.9 447.7C-1153.5 302.2 -1251.7 151.1 -1350 0L0 0Z" fill="#c4c3d0"></path></g><g transform="translate(0, 4000)"><path d="M0 -1350C177.7 -1335.5 355.4 -1321.1 516.6 -1247.2C677.9 -1173.4 822.7 -1040.2 888.8 -888.8C955 -737.5 942.4 -567.9 1006.1 -416.7C1069.8 -265.6 1209.9 -132.8 1350 0L0 0Z" fill="#c4c3d0"></path></g></svg>
\ No newline at end of file
diff --git a/src/assets/bankid.svg b/src/assets/bankid.svg
new file mode 100644
index 0000000000000000000000000000000000000000..9e1798b2466268e7c6b383839b75786030212559
--- /dev/null
+++ b/src/assets/bankid.svg
@@ -0,0 +1,11 @@
+<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="57" height="57" rx="12" fill="#39134C"/>
+<path d="M19.5001 21.0004H13.5C12.674 21.0004 12 20.3264 12 19.5004C12 18.6764 12.674 18.0004 13.5 18.0004H19.5001C20.3241 18.0004 21.0001 18.6744 21.0001 19.5004C21.0001 20.3264 20.3241 21.0004 19.5001 21.0004Z" fill="white"/>
+<path d="M19.5001 32.9992H13.5C12.674 32.9992 12 32.3252 12 31.4992C12 30.6752 12.674 29.9991 13.5 29.9991H19.5001C20.3241 29.9991 21.0001 30.6732 21.0001 31.4992C21.0001 32.3252 20.3241 32.9992 19.5001 32.9992Z" fill="white"/>
+<path d="M19.5001 38.9998H13.5C12.674 38.9998 12 38.3258 12 37.4998C12 36.6758 12.674 35.9998 13.5 35.9998H19.5001C20.3241 35.9998 21.0001 36.6738 21.0001 37.4998C21.0001 38.3258 20.3241 38.9998 19.5001 38.9998Z" fill="white"/>
+<path d="M31.5005 26.9993H25.5004C24.6744 26.9993 24.0004 26.3253 24.0004 25.4993C24.0004 24.6753 24.6744 23.9993 25.5004 23.9993H31.5005C32.3245 23.9993 33.0005 24.6733 33.0005 25.4993C33.0005 26.3253 32.3245 26.9993 31.5005 26.9993Z" fill="white"/>
+<path d="M31.5005 32.9992H25.5004C24.6744 32.9992 24.0004 32.3252 24.0004 31.4992C24.0004 30.6752 24.6744 29.9991 25.5004 29.9991H31.5005C32.3245 29.9991 33.0005 30.6732 33.0005 31.4992C33.0005 32.3252 32.3245 32.9992 31.5005 32.9992Z" fill="white"/>
+<path d="M43.5001 21H37.5C36.674 21 36 20.326 36 19.5C36 18.676 36.674 18 37.5 18H43.5001C44.3241 18 45.0001 18.674 45.0001 19.5C45.0001 20.326 44.3241 21 43.5001 21Z" fill="white"/>
+<path d="M43.5001 26.9993H37.5C36.674 26.9993 36 26.3253 36 25.4993C36 24.6753 36.674 23.9993 37.5 23.9993H43.5001C44.3241 23.9993 45.0001 24.6733 45.0001 25.4993C45.0001 26.3253 44.3241 26.9993 43.5001 26.9993Z" fill="white"/>
+<path d="M43.5001 38.9998H37.5C36.674 38.9998 36 38.3258 36 37.4998C36 36.6758 36.674 35.9998 37.5 35.9998H43.5001C44.3241 35.9998 45.0001 36.6738 45.0001 37.4998C45.0001 38.3258 44.3241 38.9998 43.5001 38.9998Z" fill="white"/>
+</svg>
diff --git a/src/assets/banners/blob.svg b/src/assets/banners/blob.svg
new file mode 100644
index 0000000000000000000000000000000000000000..76308f5017374eb6cb85fdeeaa6eb6496fea1455
--- /dev/null
+++ b/src/assets/banners/blob.svg
@@ -0,0 +1 @@
+<svg id="visual" viewBox="0 0 900 300" width="900" height="300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><rect width="900" height="300" fill="#931F1F"></rect><g><g transform="translate(405 13)"><path d="M63.2 -22.3C72.1 6.8 62.7 40 41.2 55.3C19.8 70.5 -13.7 67.8 -38.5 50.4C-63.3 33 -79.3 1 -71.4 -26.7C-63.6 -54.4 -31.8 -77.8 -2.3 -77.1C27.1 -76.3 54.3 -51.4 63.2 -22.3Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(598 177)"><path d="M48.3 -16.8C53.9 1.6 43.8 23.9 27.5 35.1C11.2 46.3 -11.2 46.3 -27.7 35C-44.1 23.8 -54.6 1.3 -49 -17.1C-43.4 -35.5 -21.7 -49.8 -0.2 -49.7C21.4 -49.7 42.7 -35.2 48.3 -16.8Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(81 122)"><path d="M57.3 -21.6C64.6 3.9 54.3 32.2 32.5 49C10.8 65.8 -22.4 71.1 -44 56.4C-65.6 41.7 -75.7 6.9 -66.5 -21.3C-57.2 -49.4 -28.6 -70.9 -1.8 -70.3C25 -69.7 50 -47.1 57.3 -21.6Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(834 202)"><path d="M37.7 -11.7C42.9 3.8 37.1 23.5 24.7 32C12.4 40.5 -6.7 37.9 -19.4 28.3C-32.2 18.6 -38.7 2 -34.5 -12.3C-30.2 -26.5 -15.1 -38.3 0.6 -38.5C16.2 -38.6 32.5 -27.2 37.7 -11.7Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(396 296)"><path d="M43.5 -15.1C49.2 3.3 41.6 25.1 25.7 37C9.8 49 -14.4 51 -30.7 39.8C-47.1 28.5 -55.6 3.8 -49.2 -15.7C-42.7 -35.1 -21.4 -49.5 -1.2 -49.1C18.9 -48.7 37.8 -33.6 43.5 -15.1Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(735 18)"><path d="M37 -11.3C41.9 3.1 35.7 21.8 23 30.8C10.4 39.8 -8.7 39 -20.5 30C-32.4 20.9 -37.1 3.7 -32.4 -10.3C-27.8 -24.4 -13.9 -35.2 1.1 -35.5C16 -35.9 32.1 -25.7 37 -11.3Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g></g></svg>
\ No newline at end of file
diff --git a/src/assets/banners/layered.svg b/src/assets/banners/layered.svg
new file mode 100644
index 0000000000000000000000000000000000000000..36bbd7a160fa7ba5da703c9f3e710e4724f5c5f8
--- /dev/null
+++ b/src/assets/banners/layered.svg
@@ -0,0 +1 @@
+<svg id="visual" viewBox="0 0 2000 200" width="2000" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><rect x="0" y="0" width="2000" height="200" fill="#001220"></rect><path d="M0 106L47.7 109.5C95.3 113 190.7 120 285.8 120.3C381 120.7 476 114.3 571.2 108.5C666.3 102.7 761.7 97.3 857 100C952.3 102.7 1047.7 113.3 1143 114.5C1238.3 115.7 1333.7 107.3 1428.8 104.8C1524 102.3 1619 105.7 1714.2 106.2C1809.3 106.7 1904.7 104.3 1952.3 103.2L2000 102L2000 201L1952.3 201C1904.7 201 1809.3 201 1714.2 201C1619 201 1524 201 1428.8 201C1333.7 201 1238.3 201 1143 201C1047.7 201 952.3 201 857 201C761.7 201 666.3 201 571.2 201C476 201 381 201 285.8 201C190.7 201 95.3 201 47.7 201L0 201Z" fill="#fa7268"></path><path d="M0 107L47.7 108C95.3 109 190.7 111 285.8 115.8C381 120.7 476 128.3 571.2 132.2C666.3 136 761.7 136 857 135.2C952.3 134.3 1047.7 132.7 1143 130.2C1238.3 127.7 1333.7 124.3 1428.8 122C1524 119.7 1619 118.3 1714.2 116.2C1809.3 114 1904.7 111 1952.3 109.5L2000 108L2000 201L1952.3 201C1904.7 201 1809.3 201 1714.2 201C1619 201 1524 201 1428.8 201C1333.7 201 1238.3 201 1143 201C1047.7 201 952.3 201 857 201C761.7 201 666.3 201 571.2 201C476 201 381 201 285.8 201C190.7 201 95.3 201 47.7 201L0 201Z" fill="#ef5f67"></path><path d="M0 144L47.7 143.7C95.3 143.3 190.7 142.7 285.8 139.2C381 135.7 476 129.3 571.2 126.7C666.3 124 761.7 125 857 125.7C952.3 126.3 1047.7 126.7 1143 128.2C1238.3 129.7 1333.7 132.3 1428.8 136.2C1524 140 1619 145 1714.2 145C1809.3 145 1904.7 140 1952.3 137.5L2000 135L2000 201L1952.3 201C1904.7 201 1809.3 201 1714.2 201C1619 201 1524 201 1428.8 201C1333.7 201 1238.3 201 1143 201C1047.7 201 952.3 201 857 201C761.7 201 666.3 201 571.2 201C476 201 381 201 285.8 201C190.7 201 95.3 201 47.7 201L0 201Z" fill="#e34c67"></path><path d="M0 157L47.7 158.8C95.3 160.7 190.7 164.3 285.8 164.3C381 164.3 476 160.7 571.2 157.5C666.3 154.3 761.7 151.7 857 149.7C952.3 147.7 1047.7 146.3 1143 146.2C1238.3 146 1333.7 147 1428.8 148.2C1524 149.3 1619 150.7 1714.2 151.8C1809.3 153 1904.7 154 1952.3 154.5L2000 155L2000 201L1952.3 201C1904.7 201 1809.3 201 1714.2 201C1619 201 1524 201 1428.8 201C1333.7 201 1238.3 201 1143 201C1047.7 201 952.3 201 857 201C761.7 201 666.3 201 571.2 201C476 201 381 201 285.8 201C190.7 201 95.3 201 47.7 201L0 201Z" fill="#d53867"></path><path d="M0 180L47.7 178.7C95.3 177.3 190.7 174.7 285.8 173C381 171.3 476 170.7 571.2 172.2C666.3 173.7 761.7 177.3 857 177.8C952.3 178.3 1047.7 175.7 1143 173.5C1238.3 171.3 1333.7 169.7 1428.8 169.7C1524 169.7 1619 171.3 1714.2 171.5C1809.3 171.7 1904.7 170.3 1952.3 169.7L2000 169L2000 201L1952.3 201C1904.7 201 1809.3 201 1714.2 201C1619 201 1524 201 1428.8 201C1333.7 201 1238.3 201 1143 201C1047.7 201 952.3 201 857 201C761.7 201 666.3 201 571.2 201C476 201 381 201 285.8 201C190.7 201 95.3 201 47.7 201L0 201Z" fill="#c62368"></path></svg>
\ No newline at end of file
diff --git a/src/assets/banners/stacked.svg b/src/assets/banners/stacked.svg
new file mode 100644
index 0000000000000000000000000000000000000000..04f07004594034bc415222f3139fac781b197266
--- /dev/null
+++ b/src/assets/banners/stacked.svg
@@ -0,0 +1 @@
+<svg id="visual" viewBox="0 0 2000 200" width="2000" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><path d="M0 55L30.3 53C60.7 51 121.3 47 182 51.3C242.7 55.7 303.3 68.3 363.8 72.3C424.3 76.3 484.7 71.7 545.2 65.7C605.7 59.7 666.3 52.3 727 47.7C787.7 43 848.3 41 909 42C969.7 43 1030.3 47 1091 55.7C1151.7 64.3 1212.3 77.7 1273 83C1333.7 88.3 1394.3 85.7 1454.8 84C1515.3 82.3 1575.7 81.7 1636.2 77C1696.7 72.3 1757.3 63.7 1818 56.3C1878.7 49 1939.3 43 1969.7 40L2000 37L2000 0L1969.7 0C1939.3 0 1878.7 0 1818 0C1757.3 0 1696.7 0 1636.2 0C1575.7 0 1515.3 0 1454.8 0C1394.3 0 1333.7 0 1273 0C1212.3 0 1151.7 0 1091 0C1030.3 0 969.7 0 909 0C848.3 0 787.7 0 727 0C666.3 0 605.7 0 545.2 0C484.7 0 424.3 0 363.8 0C303.3 0 242.7 0 182 0C121.3 0 60.7 0 30.3 0L0 0Z" fill="#6198ff"></path><path d="M0 103L30.3 103C60.7 103 121.3 103 182 107C242.7 111 303.3 119 363.8 120.3C424.3 121.7 484.7 116.3 545.2 111C605.7 105.7 666.3 100.3 727 103C787.7 105.7 848.3 116.3 909 116.7C969.7 117 1030.3 107 1091 107.3C1151.7 107.7 1212.3 118.3 1273 120.7C1333.7 123 1394.3 117 1454.8 115C1515.3 113 1575.7 115 1636.2 117.7C1696.7 120.3 1757.3 123.7 1818 121.3C1878.7 119 1939.3 111 1969.7 107L2000 103L2000 35L1969.7 38C1939.3 41 1878.7 47 1818 54.3C1757.3 61.7 1696.7 70.3 1636.2 75C1575.7 79.7 1515.3 80.3 1454.8 82C1394.3 83.7 1333.7 86.3 1273 81C1212.3 75.7 1151.7 62.3 1091 53.7C1030.3 45 969.7 41 909 40C848.3 39 787.7 41 727 45.7C666.3 50.3 605.7 57.7 545.2 63.7C484.7 69.7 424.3 74.3 363.8 70.3C303.3 66.3 242.7 53.7 182 49.3C121.3 45 60.7 49 30.3 51L0 53Z" fill="#3c80ff"></path><path d="M0 129L30.3 128.7C60.7 128.3 121.3 127.7 182 129.3C242.7 131 303.3 135 363.8 135.7C424.3 136.3 484.7 133.7 545.2 132C605.7 130.3 666.3 129.7 727 132.3C787.7 135 848.3 141 909 140.7C969.7 140.3 1030.3 133.7 1091 134.7C1151.7 135.7 1212.3 144.3 1273 144.3C1333.7 144.3 1394.3 135.7 1454.8 132.7C1515.3 129.7 1575.7 132.3 1636.2 135.7C1696.7 139 1757.3 143 1818 142.3C1878.7 141.7 1939.3 136.3 1969.7 133.7L2000 131L2000 101L1969.7 105C1939.3 109 1878.7 117 1818 119.3C1757.3 121.7 1696.7 118.3 1636.2 115.7C1575.7 113 1515.3 111 1454.8 113C1394.3 115 1333.7 121 1273 118.7C1212.3 116.3 1151.7 105.7 1091 105.3C1030.3 105 969.7 115 909 114.7C848.3 114.3 787.7 103.7 727 101C666.3 98.3 605.7 103.7 545.2 109C484.7 114.3 424.3 119.7 363.8 118.3C303.3 117 242.7 109 182 105C121.3 101 60.7 101 30.3 101L0 101Z" fill="#0066ff"></path><path d="M0 187L30.3 182.7C60.7 178.3 121.3 169.7 182 167.7C242.7 165.7 303.3 170.3 363.8 173.3C424.3 176.3 484.7 177.7 545.2 177.3C605.7 177 666.3 175 727 176C787.7 177 848.3 181 909 180.7C969.7 180.3 1030.3 175.7 1091 174C1151.7 172.3 1212.3 173.7 1273 172.7C1333.7 171.7 1394.3 168.3 1454.8 165.7C1515.3 163 1575.7 161 1636.2 163C1696.7 165 1757.3 171 1818 175C1878.7 179 1939.3 181 1969.7 182L2000 183L2000 129L1969.7 131.7C1939.3 134.3 1878.7 139.7 1818 140.3C1757.3 141 1696.7 137 1636.2 133.7C1575.7 130.3 1515.3 127.7 1454.8 130.7C1394.3 133.7 1333.7 142.3 1273 142.3C1212.3 142.3 1151.7 133.7 1091 132.7C1030.3 131.7 969.7 138.3 909 138.7C848.3 139 787.7 133 727 130.3C666.3 127.7 605.7 128.3 545.2 130C484.7 131.7 424.3 134.3 363.8 133.7C303.3 133 242.7 129 182 127.3C121.3 125.7 60.7 126.3 30.3 126.7L0 127Z" fill="#0059dd"></path><path d="M0 201L30.3 201C60.7 201 121.3 201 182 201C242.7 201 303.3 201 363.8 201C424.3 201 484.7 201 545.2 201C605.7 201 666.3 201 727 201C787.7 201 848.3 201 909 201C969.7 201 1030.3 201 1091 201C1151.7 201 1212.3 201 1273 201C1333.7 201 1394.3 201 1454.8 201C1515.3 201 1575.7 201 1636.2 201C1696.7 201 1757.3 201 1818 201C1878.7 201 1939.3 201 1969.7 201L2000 201L2000 181L1969.7 180C1939.3 179 1878.7 177 1818 173C1757.3 169 1696.7 163 1636.2 161C1575.7 159 1515.3 161 1454.8 163.7C1394.3 166.3 1333.7 169.7 1273 170.7C1212.3 171.7 1151.7 170.3 1091 172C1030.3 173.7 969.7 178.3 909 178.7C848.3 179 787.7 175 727 174C666.3 173 605.7 175 545.2 175.3C484.7 175.7 424.3 174.3 363.8 171.3C303.3 168.3 242.7 163.7 182 165.7C121.3 167.7 60.7 176.3 30.3 180.7L0 185Z" fill="#004cbb"></path></svg>
\ No newline at end of file
diff --git a/src/assets/banners/stars.svg b/src/assets/banners/stars.svg
new file mode 100644
index 0000000000000000000000000000000000000000..954cce4656b9b49cbf116b5723eac3a5af7b8cb5
--- /dev/null
+++ b/src/assets/banners/stars.svg
@@ -0,0 +1 @@
+<svg id="visual" viewBox="0 0 2000 200" width="2000" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><rect x="0" y="0" width="2000" height="200" fill="#001829"></rect><g fill="#297EA6"><path d="M0 -96.3L21.6 -29.7L91.6 -29.7L35 11.4L56.6 77.9L0 36.8L-56.6 77.9L-35 11.4L-91.6 -29.7L-21.6 -29.7Z" transform="translate(1672 170)"></path><path d="M0 -42.5L9.5 -13.1L40.4 -13.1L15.4 5L25 34.4L0 16.2L-25 34.4L-15.4 5L-40.4 -13.1L-9.5 -13.1Z" transform="translate(1330 135)"></path><path d="M0 -56.6L12.7 -17.5L53.9 -17.5L20.6 6.7L33.3 45.8L0 21.6L-33.3 45.8L-20.6 6.7L-53.9 -17.5L-12.7 -17.5Z" transform="translate(274 47)"></path><path d="M0 -45.3L10.2 -14L43.1 -14L16.5 5.3L26.6 36.7L0 17.3L-26.6 36.7L-16.5 5.3L-43.1 -14L-10.2 -14Z" transform="translate(800 197)"></path><path d="M0 -49.1L11 -15.2L46.7 -15.2L17.8 5.8L28.8 39.7L0 18.7L-28.8 39.7L-17.8 5.8L-46.7 -15.2L-11 -15.2Z" transform="translate(80 113)"></path><path d="M0 -51L11.4 -15.7L48.5 -15.7L18.5 6L30 41.2L0 19.5L-30 41.2L-18.5 6L-48.5 -15.7L-11.4 -15.7Z" transform="translate(505 147)"></path><path d="M0 -84.9L19.1 -26.2L80.8 -26.2L30.9 10L49.9 68.7L0 32.4L-49.9 68.7L-30.9 10L-80.8 -26.2L-19.1 -26.2Z" transform="translate(917 12)"></path><path d="M0 -68.9L15.5 -21.3L65.5 -21.3L25 8.1L40.5 55.7L0 26.3L-40.5 55.7L-25 8.1L-65.5 -21.3L-15.5 -21.3Z" transform="translate(1951 109)"></path><path d="M0 -54.7L12.3 -16.9L52.1 -16.9L19.9 6.5L32.2 44.3L0 20.9L-32.2 44.3L-19.9 6.5L-52.1 -16.9L-12.3 -16.9Z" transform="translate(1527 27)"></path><path d="M0 -54.7L12.3 -16.9L52.1 -16.9L19.9 6.5L32.2 44.3L0 20.9L-32.2 44.3L-19.9 6.5L-52.1 -16.9L-12.3 -16.9Z" transform="translate(1107 109)"></path><path d="M0 -65.1L14.6 -20.1L61.9 -20.1L23.7 7.7L38.3 52.7L0 24.9L-38.3 52.7L-23.7 7.7L-61.9 -20.1L-14.6 -20.1Z" transform="translate(667 11)"></path></g></svg>
\ No newline at end of file
diff --git a/src/assets/icons/admin.svg b/src/assets/icons/admin.svg
index e75e106806f0bf9e3d18092b4b60efdd75fe7a0e..6600cf93ba52d15933c85762fa6f684fb632f933 100644
--- a/src/assets/icons/admin.svg
+++ b/src/assets/icons/admin.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M680-280q25 0 42.5-17.5T740-340q0-25-17.5-42.5T680-400q-25 0-42.5 17.5T620-340q0 25 17.5 42.5T680-280Zm0 120q31 0 57-14.5t42-38.5q-22-13-47-20t-52-7q-27 0-52 7t-47 20q16 24 42 38.5t57 14.5ZM480-80q-139-35-229.5-159.5T160-516v-244l320-120 320 120v227q-19-8-39-14.5t-41-9.5v-147l-240-90-240 90v188q0 47 12.5 94t35 89.5Q310-290 342-254t71 60q11 32 29 61t41 52q-1 0-1.5.5t-1.5.5Zm200 0q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80ZM480-494Z" fill="#ffffff"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M680-280q25 0 42.5-17.5T740-340q0-25-17.5-42.5T680-400q-25 0-42.5 17.5T620-340q0 25 17.5 42.5T680-280Zm0 120q31 0 57-14.5t42-38.5q-22-13-47-20t-52-7q-27 0-52 7t-47 20q16 24 42 38.5t57 14.5ZM480-80q-139-35-229.5-159.5T160-516v-244l320-120 320 120v227q-19-8-39-14.5t-41-9.5v-147l-240-90-240 90v188q0 47 12.5 94t35 89.5Q310-290 342-254t71 60q11 32 29 61t41 52q-1 0-1.5.5t-1.5.5Zm200 0q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80ZM480-494Z" fill="#000000"/></svg>
\ No newline at end of file
diff --git a/src/assets/icons/black_friends.svg b/src/assets/icons/black_friends.svg
new file mode 100644
index 0000000000000000000000000000000000000000..76e388b5334e9b630d23682a7495a9335febae08
--- /dev/null
+++ b/src/assets/icons/black_friends.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M40-160v-112q0-34 17.5-62.5T104-378q62-31 126-46.5T360-440q66 0 130 15.5T616-378q29 15 46.5 43.5T680-272v112H40Zm720 0v-120q0-44-24.5-84.5T666-434q51 6 96 20.5t84 35.5q36 20 55 44.5t19 53.5v120H760ZM360-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm400-160q0 66-47 113t-113 47q-11 0-28-2.5t-28-5.5q27-32 41.5-71t14.5-81q0-42-14.5-81T544-792q14-5 28-6.5t28-1.5q66 0 113 47t47 113ZM120-240h480v-32q0-11-5.5-20T580-306q-54-27-109-40.5T360-360q-56 0-111 13.5T140-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T440-640q0-33-23.5-56.5T360-720q-33 0-56.5 23.5T280-640q0 33 23.5 56.5T360-560Zm0 320Zm0-400Z" fill="#000000"/></svg>
\ No newline at end of file
diff --git a/src/assets/icons/black_person.svg b/src/assets/icons/black_person.svg
index 787c1a2c5f8ba200d2254734be28326996a3f678..a1f5ae73b8e5f1202bdb1dcd829fb22091e85614 100644
--- a/src/assets/icons/black_person.svg
+++ b/src/assets/icons/black_person.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 -960 960 960" width="32"><path d="M480-481q-66 0-108-42t-42-108q0-66 42-108t108-42q66 0 108 42t42 108q0 66-42 108t-108 42ZM160-160v-94q0-38 19-65t49-41q67-30 128.5-45T480-420q62 0 123 15.5t127.921 44.694q31.301 14.126 50.19 40.966Q800-292 800-254v94H160Zm60-60h520v-34q0-16-9.5-30.5T707-306q-64-31-117-42.5T480-360q-57 0-111 11.5T252-306q-14 7-23 21.5t-9 30.5v34Zm260-321q39 0 64.5-25.5T570-631q0-39-25.5-64.5T480-721q-39 0-64.5 25.5T390-631q0 39 25.5 64.5T480-541Zm0-90Zm0 411Z" fill="#000"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm246-164q-59 0-99.5-40.5T340-580q0-59 40.5-99.5T480-720q59 0 99.5 40.5T620-580q0 59-40.5 99.5T480-440Zm0 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q53 0 100-15.5t86-44.5q-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160Zm0-360q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm0-60Zm0 360Z" fill="#000000"/></svg>
\ No newline at end of file
diff --git a/src/assets/icons/budget.svg b/src/assets/icons/budget.svg
new file mode 100644
index 0000000000000000000000000000000000000000..f00f6f4ef6e38c66edae2300e881f6fbedfaaca4
--- /dev/null
+++ b/src/assets/icons/budget.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M840-320 464-614 305-395 120-540v-140l160 120 200-280 200 160h160v360ZM120-160v-280l200 160 160-220 360 281v59H120Z"/></svg>
\ No newline at end of file
diff --git a/src/assets/icons/calculator.svg b/src/assets/icons/calculator.svg
new file mode 100644
index 0000000000000000000000000000000000000000..6a7aa0620e1a68af6ed6bf601638b8aaa95f3133
--- /dev/null
+++ b/src/assets/icons/calculator.svg
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#FFF" height="40px" width="40px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+	 viewBox="0 0 460 460" xml:space="preserve">
+<g id="XMLID_241_">
+	<g>
+		<path d="M369.635,0H90.365C73.595,0,60,13.595,60,30.365v399.27C60,446.405,73.595,460,90.365,460h279.27
+			c16.77,0,30.365-13.595,30.365-30.365V30.365C400,13.595,386.405,0,369.635,0z M108.204,343.61v-43.196
+			c0-3.451,2.797-6.248,6.248-6.248h43.196c3.451,0,6.248,2.797,6.248,6.248v43.196c0,3.451-2.797,6.248-6.248,6.248h-43.196
+			C111.001,349.858,108.204,347.06,108.204,343.61z M108.204,256.61v-43.196c0-3.451,2.797-6.248,6.248-6.248h43.196
+			c3.451,0,6.248,2.797,6.248,6.248v43.196c0,3.451-2.797,6.248-6.248,6.248h-43.196C111.001,262.858,108.204,260.06,108.204,256.61
+			z M308.891,421H151.109c-11.046,0-20-8.954-20-20c0-11.046,8.954-20,20-20h157.782c11.046,0,20,8.954,20,20
+			C328.891,412.046,319.937,421,308.891,421z M208.402,294.165h43.196c3.451,0,6.248,2.797,6.248,6.248v43.196
+			c0,3.451-2.797,6.248-6.248,6.248h-43.196c-3.451,0-6.248-2.797-6.248-6.248v-43.196
+			C202.154,296.963,204.951,294.165,208.402,294.165z M202.154,256.61v-43.196c0-3.451,2.797-6.248,6.248-6.248h43.196
+			c3.451,0,6.248,2.797,6.248,6.248v43.196c0,3.451-2.797,6.248-6.248,6.248h-43.196C204.951,262.858,202.154,260.06,202.154,256.61
+			z M345.548,349.858h-43.196c-3.451,0-6.248-2.797-6.248-6.248v-43.196c0-3.451,2.797-6.248,6.248-6.248h43.196
+			c3.451,0,6.248,2.797,6.248,6.248v43.196h0C351.796,347.061,348.999,349.858,345.548,349.858z M345.548,262.858h-43.196
+			c-3.451,0-6.248-2.797-6.248-6.248v-43.196c0-3.451,2.797-6.248,6.248-6.248h43.196c3.451,0,6.248,2.797,6.248,6.248v43.196h0
+			C351.796,260.061,348.999,262.858,345.548,262.858z M354,149.637c0,11.799-9.565,21.363-21.363,21.363H127.364
+			C115.565,171,106,161.435,106,149.637V62.363C106,50.565,115.565,41,127.364,41h205.273C344.435,41,354,50.565,354,62.363V149.637
+			z"/>
+	</g>
+</g>
+</svg>
\ No newline at end of file
diff --git a/src/assets/icons/feedback.svg b/src/assets/icons/feedback.svg
index 796e4346c08bed42140a3d053a93e4a5dee90093..8b482dede238bcb8a60f8cee2a6b76559ff7202f 100644
--- a/src/assets/icons/feedback.svg
+++ b/src/assets/icons/feedback.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M240-399h313v-60H240v60Zm0-130h480v-60H240v60Zm0-130h480v-60H240v60ZM80-80v-740q0-24 18-42t42-18h680q24 0 42 18t18 42v520q0 24-18 42t-42 18H240L80-80Zm134-220h606v-520H140v600l74-80Zm-74 0v-520 520Z" fill="#ffffff"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M240-399h313v-60H240v60Zm0-130h480v-60H240v60Zm0-130h480v-60H240v60ZM80-80v-740q0-24 18-42t42-18h680q24 0 42 18t18 42v520q0 24-18 42t-42 18H240L80-80Zm134-220h606v-520H140v600l74-80Zm-74 0v-520 520Z" fill="#000000"/></svg>
\ No newline at end of file
diff --git a/src/assets/icons/logout.svg b/src/assets/icons/logout.svg
index 1c5e27e1a1886b2c5acc18c7aca5de957f4569f2..f0599077fea365397af7aebdd441b0d103d52211 100644
--- a/src/assets/icons/logout.svg
+++ b/src/assets/icons/logout.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M180-120q-24 0-42-18t-18-42v-600q0-24 18-42t42-18h299v60H180v600h299v60H180Zm486-185-43-43 102-102H360v-60h363L621-612l43-43 176 176-174 174Z" fill="#ffffff"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M180-120q-24 0-42-18t-18-42v-600q0-24 18-42t42-18h299v60H180v600h299v60H180Zm486-185-43-43 102-102H360v-60h363L621-612l43-43 176 176-174 174Z" fill="#000000"/></svg>
\ No newline at end of file
diff --git a/src/assets/icons/person.svg b/src/assets/icons/person.svg
index ef3c9d45ac4c8345e1444ae4361c56641ad4b0c0..bacdbe013fa843a18d41dca5223ffdc7635ffd58 100644
--- a/src/assets/icons/person.svg
+++ b/src/assets/icons/person.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M480-481q-66 0-108-42t-42-108q0-66 42-108t108-42q66 0 108 42t42 108q0 66-42 108t-108 42ZM160-160v-94q0-38 19-65t49-41q67-30 128.5-45T480-420q62 0 123 15.5t127.921 44.694q31.301 14.126 50.19 40.966Q800-292 800-254v94H160Zm60-60h520v-34q0-16-9.5-30.5T707-306q-64-31-117-42.5T480-360q-57 0-111 11.5T252-306q-14 7-23 21.5t-9 30.5v34Zm260-321q39 0 64.5-25.5T570-631q0-39-25.5-64.5T480-721q-39 0-64.5 25.5T390-631q0 39 25.5 64.5T480-541Zm0-90Zm0 411Z" fill="#ffffff"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm246-164q-59 0-99.5-40.5T340-580q0-59 40.5-99.5T480-720q59 0 99.5 40.5T620-580q0 59-40.5 99.5T480-440Zm0 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q53 0 100-15.5t86-44.5q-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160Zm0-360q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm0-60Zm0 360Z" fill="#ffffff"/></svg>
\ No newline at end of file
diff --git a/src/assets/icons/settings.svg b/src/assets/icons/settings.svg
index 542fa092683df8d0777dd62eedfe9260983b14e1..56a1cfb009e2a1742df20ec89b62267dad71c2dc 100644
--- a/src/assets/icons/settings.svg
+++ b/src/assets/icons/settings.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="m388-80-20-126q-19-7-40-19t-37-25l-118 54-93-164 108-79q-2-9-2.5-20.5T185-480q0-9 .5-20.5T188-521L80-600l93-164 118 54q16-13 37-25t40-18l20-127h184l20 126q19 7 40.5 18.5T669-710l118-54 93 164-108 77q2 10 2.5 21.5t.5 21.5q0 10-.5 21t-2.5 21l108 78-93 164-118-54q-16 13-36.5 25.5T592-206L572-80H388Zm48-60h88l14-112q33-8 62.5-25t53.5-41l106 46 40-72-94-69q4-17 6.5-33.5T715-480q0-17-2-33.5t-7-33.5l94-69-40-72-106 46q-23-26-52-43.5T538-708l-14-112h-88l-14 112q-34 7-63.5 24T306-642l-106-46-40 72 94 69q-4 17-6.5 33.5T245-480q0 17 2.5 33.5T254-413l-94 69 40 72 106-46q24 24 53.5 41t62.5 25l14 112Zm44-210q54 0 92-38t38-92q0-54-38-92t-92-38q-54 0-92 38t-38 92q0 54 38 92t92 38Zm0-130Z" fill="#ffffff"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="m388-80-20-126q-19-7-40-19t-37-25l-118 54-93-164 108-79q-2-9-2.5-20.5T185-480q0-9 .5-20.5T188-521L80-600l93-164 118 54q16-13 37-25t40-18l20-127h184l20 126q19 7 40.5 18.5T669-710l118-54 93 164-108 77q2 10 2.5 21.5t.5 21.5q0 10-.5 21t-2.5 21l108 78-93 164-118-54q-16 13-36.5 25.5T592-206L572-80H388Zm48-60h88l14-112q33-8 62.5-25t53.5-41l106 46 40-72-94-69q4-17 6.5-33.5T715-480q0-17-2-33.5t-7-33.5l94-69-40-72-106 46q-23-26-52-43.5T538-708l-14-112h-88l-14 112q-34 7-63.5 24T306-642l-106-46-40 72 94 69q-4 17-6.5 33.5T245-480q0 17 2.5 33.5T254-413l-94 69 40 72 106-46q24 24 53.5 41t62.5 25l14 112Zm44-210q54 0 92-38t38-92q0-54-38-92t-92-38q-54 0-92 38t-38 92q0 54 38 92t92 38Zm0-130Z" fill="#000000"/></svg>
\ No newline at end of file
diff --git a/src/assets/shop-background.svg b/src/assets/shop-background.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0c8f7e41d593aba7339abf5f4e5ef71bf3613b31
--- /dev/null
+++ b/src/assets/shop-background.svg
@@ -0,0 +1 @@
+<svg id="visual" viewBox="0 0 2000 200" width="2000" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><rect width="2000" height="200" fill="#931F1F"></rect><g><g transform="translate(47 22)"><path d="M81.9 -28.5C92.5 5.8 77.8 46.3 50.6 65C23.3 83.7 -16.5 80.6 -44.5 60.4C-72.6 40.2 -88.9 3 -79.5 -29.7C-70.1 -62.4 -35.1 -90.6 0.3 -90.7C35.7 -90.8 71.4 -62.8 81.9 -28.5Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(1876 62)"><path d="M47.2 -13.7C53.6 4.4 46 28.7 29.2 41C12.5 53.4 -13.5 53.9 -29.1 42.1C-44.7 30.3 -50 6.2 -43.4 -12.2C-36.8 -30.6 -18.4 -43.2 1 -43.5C20.4 -43.8 40.8 -31.9 47.2 -13.7Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(480 114)"><path d="M38 -12.3C44.2 6.7 40.7 28.9 27.9 38.1C15.1 47.4 -7 43.7 -22 32.3C-37 20.9 -44.9 1.8 -40.1 -15.3C-35.3 -32.4 -17.6 -47.7 -0.9 -47.4C15.9 -47.1 31.9 -31.3 38 -12.3Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(1093 186)"><path d="M70.5 -21.4C80.3 7.1 69.4 43.9 43.5 63.5C17.7 83.2 -23.2 85.7 -48.2 67.4C-73.1 49 -82.1 9.7 -71.4 -20.1C-60.7 -50 -30.4 -70.3 0 -70.3C30.4 -70.3 60.7 -50 70.5 -21.4Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(1631 144)"><path d="M58.4 -22.4C64.9 0.9 51.8 27.1 32 40.7C12.2 54.3 -14.4 55.3 -34.2 42.1C-54 28.9 -67 1.5 -60.1 -22.3C-53.3 -46 -26.7 -66 -0.3 -65.9C26 -65.8 52 -45.6 58.4 -22.4Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g><g transform="translate(789 190)"><path d="M66.4 -19.3C76.4 8.9 67.9 45.4 43.9 63.6C19.9 81.8 -19.7 81.7 -42.6 63.8C-65.6 45.9 -71.9 10.2 -62 -17.9C-52.2 -46.1 -26.1 -66.8 1.1 -67.1C28.3 -67.5 56.5 -47.5 66.4 -19.3Z" stroke="#F7760E" fill="none" stroke-width="20"></path></g></g></svg>
\ No newline at end of file
diff --git a/src/assets/wave.svg b/src/assets/wave.svg
new file mode 100644
index 0000000000000000000000000000000000000000..92d9e7c1b23bba3d8bd8f9ee0290f769cc64abb6
--- /dev/null
+++ b/src/assets/wave.svg
@@ -0,0 +1 @@
+<svg id="visual" viewBox="0 0 900 600" width="900" height="600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><rect x="0" y="0" width="900" height="600" fill="#003a58"></rect><path d="M0 314L16.7 321.3C33.3 328.7 66.7 343.3 100 341C133.3 338.7 166.7 319.3 200 308.7C233.3 298 266.7 296 300 299.8C333.3 303.7 366.7 313.3 400 323.8C433.3 334.3 466.7 345.7 500 346.7C533.3 347.7 566.7 338.3 600 336.7C633.3 335 666.7 341 700 345.7C733.3 350.3 766.7 353.7 800 344C833.3 334.3 866.7 311.7 883.3 300.3L900 289L900 601L883.3 601C866.7 601 833.3 601 800 601C766.7 601 733.3 601 700 601C666.7 601 633.3 601 600 601C566.7 601 533.3 601 500 601C466.7 601 433.3 601 400 601C366.7 601 333.3 601 300 601C266.7 601 233.3 601 200 601C166.7 601 133.3 601 100 601C66.7 601 33.3 601 16.7 601L0 601Z" fill="#ffffff" stroke-linecap="round" stroke-linejoin="miter"></path></svg>
\ No newline at end of file
diff --git a/src/components/BaseComponents/Footer.vue b/src/components/BaseComponents/BaseFooter.vue
similarity index 50%
rename from src/components/BaseComponents/Footer.vue
rename to src/components/BaseComponents/BaseFooter.vue
index 7fddbaae0fe94207787bd1d31cc1c2798eeabaa9..d9628730141561e16a323cc7bc2cb0ff66610613 100644
--- a/src/components/BaseComponents/Footer.vue
+++ b/src/components/BaseComponents/BaseFooter.vue
@@ -2,10 +2,14 @@
     <div>
         <footer id = "footer" class="text-center text-white" style="width: 100%">
           <div class="text-center p-3">
-            © 2024 Copyright: Anders Høvik, Andreas Svendsrud, Henrik Dybdal, Henrik Sandok, Jens Aanestad, Victor Kaste, Viktor Grevskott
+            © SpareSti 2024
           </div>
         </footer>
     </div>
 </template>
 
-<style scoped> #footer {background-color: #0A58CA;}</style>
+<style scoped>
+#footer {
+  background-color: #003A58;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/BaseComponents/Buttons/BaseButton.vue b/src/components/BaseComponents/Buttons/BaseButton.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f57ef80ede1de7c53b8466b13ed7dab8e926b7c3
--- /dev/null
+++ b/src/components/BaseComponents/Buttons/BaseButton.vue
@@ -0,0 +1,32 @@
+<template>
+    <button type="button" class="btn btn-primary" id="buttonStyle">{{ buttonText }}</button>
+</template>
+
+<script setup lang="ts">
+defineProps<{ buttonText: string }>();
+</script>
+
+<style scoped>
+    #buttonStyle {
+        padding: 0.5rem 4rem;
+        font-size: 1.5rem;
+        font-weight: 600;
+    }
+
+    .btn-primary {
+      background-color: #003A58;
+      border-color: #003A58;
+      font-weight: 600;
+    }
+
+    .btn-primary:hover, .btn-primary:active, .btn-primary:visited {
+      background-color: #004a72 !important;
+      border-color: #004a72 !important;
+    }
+
+    .btn-primary:disabled {
+      background-color: rgba(0, 74, 114, 0.56) !important;
+      border-color: rgba(0, 74, 114, 0.56) !important;
+    }
+
+</style>
diff --git a/src/components/Buttons/__tests__/Button1.spec.ts b/src/components/BaseComponents/Buttons/__tests__/BaseButton.spec.ts
similarity index 87%
rename from src/components/Buttons/__tests__/Button1.spec.ts
rename to src/components/BaseComponents/Buttons/__tests__/BaseButton.spec.ts
index e1c2a39182663c7d37365f9973ff4953fe8d1768..8e7c84193f26f460848744d1266f26d07d61e5c4 100644
--- a/src/components/Buttons/__tests__/Button1.spec.ts
+++ b/src/components/BaseComponents/Buttons/__tests__/BaseButton.spec.ts
@@ -1,6 +1,6 @@
 import { describe, it, expect } from 'vitest'
 import { mount } from '@vue/test-utils'
-import ButtonComponent from '@/components/Buttons/Button1.vue'
+import ButtonComponent from '../BaseButton.vue'
 
 describe('ButtonComponent', () => {
   it('displays the passed buttonText prop', () => {
diff --git a/src/components/BaseComponents/FooterAlternative.vue b/src/components/BaseComponents/FooterAlternative.vue
deleted file mode 100644
index 28824a1455ea2ee665ee0a7de42ecb36e76dfdeb..0000000000000000000000000000000000000000
--- a/src/components/BaseComponents/FooterAlternative.vue
+++ /dev/null
@@ -1,137 +0,0 @@
-<script setup lang="ts">
-import '@fortawesome/fontawesome-free/css/all.css'
-import { RouterLink } from 'vue-router'
-import {logDOM} from "@testing-library/vue";
-
-
-
-
-const ifNotLoggedInLogin  = () => {
- /* if (useUserInfoStore.isActive) {
-    return '/discover'
-  }
-  return '/login'*/
-  return '/login'
-}
-
-const ifLoggedInDiscover = () => {
-  /*if (store.isActive) {
-    return '/discover'
-  }
-  return '/'*/
-  return '/'
-}
-
-const ifLoggedInReset = () => {
-  /*if (store.isActive) {
-    store.resetAll()
-  }*/
-  return '/login'
-}
-</script>
-
-<template>
-  <div class="footer-wrapper" style="background-color: #3B71CA">
-
-    <div class="links-wrapper">
-      <p class="links-header">Links</p>
-      <div class="links-container">
-        <RouterLink class="router" id="home" :to="ifLoggedInDiscover">Home</RouterLink>
-        <RouterLink class="router" id="discover" :to="ifNotLoggedInLogin()">Discover</RouterLink>
-        <RouterLink class="router" id="login" to="/login" @click="ifLoggedInReset()">Login</RouterLink>
-      </div>
-    </div>
-
-    <div class="support-wrapper">
-      <p class="support-header">Support us</p>
-      <div class="support-container">
-        <a href="https://twitter.com" target="_blank">
-          <i class="fab fa-twitter"></i>
-          Twitter
-        </a>
-        <a href="https://instagram.com" target="_blank">
-          <i class="fab fa-instagram"></i>
-           Instagram
-        </a>
-        <a href="https://facebook.com" target="_blank">
-          <i class="fab fa-facebook"></i>
-           Facebook
-        </a>
-        <a href="https://discord.gg" target="_blank">
-          <i class="fab fa-discord"></i>
-           Discord
-        </a>
-      </div>
-    </div>
-
-    <div class="info-wrapper">
-      <p class="info-header">Company</p>
-      <div class="info-container">
-        <RouterLink class="router" to="/about-us">About us</RouterLink>
-        <RouterLink class="router" to="/privacy-policy">Privacy</RouterLink>
-      </div>
-    </div>
-
-  </div>
-</template>
-
-<style scoped>
-:root {
-  --footer-margin: 2rem
-}
-
-.footer-wrapper {
-  width: 100%;
-  display: grid;
-  grid-template-columns: 1fr 1fr 1fr;
-  background-size: cover;
-  justify-content: center;
-}
-
-.links-header, .support-header, .info-header {
-  font-family: Inter,sans-serif;
-  font-size: 26px;
-  font-weight: 600;
-  color: #FFFFFF;
-  margin: var(--footer-margin);
-  padding-left: 10px;
-}
-
-.links-container, .support-container, .info-container {
-  display: flex;
-  flex-direction: column;
-  margin: var(--footer-margin);
-}
-
-.support-container a i {
-  margin-right: 0.7rem;
-}
-
-.router, .support-container a {
-  width: 100%;
-  height: 39px;
-  font-family: 'Inter', serif;
-  font-weight: 500;
-  font-size: 18px;
-  text-decoration: none;
-  border-radius: 10px;
-  align-content: center;
-  color: #FFFFFF;
-  border: 1px solid #3B71CA;
-  padding-left: 10px;
-}
-
-.router:hover, .support-container a:hover {
-  background-color: #FFFFFF;
-  color: #3B71CA;
-  font-weight: 500;
-  font-size: 18px;
-}
-
-@media (max-width: 588px) {
-  .footer-wrapper {
-    display: flex;
-    flex-direction: column;
-  }
-}
-</style>
diff --git a/src/components/InputFields/BaseInput.vue b/src/components/BaseComponents/Input/BaseInput.vue
similarity index 65%
rename from src/components/InputFields/BaseInput.vue
rename to src/components/BaseComponents/Input/BaseInput.vue
index 19a7c2e0188220bde30f3c5bdd60fc9e5ba3a931..80901c51577e8b562b68e7c4d8e5f2fef27cbeb1 100644
--- a/src/components/InputFields/BaseInput.vue
+++ b/src/components/BaseComponents/Input/BaseInput.vue
@@ -1,5 +1,7 @@
 <script setup lang="ts">
 
+import { ref } from 'vue'
+
 const emit = defineEmits(['inputChangeEvent']);
 const props = defineProps({
   label: {
@@ -19,13 +21,15 @@ const props = defineProps({
     required: true
   },
   modelValue: {
-    type: String,
-    default: ""
   },
   min: {
     type: String,
     required: false
   },
+  max: {
+    type: String,
+    required: false
+  },
   pattern: {
     type: String,
     default: null
@@ -41,29 +45,38 @@ const props = defineProps({
   required: {
     type: Boolean,
     default: true
+  },
+  inputClass: {
+    type: String,
+    default: "form-control"
   }
 });
 
+const formRef = ref();
+
 const onInputEvent = (event: any) => {
+  formRef.value.classList.add("was-validated")
   emit('inputChangeEvent', event.target.value)
 }
 </script>
 
 <template>
-  <div>
-    <label :for="inputId">{{ label }}</label>
+  <div ref="formRef">
+    <label :for="inputId" data-cy="bi-label">{{ label }}</label>
     <input :value="modelValue"
            @input="onInputEvent"
            :type="type"
-           class="form-control"
+           :class="inputClass"
            :placeholder="placeholder"
            :id="inputId"
            :min="min"
+           :max="max"
            :pattern="pattern"
            :required="required"
+           data-cy="bi-input"
     />
-    <div class="valid-feedback">{{ validMessage }}</div>
-    <div class="invalid-feedback" id="invalid">{{ invalidMessage }}</div>
+    <div data-cy="bi-valid-msg" class="valid-feedback">{{ validMessage }}</div>
+    <div data-cy="bi-invalid-msg" class="invalid-feedback" id="invalid">{{ invalidMessage }}</div>
   </div>
 </template>
 
diff --git a/src/components/InputFields/__tests__/BaseInput.spec.ts b/src/components/BaseComponents/Input/__tests__/BaseInput.spec.ts
similarity index 89%
rename from src/components/InputFields/__tests__/BaseInput.spec.ts
rename to src/components/BaseComponents/Input/__tests__/BaseInput.spec.ts
index 90f881ef89744bd7c300e04ddc9ed3bf19bc64f8..b795f41627a01c0d19fc748f40a5619194b4b2a4 100644
--- a/src/components/InputFields/__tests__/BaseInput.spec.ts
+++ b/src/components/BaseComponents/Input/__tests__/BaseInput.spec.ts
@@ -1,6 +1,6 @@
 import { describe, it, expect } from 'vitest'
 import { mount } from '@vue/test-utils';
-import InputField from '@/components/InputFields/BaseInput.vue';
+import InputField from '../BaseInput.vue';
 
 describe('InputField.vue', () => {
   it('emits inputChangeEvent when input event is triggered', async () => {
diff --git a/src/components/BaseComponents/Menu.vue b/src/components/BaseComponents/Menu.vue
deleted file mode 100644
index 74ed16328a0cbc6d181fa70bb96ebce1a809b624..0000000000000000000000000000000000000000
--- a/src/components/BaseComponents/Menu.vue
+++ /dev/null
@@ -1,327 +0,0 @@
-<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>
-            </router-link>
-            <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
-                data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
-                aria-label="Toggle navigation">
-                <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">Saving goals</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">Leaderboard</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">News</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">Store</router-link>
-                    </li>
-                    <li class="nav-item dropdown">
-                        <a data-mdb-dropdown-init class=" nav-link me-3 dropdown-toggle hidden-arrow notification" href="#" id="navbarDropdownMenuLink"
-                           role="button" data-bs-toggle="dropdown" aria-expanded="false">
-                          <i class="fas fa-bell text-white"></i>
-                          <span class="badge rounded-pill badge-notification bg-danger">{{counter}}</span>
-                        </a>
-                        <ul 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="Notification Icon" class="notification-icon" style="height: 20px; width: 20px">
-                              </div>
-                              <div v-if="array[1][0] === '2'" class="flex-shrink-0">
-                                <img src="/src/assets/userprofile.png" alt="Notification Icon" class="notification-icon" style="height: 20px; width: 20px">
-                              </div>
-                              <div v-if="array[1][0] === '3'" class="flex-shrink-0">
-                                <img src="/src/assets/icons/piggybank.svg" alt="Notification Icon" class="notification-icon" style="height: 20px; width: 20px">
-                              </div>
-                              <div class="flex-grow-1 ms-3">
-                                <router-link class="not-item dropdown-item text-white"   :to="getPath(array[1][0])">{{array[1][1]}}</router-link>
-                              </div>
-                            </div>
-
-
-                          </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="useUserInfoStore().profileImage ? 'http://localhost:8080/api/images/' + useUserInfoStore().profileImage : 'src/assets/userprofile.png'"
-                                style="width: 50px; border: 2px solid black; border-radius: 50%">{{
-                useUserInfoStore().firstname }}
-                        </a>
-                        <ul class="dropdown-menu dropdown-username-content">
-                            <li><router-link data-cy="profile"
-                              class="dropdown-item text-white dropdown-username-link" :to="toUserProfile()"><img
-                                  src="@/assets/icons/person.svg">User Profile</router-link></li>
-                            <li v-if="useUserInfoStore().isPremium"><router-link data-cy="budget"
-                              class="dropdown-item text-white dropdown-username-link" :to="toBudget()"><img>Budget</router-link></li>
-                            <li><router-link data-cy="friends"
-                              class="dropdown-item text-white dropdown-username-link" :to="toFriends()"><img
-                                src="@/assets/icons/friends.svg">Friends</router-link></li>
-                            <li><router-link data-cy="settings"
-                              class="dropdown-item text-white dropdown-username-link" :to="toSetting()"><img
-                                src="@/assets/icons/settings.svg">Settings</router-link></li>
-                            <li><router-link data-cy="feedback"
-                              class="dropdown-item text-white dropdown-username-link" :to="toFeedback()"><img
-                                src="@/assets/icons/feedback.svg">Feedback</router-link></li>
-                            <li><router-link data-cy="admin"
-                              class="dropdown-item text-white dropdown-username-link" :to="toSetting()"><img
-                                src="@/assets/icons/admin.svg">Admin</router-link></li>
-                            <li><a data-testid="logout" class="dropdown-item text-white dropdown-username-link" ref="#" @click="toLogout()"><img
-                                src="@/assets/icons/logout.svg">Log out</a></li>
-                        </ul>
-                    </li>
-                    <li v-else class="nav-item">
-                        <a class="nav-link text-white" href="#" @click="toLogout">Login</a>
-                    </li>
-                </ul>
-            </div>
-        </div>
-    </nav>
-</template>
-<script setup lang="ts">
-import { useRouter } from "vue-router";
-import { useUserInfoStore } from '@/stores/UserStore';
-import {onMounted, ref} from "vue";
-
-
-
-const router = useRouter();
-
-const userStore: any = useUserInfoStore();
-
-let profileImage: any = ref('');
-
-if (useUserInfoStore().profileImage !== 0) {
-    profileImage = 'http://localhost:8080/api/images/' + useUserInfoStore().profileImage;
-} else {
-    profileImage = 'src/assets/userprofile.png';
-}
-
-//Hashmap that contains the path to the Badges, The Friend, The dashboard etc.
-//The key value pair is the message of the notification and the path of the route
-let notifMap = ref (new Map<number, any[]>);
-
-let notifId = ref(0);
-
-let path = ref('#');
-
-let counter = ref(0)
-
-
-/* id: 0 -> /roadmap
-   id: 1 -> /profile
-   id: 2 -> /friend
- */
-
-
-
-function getNotification(){
-  //axios call
-  let response: any = ref( ['1', 'You have recived a award for getting 200 points'])
-  let response2: any = ref( ['2', 'You have recived a friend request from Jens Aanestad'])
-  let response3: any = ref( ['3', 'You have lost your streak. Come back to try again'])
-  notifMap.value.set(notifId.value,response.value)
-  notifId.value++
-  notifMap.value.set(notifId.value,response2.value)
-  notifId.value++
-  notifMap.value.set(notifId.value,response3.value)
-  notifId.value++
-
-  counter.value = notifMap.value.size
-}
-function toBadges(){
-
-}
-
-function getPath(id : string){
-  if(id === '1'){
-    return path.value = '/profile'
-  }
-  if(id === '2'){
-    return path.value = '/friends'
-  }
-  if(id === '3'){
-    return path.value = '/roadmap'
-  }
-
-  return '#';
-}
-
-function updateNotification(){
-  //Axios get request to the getFunction
-}
-
-function removeNotification() {
-
-}
-
-
-function toHome() {
-    return '/'
-}
-
-function toBudget() {
-    return '/budget-overview'
-}
-
-function toSavingGoals() {
-    return '/roadmap'
-}
-
-function toLeaderboard() {
-    return '/leaderboard'
-}
-
-function toNews() {
-    return '/news'
-}
-
-function toStore() {
-    return '/shop'
-}
-
-function toSetting() {
-    return '/settings/profile'
-}
-
-function toFeedback() {
-    return '/feedback'
-}
-
-function toFriends() {
-    return '/friends'
-}
-
-function toUserProfile() {
-    return '/profile'
-}
-
-function toLogout() {
-    userStore.clearUserInfo();
-    router.push('login')
-}
-onMounted(() => {
-  getNotification()
-})
-
-</script>
-<style scoped>
-.navbar-brand {
-    display: flex;
-    align-items: center;
-}
-
-.navbar-toggler-icon {
-    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3E%3Cpath stroke='rgba(255, 255, 255)' stroke-width='2' stroke-linecap='round' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E");
-}
-
-.nav-item {
-    padding: 0.3rem 0.6rem;
-    font-size: 1.7rem;
-}
-
-.nav-item:hover {
-    background-color: #2b6ac7;
-}
-.not-item:hover {
-  background-color: #2b6ac7;
-}
-
-.nav-item .dropdown {
-    display: flex;
-    justify-content: center;
-}
-
-.nav-link {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-}
-
-.dropdown-item {
-    width: 100%;
-    display: flex;
-    justify-content: center;
-}
-
-.dropdown-menu {
-    background-color: #0A58CA;
-    right: -0.5rem;
-}
-
-#notifyBtn  {
-  background-color: #0A58CA;
-  border: #0A58CA;
-}
-
-#notifyBtn:hover {
-  background-color: #2b6ac7;
-  border: #2b6ac7;
-}
-
-.dropdown-menu[data-bs-popper] {
-    left: auto;
-}
-
-.dropdown-username-link {
-    font-size: 1.7rem;
-    display: flex;
-    justify-self: center;
-}
-
-.dropdown-username-link:hover {
-    background-color: #2b6ac7;
-}
-
-#navBar {
-    background-color: #0A58CA;
-}
-
-.navbar {
-    display: flex;
-    align-items: center;
-}
-
-.container-fluid {
-    font-size: 1.7rem;
-}
-
-#logo {
-    font-size: 2.5rem;
-    height: 100%;
-}
-
-.nav-link img {
-    margin-right: 5px;
-}
-
-#logoImg {
-    margin-right: 0.3rem;
-    width: 75px;
-    height: auto;
-    aspect-ratio: 1.3/1;
-}
-.notification.hidden-arrow::after{
-  display: none;
-}
-
-
-</style>
\ No newline at end of file
diff --git a/src/components/BaseComponents/NavBar.vue b/src/components/BaseComponents/NavBar.vue
new file mode 100644
index 0000000000000000000000000000000000000000..62cb230905705022153d26ddd20449d532782f4f
--- /dev/null
+++ b/src/components/BaseComponents/NavBar.vue
@@ -0,0 +1,442 @@
+<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>
+      </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>
+          </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 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="notificationListRef.length > 0" class="badge rounded-pill badge-notification bg-danger">{{ notificationListRef.length }}</span>
+                        </a>
+                        <ul v-if="notificationListRef.length > 0" class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
+                          <li v-for="(item, index) in notificationListRef" :key="index" >
+                            <router-link :to="notificationPathMapper[String(item.notificationType)]"
+                                         class="d-flex align-items-center"
+                                         @click="readNotification(item)">
+                              <div class="flex-shrink-0">
+                                <img :src="notificationImageMapper[String(item.notificationType)]" alt="Varslingsikon"          class="notification-icon">
+                              </div>
+                              <div class="flex-grow-1 ms-3">
+                                <div class="not-item dropdown-item">{{item.message}}</div>
+                              </div>
+                            </router-link>
+                          </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', { '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="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, useRoute } from "vue-router";
+import { useUserInfoStore } from '@/stores/UserStore';
+import {onMounted, ref} from "vue";
+import { type NotificationDTO, NotificationService } from '@/api'
+import { afterWrite } from '@popperjs/core'
+
+
+
+const router = useRouter();
+const route = useRoute();
+
+const userStore: any = useUserInfoStore();
+
+let profileImage: any = ref('');
+
+if (useUserInfoStore().profileImage !== 0) {
+    profileImage = 'http://localhost:8080/api/images/' + useUserInfoStore().profileImage;
+} else {
+    profileImage = 'src/assets/userprofile.png';
+}
+
+
+let path = ref('#');
+
+let notificationListRef = ref<NotificationDTO[]>([]);
+
+
+ function isAnyActivePage() {
+  const activeRoutes = ['/roadmap', '/leaderboard', '/news', '/shop']; // Add other pages here
+  return activeRoutes.includes(route.path);
+}
+
+function toggleDropdown(event: any) {
+  const dropdownMenu = event.target.closest('.dropdown-menu');
+  if (dropdownMenu) {
+    dropdownMenu.classList.remove('show');
+  }
+}
+
+
+const notificationImageMapper: any = {
+  "FRIEND_REQUEST": "/src/assets/userprofile.png",
+  "BADGE": "/src/assets/icons/medal.png",
+  "COMPLETED_GOAL": "/src/assets/icons/piggybank.svg"
+}
+
+const notificationPathMapper: any = {
+  "FRIEND_REQUEST": "/friends",
+  "BADGE": "/profile",
+  "COMPLETED_GOAL": "/roadmap"
+}
+const getNotifications = async () => {
+  try {
+    notificationListRef.value = await NotificationService.getUnreadNotificationByUser()
+  } catch (error) {
+    notificationListRef.value = []
+  }
+}
+
+const readNotification = async (notification: NotificationDTO) => {
+  try {
+    notification.unread = false;
+    await NotificationService.updateNotification({requestBody: notification});
+    notificationListRef.value = await NotificationService.getUnreadNotificationByUser()
+  } catch (error) {
+    notificationListRef.value = [];
+  }
+}
+
+function toBadges(){
+
+}
+
+function getPath(id : string){
+  if(id === '1'){
+    return path.value = '/profile'
+  }
+  if(id === '2'){
+    return path.value = '/friends'
+  }
+  if(id === '3'){
+    return path.value = '/roadmap'
+  }
+
+  return '#';
+}
+
+function updateNotification(){
+  //Axios get request to the getFunction
+}
+
+function removeNotification() {
+
+}
+
+
+function toHome() {
+    return '/'
+}
+
+function toBudget() {
+    return '/budget-overview'
+}
+
+function toSavingGoals() {
+    return '/roadmap'
+}
+
+function toLeaderboard() {
+    return '/leaderboard'
+}
+
+function toNews() {
+    return '/news'
+}
+
+function toStore() {
+    return '/shop'
+}
+
+function toSetting() {
+    return '/settings/profile'
+}
+
+function toFeedback() {
+    return '/feedback'
+}
+
+function toFriends() {
+    return '/friends'
+}
+
+function toUserProfile() {
+    return '/profile'
+}
+
+function toLogout() {
+    userStore.clearUserInfo();
+    router.push('login')
+}
+onMounted(() => {
+  getNotifications()
+})
+
+</script>
+<style scoped>
+.navbar-brand {
+    display: flex;
+    align-items: center;
+}
+
+.navbar-toggler-icon {
+    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3E%3Cpath stroke='rgba(255, 255, 255)' stroke-width='2' stroke-linecap='round' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E");
+}
+
+.nav-item {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    padding: 0.1rem 0.3rem;
+    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;
+}
+
+.not-item:hover {
+  background-color: #f3f3f3;
+}
+
+.nav-item .dropdown {
+    display: flex;
+    justify-content: center;
+}
+
+.nav-link {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+}
+
+.dropdown-item {
+    width: 100%;
+    display: flex;
+    justify-content: left;
+}
+
+.dropdown-item:hover {
+  width: 100%;
+}
+
+.dropdown-menu {
+  padding: 5px;
+  right: -0.5rem;
+}
+
+.dropdown-menu[data-bs-popper] {
+    left: auto;
+}
+
+.dropdown-username-link {
+    font-size: 1.7rem;
+    display: flex;
+    justify-self: center;
+}
+
+.dropdown-username-link:hover {
+    background-color: #f3f3f3;
+}
+
+.dropdown-item img {
+  height: 35px;
+  width: 35px;
+  margin-right: 5px;
+}
+
+#navBar {
+    background-color: #003A58;
+}
+
+.notification-icon {
+  height: 35px;
+  width: 35px;
+}
+
+.nav-item a {
+  font-size: 19px;
+}
+
+.navbar {
+    display: flex;
+    align-items: center;
+}
+
+.container-fluid {
+    font-size: 1.7rem;
+}
+
+#logo {
+    font-size: 2.5rem;
+    height: 100%;
+}
+
+.nav-link img {
+    margin-right: 5px;
+  height: 35px;
+  width: 35px;
+}
+
+#logoImg {
+    margin-right: 0.3rem;
+    width: 75px;
+    height: auto;
+    aspect-ratio: 1.3/1;
+}
+
+.notification.hidden-arrow::after{
+  display: none;
+}
+
+
+</style>
\ No newline at end of file
diff --git a/src/components/BaseComponents/__tests__/Footer.spec.ts b/src/components/BaseComponents/__tests__/BaseFooter.spec.ts
similarity index 58%
rename from src/components/BaseComponents/__tests__/Footer.spec.ts
rename to src/components/BaseComponents/__tests__/BaseFooter.spec.ts
index 25968d67433031c9353e3aaab288b1032fc8085e..4bf16d9bcd500003c0260e456a8633d40c1f4a17 100644
--- a/src/components/BaseComponents/__tests__/Footer.spec.ts
+++ b/src/components/BaseComponents/__tests__/BaseFooter.spec.ts
@@ -1,12 +1,12 @@
 import { describe, it, expect } from 'vitest'
 import { mount } from '@vue/test-utils'
-import FooterComponent from '@/components/BaseComponents/Footer.vue'
+import FooterComponent from '../BaseFooter.vue'
 
 describe('FooterComponent', () => {
   it('renders properly and includes the correct copyright notice', () => {
     const wrapper = mount(FooterComponent)
     const footer = wrapper.find('#footer')
     expect(footer.exists()).toBe(true)
-    expect(footer.text()).toContain('© 2024 Copyright: Anders Høvik, Andreas Svendsrud, Henrik Dybdal, Henrik Sandok, Jens Aanestad, Victor Kaste, Viktor Grevskott')
+    expect(footer.text()).toContain('© SpareSti 2024')
   })
 })
diff --git a/src/components/BaseComponents/__tests__/Menu.spec.ts b/src/components/BaseComponents/__tests__/NavBar.spec.ts
similarity index 97%
rename from src/components/BaseComponents/__tests__/Menu.spec.ts
rename to src/components/BaseComponents/__tests__/NavBar.spec.ts
index 2ce9eec0a4007d222b8f5ce61aef4b0387471e91..dcbc92d44f1f013375c4a5d60b5d6b0bd49cfd92 100644
--- a/src/components/BaseComponents/__tests__/Menu.spec.ts
+++ b/src/components/BaseComponents/__tests__/NavBar.spec.ts
@@ -3,7 +3,7 @@ import { mount } from '@vue/test-utils';
 import { createRouter, createMemoryHistory } from 'vue-router';
 import { createPinia, setActivePinia } from 'pinia';
 import { useUserInfoStore } from '@/stores/UserStore';
-import MyComponent from '@/components/BaseComponents/Menu.vue'; // Adjust path as needed
+import MyComponent from '../NavBar.vue'; // Adjust path as needed
 import router from '@/router/index'; // Adjust path as needed
 import { access } from 'fs';
 import { render, screen } from '@testing-library/vue';
diff --git a/src/components/Budget/BudgetBox.vue b/src/components/Budget/BudgetBox.vue
index 41a1c56296cadc428314bae52730e13dff3ec6c2..96fafc1b3aeb446457e638722c6899067fb17b14 100644
--- a/src/components/Budget/BudgetBox.vue
+++ b/src/components/Budget/BudgetBox.vue
@@ -91,7 +91,7 @@ const onBudgetDeleted = () => {
       </i>
       <div class="expenses-container">
         <h5>{{expenses}} kr</h5>
-        <p>Expenses</p>
+        <p>Utgifter</p>
       </div>
     </div>
 
@@ -101,7 +101,7 @@ const onBudgetDeleted = () => {
       </i>
       <div class="balance-container">
         <h5>{{balance}} kr</h5>
-        <p>Balance</p>
+        <p>Saldo</p>
       </div>
     </div>
   </div>
diff --git a/src/components/Budget/ExpenseBox.vue b/src/components/Budget/ExpenseBox.vue
index 1100cd486f9900e90b196e457a96a37d36eb8fcb..7cf7c976fd2385453b74ddde964ba596d4902c46 100644
--- a/src/components/Budget/ExpenseBox.vue
+++ b/src/components/Budget/ExpenseBox.vue
@@ -50,11 +50,11 @@ const emitEditEvent = () => {
     <p>{{amount}} kr</p>
     <button class="btn btn-success" data-bs-toggle="collapse" :data-bs-target="'#' + index" aria-expanded="false" aria-controls="editBudgetCollapse">
       <img src="../../assets/icons/edit-button.svg" alt="Edit" height="18" width="18">
-      Edit
+      Endre
     </button>
     <button class="btn btn-danger" @click="emitDeleteEvent">
       <img src="../../assets/icons/trash-can.svg" alt="Edit" height="18" width="18">
-      Delete
+      Slett
     </button>
   </div>
 
@@ -62,10 +62,10 @@ const emitEditEvent = () => {
     <div class="container collapse-container">
       <form @submit.prevent="emitEditEvent">
         <div class="input-group">
-          <span class="input-group-text">Edit expense {{ index+1 }} </span>
-          <input type="text" class="form-control" placeholder="Expense description" required v-model="editDescription">
+          <span class="input-group-text">Endre utgift {{ index+1 }} </span>
+          <input type="text" class="form-control" placeholder="Utgift beskrivelse" required v-model="editDescription">
           <input type="number" min="0" class="form-control" placeholder="Amount (kr)" required v-model="editAmount">
-          <button type="submit" class="btn btn-primary" data-bs-toggle="collapse" :data-bs-target="'#' + index">Confirm</button>
+          <button type="submit" class="btn btn-primary" data-bs-toggle="collapse" :data-bs-target="'#' + index">Bekreft</button>
         </div>
       </form>
     </div>
diff --git a/src/components/Budget/Modal/ConfirmDeleteModal.vue b/src/components/Budget/Modal/ConfirmDeleteModal.vue
index a0966b9aa6ac4edb4e67aafa078d942897519d64..0644da13bdc34b26a4a04955c404c566085972ae 100644
--- a/src/components/Budget/Modal/ConfirmDeleteModal.vue
+++ b/src/components/Budget/Modal/ConfirmDeleteModal.vue
@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { UserService } from '@/api'
+import { BudgetService } from '@/api'
 
 const emit = defineEmits(['errorEvent', 'deletedEvent'])
 const props = defineProps({
@@ -22,7 +22,7 @@ const props = defineProps({
  */
 const deleteBudget = async () => {
   try {
-    await UserService.deleteBudget({budgetId: props.budgetId})
+    await BudgetService.deleteBudget({budgetId: props.budgetId})
     emit('deletedEvent')
   } catch (error) {
     emit('errorEvent', error)
@@ -36,12 +36,12 @@ const deleteBudget = async () => {
     <div class="modal-dialog modal-dialog-centered">
       <div class="modal-content">
         <div class="modal-header">
-          <h3>Are you sure you want to delete this budget <i>{{ budgetTitle }}?</i></h3>
+          <h3>Er du sikker på at du vil slette dette budgettet <i>{{ budgetTitle }}?</i></h3>
           <button class="btn btn-close" data-bs-dismiss="modal"></button>
         </div>
         <div class="modal-body">
-          <button class="btn btn-primary" data-bs-dismiss="modal" @click="deleteBudget">Yes</button>
-          <button class="btn btn-primary" data-bs-dismiss="modal">No</button>
+          <button class="btn btn-primary" data-bs-dismiss="modal" @click="deleteBudget">Ja</button>
+          <button class="btn btn-primary" data-bs-dismiss="modal">Nei</button>
         </div>
       </div>
     </div>
diff --git a/src/components/Budget/Modal/ImportBudgetModal.vue b/src/components/Budget/Modal/ImportBudgetModal.vue
index 47ab56b45c0d83de337a09af0cbd880bbd656cc2..cd39a0434c49def5f87bdc311c55d8c753253e7f 100644
--- a/src/components/Budget/Modal/ImportBudgetModal.vue
+++ b/src/components/Budget/Modal/ImportBudgetModal.vue
@@ -30,7 +30,7 @@ const emitImportBudgetEvent = (budgetId: number) => {
     <div class="modal-dialog modal-dialog-centered modal-lg">
       <div class="modal-content">
         <div class="modal-header">
-          <h3>Choose a budget you would like to import</h3>
+          <h3>Velg et budget du vil importere</h3>
           <button class="btn btn-close" data-bs-dismiss="modal"></button>
         </div>
         <div class="modal-body">
@@ -41,7 +41,7 @@ const emitImportBudgetEvent = (budgetId: number) => {
                          :budget-amount="Number(item.budgetAmount)"
                          :expense-amount="Number(item.expenseAmount)"
                          @importBudgetEvent="emitImportBudgetEvent"
-          >
+                         data-bs-dismiss="modal">
           </MiniBudgetBox>
         </div>
       </div>
diff --git a/src/components/Buttons/Button1.vue b/src/components/Buttons/Button1.vue
deleted file mode 100644
index 09ee44c50d14e81245926400342e4fc8f378ac9e..0000000000000000000000000000000000000000
--- a/src/components/Buttons/Button1.vue
+++ /dev/null
@@ -1,15 +0,0 @@
-<template>
-    <button type="button" class="btn btn-primary" id="buttonStyle">{{ buttonText }}</button>
-</template>
-
-<script setup lang="ts">
-defineProps<{ buttonText: string }>();
-</script>
-
-<style scoped>
-    #buttonStyle {
-        padding: 0.5rem 4rem;
-        font-size: 1.5rem;
-        font-weight: 600;
-    }
-</style>
diff --git a/src/components/Configuration/ChallangeCheckBox.vue b/src/components/Configuration/ChallangeCheckBox.vue
index 2157aa34568ad97ab1634ba44fec076463914a74..58720ba2308be0bb592db6118c09e9939fba82fe 100644
--- a/src/components/Configuration/ChallangeCheckBox.vue
+++ b/src/components/Configuration/ChallangeCheckBox.vue
@@ -10,6 +10,10 @@ const props = defineProps({
     type: String,
     default: ''
   },
+  enumValue: {
+    type: String,
+    default: ''
+  },
   modelValue: {
     type: Boolean,
     default: false
@@ -24,21 +28,24 @@ const props = defineProps({
  */
 const onChallengeChanged = (event: any) => {
   const value = event.target.checked
-  const data = [props.text, value]
+  const data = [props.enumValue, value]
   emit('challengeChangedEvent', data)
 }
 
 </script>
 
 <template>
-  <span>
+  <div class="col-auto">
     <input @change="onChallengeChanged" type="checkbox" class="btn-check" :id="props.id" autocomplete="off">
     <label class="btn btn-outline-primary align-items-center justify-content-center" :for="props.id">{{ props.text }}</label>
-  </span>
+  </div>
 </template>
 
 <style scoped>
 label {
   margin: 5px
 }
+div.col-auto {
+  padding: 0;
+}
 </style>
\ No newline at end of file
diff --git a/src/components/Configuration/Configuration.vue b/src/components/Configuration/ConfigurationParent.vue
similarity index 88%
rename from src/components/Configuration/Configuration.vue
rename to src/components/Configuration/ConfigurationParent.vue
index 4f52d07e4f2aa9e2d66860a9683ad1f1198395a6..06a6872cc8663d40d5d4a8fd6828a14e329c8ea9 100644
--- a/src/components/Configuration/Configuration.vue
+++ b/src/components/Configuration/ConfigurationParent.vue
@@ -7,7 +7,7 @@ import { useRoute } from 'vue-router'
 const router = useRouter()
 
 // The configuration steps with path and order value.
-const configurationSteps = {'/commitment': 1, '/experience': 2, '/suitable-challenges': 3}
+const configurationSteps = {'/bank-account': 1,'/commitment': 2, '/experience': 3, '/suitable-challenges': 4, '/first-saving-goal': 5, '/finished-configuration': 6}
 const length = Object.keys(configurationSteps).length
 let percentage = ref(1/length);
 
diff --git a/src/components/Configuration/ConfigurationSteps/BankAccount.vue b/src/components/Configuration/ConfigurationSteps/BankAccount.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e37709b89e5681de22914d80683993007bc4838c
--- /dev/null
+++ b/src/components/Configuration/ConfigurationSteps/BankAccount.vue
@@ -0,0 +1,89 @@
+<script setup lang="ts">
+import { useRouter } from 'vue-router'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
+import { ref } from 'vue'
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue'
+import { useConfigurationStore } from '@/stores/ConfigurationStore'
+
+const router = useRouter();
+
+const formRef = ref();
+const spendingAccount = ref<string>('');
+const savingsAccount = ref<string>('');
+let errorMsg = ref('');
+
+// Updates progress bar in the parent Configuration component.
+const emit = defineEmits(['changeRouterEvent'])
+emit('changeRouterEvent', '/bank-account')
+
+const handleSpendingInputEvent = (newValue: any) => {
+  spendingAccount.value = newValue
+}
+
+const handleSavingInputEvent = (newValue: any) => {
+  savingsAccount.value = newValue
+}
+const handleSubmit = () => {
+  formRef.value.classList.add("was-validated")
+  const form = formRef.value;
+  if (form.checkValidity()) {
+    useConfigurationStore().setSpendingAccount(Number(spendingAccount.value))
+    useConfigurationStore().setSavingsAccount(Number(savingsAccount.value))
+    router.push("/commitment")
+  }
+}
+</script>
+
+<template>
+  <div class="container">
+    <h3 id="bankAccountText" class="d-flex align-items-center justify-content-center">
+      Velg forburkskonto og sparekonto
+    </h3>
+    <form ref="formRef">
+      <BaseInput data-cy="spending-account-input"
+                 :model-value="spendingAccount"
+                 @input-change-event="handleSpendingInputEvent"
+                 id="spending-account-base-input"
+                 input-id="spending-account-input"
+                 type="number"
+                 min="10000000000"
+                 max="99999999999"
+                 label="Brukskonto"
+                 placeholder="Skriv inn din brukskonto"
+                 invalid-message="Vennligst skriv inn din brukskonto (11 siffer)"/>
+
+      <BaseInput data-cy="savings-account-input"
+                 :model-value="savingsAccount"
+                 @input-change-event="handleSavingInputEvent"
+                 id="saving-account-base-input"
+                 input-id="savings-account-input"
+                 type="number"
+                 min="10000000000"
+                 max="99999999999"
+                 label="Sparekonto"
+                 placeholder="Skriv inn din sparekonto"
+                 invalid-message="Vennligst skriv inn din sparekonto (11 siffer)"/>
+    </form>
+    <div style="color: red">{{ errorMsg }}</div>
+    <div class="confirm-button-container">
+      <BaseButton id="confirmButton" @click="handleSubmit" button-text="Fortsett"></BaseButton>
+    </div>
+  </div>
+</template>
+
+<style scoped>
+#confirmButton {
+  margin: 2rem 0 ;
+  height: 38px;
+  width: 300px;
+}
+
+#spending-account-base-input, #spending-account-base-input {
+  margin: 1rem 0;
+}
+
+.confirm-button-container {
+  display: flex;
+  justify-content: center;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/Configuration/ConfigurationSteps/BankId.vue b/src/components/Configuration/ConfigurationSteps/BankId.vue
deleted file mode 100644
index bc40db3e7cd5aa6501e2daef33dc14842df2637c..0000000000000000000000000000000000000000
--- a/src/components/Configuration/ConfigurationSteps/BankId.vue
+++ /dev/null
@@ -1,82 +0,0 @@
-<script setup lang="ts">
-/*
-import Button1 from '@/components/Buttons/Button1.vue'
-import { useRouter } from 'vue-router'
-import { ref } from 'vue'
-
-const formRef = ref()
-const bankIDRef = ref(false)
-const minIdRef = ref(false)
-const vippsRef = ref(false)
-
-
-const router = useRouter();
-const emit = defineEmits(['changeRouterEvent']);
-emit('changeRouterEvent', '/bank-id');
-
-const onClick = () => {
-  const radios = formRef.value.querySelectorAll('input[type="radio"]');
-  const checkedRadios = Array.from(radios).filter(radio => radio.checked);
-
-  if (checkedRadios.length === 0) {
-    alert('Please select an option.');
-    return;
-  }
-
-  let choice = ''
-  if (bankIDRef.value.checked) choice = 'BankId på mobil'
-  else if (minIdRef.value.checked) choice = 'MinId'
-  else if (vippsRef.value.checked) choice = 'Vipps'
-
-  emit('bankIdSelectedEvent', choice)
-  router.push('/commitment')
-}
-*/
-</script>
-
-<template>
-  <!--
-  <div class="container">
-    <div>
-      <h3 class="d-flex align-items-center justify-content-center">
-        In order to provide best advice we need to connect to your bank account
-      </h3>
-    </div>
-
-    <form class="btn-group-vertical" ref="formRef" @submit.prevent="onClick">
-
-      <input ref="bankIDRef" type="radio" class="btn-check" name="bank-id" id="btn-check-outlined" autocomplete="off">
-      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check-outlined">BankID på mobil</label>
-
-      <input ref="minIdRef" type="radio" class="btn-check" name="bank-id" id="btn-check2-outlined" autocomplete="off">
-      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check2-outlined">MinID</label>
-
-      <input ref="vippsRef" type="radio" class="btn-check" name="bank-id" id="btn-check3-outlined" autocomplete="off">
-      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check3-outlined">Vipps</label>
-
-    </form>
-
-    <div class="confirm-button-container">
-      <button1 id="confirmButton"
-               @click="onClick"
-               button-text="Continue">
-      </button1>
-    </div>
-
-  </div>
-  -->
-</template>
-
-<style scoped>
-/*
-#confirmButton {
-  margin-bottom: 2rem;
-  width: 300px;
-}
-
-.confirm-button-container {
-  display: flex;
-  justify-content: center;
-}
- */
-</style>
\ No newline at end of file
diff --git a/src/components/Configuration/ConfigurationSteps/Commitment.vue b/src/components/Configuration/ConfigurationSteps/ConfigurationCommitment.vue
similarity index 82%
rename from src/components/Configuration/ConfigurationSteps/Commitment.vue
rename to src/components/Configuration/ConfigurationSteps/ConfigurationCommitment.vue
index c1bada78d6fb8d8266eabec74833dcff8a8c3543..836ec18e28f118e65a09a76e803cdac2317d5700 100644
--- a/src/components/Configuration/ConfigurationSteps/Commitment.vue
+++ b/src/components/Configuration/ConfigurationSteps/ConfigurationCommitment.vue
@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import Button1 from '@/components/Buttons/Button1.vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
 import { useRouter } from 'vue-router'
 import { ref } from 'vue'
 import { useConfigurationStore } from '@/stores/ConfigurationStore'
@@ -23,7 +23,7 @@ let errorMsg = ref();
  * and navigates to the '/experience' route. If form validation fails, displays
  * an error message prompting the user to select an option before continuing.
  */
-const onClick = () => {
+const handleSubmit = () => {
   const form = formRef.value;
   if (form.checkValidity()) {
     let choice = '';
@@ -43,27 +43,28 @@ const onClick = () => {
 <template>
   <div class="container">
     <h3 id="commitmentText" class="align-items-center justify-content-center">
-      In which degree are you willing to make changes?
+      I hvilken grad er du villig til å gjøre endringer?
     </h3>
-    <form class="btn-group-vertical" ref="formRef" @submit.prevent="onClick">
+    <form class="btn-group-vertical" ref="formRef">
 
       <input ref="lowRef" type="radio" class="btn-check" name="commitment" id="btn-check-outlined" autocomplete="off" required>
-      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check-outlined">Low</label>
+      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check-outlined">Lav</label>
 
       <input ref="mediumRef" type="radio" class="btn-check" name="commitment" id="btn-check2-outlined" autocomplete="off" required>
-      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check2-outlined">Medium</label>
+      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check2-outlined">Middels</label>
 
       <input ref="highRef" type="radio" class="btn-check" name="commitment" id="btn-check3-outlined" autocomplete="off" required>
-      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check3-outlined">High</label>
+      <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check3-outlined">Høy</label>
 
     </form>
     <p class="text-danger">{{ errorMsg }}</p>
     <div class="confirm-button-container">
-      <button1 id="confirmButton" @click="onClick" button-text="Continue"></button1>
+      <BaseButton id="confirmButton" @click="handleSubmit" button-text="Fortsett"></BaseButton>
     </div>
   </div>
 </template>
 
+
 <style scoped>
 div.container {
   display: flex;
diff --git a/src/components/Configuration/ConfigurationSteps/Experience.vue b/src/components/Configuration/ConfigurationSteps/ConfigurationExperience.vue
similarity index 91%
rename from src/components/Configuration/ConfigurationSteps/Experience.vue
rename to src/components/Configuration/ConfigurationSteps/ConfigurationExperience.vue
index c750f58d2c8c474b8488ae1770cc84b1cf055c7c..2118af6a65afe5d0c8e6abe29f990db7416a595f 100644
--- a/src/components/Configuration/ConfigurationSteps/Experience.vue
+++ b/src/components/Configuration/ConfigurationSteps/ConfigurationExperience.vue
@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import Button1 from '@/components/Buttons/Button1.vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
 import { useRouter } from 'vue-router'
 import { ref } from 'vue'
 import { useConfigurationStore } from '@/stores/ConfigurationStore'
@@ -23,7 +23,7 @@ let errorMsg = ref();
  * and navigates to the '/suitable challenges' route. If form validation fails, displays
  * an error message prompting the user to select an option before continuing.
  */
-const onClick = () => {
+const handleSubmit = () => {
   const form = formRef.value;
   if (form.checkValidity()) {
     let choice = ''
@@ -48,7 +48,7 @@ const onClick = () => {
       </h3>
     </div>
 
-    <form class="btn-group-vertical" ref="formRef" @submit.prevent="onClick">
+    <form class="btn-group-vertical" ref="formRef">
 
       <input ref="beginnerRef" type="radio" class="btn-check" name="experience" id="btn-check-outlined" autocomplete="off" required>
       <label class="btn btn-outline-primary d-flex align-items-center justify-content-center" for="btn-check-outlined">Beginner</label>
@@ -61,7 +61,7 @@ const onClick = () => {
     </form>
     <p class="text-danger">{{ errorMsg }}</p>
     <div class="confirm-button-container">
-      <button1 id="confirmButton" @click="onClick" button-text="Continue"></button1>
+      <BaseButton id="confirmButton" @click="handleSubmit" button-text="Continue"/>
     </div>
 </div>
 </template>
diff --git a/src/components/Configuration/ConfigurationSteps/ConfigurationSavingGoal.vue b/src/components/Configuration/ConfigurationSteps/ConfigurationSavingGoal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f6bf338f7ff5455a9777ed3c00aa51cf6c39747f
--- /dev/null
+++ b/src/components/Configuration/ConfigurationSteps/ConfigurationSavingGoal.vue
@@ -0,0 +1,141 @@
+<script setup lang="ts">
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue'
+import { ref } from 'vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
+import { useRouter } from 'vue-router'
+import {type CreateGoalDTO, GoalService} from "@/api";
+
+const router = useRouter();
+const emit = defineEmits(['changeRouterEvent'])
+emit('changeRouterEvent', '/first-saving-goal')
+
+const formRef = ref<any>()
+const titleRef = ref<string>()
+let descriptionRef = ref<string>()
+const sumRef = ref<number>()
+const dateRef = ref<string>()
+const errorMessage = ref("")
+
+const handleSubmit = async () => {
+  formRef.value.classList.add("was-validated")
+  const form = formRef.value
+  if (!form.checkValidity()) {
+    return;
+  }
+
+  // TODO integrate user creation and goal creation with backend.
+  const createGoalPayload: CreateGoalDTO = {
+    name: titleRef.value,
+    description: descriptionRef.value,
+    targetAmount: sumRef.value,
+    targetDate: dateRef.value + " 00:00:00.000000000",
+  };
+
+  try {
+    await GoalService.createGoal({ requestBody: createGoalPayload });
+    await router.push("/")
+  } catch (error: any) {
+    console.log(error.message);
+    errorMessage.value = error.message;
+  }
+}
+
+const getTodayDate = () => {
+  const today = new Date();
+  const year = today.getFullYear();
+  let month: string | number = today.getMonth() + 1;
+  let day: string | number = today.getDate();
+  // Ensure month and day are in double digits
+  month = month < 10 ? `0${month}` : month;
+  day = day < 10 ? `0${day}` : day;
+  return `${year}-${month}-${day}`;
+};
+
+const handleTitleInputEvent = (newTitle: string) => {
+  titleRef.value = newTitle;
+}
+
+const handleDateInputEvent = (newDate: string) => {
+  dateRef.value = newDate;
+}
+
+const handleSumInputEvent = (newSum: number) => {
+  sumRef.value = newSum;
+}
+
+</script>
+
+<template>
+
+  <div class="container">
+    <div>
+      <h3 class="d-flex align-items-center justify-content-center">
+        Now it remains only one step
+      </h3>
+      <h5 class="d-flex align-items-center justify-content-center">
+        Create your first saving goal
+      </h5>
+    </div>
+
+    <form ref="formRef" id="loginForm">
+      <BaseInput :model-value="titleRef"
+                 @input-change-event="handleTitleInputEvent"
+                 id="titleInput"
+                 input-id="title"
+                 label="Title"
+                 placeholder="Enter the title of the saving goal"/>
+      <div>
+        <label for="description">Description</label>
+        <textarea v-model="descriptionRef"
+                  type="text"
+                  maxlength="150"
+                  class="form-control"
+                  placeholder="Enter description of the saving goal here (optional)"
+                  id="description"/>
+      </div>
+      <BaseInput :model-value="dateRef"
+                 @input-change-event="handleDateInputEvent"
+                 id="dueDateInput"
+                 input-id="dueDate"
+                 type="date"
+                 :min="getTodayDate()"
+                 label="Due date"/>
+      <BaseInput :model-value="sumRef"
+                 @input-change-event="handleSumInputEvent"
+                 id="sumToSaveInput"
+                 input-id="sumToSpareInput"
+                 type="number"
+                 label="Sum to save"
+                 min="0"
+                 placeholder="Enter the sum you would like to spare (kr)"/>
+    </form>
+
+    <div class="confirm-button-container">
+      <BaseButton id="confirmButton" @click="handleSubmit" button-text="Continue"></BaseButton>
+    </div>
+    <div style="color: red">
+      {{ errorMessage }}
+    </div>
+  </div>
+
+</template>
+
+<style scoped>
+
+#description {
+  resize: none;
+  height: auto;
+}
+
+#confirmButton {
+  margin-top: 1rem;
+  margin-bottom: 2rem;
+  width: 300px;
+}
+
+.confirm-button-container {
+  display: flex;
+  justify-content: center;
+}
+
+</style>
\ No newline at end of file
diff --git a/src/components/Configuration/ConfigurationSteps/FirstSavingGoal.vue b/src/components/Configuration/ConfigurationSteps/FirstSavingGoal.vue
deleted file mode 100644
index da397304a8cdc40ea8e21212fc440a64d30c2a1c..0000000000000000000000000000000000000000
--- a/src/components/Configuration/ConfigurationSteps/FirstSavingGoal.vue
+++ /dev/null
@@ -1,92 +0,0 @@
-<script setup lang="ts">
-/*
-import BaseInput from '@/components/InputFields/BaseInput.vue'
-import { ref } from 'vue'
-import Button1 from '@/components/Buttons/Button1.vue'
-
-import { useRouter } from 'vue-router'
-
-const router = useRouter();
-
-const emit = defineEmits(['changeRouterEvent'])
-emit('changeRouterEvent', '/first-saving-goal')
-
-const formRef = ref()
-const titleRef = ref()
-const sumRef = ref()
-const dateRef = ref()
-
-const onClick = () => {
-  formRef.value.classList.add("was-validated")
-}
-
-const getTodayDate = () => {
-  const today = new Date();
-  const year = today.getFullYear();
-  let month = today.getMonth() + 1;
-  let day = today.getDate();
-
-  // Ensure month and day are in double digits
-  month = month < 10 ? `0${month}` : month;
-  day = day < 10 ? `0${day}` : day;
-
-  console.log(`${year}-${month}-${day}`)
-
-  return `${year}-${month}-${day}`;
-};
- */
-</script>
-
-<template>
-  <!--
-  <div class="container">
-    <div>
-      <h3 class="d-flex align-items-center justify-content-center">
-        Create your first saving goal
-      </h3>
-    </div>
-
-    <form ref="formRef" id="loginForm" @submit.prevent="handleSubmit">
-      <BaseInput :model-value="titleRef"
-                 @input-change-event="handleEmailInputEvent"
-                 id="titleInput"
-                 input-id="title"
-                 label="Title"
-                 placeholder="Enter the title of the saving goal"/>
-      <BaseInput :model-value="sumRef"
-                 @input-change-event="handlePasswordInputEvent"
-                 id="sumToSaveInput"
-                 input-id="sumToSpareInput"
-                 type="number"
-                 label="Sum to save"
-                 min="0"
-                 placeholder="Enter the sum you would like to spare"/>
-      <BaseInput :model-value="dateRef"
-                 @input-change-event="handlePasswordInputEvent"
-                 id="dueDateInput"
-                 input-id="dueDate"
-                 type="date"
-                 :min="getTodayDate()"
-                 label="Due date"/>
-    </form>
-
-    <div class="confirm-button-container">
-      <button1 id="confirmButton" @click="onClick" button-text="Continue"></button1>
-    </div>
-  </div>
-  -->
-</template>
-
-<style scoped>
-/*
-#confirmButton {
-  margin-bottom: 2rem;
-  width: 300px;
-}
-
-.confirm-button-container {
-  display: flex;
-  justify-content: center;
-}
-*/
-</style>
\ No newline at end of file
diff --git a/src/components/Configuration/ConfigurationSteps/SuitableChallenges.vue b/src/components/Configuration/ConfigurationSteps/SuitableChallenges.vue
index fdd40040bc6141518e62002c4979711cd9f920d6..75adea95c76415912777c1dbd0dee504bdac04ec 100644
--- a/src/components/Configuration/ConfigurationSteps/SuitableChallenges.vue
+++ b/src/components/Configuration/ConfigurationSteps/SuitableChallenges.vue
@@ -1,11 +1,11 @@
 <script setup lang="ts">
 import { useRouter } from 'vue-router'
 import ChallangeCheckBox from '@/components/Configuration/ChallangeCheckBox.vue'
-import Button1 from '@/components/Buttons/Button1.vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
 import { ref } from 'vue'
 import { useConfigurationStore } from '@/stores/ConfigurationStore'
 import { useUserInfoStore } from '@/stores/UserStore'
-import { AuthenticationService, OpenAPI} from '@/api'
+import { AuthenticationService, OpenAPI, type SignUpRequest } from '@/api'
 import handleUnknownError from '@/components/Exceptions/unkownErrorHandler'
 
 const router = useRouter();
@@ -15,12 +15,11 @@ const emit = defineEmits(['changeRouterEvent'])
 emit('changeRouterEvent', '/suitable-challenges')
 
 // Reactive variables for chosen challenges and error message.
-let chosenChallenges = ref([])
+let chosenChallenges = ref<string[]>([])
 let errorMsg = ref('')
 
 // Represents a list of available challenges.
-const challenges = ['Make packed lunch', 'Stop shopping', 'Drop coffee',
-  'Quit subscription', 'Drop car', 'Short showers', 'Exercise outside', 'Make budget']
+const challenges: string[] = ['NO_COFFEE' , 'NO_CAR' , 'SHORTER_SHOWER' , 'SPEND_LESS_ON_FOOD' , 'BUY_USED_CLOTHES' , 'LESS_SHOPPING' , 'DROP_SUBSCRIPTION' , 'SELL_SOMETHING' , 'BUY_USED' , 'EAT_PACKED_LUNCH' , 'STOP_SHOPPING' , 'ZERO_SPENDING' , 'RENT_YOUR_STUFF' , 'MEATLESS' , 'SCREEN_TIME_LIMIT' , 'UNPLUGGED_ENTERTAINMENT']
 
 /**
  * Handles the event when a challenge is selected or deselected.
@@ -40,38 +39,29 @@ const onChangedChallengeEvent = (value: never) => {
   console.log(chosenChallenges.value)
 }
 
+const convertEnumToText = (enumValue: String) => {
+  return enumValue.charAt(0).toUpperCase() + enumValue.slice(1).replace(/_/g, ' ').toLowerCase();
+}
+
 /**
  * Retrieves user configuration and signup information, sends a signup request to the backend.
  *
  * @throws {Error} Throws an error if signup fails.
  */
-const onClick = async () => {
+const signUpUser = async () => {
   try {
     // Saves the chosen challenges to the configuration store
     useConfigurationStore().setChallenges(chosenChallenges.value)
 
-    /*
-    TODO: 'changeWilling' are updated to 'commitment' in backend, must update it in frontend
-    const signUpPayLoad: SignUpRequest = {
-      changeWilling: useConfigurationStore().getCommitment,
-      experience: useConfigurationStore().getExperience,
-      challenges: useConfigurationStore().getChallenges,
+    const signUpPayLoad: SignUpRequest  = {
       firstName: useUserInfoStore().getFirstName,
       lastName: useUserInfoStore().getLastname,
       email: useUserInfoStore().getEmail,
       password: useUserInfoStore().getPassword,
-    };
-     */
-
-    const signUpPayLoad = {
-      "firstName": useUserInfoStore().getFirstName,
-      "lastName": useUserInfoStore().getLastname,
-      "email": useUserInfoStore().getEmail,
-      "password": useUserInfoStore().getPassword,
-      "configuration": {
-        "commitment": useConfigurationStore().getCommitment,
-        "experience": useConfigurationStore().getExperience,
-        "challenges": useConfigurationStore().getChallenges
+      configuration: {
+        commitment: useConfigurationStore().getCommitment,
+        experience: useConfigurationStore().getExperience,
+        challengeTypes: useConfigurationStore().getChallenges
       }
     };
 
@@ -86,13 +76,26 @@ const onClick = async () => {
       role: response.role,
     });
     useUserInfoStore().resetPassword()
-    await router.push({ name: 'home' });
+    await router.push("/first-saving-goal")
   }
   catch (error) {
     errorMsg.value = handleUnknownError(error);
   }
 }
 
+const handleSubmit = () => {
+  if (chosenChallenges.value.length === 0) {
+    chosenChallenges.value = challenges
+  }
+  useConfigurationStore().setChallenges(chosenChallenges.value)
+  console.log(useConfigurationStore().getChallenges)
+  try {
+    signUpUser()
+  } catch (e) {
+    console.log(e)
+  }
+}
+
 </script>
 
 <template>
@@ -103,16 +106,18 @@ const onClick = async () => {
       </h3>
     </div>
 
-    <div class="challenge-container">
-      <ChallangeCheckBox v-for="(item, index) in challenges" :id="String(index)" :text="item"
-                         @challengeChangedEvent="onChangedChallengeEvent"
-      />
+    <div class="challenge-container row justify-content-center">
+      <ChallangeCheckBox v-for="(item, index) in challenges"
+                         :id="String(index)"
+                         :text="convertEnumToText(item)"
+                         :enum-value="item"
+                         @challengeChangedEvent="onChangedChallengeEvent"/>
     </div>
 
     <p class="text-danger">{{ errorMsg }}</p>
 
     <div class="confirm-button-container">
-      <button1 id="confirmButton" @click="onClick" button-text="Finish configuration"></button1>
+      <BaseButton id="confirmButton" @click="handleSubmit" button-text="Continue"/>
     </div>
   </div>
 </template>
@@ -126,10 +131,12 @@ const onClick = async () => {
 #confirmButton {
   margin-bottom: 2rem;
   width: 300px;
+  height: 38px;
 }
 
 .confirm-button-container {
   display: flex;
   justify-content: center;
 }
+
 </style>
\ No newline at end of file
diff --git a/src/views/NotFoundView.vue b/src/components/Exceptions/NotFoundPage.vue
similarity index 63%
rename from src/views/NotFoundView.vue
rename to src/components/Exceptions/NotFoundPage.vue
index 7637014bf836c4e94a3526e503080990f93bab13..fceb97ac6adf0017e00025fa1703f5509117497c 100644
--- a/src/views/NotFoundView.vue
+++ b/src/components/Exceptions/NotFoundPage.vue
@@ -1,17 +1,17 @@
 <template>
-    <div class="container-fluid"> <!-- Changed from 'container' to 'container-fluid' -->
+    <div class="container-fluid">
         <div class="row">
             <div class="col-md-12">
-                <div class="error-template text-center"> <!-- 'text-center' for centering text content -->
+                <div class="error-template text-center">
                     <h1>
-                        Oops!</h1>
-                    <h2>
-                        404 Not Found</h2>
+                        Oi!</h1>
+                    <h2 data-cy="404-error">
+                        404 Ikke funnet</h2>
                     <div class="error-details">
-                        Sorry, an error has occurred, Requested page not found!
+                        Beklager, det har oppstått en feil. Forespurt side ikke funnet!
                     </div>
                     <div class="error-actions">
-                        <Button1 button-text="Take Me Home" @click="home" />
+                        <BaseButton data-cy="to-home" button-text="Ta meg hjem" @click="home" />
                     </div>
                 </div>
             </div>
@@ -19,9 +19,10 @@
     </div>
 </template>
 
+
 <script setup lang="ts">
 import { useRouter } from 'vue-router';
-import Button1 from '@/components/Buttons/Button1.vue';
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue';
 
 const router = useRouter();
 
diff --git a/src/components/Exceptions/UnauthorizedPage.vue b/src/components/Exceptions/UnauthorizedPage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..99bfe00e211b79514f6fbb1b4ac8a2983b40018b
--- /dev/null
+++ b/src/components/Exceptions/UnauthorizedPage.vue
@@ -0,0 +1,33 @@
+<template>
+    <body class="bg-dark text-white py-5">
+        <div class="container py-5">
+            <div class="row">
+                <div class="col-md-2 text-center">
+                    <p><img src="../../assets/icons/danger.svg" alt="fare"> <br/>Statuskode: 403</p>
+                </div>
+                <div class="col-md-10">
+                    <h3>OOPS!!! Beklager...</h3>
+                    <p>Beklager, din tilgang er nektet av sikkerhetsgrunner på serveren vår og også våre sensitive data.<br/>Vennligst gå tilbake til startsiden for å fortsette å surfe.</p>
+                    <BaseButton :button-text="'Ta meg hjem'" @click="home" />
+                </div>
+            </div>
+        </div>
+    </body>
+</template>
+
+
+<script setup lang="ts">
+import { useRouter } from 'vue-router';
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue';
+
+const router = useRouter();
+
+const home = () => {
+    router.push('/'); 
+};
+</script>
+
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/components/Friends/UserFriends.vue b/src/components/Friends/UserFriends.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d97189bedc05e1d1f590bce0233249732dc824bd
--- /dev/null
+++ b/src/components/Friends/UserFriends.vue
@@ -0,0 +1,605 @@
+<template>
+    <div class="container" style="margin-bottom: 3rem;">
+        <h1 class="my-3">Dine venner</h1>
+        <div>
+            <button class="btn pull-right" @click="addNewFriends" id="addFriend">+ Legg til venn</button>
+            <div class="my-3">
+                <button class="btn pages" @click="setupFriends" :class="{ 'active-tab': showFriends }">
+                    Dine venner
+                </button>
+                <button class="btn pages" @click="requestFriend" :class="{ 'active-tab': showRequests }">
+                    Venneforespørsler
+                </button>
+            </div>
+        </div>
+        <div v-if="showFriends">
+            <div v-if="elementsInFriends">
+                <div class="row">
+                    <div class="col-lg-3" v-for="friend in friends" :key="friend.id">
+                        <div class="card card-one">
+                            <div class="header">
+                                <div v-if="friend.profileImage" class="avatar">
+                                    <img :src="'http://localhost:8080/api/images/' + friend.profileImage" alt="">
+                                </div>
+                                <div v-else class="avatar">
+                                    <img :src="'../src/assets/userprofile.png'" alt="">
+                                </div>
+                            </div>
+                            <h3><router-link to="" data-cy="navigateToFriend" href="#" class="btn stretched-link"
+                                    id="profileName" @click="navigateToFriend(friend.id)">{{
+                friend.firstName }} {{ friend.lastName }}</router-link></h3>
+                            <div class="desc">{{ friend.firstName }} {{ friend.lastName }}</div>
+                            <div class="contacts">
+                                <a class="text removeFriend" data-bs-toggle="collapse"
+                                    :href="'#collapseExample' + friend.id" role="button" aria-expanded="false"
+                                    :aria-controls="'collapseExample' + friend.id">
+                                    Se mer
+                                </a>
+                                <div class="collapse" :id="'collapseExample' + friend.id">
+                                    <button class="btn btn-danger" @click="removeFriend(friend.id)">
+                                        <h5><img src="@/assets/icons/remove-white.svg" style="width: 30px"> Fjern venn
+                                        </h5>
+                                    </button>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div v-else>Ingen venner</div>
+        </div>
+        <div v-else-if="showRequests" class="row">
+            <div class="content-body">
+                <div v-if="elementsInFriendRequest" id="requests">
+                    <div class="request" v-for="(friend) in friendRequests" :key="friend.id">
+                        <div v-if="friend.profileImage !== null"><img id="profilePicture"
+                                :src="'http://localhost:8080/api/images/' + friend.profileImage" alt="bruker"
+                                class="profile-photo-lg"></div>
+                        <div v-else><img id="profilePicture" :src="'../src/assets/userprofile.png'" alt="bruker"
+                                class="profile-photo-lg"></div>
+                        <h2>{{ friend.firstName }}</h2> - <button class="btn btn-success mx-2"
+                            @click="acceptRequest(friend.id)">Godta</button>
+                        <button class="btn btn-danger" @click="rejectRequest(friend.id)">Avslå</button>
+                    </div>
+                </div>
+                <div v-else>Ingen venneforespørsler</div>
+            </div>
+        </div>
+        <div v-if="showAddFriend" class="modal" tabindex="-1" role="dialog"
+            style="display:block; background-color: rgba(0,0,0,0.5);">
+            <div class="modal-dialog" role="document">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <h5 class="modal-title">Legg til venn</h5>
+                        <button type="button" class="close" @click="showAddFriend = false">
+                            <span aria-hidden="true">&times;</span>
+                        </button>
+                    </div>
+                    <div class="modal-body d-flex justify-content-center align-items-center flex-column">
+                        <form class="col-md-10 d-flex justify-content-center align-items-center flex-row my-4"
+                            id="searchBox" role="search" @submit.prevent="searchProfile(searchWord)">
+                            <input class="form-control me-2 custom-border" type="search" placeholder="Søk"
+                                aria-label="Søk" v-model="searchWord">
+                            <button class="btn btn-success" type="submit">Søk</button>
+                        </form>
+                        <div class="col-md-12">
+                            <div class="people-nearby">
+                                <div v-for="user in searchedUsers" :key="user.id" class="nearby-user">
+                                    <div class="row d-flex align-items-center">
+                                        <div class="col-md-2 col-sm-2">
+                                            <div v-if="user.profileImage !== null"><img id="profilePicture"
+                                                    :src="'http://localhost:8080/api/images/' + user.profileImage"
+                                                    alt="bruker" class="profile-photo-lg"></div>
+                                            <div v-else><img id="profilePicture" :src="'../src/assets/userprofile.png'"
+                                                    alt="bruker" class="profile-photo-lg"></div>
+                                        </div>
+                                        <div class="col-md-7 col-sm-7">
+                                            <h5><a href="#" class="profile-link" @click="toUserProfile(user.id)">{{
+                user.firstName }} {{ user.lastName }}</a>
+                                            </h5>
+                                        </div>
+                                        <div class="col-md-3 col-sm-3">
+                                            <button class="btn btn-primary pull-right" @click="addFriend(user.id)"
+                                                :disabled="friendRequestsSent[user.id]"
+                                                v-if="!friendRequestsSent[user.id]">Legg til venn</button>
+                                            <button class="btn btn-secondary pull-right" disabled
+                                                v-if="friendRequestsSent[user.id]">Forespørsel sendt</button>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+
+
+
+<script setup lang="ts">
+import { type Ref, ref, onMounted } from 'vue';
+import { useRouter } from 'vue-router';
+import { FriendService, UserService } from '@/api';
+import type { UserDTO } from '@/api';
+
+const router = useRouter();
+const friends = ref();
+const showFriends = ref(true);
+const showRequests = ref(false);
+const showAddFriend = ref(false);
+const friendRequests = ref([] as any);
+const addFriends = ref([] as any);
+const searchedUsers = ref([] as any);
+
+const friendRequestsSent: Ref<Record<number, boolean>> = ref({});
+
+const searchWord = ref("");
+
+const elementsInFriendRequest = ref(false);
+const elementsInFriends = ref(false);
+
+const toUserProfile = (userId: number) => {
+    router.push('/profile/' + userId);
+};
+
+const searchProfile = async (searchTerm: string) => {
+    const userPayload = {
+        searchTerm: searchTerm as string,
+        filter: 'NON_FRIENDS' as string,
+    };
+    try {
+        const response = await UserService.getUsersByNameAndFilter(userPayload);
+        searchedUsers.value = response;
+        console.log(response);
+    } catch (error) {
+        console.error('Failed to search for profile', error);
+    }
+};
+
+const addNewFriends = async () => {
+    const userPayload = {
+        amount: 6 as number,
+        filter: 'NON_FRIENDS' as string,
+    };
+    try {
+        const response = await UserService.getRandomUsers(userPayload);
+        searchedUsers.value = response;
+        showAddFriend.value = true;
+    } catch (error) {
+        console.error('Failed to add friend', error);
+    }
+};
+
+async function addFriend(friendID: number) {
+    try {
+        await FriendService.addFriendRequest({ userId: friendID });
+        // Use a spread to update the state and keep immutability
+        friendRequestsSent.value = { ...friendRequestsSent.value, [friendID]: true };
+    } catch (error) {
+        console.error('Failed to send friend request', error);
+    }
+}
+
+async function requestFriend() {
+    showRequests.value = true;
+    showFriends.value = false;
+    try {
+        const response = await FriendService.getFriendRequests();
+        friendRequests.value = response;
+        elementsInFriendRequest.value = response.length > 0;
+        console.log("Friend requests: " + response);
+    } catch (error) {
+        console.error('Failed to fetch friend requests', error);
+    }
+}
+
+const navigateToFriend = (friendID: number) => {
+    router.push('/profile/' + friendID);
+};
+
+const removeFriend = async (friendID: number) => {
+    try {
+        await FriendService.deleteFriendOrFriendRequest({ friendId: friendID });
+        const responseFriends = await FriendService.getFriends();
+        friends.value = responseFriends;
+    } catch (error) {
+        console.error('Failed to remove friend', error);
+    }
+};
+
+const setupFriends = async () => {
+    showFriends.value = true;
+    showRequests.value = false;
+    try {
+        const response = await FriendService.getFriends();
+        friends.value = response;
+        elementsInFriends.value = response.length > 0;
+        console.log(response);
+    } catch (error) {
+        console.error('Failed to fetch friends', error);
+    }
+};
+
+const acceptRequest = async (requestID: number) => {
+    try {
+        await FriendService.acceptFriendRequest({ friendId: requestID });
+        const responseRequest = await FriendService.getFriendRequests();
+        friendRequests.value = responseRequest;
+        const responseFriends = await FriendService.getFriends();
+        friends.value = responseFriends;
+    } catch (error) {
+        console.error('Failed to accept friend request', error);
+    }
+};
+
+const rejectRequest = async (requestID: number) => {
+    try {
+        await FriendService.deleteFriendOrFriendRequest({ friendId: requestID });
+        const response = await FriendService.getFriendRequests();
+        friendRequests.value = response;
+    } catch (error) {
+        console.error('Failed to reject friend request', error);
+    }
+};
+
+onMounted(() => {
+    setupFriends();
+});
+</script>
+
+
+<style scoped>
+body {
+    background-color: #f0f6ff;
+    color: #28384d;
+
+}
+
+/*social */
+.card-one {
+    position: relative;
+    width: 300px;
+    background: #fff;
+    box-shadow: 0 10px 7px -5px rgba(0, 0, 0, 0.4);
+}
+
+.card {
+    margin-bottom: 35px;
+    padding-bottom: 1rem;
+    box-shadow: 0 10px 20px 0 rgba(26, 44, 57, 0.14);
+    border: none;
+}
+
+.follower-wrapper li {
+    list-style-type: none;
+    color: #fff;
+    display: inline-block;
+    float: left;
+    margin-right: 20px;
+}
+
+.social-profile {
+    color: #fff;
+}
+
+.social-profile a {
+    color: #fff;
+}
+
+.social-profile {
+    position: relative;
+    margin-bottom: 150px;
+}
+
+.social-profile .user-profile {
+    position: absolute;
+    bottom: -75px;
+    width: 150px;
+    height: 150px;
+    border-radius: 50%;
+    left: 50px;
+}
+
+.social-nav {
+    position: absolute;
+    bottom: 0;
+}
+
+.social-prof {
+    color: #333;
+    text-align: center;
+}
+
+.social-prof .wrapper {
+    width: 70%;
+    margin: auto;
+    margin-top: -100px;
+}
+
+.social-prof img {
+    width: 150px;
+    height: 150px;
+    border-radius: 50%;
+    margin-bottom: 20px;
+    border: 5px solid #fff;
+    /*border: 10px solid #70b5e6ee;*/
+}
+
+.social-prof h3 {
+    font-size: 36px;
+    font-weight: 700;
+    margin-bottom: 0;
+}
+
+.social-prof p {
+    font-size: 18px;
+}
+
+.social-prof .nav-tabs {
+    border: none;
+}
+
+.card .nav>li {
+    position: relative;
+    display: block;
+}
+
+.card .nav>li>a {
+    position: relative;
+    display: block;
+    padding: 10px 15px;
+    font-weight: 300;
+    border-radius: 4px;
+}
+
+.card .nav>li>a:focus,
+.card .nav>li>a:hover {
+    text-decoration: none;
+    background-color: #eee;
+}
+
+.card .s-nav>li>a.active {
+    text-decoration: none;
+    background-color: #3afe;
+    color: #fff;
+}
+
+.text-blue {
+    color: #3afe;
+}
+
+ul.friend-list {
+    margin: 0;
+    padding: 0;
+}
+
+ul.friend-list li {
+    list-style-type: none;
+    display: flex;
+    align-items: center;
+}
+
+ul.friend-list li:hover {
+    background: rgba(0, 0, 0, .1);
+    cursor: pointer;
+}
+
+ul.friend-list .left img {
+    width: 45px;
+    height: 45px;
+    border-radius: 50%;
+    margin-right: 20px;
+}
+
+ul.friend-list li {
+    padding: 10px;
+}
+
+ul.friend-list .right h3 {
+    font-size: 16px;
+    font-weight: 700;
+    margin-bottom: 0;
+}
+
+ul.friend-list .right p {
+    font-size: 11px;
+    color: #6c757d;
+    margin: 0;
+}
+
+.social-timeline-card .dropdown-toggle::after {
+    display: none;
+}
+
+.info-card h4 {
+    font-size: 15px;
+}
+
+.info-card h2 {
+    font-size: 18px;
+    margin-bottom: 20px;
+}
+
+.social-about .social-info {
+    font-size: 16px;
+    margin-bottom: 20px;
+}
+
+.social-about p {
+    margin-bottom: 20px;
+}
+
+.info-card i {
+    color: #3afe;
+}
+
+.card-one {
+    position: relative;
+    width: 300px;
+    background: #fff;
+    box-shadow: 0 10px 7px -5px rgba(0, 0, 0, 0.4);
+}
+
+.card-one .header {
+    position: relative;
+    width: 100%;
+    height: 60px;
+    background-color: rgba(7, 46, 74, 0.895);
+}
+
+.card-one .header::before,
+.card-one .header::after {
+    content: '';
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    background: inherit;
+}
+
+.card-one .header::before {
+    -webkit-transform: skewY(-8deg);
+    transform: skewY(-8deg);
+    -webkit-transform-origin: 100% 100%;
+    transform-origin: 100% 100%;
+}
+
+.card-one .header::after {
+    -webkit-transform: skewY(8deg);
+    transform: skewY(8deg);
+    -webkit-transform-origin: 0 100%;
+    transform-origin: 0 100%;
+}
+
+.card-one .header .avatar {
+    position: absolute;
+    left: 50%;
+    top: 30px;
+    margin-left: -50px;
+    z-index: 5;
+    width: 100px;
+    height: 100px;
+    border-radius: 50%;
+    overflow: hidden;
+    background: #ccc;
+    border: 3px solid #fff;
+}
+
+.card-one .header .avatar img {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    -webkit-transform: translate(-50%, -50%);
+    transform: translate(-50%, -50%);
+    width: 100px;
+    height: auto;
+}
+
+.card-one h3 {
+    position: relative;
+    margin: 80px 0 30px;
+    text-align: center;
+}
+
+.card-one h3::after {
+    content: '';
+    position: absolute;
+    bottom: -15px;
+    left: 50%;
+    margin-left: -15px;
+    width: 30px;
+    height: 1px;
+    background: #000;
+}
+
+.card-one .desc {
+    padding: 0 1rem 2rem;
+    text-align: center;
+    line-height: 1.5;
+    color: #777;
+}
+
+#gallery li {
+    width: 24%;
+    float: left;
+    margin: 6px;
+
+}
+
+.removeFriend {
+    text-wrap: nowrap;
+}
+
+.contacts {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+}
+
+#profileName {
+    font-size: 1.5rem;
+    font-weight: 600;
+    width: 100%;
+}
+
+#requests {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.request {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin: 1rem;
+}
+
+#profilePicture {
+    width: 70px;
+    height: 70px;
+    border-radius: 50%;
+    margin-right: 1rem;
+    border: 2px solid #000;
+}
+
+.modal-content {
+    padding: 1rem;
+}
+
+.modal-header {
+    margin-bottom: 5px;
+}
+
+.pages {
+    border-bottom: 1px solid #000;
+    border-radius: 0px;
+    margin: 0px 5px;
+}
+
+.pages {
+    border-bottom: 2px solid #000;
+    /* default border */
+    border-radius: 0px;
+    margin: 0px 5px;
+}
+
+.active-tab {
+    border-bottom: 4px solid #000;
+    /* thicker border when active */
+}
+
+#addFriend {
+    background-color: #084766;
+    color: white;
+}
+
+#addFriend:hover {
+    background-color: #003b58f5;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/LeaderboardView.vue b/src/components/Leaderboard/LeaderboardRank.vue
similarity index 63%
rename from src/views/LeaderboardView.vue
rename to src/components/Leaderboard/LeaderboardRank.vue
index 12acc33fe8c791a95188ebdc829294b90752f25a..b3432f49675eefd694e027b6d55c738eddc47b93 100644
--- a/src/views/LeaderboardView.vue
+++ b/src/components/Leaderboard/LeaderboardRank.vue
@@ -1,45 +1,51 @@
 <template>
     <br>
     <div id="dropdownContainer">
-        <h1 class="box">Leaderboard</h1>
+        <h1 class="box">Poengtavle</h1>
     </div>
-    <div id = "content">
+    <div id="content">
         <div id="dropdownContainer">
-        <div class="box">
-            <div class="btn-group-vertical" id="radioContainer" role="group"
-            aria-label="Vertical radio toggle button group">
-            <input type="radio" class="btn-check" name="vbtn-radio" id="vbtn-radio1" autocomplete="off" checked>
-            <label class="btn btn-outline-primary" for="vbtn-radio1" @click="global"><img src="@/assets/globe.png" style="width: 60px" alt="globe">  Global</label>
-            <input type="radio" class="btn-check" name="vbtn-radio" id="vbtn-radio2" autocomplete="off">
-            <label class="btn btn-outline-primary" for="vbtn-radio2" @click="friends"><img src="@/assets/friends.png" style="width: 60px" alt="friends">  Friends</label>
+            <div class="box">
+                <div class="btn-group-vertical" id="radioContainer" role="group"
+                     aria-label="Vertikal radio knappgruppe">
+                    <input type="radio" class="btn-check" name="vbtn-radio" id="vbtn-radio1" autocomplete="off" checked>
+                    <label class="btn btn-outline-primary" for="vbtn-radio1" @click="global"><img src="../../assets/globe.png" style="width: 60px" alt="globus"> Global</label>
+                    <input type="radio" class="btn-check" name="vbtn-radio" id="vbtn-radio2" autocomplete="off">
+                    <label data-cy="friends-leaderboard-btn" class="btn btn-outline-primary"
+                           for="vbtn-radio2"
+                            @click="friends"><img src="../../assets/friends.png" style="width: 60px" alt="venner"> Venner</label>
+                </div>
+            </div>
         </div>
-        </div>
-    </div>
-    <main>
-        <div id="leaderboard">
-            <h1><img src="@/assets/items/pigcoin.png" style="width: 2rem" alt="pig coin"> Total points</h1>
-            <Leaderboard :leaderboard="pointsLeaderboardData" :leaderboardExtra="pointsLeaderboardDataExtra" @navigateToUserProfile="navigateToUserProfile" />
-        </div>
-        <div id="leaderboard">
-            <h1><img src="@/assets/icons/fire.png" style="width: 2rem" alt="fire"> Current streak</h1>
-            <Leaderboard :leaderboard="currentLeaderboardData" :leaderboardExtra="currentLeaderboardDataExtra" @navigateToUserProfile="navigateToUserProfile" />
-        </div>
-        <div id="leaderboard">
-            <h1><img src="@/assets/icons/fire.png" style="width: 2rem" alt="fire"> Highest streak</h1>
-            <Leaderboard :leaderboard="streakLeaderboardData" :leaderboardExtra="streakLeaderboardDataExtra" @navigateToUserProfile="navigateToUserProfile" />
-        </div>
-    </main>
+        <main>
+            <div id="leaderboard">
+                <h1><img src="../../assets/items/pigcoin.png" style="width: 2rem" alt="pig coin"> Totale poeng</h1>
+                <Leaderboard data-cy="total-points-board" :leaderboard="pointsLeaderboardData"
+                              :leaderboardExtra="pointsLeaderboardDataExtra" @navigateToUserProfile="navigateToUserProfile" />
+            </div>
+            <div id="leaderboard">
+                <h1><img src="../../assets/icons/fire.png" style="width: 2rem" alt="ild"> Nåværende rekke</h1>
+                <Leaderboard data-cy="current-points-board" :leaderboard="currentLeaderboardData"
+                              :leaderboardExtra="currentLeaderboardDataExtra" @navigateToUserProfile="navigateToUserProfile" />
+            </div>
+            <div id="leaderboard">
+                <h1><img src="../../assets/icons/fire.png" style="width: 2rem" alt="ild"> Høyeste rekke</h1>
+                <Leaderboard data-cy="streak-board" :leaderboard="streakLeaderboardData"
+                              :leaderboardExtra="streakLeaderboardDataExtra" @navigateToUserProfile="navigateToUserProfile" />
+            </div>
+        </main>
     </div>
     <div id="communityContainer">
-        <h1>Total points earned as a community</h1>
-        <h2>1000000 <img src="@/assets/items/v-buck.png" style="width: 2rem" alt="alt"></h2>
+        <h1>Totale poeng opptjent som et fellesskap</h1>
+        <h2>{{communityPoints}} <img src="../../assets/items/pigcoin.png" style="width: 2rem" alt="alt"></h2>
     </div>
 </template>
 
+
 <script setup lang="ts">
 import { onMounted, ref } from 'vue';
 import { useRouter } from 'vue-router';
-import Leaderboard from '@/components/LeaderboardComponents/Leaderboard.vue';
+import Leaderboard from '@/components/Leaderboard/LeaderboardTable.vue';
 import { LeaderboardService } from '@/api';
 
 let streakLeaderboardData = ref([] as  any);
@@ -50,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(() => {
@@ -174,7 +185,7 @@ main {
 }
 
 h1 {
-    font-weight: 500;
+    font-weight: 700;
     margin-bottom: 1rem;
 }
 
diff --git a/src/components/LeaderboardComponents/Leaderboard.vue b/src/components/Leaderboard/LeaderboardTable.vue
similarity index 78%
rename from src/components/LeaderboardComponents/Leaderboard.vue
rename to src/components/Leaderboard/LeaderboardTable.vue
index 4b1006543b6a7526b3d91805e416c499b8fc765c..71b11995c1e5c8d94fedc8855802506ed90696bb 100644
--- a/src/components/LeaderboardComponents/Leaderboard.vue
+++ b/src/components/Leaderboard/LeaderboardTable.vue
@@ -1,26 +1,24 @@
 <template>
   <div id="leaderboard">
-    <div class="ribbon"></div>
+
     <table>
-      <tbody>
-        <tr v-for="(entry, index) in leaderboard" :key="entry.user?.id" :class="{ 'is-user-5': entry.user?.id === userStore.id }">
+      <tbody data-cy="top-leaderboard-table">
+        <tr data-cy="top-leaderboard-tablerow" v-for="(entry, index) in leaderboard" :key="entry.user?.id" :class="{
+          'is-user-5':
+            entry.user?.id === userStore.id
+        }">
           <td class="number">{{ entry.rank }}</td>
           <td class="name" @click="navigateToUserProfile(entry.user?.id ?? 0)">{{ entry.user?.firstName }}</td>
           <td class="points" v-if="index === 0">
             {{ entry.score }}
-            <div class="medal">
-              <img class="gold-medal"
-                src="https://github.com/malunaridev/Challenges-iCodeThis/blob/master/4-leaderboard/assets/gold-medal.png?raw=true"
-                alt="gold medal" />
-            </div>
           </td>
           <td v-else class="points">{{ entry.score }}</td>
         </tr>
       </tbody>
       <tbody id="line">`</tbody>
-      <tbody v-if="!userInLeaderboard">
-        <tr></tr>
-        <tr v-for="(entry, index) in leaderboardExtra" :key="entry.user?.id" :class="{ 'is-user-5': entry.user?.id === userStore.id }">
+      <tbody data-cy="surrounding-user-leaderboard-table" v-if="!userInLeaderboard">
+        <tr data-cy="surrounding-user-leaderboard-tablerow" v-for="(entry, index) in leaderboardExtra" :key="entry.user?.id"
+          :class="{ 'is-user-5': entry.user?.id === userStore.id }">
           <td class="number">{{ entry.rank }}</td>
           <td class="name" @click="navigateToUserProfile(entry.user?.id ?? 0)">{{ entry.user?.firstName }}</td>
           <td class="points">{{ entry.score }}</td>
@@ -63,8 +61,9 @@ const navigateToUserProfile = (id: number) => {
 
 <style scoped>
 #leaderboard {
-  width: 100%;
+  max-width: 80%;
   position: relative;
+  box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
 }
 
 table {
@@ -84,7 +83,7 @@ tr {
   height: 4rem;
 }
 
-tr:not(:first-child):hover {
+tr:hover {
   background-color: #fff;
   transform: scale(1.1);
   -webkit-box-shadow: 0px 5px 15px 8px #e4e7fb;
@@ -95,10 +94,6 @@ tr:nth-child(even) {
   background-color: #f9f9f9;
 }
 
-tr:nth-child(1) {
-  color: #fff;
-}
-
 td {
   height: 2rem;
   font-family: "Rubik", sans-serif;
@@ -109,7 +104,7 @@ td {
 
 .number {
   width: 1rem;
-  font-size: 2.2rem;
+  font-size: 1.4rem;
   font-weight: bold;
   text-align: left;
   display: flex;
@@ -117,7 +112,7 @@ td {
 }
 
 .name {
-  font-size: 1.3rem;
+  font-size: 1rem;
   cursor: pointer;
   display: flex;
   align-items: center;
@@ -125,7 +120,7 @@ td {
 
 .points {
   font-weight: bold;
-  font-size: 1.3rem;
+  font-size: 1rem;
   display: flex;
   justify-content: flex-end;
   align-items: center;
@@ -155,7 +150,7 @@ td {
   width: 106%;
   height: 4.5rem;
   top: -0.5rem;
-  background-color: #0A58CA;
+  background-color: #003A58;
   position: absolute;
   /**left: -1rem;*/
   box-shadow: 0px 15px 11px -6px #7a7a7d;
@@ -168,7 +163,7 @@ td {
   bottom: -0.8rem;
   left: 0.35rem;
   transform: rotate(45deg);
-  background-color: #0A58CA;
+  background-color: #003A58;
   position: absolute;
   z-index: -1;
 }
@@ -180,7 +175,7 @@ td {
   bottom: -0.8rem;
   right: 0.35rem;
   transform: rotate(45deg);
-  background-color: #0A58CA;
+  background-color: #003A58;
   position: absolute;
   z-index: -1;
 }
@@ -188,7 +183,7 @@ td {
 #line {
   width: 100%;
   height: 0.01rem;
-  border-top: 8px solid #0A58CA;
+  border-top: 8px solid #003A58
 }
 
 tr.is-user-5 {
diff --git a/src/components/LeaderboardComponents/__tests__/Leaderboard.spec.ts b/src/components/Leaderboard/__tests__/LeaderboardTable.spec.ts
similarity index 83%
rename from src/components/LeaderboardComponents/__tests__/Leaderboard.spec.ts
rename to src/components/Leaderboard/__tests__/LeaderboardTable.spec.ts
index ed89975252b68f12b630473de9fe6d60d646899b..1e358426983dfe36f7089ffcca8def2100b3f16a 100644
--- a/src/components/LeaderboardComponents/__tests__/Leaderboard.spec.ts
+++ b/src/components/Leaderboard/__tests__/LeaderboardTable.spec.ts
@@ -2,9 +2,9 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
 import { mount } from '@vue/test-utils';
 import { createRouter, createMemoryHistory } from 'vue-router';
 import { createPinia, setActivePinia } from 'pinia';
-import Leaderboard from '@/components/LeaderboardComponents/Leaderboard.vue';
-import { useUserInfoStore } from '@/stores/UserStore';
-import router from '@/router/index';
+import Leaderboard from '../LeaderboardTable.vue';
+import { useUserInfoStore } from '../../../stores/UserStore';
+import router from '../../../router';
 
 describe('Leaderboard', () => {
 
@@ -56,11 +56,6 @@ describe('Leaderboard', () => {
     expect(wrapper.vm.userInLeaderboard).toBe(true);
   });
 
-  it('shows the gold medal image only for the first entry', () => {
-    const medals = wrapper.findAll('.gold-medal');
-    expect(medals.length).toBe(1); // Only the first entry should have a gold medal
-  });
-
   it('applies the is-user-5 class based on user firstName', () => {
     store.$state.firstname = 'User'; // Change state to match the condition
     expect(wrapper.find('.is-user-5').exists()).toBe(false); // Check if the class is applied
diff --git a/src/components/Login/ChangePassword.vue b/src/components/Login/ChangePassword.vue
new file mode 100644
index 0000000000000000000000000000000000000000..2e15299f39c4aca4bc6d87248ed6c72a13d49a8d
--- /dev/null
+++ b/src/components/Login/ChangePassword.vue
@@ -0,0 +1,171 @@
+<template>
+    <div class="containers">
+      <div class="box">
+        <div class="container-fluid">
+          <div class="container-fluid d-flex justify-content-center align-items-center flex-column mt-5">
+            <h1>Opprett nytt passord</h1>
+          </div>
+          <form ref="formRef" id="loginForm" @submit.prevent="handleSubmit" novalidate>
+
+            <BaseInput :model-value="newPassword"
+                       @input-change-event="handlePasswordInputEvent"
+                       id="passwordInput"
+                       input-id="password"
+                       type="password"
+                       pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
+                       label="Passord"
+                       placeholder="Skriv inn ditt passord"
+                       invalid-message="Passordet må være mellom 4 og 16 tegn og inneholde én stor bokstav, liten bokstav og et tall"
+            />
+
+            <BaseInput :model-value="confirmPassword"
+                       @input-change-event="handleConfirmPasswordInputEvent"
+                       id="confirmPasswordInput"
+                       input-id="password"
+                       type="password"
+                       pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
+                       label="Bekreft Passord"
+                       placeholder="Skriv inn ditt passord"
+                       invalid-message="Passordet må være mellom 4 og 16 tegn og inneholde én stor bokstav, liten bokstav og et tall"
+            />
+
+            <p class="text-danger" data-cy="error">{{ errorMsg }}</p>
+            <p v-if="!samePasswords" class="text-danger">Passordene er ikke like</p>
+            <BaseButton id="confirmButton" type="submit" @click="handleSubmit" :disabled="isSubmitting" button-text="Oppdater passordet"></BaseButton>
+
+            <SignUpLink/>
+          </form>
+        </div>
+          <!--<div class="row justify-content-center">
+              <div class="col-lg-5">
+                  <div class="card shadow-lg border-0 rounded-lg mt-5">
+                      <div class="card-header">
+                          <h3 class="text-center font-weight-light my-4">Password Recovery</h3>
+                      </div>
+                      <div class="card-body">
+                          <div class="small mb-3 text-muted">Enter the new password for your account</div>
+                          <form @submit.prevent="submitForm">
+                              <div class="form-floating mb-3">
+                                  <input v-model="newPassword" class="form-control" id="newPassword" type="password"
+                                      placeholder="New Password" required>
+                                  <label for="newPassword">Enter your new password</label>
+                              </div>
+                              <div class="form-floating mb-3">
+                                  <input v-model="confirmPassword" class="form-control" id="confirmPassword"
+                                      type="password" placeholder="Confirm Password" required>
+                                  <label for="confirmPassword">Confirm your new password</label>
+                              </div>
+                              <div class="errorMsg">{{ errormsg }}</div>
+                              <div class="d-flex align-items-center justify-content-between mt-4 mb-0">
+                                  <router-link to="/login" class="small">Return to login</router-link>
+                                  <button class="btn btn-primary" type="submit">Confirm Password</button>
+                              </div>
+                          </form>
+                      </div>
+                      <div class="card-footer text-center py-3">
+                          <div class="small"><router-link to="/sign-up">Need an account? Sign up!</router-link></div>
+                      </div>
+                  </div>
+              </div>
+          </div>-->
+      </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import { useRouter, useRoute } from 'vue-router';
+import { UserService } from '@/api';
+import SignUpLink from '@/components/SignUp/SignUpLink.vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue'
+import handleUnknownError from '@/components/Exceptions/unkownErrorHandler'
+
+const router = useRouter();
+const route = useRoute();
+
+const token = route.params.token;
+
+const newPassword = ref('');
+const confirmPassword = ref('');
+const formRef = ref()
+let samePasswords = ref(true)
+let errorMsg = ref('');
+const isSubmitting = ref(false);
+
+const handlePasswordInputEvent = (newValue: any) => {
+  newPassword.value = newValue
+}
+
+const handleConfirmPasswordInputEvent = (newValue: any) => {
+  confirmPassword.value = newValue
+}
+
+const handleSubmit = async () => {
+  if (isSubmitting.value) return;
+  isSubmitting.value = true;
+
+  samePasswords.value = (newPassword.value === confirmPassword.value)
+  formRef.value.classList.add("was-validated")
+
+  const form = formRef.value;
+  if (form.checkValidity()) {
+    if (samePasswords.value) {
+      try {
+        const resetPassword = {
+          password: newPassword.value,
+          token: token as string,
+        };
+        await UserService.confirmPasswordReset({ requestBody: resetPassword });
+        router.push('/login');
+      } catch (error) {
+        errorMsg.value = handleUnknownError(error);
+      }
+    }
+  }
+  isSubmitting.value = false;
+};
+
+</script>
+
+<style scoped>
+.containers {
+  background: url('@/assets/wave.svg');
+  background-repeat: no-repeat;
+  background-size: cover;
+  height: 100vh;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+}
+
+.box {
+  background-color: white;
+  border-radius: 1rem;
+  max-width: 450px;
+  padding: 0 3rem 1rem 3rem;
+  box-shadow: rgba(57, 57, 63, 0.5) 0px 1px 20px 0px;
+}
+
+h1 {
+  font-size: 2rem;
+  font-weight: bold;
+}
+
+.container-fluid {
+  max-width: 450px;
+}
+
+#loginForm {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+#passwordInput,
+#confirmPasswordInput {
+  margin: 1rem 10rem;
+  width: 100%;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/Login/ForgottenPassword.vue b/src/components/Login/ForgottenPassword.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6d5e7fc808c4eb43be34b7550cf0b4e78d8fa82d
--- /dev/null
+++ b/src/components/Login/ForgottenPassword.vue
@@ -0,0 +1,103 @@
+<template>
+    <div class="containers">
+      <div class="box">
+        <h1 class="title">Tilbakestill passord</h1>
+        <p>Fyll inn e-posten din, så sender vi deg instruksjoner for å tilbakestille passordet ditt.</p>
+        <form @submit.prevent="submitForm" id="resetForm" ref="formRef" novalidate>
+          <div class="form-floating inputBox">
+            <input v-model="email" class="form-control" id="inputEmail" type="email"
+                   placeholder="name@example.com" required>
+            <label for="emailInput">Skriv inn din e-post</label>
+          </div>
+  
+          <div v-if="errorMessage" class="text-danger">
+            {{ errorMessage }}
+          </div>
+          <div v-else class="text-success">
+            {{ confirmationMessage }}
+          </div>
+          <BaseButton id="confirmButton" type="submit" :disabled="isSubmitting" button-text="Send e-post"></BaseButton>
+  
+          <div class="login-link">
+            <Router-Link to="/login" class="small">Gå tilbake</Router-Link>
+          </div>
+        </form>
+      </div>
+    </div>
+  </template>
+  
+  <script setup lang="ts">
+  import { ref } from 'vue';
+  import { UserService } from '@/api';
+  import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
+  
+  const formRef = ref()
+  const form = formRef.value;
+  const email = ref('');
+  const confirmationMessage = ref('');
+  const errorMessage = ref('');
+  const isSubmitting = ref(false);
+  
+  const submitForm = async () => {
+    if (isSubmitting.value) return;
+    isSubmitting.value = true;
+  
+    formRef.value.classList.add("was-validated")
+  
+    try {
+      await UserService.resetPassword({ requestBody: email.value });
+      confirmationMessage.value = 'An email has been sent to your email address with a link to reset your password.';
+      errorMessage.value = '';
+    } catch (error) {
+      errorMessage.value = 'Failed to send email. Please try again.';
+      confirmationMessage.value = '';
+    }
+    isSubmitting.value = false;
+  };
+  </script>
+  
+  <style scoped>
+  .containers {
+    background: url('@/assets/wave.svg');
+    background-size: cover;
+    height: 100vh;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  
+  .box {
+    background-color: white;
+    border-radius: 1rem;
+    width: 100%;
+    max-width: 450px;
+    padding: 2rem;
+    box-shadow: rgba(57, 57, 63, 0.5) 0px 1px 20px 0px;
+    text-align: center;
+  }
+  
+  h1 {
+    font-size: 2rem;
+    font-weight: bold;
+    text-align: center;
+  }
+  
+  #resetForm {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+  
+  .login-link {
+    width: 100%;
+    font-size: 14px;
+    margin-top: 10px;
+    text-align: center;
+  }
+  
+  .inputBox {
+    width: 100%;
+    margin: 20px;
+  }
+  </style>
+  
\ No newline at end of file
diff --git a/src/components/Login/LoginForm.vue b/src/components/Login/LoginForm.vue
index 31cf6d2cc8e87e56bc4beb815002b36ceb00b8d4..f0ca531608a6ec0bc966fffe6223f51a5c7629b8 100644
--- a/src/components/Login/LoginForm.vue
+++ b/src/components/Login/LoginForm.vue
@@ -1,6 +1,6 @@
 <script setup lang="ts">
-import BaseInput from '@/components/InputFields/BaseInput.vue'
-import Button1 from '@/components/Buttons/Button1.vue'
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
 import { ref } from 'vue'
 import { useUserInfoStore } from '@/stores/UserStore';
 import { AuthenticationService, OpenAPI, type LoginRequest } from '@/api';
@@ -13,6 +13,7 @@ const emailRef = ref('')
 const passwordRef = ref('')
 const formRef = ref()
 let errorMsg = ref('');
+const isSubmitting = ref(false);
 
 const errorStore = useErrorStore();
 const router = useRouter();
@@ -20,23 +21,23 @@ const userStore = useUserInfoStore();
 
 const handleEmailInputEvent = (newValue: any) => {
   emailRef.value = newValue
-  console.log(emailRef.value)
 }
 
 const handlePasswordInputEvent = (newValue: any) => {
   passwordRef.value = newValue
-  console.log(passwordRef.value)
 }
 
 const handleSubmit = async () => {
   console.log(emailRef.value)
   console.log(passwordRef.value)
-
+  if (isSubmitting.value) return;
+  isSubmitting.value = true;
 
   formRef.value.classList.add("was-validated")
 
   const form = formRef.value;
   if (!form.checkValidity()) {
+    isSubmitting.value = false;
     return;
   }
 
@@ -49,6 +50,7 @@ const handleSubmit = async () => {
     let response = await AuthenticationService.login({ requestBody: loginUserPayload });
     if (response.token == null || response.token == undefined) {
       errorMsg.value = 'A valid token could not be created';
+      isSubmitting.value = false;
       return;
     }
 
@@ -64,9 +66,13 @@ const handleSubmit = async () => {
       subscriptionLevel: response.subscriptionLevel,
       profileImage: response.profileImage
     });
-    await router.push({ name: 'home' });
+
+    console.log(response.token)
+
+    await router.push({ name: 'roadmap' });
   } catch (error: any) {
     errorMsg.value = handleUnknownError(error);
+    isSubmitting.value = false;
   }
 }
 
@@ -75,8 +81,7 @@ const handleSubmit = async () => {
 <template>
   <div class="container-fluid">
     <div class="container-fluid d-flex justify-content-center align-items-center flex-column mt-5">
-      <img src="@/assets/Sparesti-logo.png" style="width: 300px">
-      <h1>Sparesti.no</h1>
+      <h1>Logg inn</h1>
     </div>
     <form ref="formRef" id="loginForm" @submit.prevent="handleSubmit" novalidate>
 
@@ -85,10 +90,9 @@ const handleSubmit = async () => {
                  id="emailInput"
                  input-id="email"
                  type="email"
-                 label="Email"
-                 placeholder="Enter your email"
-                 valid-message="Valid email"
-                 invalid-message="Invalid email"
+                 label="E-post"
+                 placeholder="Skriv inn din e-post"
+                 invalid-message="Ugyldig e-post"
       />
 
       <BaseInput :model-value="passwordRef"
@@ -97,15 +101,23 @@ const handleSubmit = async () => {
                  input-id="password"
                  type="password"
                  pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
-                 label="Password"
-                 placeholder="Enter password"
-                 valid-message="Valid password"
-                 invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number"
+                 label="Passord"
+                 placeholder="Skriv inn ditt passord"
+                 invalid-message="Passordet må være mellom 4 og 16 tegn og inneholde én stor bokstav, liten bokstav og et tall"
       />
-      <p>Forgotten password? <RouterLink to="/forgotten-password">Reset password</RouterLink></p>
+
+      <div class="password-reset-link">
+        <RouterLink to="/forgotten-password">Glemt passord?</RouterLink>
+      </div>
 
       <p class="text-danger" data-cy="error">{{ errorMsg }}</p>
-      <button1 id="confirmButton" type="submit" @click="handleSubmit" button-text="Login"></button1>
+      <BaseButton id="confirmButton" type="submit" @click="handleSubmit" :disabled="isSubmitting" button-text="Logg inn"></BaseButton>
+
+      <a class="btn bankid-btn" href="https://preprod.signicat.com/oidc/authorize?response_type=code&scope=openid+profile+signicat.national_id&client_id=demo-preprod&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fredirect&acr_values=urn:signicat:oidc:method:nbid&state=nbid:auth_demo_bankid:123456789">
+        <img src="/src/assets/bankid.svg" width="26" height="26">
+        Fortsett med BankID
+      </a>
+
       <SignUpLink/>
     </form>
   </div>
@@ -119,16 +131,30 @@ const handleSubmit = async () => {
 #loginForm {
   display: flex;
   flex-direction: column;
-  justify-items: center;
+  align-items: center;
 }
 
 #emailInput,
 #passwordInput,
 #confirmButton {
-  margin: 1rem 0;
+  margin: 1rem 10rem;
+  width: 100%;
 }
 
 h1 {
-  font-size: 4rem;
+  font-size: 2rem;
+  font-weight: bold;
+}
+
+.bankid-btn {
+  margin: 15px;
+  font-weight: 500;
+}
+
+.password-reset-link {
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+  font-size: 14px;
 }
 </style>
\ No newline at end of file
diff --git a/src/components/Login/LoginLink.vue b/src/components/Login/LoginLink.vue
index 8f1db76b8746d93bbdb0ec2c16526d93fc55149b..d52d948ef108f12394f09d1ac558fc007c19087d 100644
--- a/src/components/Login/LoginLink.vue
+++ b/src/components/Login/LoginLink.vue
@@ -3,7 +3,7 @@
 </script>
 
 <template>
-  <p>Already have an account? <RouterLink to="/login" id="login">Login</RouterLink></p>
+  <p>Har du en bruker? <RouterLink to="/login" id="login">Logg inn</RouterLink></p>
 </template>
 
 <style scoped>
diff --git a/src/components/Login/Login.vue b/src/components/Login/LoginParent.vue
similarity index 51%
rename from src/components/Login/Login.vue
rename to src/components/Login/LoginParent.vue
index 834e1b7e7e3c7c62076dbfdb0c3897abc3f1daaa..bacabbcef217d37c525a4ae92d8e06aff2e2e23f 100644
--- a/src/components/Login/Login.vue
+++ b/src/components/Login/LoginParent.vue
@@ -4,6 +4,7 @@ import LoginForm from '@/components/Login/LoginForm.vue'
 
 <template>
   <div class="containers">
+    <h1 class="title">SpareSti</h1>
     <div class="box">
       <LoginForm/>
     </div>
@@ -12,20 +13,29 @@ import LoginForm from '@/components/Login/LoginForm.vue'
 
 <style scoped>
   .containers {
-    background-color: #A2CC99;
+    background: url('@/assets/wave.svg');
+    background-repeat: no-repeat;
+    background-size: cover;
     height: 100vh;
     display: flex;
     justify-content: center;
     align-items: center;
+    flex-direction: column;
   }
 
   .box {
     background-color: white;
-    border-radius: 3rem;
+    border-radius: 1rem;
     max-width: 450px;
-    padding: 1rem 4rem;
-    box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
+    padding: 0 3rem 1rem 3rem;
+    box-shadow: rgba(57, 57, 63, 0.5) 0px 1px 20px 0px;
   }
 
+  .title {
+    font-size: 60px;
+    color: white;
+    margin-bottom: 40px;
+    font-weight: 700;
+  }
   
 </style>
\ No newline at end of file
diff --git a/src/components/Login/__tests__/LoginForm.spec.ts b/src/components/Login/__tests__/LoginForm.spec.ts
index ad99a5c0d2db05cdaf44389040ad1255893271d4..d97fadf173e8a5568b802de05fec6dcc67973a52 100644
--- a/src/components/Login/__tests__/LoginForm.spec.ts
+++ b/src/components/Login/__tests__/LoginForm.spec.ts
@@ -41,8 +41,8 @@ describe('Menu and Router Tests', () => {
                 },
             });
 
-            expect(wrapper.text()).toContain('email');
-            expect(wrapper.text()).toContain('password');
+            expect(wrapper.text()).toContain('E-post');
+            expect(wrapper.text()).toContain('Passord');
         });
     });
 
@@ -72,8 +72,8 @@ describe('Menu and Router Tests', () => {
         it('updates user credetials correctly', async () => {
             const { getByPlaceholderText } = render(MyComponent);
 
-            const emailInput = getByPlaceholderText('Enter your email') as HTMLInputElement;
-            const passwordInput = getByPlaceholderText('Enter password') as HTMLInputElement;
+            const emailInput = getByPlaceholderText('Skriv inn din e-post') as HTMLInputElement;
+            const passwordInput = getByPlaceholderText('Skriv inn ditt passord') as HTMLInputElement;
             await fireEvent.update(emailInput, 'user@example.com');
             await fireEvent.update(passwordInput, 'Password1');
 
diff --git a/src/components/Login/__tests__/LoginLink.spec.ts b/src/components/Login/__tests__/LoginLink.spec.ts
index 299e1258c402a5c05f847ec51f9c84380ac1d43b..79b1a00b43514585a5175386ea7e346e35cfb440 100644
--- a/src/components/Login/__tests__/LoginLink.spec.ts
+++ b/src/components/Login/__tests__/LoginLink.spec.ts
@@ -43,7 +43,7 @@ describe('LoginPrompt', () => {
 
         await router.isReady(); // Ensure the router is ready before asserting
 
-        const loginLink = getByText('Login');
+        const loginLink = getByText('Logg inn');
         expect(loginLink).toBeDefined(); // Check if the 'Login' link is rendered
     });
 
diff --git a/src/components/NewsComponents/NewsComponent.vue b/src/components/News/NewsFeed.vue
similarity index 97%
rename from src/components/NewsComponents/NewsComponent.vue
rename to src/components/News/NewsFeed.vue
index 351bcebaf8e755dea418f44b069910264f75bc8d..047b7800de20425e8dbf7544a41dcdcb994ca622 100644
--- a/src/components/NewsComponents/NewsComponent.vue
+++ b/src/components/News/NewsFeed.vue
@@ -49,7 +49,7 @@ export default {
         <div class="content">
           <h3>{{ article.title }}</h3>
           <p>{{ article.description }}</p>
-          <a :href="article.url" target="_blank">Read more</a>
+          <a :href="article.url" target="_blank">Les mer</a>
         </div>
         <div class="image">
           <img :src="article.urlToImage" alt="Article Image"/>
diff --git a/src/components/NewsComponents/__tests__/NewsComponent.spec.ts b/src/components/News/__tests__/NewsFeed.spec.ts
similarity index 89%
rename from src/components/NewsComponents/__tests__/NewsComponent.spec.ts
rename to src/components/News/__tests__/NewsFeed.spec.ts
index ac57f8a37cecb8f2983c52ae3e163520d6c33ae8..0c2a4e092954b6a74218fa0d4998cdb8910574bb 100644
--- a/src/components/NewsComponents/__tests__/NewsComponent.spec.ts
+++ b/src/components/News/__tests__/NewsFeed.spec.ts
@@ -1,6 +1,6 @@
 import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
 import { mount } from '@vue/test-utils';
-import MyComponent from '@/components/NewsComponents/NewsComponent.vue'; // Adjust the import path according to your setup
+import MyComponent from '../NewsFeed.vue'; // Adjust the import path according to your setup
 
 global.fetch = vi.fn(() =>
   Promise.resolve(
diff --git a/src/components/SavingGoalComponents/SavingGoal.vue b/src/components/SavingGoal/SavingGoal.vue
similarity index 52%
rename from src/components/SavingGoalComponents/SavingGoal.vue
rename to src/components/SavingGoal/SavingGoal.vue
index e3de05112d6f449f7d2a1f3f0ba047d8b056fcd7..3644980546960ef148747fa116d97ccdade6a8a6 100644
--- a/src/components/SavingGoalComponents/SavingGoal.vue
+++ b/src/components/SavingGoal/SavingGoal.vue
@@ -1,13 +1,19 @@
 <script lang="ts">
-import SavingGoalList from "@/components/SavingGoalComponents/SavingGoalList.vue";
-import SavingGoalRoadmap from "@/components/SavingGoalComponents/SavingGoalRoadmap.vue";
-import SavingGoalCreate from "@/components/SavingGoalComponents/SavingGoalCreate.vue";
+import SavingGoalList from "@/components/SavingGoal/SavingGoalList.vue";
+import SavingGoalRoadmap from "@/components/SavingGoal/SavingGoalRoadmap.vue";
+import SavingGoalCreate from "@/components/SavingGoal/SavingGoalCreate.vue";
+import type {GoalDTO} from "@/api";
+import {GoalService} from "@/api";
+
 export default {
   components: {SavingGoalCreate, SavingGoalRoadmap, SavingGoalList},
   data() {
     return {
       bluePanelMaxHeight: 'auto' as string,
-      createClicked: false as boolean,
+      createClicked: true as boolean,
+      selectedGoal: [] as any,
+      createdGoal: [] as any,
+      key: 0 as number,
     };
   },
   mounted() {
@@ -20,7 +26,7 @@ export default {
       if (timelineElement instanceof HTMLElement) {
         // Calculate the max-height based on the height of the timeline
         const timelineHeight = timelineElement.offsetHeight;
-        this.bluePanelMaxHeight = `${timelineHeight*1.55}px`;
+        this.bluePanelMaxHeight = '700px';
       } else {
         this.bluePanelMaxHeight = '700px';
       }
@@ -28,9 +34,19 @@ export default {
     createGoal() {
       this.createClicked = true;
     },
-    goToSavingGoal() {
+    async goToSavingGoal(savingGoal: GoalDTO) {
+      this.$emit('goToSavingGoal', savingGoal);
+      let response = await GoalService.getGoal({id: savingGoal.id as number});
+      console.log(response)
+      this.selectedGoal = response
       this.createClicked = false;
+      this.key++
     },
+    createSavingGoal(savingGoal: GoalDTO) {
+      this.$emit('createSavingGoal', savingGoal)
+      this.createdGoal = savingGoal;
+      this.createClicked = false;
+    }
   },
 };
 </script>
@@ -38,7 +54,7 @@ export default {
 <template>
   <div class="cont">
     <div class="row">
-      <div class="col-lg-4 blue-background overflow-auto" :style="{ 'max-height': bluePanelMaxHeight }">
+      <div class="col-lg-4 blue-background overflow-scroll" :style="{ 'max-height': bluePanelMaxHeight }">
         <h3 style="color: white; margin-bottom: 16px">Your saving goals</h3>
         <div>
           <button class="btn btn-success btn-lg" style="font-weight: 600; margin-bottom: 20px" @click="createGoal">Create new saving goal</button>
@@ -46,8 +62,8 @@ export default {
         <saving-goal-list @goToSavingGoal="goToSavingGoal"></saving-goal-list>
       </div>
       <div class="spacer"/>
-      <saving-goal-create v-if="createClicked"></saving-goal-create>
-      <saving-goal-roadmap v-else></saving-goal-roadmap>
+      <saving-goal-create @createGoalClick="createSavingGoal" v-if="createClicked"></saving-goal-create>
+      <saving-goal-roadmap :key="key" :selected-goal="selectedGoal" v-else></saving-goal-roadmap>
     </div>
   </div>
 </template>
@@ -61,8 +77,12 @@ export default {
 }
 
 .blue-background {
-  background-color: #0A58CA;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  padding: 12px;
+  background-color: #003A58;
   width: 27%;
+  border-radius: 0 2em 2em 0;
 }
 
 .spacer {
diff --git a/src/components/SavingGoal/SavingGoalCreate.vue b/src/components/SavingGoal/SavingGoalCreate.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e5b1d5a99201c6b085e6c8e97cd3783da1dd5120
--- /dev/null
+++ b/src/components/SavingGoal/SavingGoalCreate.vue
@@ -0,0 +1,90 @@
+<script setup lang="ts">
+import {GoalService, type CreateGoalDTO, type GoalDTO} from "@/api"
+import {ref} from "vue";
+
+const name = ref("")
+const desc = ref("")
+const date = ref("")
+const amount = ref(0)
+const createdConfirm = ref("");
+const errorMessage = ref("")
+
+const createGoalClick = async () => {
+  console.log("create goal clicked")
+  console.log(name.value)
+  console.log(desc.value)
+  console.log(date.value)
+  console.log(amount.value)
+
+
+  const createGoalPayload: CreateGoalDTO = {
+    name: name.value,
+    description: desc.value,
+    targetAmount: amount.value,
+    targetDate: date.value + " 00:00:00.000000000",
+  };
+
+
+  try {
+    let response = await GoalService.createGoal({ requestBody: createGoalPayload });
+    if(response.name != "") {
+      createdConfirm.value = "Your goal has been created! Refresh the page to se it in the list"
+      errorMessage.value = ""
+    }
+  } catch (error: any) {
+    console.log(error.message);
+    errorMessage.value = error.message;
+  }
+}
+
+</script>
+
+<template>
+  <div class="col-lg-8">
+    <h1>Create a new saving goal!</h1>
+    <br>
+    <p>Create a name for this saving goal </p>
+    <div class="input-group mb-3">
+      <span class="input-group-text" id="basic-addon1">Name</span>
+      <input v-model="name" type="text" class="form-control" placeholder="Name of Saving Goal" aria-label="Username" aria-describedby="basic-addon1" required>
+    </div>
+
+    <p>Add a description to this saving goal </p>
+    <div class="input-group mb-3">
+      <span class="input-group-text" id="basic-addon2">Description</span>
+      <textarea v-model="desc" class="form-control" aria-label="With textarea"></textarea>
+    </div>
+
+    <!--Change this to date picker?-->
+    <p>When should this saving goal end?</p>
+    <div class="input-group mb-3">
+      <input v-model="date" type="date" class="form-control" aria-label="Amount of days" placeholder="Amount of days (as number)" required>
+    </div>
+
+    <p>How much do you want to save during this saving goal? </p>
+    <div class="input-group">
+      <input v-model="amount" type="number" class="form-control" aria-label="" placeholder="NOK (as number)" required>
+      <span class="input-group-text">NOK</span>
+    </div>
+
+    <br>
+    <button class="btn btn-primary btn-lg" @click="createGoalClick">Create goal!</button>
+
+    <div style="color: green; font-size: 32px">
+      {{ createdConfirm }}
+    </div>
+
+    <div style="color: red; font-size: 32px">
+      {{ errorMessage }}
+    </div>
+  </div>
+</template>
+
+<style scoped>
+.col-lg-8 {
+  width: 63%;
+  margin-top: 50px;
+  padding-right: 56px;
+  padding-bottom: 28px;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/SavingGoal/SavingGoalList.vue b/src/components/SavingGoal/SavingGoalList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..23604b4bea8ff280bb018c04811c900a44fb362b
--- /dev/null
+++ b/src/components/SavingGoal/SavingGoalList.vue
@@ -0,0 +1,66 @@
+<script setup lang="ts">
+import {ref, onMounted} from "vue";
+import {GoalService, type GoalDTO, type CreateGoalDTO} from "@/api"
+
+const savingGoalList = ref([] as any)
+
+defineProps()
+
+const getGoals = async () => {
+  try {
+    let response = await GoalService.getGoals();
+    savingGoalList.value = response
+  } catch (error: any) {
+    console.log(error.message);
+  }
+}
+
+onMounted(getGoals)
+
+const emits = defineEmits(['goToSavingGoal']);
+
+const goToSavingGoal = (savingGoal: GoalDTO) => {
+  emits('goToSavingGoal', savingGoal);
+};
+
+const deleteSavingGoal = () => {
+
+};
+</script>
+
+<template>
+  <div v-for="(savingGoal, index) in savingGoalList" :key="index" class="card bg-body">
+    <div class="card-header">
+      Saving goal {{ index + 1 }}
+    </div>
+    <div class="card-body">
+      <h5 class="card-title">{{ savingGoal.goalName }}</h5>
+      <p class="card-text">{{ savingGoal.description }}</p>
+      <a href="#" class="btn btn-primary" @click="goToSavingGoal(savingGoal)">Go to saving goal</a>
+      <a href="#" class="btn btn-danger" @click="deleteSavingGoal" style="margin-left: 8px">Delete</a>
+    </div>
+  </div>
+</template>
+
+<style scoped>
+.card-header, .card-text, .card-title {
+  color: white;
+}
+
+.card-header {
+  background-color: #40698A;
+}
+
+.card-body {
+  background-color: #447093;
+}
+
+* {
+  font-weight: 600;
+}
+
+.card {
+  margin-bottom: 20px;
+  border: none;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/SavingGoal/SavingGoalRoadmap.vue b/src/components/SavingGoal/SavingGoalRoadmap.vue
new file mode 100644
index 0000000000000000000000000000000000000000..65bbfb8876c1ed6f2b076ee56cbed0621f3a187f
--- /dev/null
+++ b/src/components/SavingGoal/SavingGoalRoadmap.vue
@@ -0,0 +1,707 @@
+<script lang="ts">
+import {CategoryScale, Chart as ChartJS, Legend, LinearScale, LineElement, PointElement, Title, Tooltip} from 'chart.js'
+import {Line} from 'vue-chartjs'
+import type {ChallengeDTO, GoalDTO, MarkChallengeDTO} from "@/api";
+import {GoalService} from '@/api'
+
+ChartJS.register(
+    CategoryScale,
+    LinearScale,
+    PointElement,
+    LineElement,
+    Title,
+    Tooltip,
+    Legend
+)
+
+
+export default {
+  components: {
+    Line
+  },
+  data() {
+    return {
+      image: 'https://th.bing.com/th/id/OIG3.NMbdxmKYKVnxYGLOa0Z0?w=1024&h=1024&rs=1&pid=ImgDetMain' as string,
+      altImage: 'https://th.bing.com/th/id/OIG4.gVWUC.rwCb8faTNx31yU?w=1024&h=1024&rs=1&pid=ImgDetMain' as string,
+      title: 'Spain trip' as string,
+      bluePanelMaxHeight: 'auto' as string,
+      roadmapSelected: true as boolean,
+      statsSelected: false as boolean,
+      chartData: {
+        labels: ["start"],
+        datasets: [
+          {
+            label: this.selectedGoal.name,
+            backgroundColor: '#003A58',
+            data: [0]
+          }
+        ]
+      },
+      chartOptions: {
+        responsive: true,
+        maintainAspectRatio: true,
+        scales: {
+          y: {
+            min: 0,
+            max: this.selectedGoal.targetAmount
+          }
+        }
+      },
+      newPrice: 0,
+      savedSoFar: 0 as number,
+      currentChallengeIndex: 0,
+    };
+  },
+  async mounted() {
+    setTimeout(() => {
+      this.findCurrentChallenge()
+      this.disableAllChecksThatNotCurrent()
+      this.togglePanel(this.selectedGoal.challenges[this.currentChallengeIndex])
+      this.calculateSavedSoFar()
+      this.onLoadDisableChecks(this.selectedGoal)
+      this.onLoadAddDataToGraph(this.selectedGoal)
+      console.log()
+    }, 500);
+  },
+  computed: {
+    computeImageFilter() {
+      return (challenge: ChallengeDTO) => {
+        return challenge ? 'none' : 'grayscale(100%)';
+      };
+    }
+  },
+  props: {
+    selectedGoal: {
+      type: Object,
+      default: null,
+    },
+  },
+  methods: {
+    togglePanel(step: any) {
+      if (step.showPanel) {
+        step.showPanel = false;
+      } else {
+        this.selectedGoal.challenges.forEach((s: any) => (s.showPanel = false));
+        step.showPanel = true;
+        this.scrollToPanel(step);
+      }
+    },
+
+    scrollToPanel(step: any) {
+      if (step.showPanel) {
+        this.$nextTick(() => {
+          const panel = document.getElementById(`panel-${this.selectedGoal.challenges.indexOf(step)}`);
+          if (panel) {
+            panel.scrollIntoView({ behavior: 'smooth', block: 'center' });
+          }
+        });
+      }
+    },
+
+    changeDisplay() {
+      if (this.roadmapSelected) {
+        this.roadmapSelected = false
+        this.statsSelected = true
+      } else {
+        this.roadmapSelected = true
+        this.statsSelected = false
+        setTimeout(() => {
+          this.onLoadDisableChecks(this.selectedGoal)
+          this.disableAllChecksThatNotCurrent()
+        }, 100);
+      }
+    },
+
+    convertTemplateTextToChallengeText(challenge: ChallengeDTO) {
+      let challengeText: any
+      challengeText = challenge.challengeTemplate?.text
+      challengeText = challengeText.replace('{unit_amount}', challenge.challengeTemplate?.amount?.toString())
+      challengeText = challengeText.replace('{checkDays}', challenge.checkDays?.toString())
+      challengeText = challengeText.replace('{totalDays}', challenge.totalDays?.toString())
+      let totalAmount: any
+      if (challenge.checkDays !== undefined && challenge.amount !== undefined) {
+        totalAmount = challenge.checkDays * challenge.amount;
+      } else {
+        // Handle the case when challenge.checkDays or challenge.amount is undefined
+      }
+      challengeText = challengeText.replace('{total_amount}', totalAmount.toString())
+      challengeText = challengeText.replace('{amount}', challenge.amount?.toString())
+      return challengeText
+    },
+
+    calculateTotalAmountFromChallenges() {
+      let totalAmountFromChallenges = 0
+      for (const challenge of this.selectedGoal.challenges) {
+        totalAmountFromChallenges += challenge.amount
+      }
+      return totalAmountFromChallenges
+    },
+
+    async handleCheckboxClick(challenge: ChallengeDTO, index: number, amount: number) {
+
+      this.lockCheckBox(challenge, index)
+      const markChallengePayload: MarkChallengeDTO = {
+        id: challenge.id,
+        day: index,
+        amount: amount,
+      };
+
+      try {
+        await GoalService.updateChallenge({ requestBody: markChallengePayload });
+        const today: Date = new Date();
+        const dateString: string = today.toISOString().split('T')[0]; // Extract YYYY-MM-DD part
+
+        if (challenge.progressList) {
+          challenge.progressList.push({ day: index, amount: amount, completedAt: dateString })
+        }
+
+        this.addDataToChart(amount, dateString);
+        this.calculateSavedSoFar();
+      } catch (error: any) {
+        console.log(error.message);
+      }
+    },
+
+    lockCheckBox(challenge: ChallengeDTO, index: number) {
+      const checkboxId = challenge.id + 'inlineCheckbox' + index
+      const checkbox = document.getElementById(checkboxId) as HTMLInputElement | null;
+      if (checkbox) {
+        // Disable the checkbox
+        checkbox.disabled = true;
+      }
+    },
+
+    onLoadDisableChecks(goal: GoalDTO) {
+      (goal.challenges || []).forEach((challenge: any) => {
+        challenge.progressList.forEach((progress: any) => {
+          // Assuming 'amount' is the property you want to add from progressList
+          const checkBoxId = challenge.id + 'inlineCheckbox' + progress.day
+          const checkbox = document.getElementById(checkBoxId) as HTMLInputElement | null;
+          if (checkbox) {
+            // Disable the checkbox
+            checkbox.checked = true;
+            checkbox.disabled = true;
+          }
+        });
+      });
+    },
+
+    onLoadAddDataToGraph(goal: GoalDTO) {
+      (goal.challenges || []).forEach((challenge: any) => {
+        challenge.progressList.forEach((progress: any) => {
+          this.addDataToChart(progress.amount, progress.completedAt);
+        });
+      });
+    },
+
+    addDataToChart(data: number, date: string) {
+      // Find the last dataset
+      const lastDataset = this.chartData.datasets[this.chartData.datasets.length - 1];
+
+      // Calculate the new label based on the last label
+      const newLabel = date.split('T')[0];
+
+      // Calculate the new data point based on the last data point
+      const lastDataPoint = lastDataset.data[lastDataset.data.length - 1];
+      const newDataPoint = lastDataPoint + data;
+
+      // Add the new label and data point to the chart data
+      this.chartData.labels.push(newLabel);
+      lastDataset.data.push(newDataPoint);
+    },
+
+    calculateSavedSoFar() {
+      this.savedSoFar = 0; // Reset savedSoFar before calculating again
+      this.selectedGoal.challenges.forEach((challenge: ChallengeDTO) => {
+        // Check if progressList exists before accessing its elements
+        if (challenge.progressList) {
+          challenge.progressList.forEach((progress: any) => {
+            // Assuming 'amount' is the property you want to add from progressList
+            this.savedSoFar += progress.amount;
+          });
+        }
+      });
+    },
+
+    findCurrentChallenge() {
+      const today: Date = new Date();
+      this.selectedGoal.challenges.forEach((challenge: ChallengeDTO, index: number) => {
+        const startDate: Date = new Date(challenge.startDate as string);
+        const endDate: Date = new Date(challenge.endDate as string);
+
+        if (today >= startDate && today <= endDate) {
+          this.currentChallengeIndex = index
+        }
+      })
+    },
+
+    disableAllChecksThatNotCurrent() {
+      this.selectedGoal.challenges.forEach((challenge: ChallengeDTO, index: number) => {
+        if (index !== this.currentChallengeIndex && challenge.checkDays !== undefined) {
+          for (let i = 1; i < challenge.checkDays + 1; i++) {
+            this.lockCheckBox(challenge, i)
+          }
+        }
+      })
+    },
+
+    formatDate(date: string) {
+      const date1 = new Date(date);
+      return date1.toISOString().split('T')[0]
+    },
+
+    calculateSavedSoFarPerChallengeInPercent(challenge: ChallengeDTO) {
+      let savedSoFarOnChallenge = 0
+      let targetAmount = 1
+      challenge.progressList?.forEach(progress => {
+        if(progress.amount) {
+          savedSoFarOnChallenge += progress.amount
+        }
+      })
+      if(challenge.amount) {
+        targetAmount = challenge.amount
+      }
+
+      return (savedSoFarOnChallenge / targetAmount) * 100
+    },
+
+    calculateSavedSoFarPerChallenge(challenge: ChallengeDTO) {
+      let savedSoFar = 0
+      challenge.progressList?.forEach(progress => {
+        if(progress.amount) {
+          savedSoFar += progress.amount
+        }
+      })
+      return savedSoFar
+    }
+  },
+};
+</script>
+
+<template>
+  <div class="col-lg-8">
+    <div class="SavingGoalTitle text-center">
+      {{selectedGoal.name}}
+      <br>
+      <p class="d-inline-flex gap-1">
+        <button @click="changeDisplay" class="btn btn-primary" type="button" style="font-size: 25px;">
+          <div v-if="roadmapSelected">
+            Se statistikk
+          </div>
+          <div v-else>
+            Se sparesti
+          </div>
+        </button>
+      </p>
+    </div>
+    <div v-if="roadmapSelected">
+      <ul class="timeline">
+        <li v-for="(challenge, index) in selectedGoal.challenges" :key="index" :class="{ 'timeline-inverted': index % 2 !== 0 }">
+          <div class="timeline-image z-1" @click="togglePanel(challenge)">
+            <img class="circular-image" :src="challenge.showPanel ? altImage : image" :style="{ filter: computeImageFilter(challenge) }" alt="">
+          </div>
+          <div class="timeline-panel z-3" :id="'panel-' + index" v-show="challenge.showPanel">
+            <div class="timeline-heading">
+              <h4>Utfordring {{ index +1 }}</h4>
+              <h4 class="subheading">{{convertTemplateTextToChallengeText(challenge)}}</h4>
+            </div>
+            <div class="timeline-body">
+              <br>
+              <p>
+                Pris per enhet: {{challenge.challengeTemplate.amount}} kr <img src="../../assets/icons/edit-button.svg" alt="editIcon" data-bs-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false" aria-controls="exampleModal">
+              </p>
+              <br>
+              <div class="collapse" id="collapseExample" style="background-color: white; padding: 12px; border-radius: 5px">
+                <div class="card card-body">
+                  <div class="input-group mb-3">
+                    <span class="input-group-text" id="basic-addon1">Ny pris</span>
+                    <input v-model="newPrice" type="number" class="form-control" placeholder="Pris i kr" aria-label="newPrice" aria-describedby="basic-addon1" required>
+                  </div>
+                </div>
+                <br>
+                <button class="btn btn-success">Bekreft endring</button>
+              </div>
+              <br>
+              <div class="progress">
+                <div class="progress-bar" role="progressbar" :style="{ width: calculateSavedSoFarPerChallengeInPercent(challenge) + '%' }" :aria-valuenow="calculateSavedSoFarPerChallengeInPercent(challenge)" aria-valuemin="0" aria-valuemax="100">{{ calculateSavedSoFarPerChallenge(challenge)}} Kr</div>
+              </div>
+              <br>
+              <div class="checkbox-row">
+                <div class="form-check form-check-inline" v-for="(day, index) in challenge.checkDays" :key="index">
+                  <input class="form-check-input" @click="handleCheckboxClick(challenge, index+1, challenge.challengeTemplate.amount)" type="checkbox" :id="challenge.id + 'inlineCheckbox' + (index + 1)" :value="day" :disabled="day.checked">
+                  <label class="form-check-label" style="color:white;" :for="'inlineCheckbox' + (index + 1)">{{ day }}</label>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="line" v-if="index < selectedGoal.challenges.length - 1"></div>
+        </li>
+      </ul>
+    </div>
+    <div v-else>
+
+      <div class="row">
+        <div class="col-sm-3">
+          <div class="card-box tilebox-one"><i class="icon-layers float-right text-muted"></i>
+            <h6 class="text-muted text-uppercase mt-0">Du ønsker å spare</h6>
+            <h2 class="" data-plugin="counterup">Kr {{ selectedGoal.targetAmount }}</h2></div>
+        </div>
+
+        <div class="col-sm-3">
+          <div class="card-box tilebox-one"><i class="icon-rocket float-right text-muted"></i>
+            <h6 class="text-muted text-uppercase mt-0">Du kan spare</h6>
+            <h2 class="" data-plugin="counterup">Kr {{ calculateTotalAmountFromChallenges() }}</h2></div>
+        </div>
+
+        <div class="col-sm-3">
+          <div class="card-box tilebox-one"><i class="icon-paypal float-right text-muted"></i>
+            <h6 class="text-muted text-uppercase mt-0">Du har spart</h6>
+            <h2 class="">Kr <span data-plugin="counterup">{{ savedSoFar }}</span></h2></div>
+        </div>
+
+        <div class="col-sm-3">
+          <div class="card-box tilebox-one"><i class="icon-rocket float-right text-muted"></i>
+            <h6 class="text-muted text-uppercase mt-0">Sparemålet ender </h6>
+            <h2 class="" data-plugin="counterup">{{ formatDate(selectedGoal.targetDate) }}</h2></div>
+        </div>
+      </div>
+      <br>
+      <Line ref="chart" :data="chartData" :options="chartOptions" />
+    </div>
+  </div>
+</template>
+
+<style scoped>
+.col-lg-8 {
+  width: 58%;
+  margin-bottom: 20px;
+}
+
+.SavingGoalTitle {
+  font-weight: 600;
+  font-size: 45px;
+  margin-top: 20px;
+  margin-bottom:40px;
+  padding-bottom: 10px;
+  color: white;
+  border-radius: 1em;
+  background-color: #003A58;
+}
+
+.timeline {
+  position: relative;
+  padding:4px 0 0 0;
+  margin-top:22px;
+  list-style: none;
+}
+
+.timeline>li:nth-child(even) {
+  position: relative;
+  margin-bottom: 50px;
+  height: 100px;
+  right:-100px;
+}
+
+.timeline>li:nth-child(odd) {
+  position: relative;
+  margin-bottom: 50px;
+  height: 100px;
+  left:-100px;
+}
+
+.timeline>li:before,
+.timeline>li:after {
+  content: " ";
+  display: table;
+}
+
+.timeline>li:after {
+  clear: both;
+  min-height: 170px;
+}
+
+.timeline > li .timeline-panel {
+  position: relative;
+  float: left;
+  width: 31%;
+  padding: 0 20px 20px 30px;
+  text-align: right;
+  background-color: #003A58;
+  border-radius: 1em;
+  margin-left: 110px;
+}
+
+.timeline>li .timeline-panel:before {
+  right: auto;
+  left: -15px;
+  border-right-width: 15px;
+  border-left-width: 0;
+}
+
+.timeline>li .timeline-panel:after {
+  right: auto;
+  left: -14px;
+  border-right-width: 14px;
+  border-left-width: 0;
+}
+
+.timeline>li .timeline-image {
+  z-index: 100;
+  position: absolute;
+  left: 50%;
+  border: 7px solid #003A58;
+  border-radius: 100%;
+  background-color: #00ffff;
+  box-shadow: 0 0 5px #00e1ff;
+  width: 100px;
+  height: 100px;
+  margin-left: -50px;
+  cursor:pointer;
+}
+
+.timeline>li .timeline-image h4 {
+  margin-top: 12px;
+  font-size: 10px;
+  line-height: 14px;
+}
+
+.timeline>li.timeline-inverted>.timeline-panel {
+  float: right;
+  padding: 0 30px 20px 20px;
+  text-align: left;
+  margin-right: 110px;
+}
+
+.timeline>li.timeline-inverted>.timeline-panel:before {
+  right: auto;
+  left: -15px;
+  border-right-width: 15px;
+  border-left-width: 0;
+}
+
+.timeline>li.timeline-inverted>.timeline-panel:after {
+  right: auto;
+  left: -14px;
+  border-right-width: 14px;
+  border-left-width: 0;
+}
+
+.timeline>li:last-child {
+  margin-bottom: 0;
+}
+
+.timeline .timeline-heading h4 {
+  margin-top:22px;
+  margin-bottom: 4px;
+  padding:0;
+  color: white;
+  font-weight:600;
+}
+
+.timeline .timeline-heading h4.subheading {
+  margin:0;
+  padding:0;
+  text-transform: none;
+  font-size:18px;
+  color:white;
+}
+
+.timeline .timeline-body>p,
+.timeline .timeline-body>ul {
+  margin-bottom: 0;
+  color:white;
+}
+/*Style for even div.line*/
+.timeline>li:nth-child(odd) .line:before {
+  content: "";
+  position: absolute;
+  top: 30px;
+  bottom: 0;
+  left: 700px;
+  width: 30px;
+  height:320px;
+  background-color: grey;
+  -ms-transform: rotate(-44deg); /* IE 9 */
+  -webkit-transform: rotate(-44deg); /* Safari */
+  transform: rotate(-44deg);
+  border: dotted white 3px;
+  /**box-shadow: 0 0 5px #00FF00;**/
+  display:none;
+}
+/*Style for odd div.line*/
+.timeline>li:nth-child(even) .line:before  {
+  content: "";
+  position: absolute;
+  top: 30px;
+  bottom: 0;
+  left: 480px;
+  width: 30px;
+  height:320px;
+  background-color: grey;
+  -ms-transform: rotate(44deg); /* IE 9 */
+  -webkit-transform: rotate(44deg); /* Safari */
+  transform: rotate(44deg);
+  border: dotted white 3px;
+  /*box-shadow: 0 0 5px #00FF00;*/
+  display:none;
+}
+/* Medium Devices, .visible-md-* */
+@media (min-width: 992px) and (max-width: 1199px) {
+  .col-lg-8 {
+    width: 100%;
+  }
+
+  .timeline > li:nth-child(even) {
+    margin-bottom: 0;
+    min-height: 0;
+    right: 0;
+  }
+  .timeline > li:nth-child(odd) {
+    margin-bottom: 0;
+    min-height: 0;
+    left: 0;
+  }
+  .timeline>li:nth-child(even) .timeline-image {
+    left: 0;
+    margin-left: 0;
+  }
+  .timeline>li:nth-child(odd) .timeline-image {
+    left: 690px;
+    margin-left: 0;
+  }
+  .timeline > li:nth-child(even) .timeline-panel {
+    width: 76%;
+    padding: 0 0 20px 0;
+    text-align: left;
+  }
+  .timeline > li:nth-child(odd) .timeline-panel {
+    width: 70%;
+    padding: 0 0 20px 0;
+    text-align: right;
+  }
+  .timeline > li .line {
+    display: none;
+  }
+}
+/* Small Devices, Tablets */
+@media (min-width: 768px) and (max-width: 991px) {
+  .timeline > li:nth-child(even) {
+    margin-bottom: 0;
+    min-height: 0;
+    right: 0;
+  }
+  .timeline > li:nth-child(odd) {
+    margin-bottom: 0;
+    min-height: 0;
+    left: 0;
+  }
+  .timeline>li:nth-child(even) .timeline-image {
+    left: 0;
+    margin-left: 0;
+  }
+  .timeline>li:nth-child(odd) .timeline-image {
+    left: 520px;
+    margin-left: 0;
+  }
+  .timeline > li:nth-child(even) .timeline-panel {
+    width: 70%;
+    padding: 0 0 20px 0;
+    text-align: left;
+  }
+  .timeline > li:nth-child(odd) .timeline-panel {
+    width: 70%;
+    padding: 0 0 20px 0;
+    text-align: right;
+  }
+  .timeline > li .line {
+    display: none;
+  }
+}
+/* Custom, iPhone Retina */
+@media only screen and (max-width: 767px) {
+  .timeline > li:nth-child(even) {
+    margin-bottom: 0;
+    min-height: 0;
+    right: 0;
+  }
+  .timeline > li:nth-child(odd) {
+    margin-bottom: 0;
+    min-height: 0;
+    left: 0;
+  }
+  .timeline>li .timeline-image {
+    position: static;
+    width: 150px;
+    height: 150px;
+    margin-bottom:0;
+  }
+  .timeline>li:nth-child(even) .timeline-image {
+    left: 0;
+    margin-left: 0;
+  }
+  .timeline>li:nth-child(odd) .timeline-image {
+    float:right;
+    left: 0;
+    margin-left:0;
+  }
+  .timeline > li:nth-child(even) .timeline-panel {
+    width: 100%;
+    padding: 0 0 20px 14px;
+  }
+  .timeline > li:nth-child(odd) .timeline-panel {
+    width: 100%;
+    padding: 0 14px 20px 0;
+  }
+  .timeline > li .line {
+    display: none;
+  }
+}
+
+/* Additional styles for inverted timeline panels */
+.timeline > li.timeline-inverted:nth-child(even) .timeline-panel {
+  float: right;
+  padding: 0 30px 20px 20px;
+  text-align: left;
+}
+
+.timeline > li.timeline-inverted:nth-child(odd) .timeline-panel {
+  float: left;
+  padding: 0 20px 20px 30px;
+  text-align: right;
+}
+
+.timeline > li.timeline-inverted:nth-child(even) .timeline-panel:before,
+.timeline > li.timeline-inverted:nth-child(even) .timeline-panel:after {
+  right: auto;
+  left: -15px;
+  border-right-width: 15px;
+  border-left-width: 0;
+}
+
+.timeline > li.timeline-inverted:nth-child(odd) .timeline-panel:before,
+.timeline > li.timeline-inverted:nth-child(odd) .timeline-panel:after {
+  right: auto;
+  left: -14px;
+  border-right-width: 14px;
+  border-left-width: 0;
+}
+
+.circular-image {
+  border-radius: 50%;
+  max-width: 100%;
+  height: auto;
+}
+
+.checkbox-row {
+  display: flex;
+  flex-wrap: wrap;
+  margin-bottom: 12px; /* Adjust as needed */
+  text-align: left !important;
+}
+
+.form-check {
+  flex: 0 0 calc(25% - 10px); /* 20% width for each checkbox, adjust margin accordingly */
+  margin-right: 10px; /* Adjust as needed */
+}
+
+</style>
\ No newline at end of file
diff --git a/src/components/SavingGoalComponents/SavingGoalCreate.vue b/src/components/SavingGoalComponents/SavingGoalCreate.vue
deleted file mode 100644
index 280af93df3667458a4d0e26e20a9baee66553ca8..0000000000000000000000000000000000000000
--- a/src/components/SavingGoalComponents/SavingGoalCreate.vue
+++ /dev/null
@@ -1,43 +0,0 @@
-<script setup lang="ts">
-
-</script>
-
-<template>
-  <div class="col-lg-8">
-    <h1>Create a new saving goal!</h1>
-    <br>
-    <p>Create a name for this saving goal: </p>
-    <div class="input-group mb-3">
-      <span class="input-group-text" id="basic-addon1">Name:</span>
-      <input type="text" class="form-control" placeholder="Name of Saving Goal" aria-label="Username" aria-describedby="basic-addon1">
-    </div>
-
-    <p>Add a description to this saving goal: </p>
-    <div class="input-group mb-3">
-      <span class="input-group-text" id="basic-addon2">Description:</span>
-      <textarea class="form-control" aria-label="With textarea"></textarea>
-    </div>
-
-    <!--Change this to date picker?-->
-    <p>When should this saving goal end?:</p>
-    <div class="input-group mb-3">
-      <input type="date" class="form-control" aria-label="Amount of days" placeholder="Amount of days (as number)">
-    </div>
-
-    <p>How much do you want to save during this saving goal: </p>
-    <div class="input-group">
-      <input type="text" class="form-control" aria-label="" placeholder="NOK (as number)">
-      <span class="input-group-text">NOK</span>
-    </div>
-
-    <br>
-    <button class="btn btn-primary btn-lg">Create goal!</button>
-  </div>
-</template>
-
-<style scoped>
-.col-lg-8 {
-  width: 63%;
-  margin-top: 50px;
-}
-</style>
\ No newline at end of file
diff --git a/src/components/SavingGoalComponents/SavingGoalList.vue b/src/components/SavingGoalComponents/SavingGoalList.vue
deleted file mode 100644
index e792585dbd3ade07037dd7601843b58b121f5b24..0000000000000000000000000000000000000000
--- a/src/components/SavingGoalComponents/SavingGoalList.vue
+++ /dev/null
@@ -1,52 +0,0 @@
-<script setup lang="ts">
-import {ref} from "vue";
-
-const savingGoalList = ref([
-  { title: 'Spain trip', MoneyTarget: '200kr', description: 'You wanted to save 200kr for a spain trip' },
-  { title: 'Italy Escapade', MoneyTarget: '200kr', description: 'Experience the magic of Italy with us! Our goal is to save 200kr for an amazing trip to Italy.' },
-  { title: 'French Getaway', MoneyTarget: '200kr', description: 'Join us as we plan to save 200kr for a delightful trip to France!' },
-  { title: 'Exploring Greece', MoneyTarget: '200kr', description: 'Dreaming of Greece? Lets work together to save 200kr for that unforgettable trip!' },
-  { title: 'German Adventure', MoneyTarget: '200kr', description: 'Discover the charm of Germany with us! We are aiming to save 200kr for this exciting adventure.' },
-  { title: 'German Adventure', MoneyTarget: '200kr', description: 'Discover the charm of Germany with us! We are aiming to save 200kr for this exciting adventure.' },
-  { title: 'German Adventure', MoneyTarget: '200kr', description: 'Discover the charm of Germany with us! We are aiming to save 200kr for this exciting adventure.' },
-  { title: 'German Adventure', MoneyTarget: '200kr', description: 'Discover the charm of Germany with us! We are aiming to save 200kr for this exciting adventure.' }
-])
-
-const emits = defineEmits(['goToSavingGoal']);
-
-const goToSavingGoal = () => {
-  emits('goToSavingGoal');
-};
-
-const deleteSavingGoal = () => {
-
-};
-</script>
-
-<template>
-  <div v-for="(savingGoal, index) in savingGoalList" :key="index" class="card bg-primary">
-    <div class="card-header">
-      Saving goal {{ index + 1 }}
-    </div>
-    <div class="card-body">
-      <h5 class="card-title">{{ savingGoal.title }}</h5>
-      <p class="card-text">{{ savingGoal.description }}</p>
-      <a href="#" class="btn btn-light" @click="goToSavingGoal">Go to saving goal</a>
-      <a href="#" class="btn btn-danger" @click="deleteSavingGoal" style="margin-left: 8px">Delete</a>
-    </div>
-  </div>
-</template>
-
-<style scoped>
-.card-header, .card-text, .card-title {
-  color: white;
-}
-
-* {
-  font-weight: 600;
-}
-
-.card {
-  margin-bottom: 20px;
-}
-</style>
\ No newline at end of file
diff --git a/src/components/SavingGoalComponents/SavingGoalRoadmap.vue b/src/components/SavingGoalComponents/SavingGoalRoadmap.vue
deleted file mode 100644
index 018c4579e1948559e1bbc2f93220fac6f97a3d0b..0000000000000000000000000000000000000000
--- a/src/components/SavingGoalComponents/SavingGoalRoadmap.vue
+++ /dev/null
@@ -1,434 +0,0 @@
-<script lang="ts">
-interface Step {
-  title: string;
-  showPanel: boolean;
-  description: string;
-  percentFinished: number;
-  unFinished: boolean;
-}
-export default {
-  data() {
-    return {
-      image: 'https://th.bing.com/th/id/OIG3.NMbdxmKYKVnxYGLOa0Z0?w=1024&h=1024&rs=1&pid=ImgDetMain' as string,
-      altImage: 'https://th.bing.com/th/id/OIG4.gVWUC.rwCb8faTNx31yU?w=1024&h=1024&rs=1&pid=ImgDetMain' as string,
-      title: 'Spain trip' as string,
-      //This will be changed to info gathered from backend
-      steps: [
-        { title: 'Challenge 1', showPanel: false, description: 'Save 50kr on coffee in 3 days', percentFinished: 22, unFinished: false },
-        { title: 'Challenge 2', showPanel: false, description: 'Save 500kr on food in 7 days', percentFinished: 73, unFinished: false },
-        { title: 'Challenge 3', showPanel: false, description: 'Save 350kr on clothes in 5 days', percentFinished: 50, unFinished: true },
-        { title: 'Challenge 4', showPanel: false, description: 'Save 150kr on coffee in 4 days', percentFinished: 10, unFinished: true },
-        { title: 'Challenge 5', showPanel: false, description: 'Save 50kr on coffee in 3 days', percentFinished: 90, unFinished: true }
-      ]
-      ,
-      bluePanelMaxHeight: 'auto' as string
-    };
-  },
-  mounted() {
-    setTimeout(() => {
-      this.togglePanel(this.steps[2]);
-    }, 500);
-    
-  },
-  computed: {
-    computeImageFilter() {
-      return (step: Step) => {
-        return step.unFinished ? 'none' : 'grayscale(100%)';
-      };
-    }
-  },
-  methods: {
-    togglePanel(step: Step) {
-      if (step.showPanel) {
-        step.showPanel = false;
-      } else {
-        this.steps.forEach((s) => (s.showPanel = false));
-        step.showPanel = true;
-        this.scrollToPanel(step);
-      }
-    },
-    scrollToPanel(step: Step) {
-      if (step.showPanel) {
-        this.$nextTick(() => {
-          const panel = document.getElementById(`panel-${this.steps.indexOf(step)}`);
-          if (panel) {
-            panel.scrollIntoView({ behavior: 'smooth', block: 'center' });
-          }
-        });
-      }
-    },
-  },
-};
-</script>
-
-<template>
-  <div class="col-lg-8">
-    <div class="SavingGoalTitle text-center">
-      {{title}}
-      <br>
-      <p class="d-inline-flex gap-1">
-        <button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample" style="font-size: 25px;">
-          See more info
-        </button>
-      </p>
-      <div class="collapse" id="collapseExample">
-        <div class="card card-body bg-primary mx-auto" style="width: 80%;">
-          Total saved: 20kr
-        </div>
-      </div>
-    </div>
-    <ul class="timeline">
-      <li v-for="(step, index) in steps" :key="index" :class="{ 'timeline-inverted': index % 2 !== 0 }">
-          <div class="timeline-image z-1" @click="togglePanel(step)">
-            <img class="circular-image" :src="step.showPanel ? altImage : image" :style="{ filter: computeImageFilter(step) }" alt="">
-          </div>
-        <div class="timeline-panel z-3" :id="'panel-' + index" v-show="step.showPanel">
-          <div class="timeline-heading">
-            <h4>{{ step.title }}</h4>
-            <h4 class="subheading">{{step.description}}</h4>
-          </div>
-          <div class="timeline-body">
-            <br>
-            <p class="">
-              Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
-            </p>
-            <br>
-            <div class="progress">
-              <div class="progress-bar" role="progressbar" :style="{ width: step.percentFinished + '%' }" :aria-valuenow="step.percentFinished" aria-valuemin="0" aria-valuemax="100"></div>
-            </div>
-            <br>
-            <div class="form-check form-check-inline">
-              <input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1">
-              <label class="form-check-label" style="color:white;" for="inlineCheckbox1">Day 1</label>
-            </div>
-            <div class="form-check form-check-inline">
-              <input class="form-check-input" type="checkbox" id="inlineCheckbox2" value="option2">
-              <label class="form-check-label" style="color:white;" for="inlineCheckbox1">Day 2</label>
-            </div>
-          </div>
-        </div>
-        <div class="line" v-if="index < steps.length - 1"></div>
-      </li>
-    </ul>
-  </div>
-</template>
-
-<style scoped>
-.col-lg-8 {
-  width: 58%;
-  margin-bottom: 20px;
-}
-
-.SavingGoalTitle {
-  font-weight: 600;
-  font-size: 45px;
-  margin-top: 20px;
-  margin-bottom:40px;
-  padding-bottom: 10px;
-  color: white;
-  border-radius: 1em;
-  background-color: #0A58CA;
-}
-
-.timeline {
-  position: relative;
-  padding:4px 0 0 0;
-  margin-top:22px;
-  list-style: none;
-}
-
-.timeline>li:nth-child(even) {
-  position: relative;
-  margin-bottom: 50px;
-  height: 100px;
-  right:-100px;
-}
-
-.timeline>li:nth-child(odd) {
-  position: relative;
-  margin-bottom: 50px;
-  height: 100px;
-  left:-100px;
-}
-
-.timeline>li:before,
-.timeline>li:after {
-  content: " ";
-  display: table;
-}
-
-.timeline>li:after {
-  clear: both;
-  min-height: 170px;
-}
-
-.timeline > li .timeline-panel {
-  position: relative;
-  float: left;
-  width: 41%;
-  padding: 0 20px 20px 30px;
-  text-align: right;
-  background-color: #0A58CA;
-  border-radius: 1em;
-}
-
-.timeline>li .timeline-panel:before {
-  right: auto;
-  left: -15px;
-  border-right-width: 15px;
-  border-left-width: 0;
-}
-
-.timeline>li .timeline-panel:after {
-  right: auto;
-  left: -14px;
-  border-right-width: 14px;
-  border-left-width: 0;
-}
-
-.timeline>li .timeline-image {
-  z-index: 100;
-  position: absolute;
-  left: 50%;
-  border: 7px solid #001664;
-  border-radius: 100%;
-  background-color: #00ffff;
-  box-shadow: 0 0 5px #00e1ff;
-  width: 100px;
-  height: 100px;
-  margin-left: -50px;
-  cursor:pointer;
-}
-
-.timeline>li .timeline-image h4 {
-  margin-top: 12px;
-  font-size: 10px;
-  line-height: 14px;
-}
-
-.timeline>li.timeline-inverted>.timeline-panel {
-  float: right;
-  padding: 0 30px 20px 20px;
-  text-align: left;
-}
-
-.timeline>li.timeline-inverted>.timeline-panel:before {
-  right: auto;
-  left: -15px;
-  border-right-width: 15px;
-  border-left-width: 0;
-}
-
-.timeline>li.timeline-inverted>.timeline-panel:after {
-  right: auto;
-  left: -14px;
-  border-right-width: 14px;
-  border-left-width: 0;
-}
-
-.timeline>li:last-child {
-  margin-bottom: 0;
-}
-
-.timeline .timeline-heading h4 {
-  margin-top:22px;
-  margin-bottom: 4px;
-  padding:0;
-  color: white;
-  font-weight:600;
-}
-
-.timeline .timeline-heading h4.subheading {
-  margin:0;
-  padding:0;
-  text-transform: none;
-  font-size:18px;
-  color:white;
-}
-
-.timeline .timeline-body>p,
-.timeline .timeline-body>ul {
-  margin-bottom: 0;
-  color:white;
-}
-/*Style for even div.line*/
-.timeline>li:nth-child(odd) .line:before {
-  content: "";
-  position: absolute;
-  top: 30px;
-  bottom: 0;
-  left: 700px;
-  width: 30px;
-  height:320px;
-  background-color: grey;
-  -ms-transform: rotate(-44deg); /* IE 9 */
-  -webkit-transform: rotate(-44deg); /* Safari */
-  transform: rotate(-44deg);
-  border: dotted white 3px;
-  /**box-shadow: 0 0 5px #00FF00;**/
-  display:none;
-}
-/*Style for odd div.line*/
-.timeline>li:nth-child(even) .line:before  {
-  content: "";
-  position: absolute;
-  top: 30px;
-  bottom: 0;
-  left: 480px;
-  width: 30px;
-  height:320px;
-  background-color: grey;
-  -ms-transform: rotate(44deg); /* IE 9 */
-  -webkit-transform: rotate(44deg); /* Safari */
-  transform: rotate(44deg);
-  border: dotted white 3px;
-  /*box-shadow: 0 0 5px #00FF00;*/
-  display:none;
-}
-/* Medium Devices, .visible-md-* */
-@media (min-width: 992px) and (max-width: 1199px) {
-  .col-lg-8 {
-    width: 100%;
-  }
-
-  .timeline > li:nth-child(even) {
-    margin-bottom: 0;
-    min-height: 0;
-    right: 0;
-  }
-  .timeline > li:nth-child(odd) {
-    margin-bottom: 0;
-    min-height: 0;
-    left: 0;
-  }
-  .timeline>li:nth-child(even) .timeline-image {
-    left: 0;
-    margin-left: 0;
-  }
-  .timeline>li:nth-child(odd) .timeline-image {
-    left: 690px;
-    margin-left: 0;
-  }
-  .timeline > li:nth-child(even) .timeline-panel {
-    width: 76%;
-    padding: 0 0 20px 0;
-    text-align: left;
-  }
-  .timeline > li:nth-child(odd) .timeline-panel {
-    width: 70%;
-    padding: 0 0 20px 0;
-    text-align: right;
-  }
-  .timeline > li .line {
-    display: none;
-  }
-}
-/* Small Devices, Tablets */
-@media (min-width: 768px) and (max-width: 991px) {
-  .timeline > li:nth-child(even) {
-    margin-bottom: 0;
-    min-height: 0;
-    right: 0;
-  }
-  .timeline > li:nth-child(odd) {
-    margin-bottom: 0;
-    min-height: 0;
-    left: 0;
-  }
-  .timeline>li:nth-child(even) .timeline-image {
-    left: 0;
-    margin-left: 0;
-  }
-  .timeline>li:nth-child(odd) .timeline-image {
-    left: 520px;
-    margin-left: 0;
-  }
-  .timeline > li:nth-child(even) .timeline-panel {
-    width: 70%;
-    padding: 0 0 20px 0;
-    text-align: left;
-  }
-  .timeline > li:nth-child(odd) .timeline-panel {
-    width: 70%;
-    padding: 0 0 20px 0;
-    text-align: right;
-  }
-  .timeline > li .line {
-    display: none;
-  }
-}
-/* Custom, iPhone Retina */
-@media only screen and (max-width: 767px) {
-  .timeline > li:nth-child(even) {
-    margin-bottom: 0;
-    min-height: 0;
-    right: 0;
-  }
-  .timeline > li:nth-child(odd) {
-    margin-bottom: 0;
-    min-height: 0;
-    left: 0;
-  }
-  .timeline>li .timeline-image {
-    position: static;
-    width: 150px;
-    height: 150px;
-    margin-bottom:0;
-  }
-  .timeline>li:nth-child(even) .timeline-image {
-    left: 0;
-    margin-left: 0;
-  }
-  .timeline>li:nth-child(odd) .timeline-image {
-    float:right;
-    left: 0;
-    margin-left:0;
-  }
-  .timeline > li:nth-child(even) .timeline-panel {
-    width: 100%;
-    padding: 0 0 20px 14px;
-  }
-  .timeline > li:nth-child(odd) .timeline-panel {
-    width: 100%;
-    padding: 0 14px 20px 0;
-  }
-  .timeline > li .line {
-    display: none;
-  }
-}
-
-/* Additional styles for inverted timeline panels */
-.timeline > li.timeline-inverted:nth-child(even) .timeline-panel {
-  float: right;
-  padding: 0 30px 20px 20px;
-  text-align: left;
-}
-
-.timeline > li.timeline-inverted:nth-child(odd) .timeline-panel {
-  float: left;
-  padding: 0 20px 20px 30px;
-  text-align: right;
-}
-
-.timeline > li.timeline-inverted:nth-child(even) .timeline-panel:before,
-.timeline > li.timeline-inverted:nth-child(even) .timeline-panel:after {
-  right: auto;
-  left: -15px;
-  border-right-width: 15px;
-  border-left-width: 0;
-}
-
-.timeline > li.timeline-inverted:nth-child(odd) .timeline-panel:before,
-.timeline > li.timeline-inverted:nth-child(odd) .timeline-panel:after {
-  right: auto;
-  left: -14px;
-  border-right-width: 14px;
-  border-left-width: 0;
-}
-
-.circular-image {
-  border-radius: 50%;
-  max-width: 100%;
-  height: auto;
-}
-</style>
\ No newline at end of file
diff --git a/src/components/Settings/SettingsAccount.vue b/src/components/Settings/SettingsAccount.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9e01429f4c3d343d1277fcaa29b35d0e8bdae044
--- /dev/null
+++ b/src/components/Settings/SettingsAccount.vue
@@ -0,0 +1,76 @@
+<script setup lang="ts">
+import { ref, onMounted } from 'vue';
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue';
+import { useUserInfoStore } from "@/stores/UserStore";
+import { UserService } from '@/api';
+import type { UserUpdateDTO } from '@/api';
+
+const emailRef = ref('')
+const errorMsg = ref('')
+const confirmationMsg = ref('')
+
+const handleEmailInputEvent = (newValue: any) => {
+  emailRef.value = newValue
+}
+
+async function setupForm() {
+  try {
+    let response = await UserService.getUser();
+    if (response.email != null) {
+      emailRef.value = response.email
+    }
+    confirmationMsg.value = '';
+    errorMsg.value = '';
+  } catch (err) {
+    errorMsg.value = 'Error fetching email, try again!'
+    confirmationMsg.value = ''
+  }
+}
+
+const handleSubmit = async () => {
+  console.log('Yoooo')
+  const updateUserPayload: UserUpdateDTO = {
+    email: emailRef.value,
+  };
+  try {
+    UserService.update({ requestBody: updateUserPayload })
+    useUserInfoStore().setUserInfo({
+        email: emailRef.value,
+    })
+    confirmationMsg.value = 'Email updated successfully!'
+    errorMsg.value = '';
+  } catch (err) {
+    errorMsg.value = "Error updating email, try again!";
+    confirmationMsg.value = ''
+  }
+}
+onMounted(() => {
+  setupForm()
+})
+</script>
+
+<template>
+  <div class="tab-pane active" id="account">
+      <h6>KONTO INNSTILLINGER</h6>
+      <hr>
+      <form  @submit.prevent="handleSubmit">
+          <div class="form-group">
+              <BaseInput data-cy="email-input" :model-value="emailRef"
+                         @input-change-event="handleEmailInputEvent" id="emailInput-change"
+                  input-id="email-new" type="email" label="E-post" placeholder="Skriv inn din e-post"
+                  invalid-message="Ugyldig e-post"/>
+          </div>
+          <p data-cy="change-email-msg-error" class="text-danger">{{ errorMsg }}</p>
+          <p data-cy="change-email-msg-confirm" class="text-success">{{ confirmationMsg }}</p>
+          <br>
+          <button data-cy="change-email-btn" type="submit" class="btn btn-primary">Endre
+            Informasjon</button>
+          <hr>
+          <div class="form-group">
+              <label class="d-block text-danger">Slett Bruker</label>
+              <p class="text-muted font-size-sm">Når du først har slettet kontoen din, er det ingen vei tilbake. Vennligst vær sikker.</p>
+          </div>
+          <button class="btn btn-danger" type="button">Slett Bruker</button>
+      </form>
+  </div>
+</template>
diff --git a/src/views/Settings/SettingsBankView.vue b/src/components/Settings/SettingsBank.vue
similarity index 56%
rename from src/views/Settings/SettingsBankView.vue
rename to src/components/Settings/SettingsBank.vue
index 85c5b04aa3f9328e72283d74b32dd4b7043c5590..d5142d2130fd5ae83927cd8d2da5fce6bca311bb 100644
--- a/src/views/Settings/SettingsBankView.vue
+++ b/src/components/Settings/SettingsBank.vue
@@ -1,38 +1,42 @@
 <template>
     <div class="tab-pane active" id="billing">
-        <h6>BANK SETTINGS</h6>
+        <h6>BANKKONTO INNSTILLINGER</h6>
         <hr>
         <form @submit.prevent="handleSpendingSubmit">
             <div class="form-group">
-                <BaseInput :model-value="spendingAccount" @input-change-event="handleSpendingInputEvent" id="firstNameInputChange" input-id="first-name-new"
-                    type="Number" label="Spending Account" placeholder="Enter your spending account"
-                    invalid-message="Please enter your spending account" />
+                <BaseInput data-cy="spending-account-input" :model-value="spendingAccount"
+                            @input-change-event="handleSpendingInputEvent" id="firstNameInputChange" input-id="first-name-new"
+                    type="Number" label="Brukskonto" placeholder="Skriv inn din brukskonto"
+                    invalid-message="Vennligst skriv inn din brukskonto" />
             </div>
             <br>
-            <button type="submit" class="btn btn-primary">Update Spending Account</button>
+            <button data-cy="update-spending-btn" type="submit" class="btn btn-primary">Oppdater
+              brukskonto</button>
         </form>
         <br>
         <form @submit.prevent="handleSavingSubmit">
             <div class="form-group">
-                <BaseInput :model-value="savingsAccount" @input-change-event="handleSavingInputEvent" id="firstNameInputChange" input-id="first-name-new" type="Number"
-                    label="Savings Account" placeholder="Enter your Savings account"
-                    invalid-message="Please enter your Savings account" />
+                <BaseInput data-cy="savings-account-input" :model-value="savingsAccount"
+                           @input-change-event="handleSavingInputEvent" id="firstNameInputChange" input-id="first-name-new" type="Number"
+                    label="Sparekonto" placeholder="Skriv inn din sparekonto"
+                    invalid-message="Vennligst skriv inn din sparekonto" />
             </div>
             <br>
-            <button type="submit" class="btn btn-primary">Update Savings Account</button>
+            <button data-cy="update-savings-btn" type="submit" class="btn btn-primary">Oppdater
+              sparekonto</button>
         </form>
         <hr>
         <div class="form-group mb-0">
-            <label class="d-block">Payment History</label>
-            <div class="border border-gray-500 bg-gray-200 p-3 text-center font-size-sm">You
-                have not made any payment.</div>
+            <label class="d-block">Betalingshistorikk</label>
+            <div class="border border-gray-500 bg-gray-200 p-3 text-center font-size-sm">Du har ikke foretatt noen betaling.</div>
         </div>
     </div>
 </template>
 
+
 <script setup lang="ts">
 import { ref } from 'vue';
-import BaseInput from '@/components/InputFields/BaseInput.vue';
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue';
 import type { BankAccountDTO } from '@/api';
 import { UserService } from '@/api';
 
diff --git a/src/views/Settings/SettingsNotificationView.vue b/src/components/Settings/SettingsNotification.vue
similarity index 81%
rename from src/views/Settings/SettingsNotificationView.vue
rename to src/components/Settings/SettingsNotification.vue
index 225f1ae14d2fb1c26febea564ac1908461e9c4c1..f33417a59c8ff18f82595b1a28ac500805581c9d 100644
--- a/src/views/Settings/SettingsNotificationView.vue
+++ b/src/components/Settings/SettingsNotification.vue
@@ -1,56 +1,55 @@
 <template>
     <div class="tab-pane active" id="notification">
-        <h6>NOTIFICATION SETTINGS</h6>
+        <h6>VARSLINGSINNSTILLINGER</h6>
         <hr>
         <form>
             <div class="form-group">
-                <label class="d-block mb-0">Security Alerts</label>
-                <div class="small text-muted mb-3">Receive security alert notifications via email
-                </div>
+                <label class="d-block mb-0">Sikkerhetsvarsler</label>
+                <div class="small text-muted mb-3">Motta sikkerhetsvarselvarsler via e-post</div>
                 <div class="custom-control custom-checkbox">
                     <input type="checkbox" class="custom-control-input" id="customCheck1">
-                    <label class="custom-control-label" for="customCheck1">Email each time a
-                        vulnerability is found</label>
+                    <label class="custom-control-label" for="customCheck1">E-post hver gang en
+                        sårbarhet blir funnet</label>
                 </div>
                 <div class="custom-control custom-checkbox">
                     <input type="checkbox" class="custom-control-input" id="customCheck2">
-                    <label class="custom-control-label" for="customCheck2">Email a digest summary of
-                        vulnerability</label>
+                    <label class="custom-control-label" for="customCheck2">E-post et sammendrag av
+                        sårbarhet</label>
                 </div>
             </div>
             <div class="form-group mb-0">
-                <label class="d-block">SMS Notifications</label>
+                <label class="d-block">SMS-varsler</label>
                 <ul class="list-group list-group-sm">
                     <li class="list-group-item has-icon">
-                        Comments
+                        Kommentarer
                         <div class="custom-control custom-control-nolabel custom-switch ml-auto">
                             <input type="checkbox" class="custom-control-input" id="customSwitch1">
                             <label class="custom-control-label" for="customSwitch1"></label>
                         </div>
                     </li>
                     <li class="list-group-item has-icon">
-                        Updates From People
+                        Oppdateringer fra personer
                         <div class="custom-control custom-control-nolabel custom-switch ml-auto">
                             <input type="checkbox" class="custom-control-input" id="customSwitch2">
                             <label class="custom-control-label" for="customSwitch2"></label>
                         </div>
                     </li>
                     <li class="list-group-item has-icon">
-                        Reminders
+                        Påminnelser
                         <div class="custom-control custom-control-nolabel custom-switch ml-auto">
                             <input type="checkbox" class="custom-control-input" id="customSwitch3">
                             <label class="custom-control-label" for="customSwitch3"></label>
                         </div>
                     </li>
                     <li class="list-group-item has-icon">
-                        Events
+                        Hendelser
                         <div class="custom-control custom-control-nolabel custom-switch ml-auto">
                             <input type="checkbox" class="custom-control-input" id="customSwitch4">
                             <label class="custom-control-label" for="customSwitch4"></label>
                         </div>
                     </li>
                     <li class="list-group-item has-icon">
-                        Pages You Follow
+                        Sider du følger
                         <div class="custom-control custom-control-nolabel custom-switch ml-auto">
                             <input type="checkbox" class="custom-control-input" id="customSwitch5">
                             <label class="custom-control-label" for="customSwitch5"></label>
@@ -60,5 +59,4 @@
             </div>
         </form>
     </div>
-
-</template>
\ No newline at end of file
+</template>
diff --git a/src/views/Settings/SettingsProfileView.vue b/src/components/Settings/SettingsProfile.vue
similarity index 66%
rename from src/views/Settings/SettingsProfileView.vue
rename to src/components/Settings/SettingsProfile.vue
index 8f88d2622e62974bdb547f7a3bbb99baa62dc538..6d083ff4f9f60eba55a1e33ef3eb05aa6651c159 100644
--- a/src/views/Settings/SettingsProfileView.vue
+++ b/src/components/Settings/SettingsProfile.vue
@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import { ref, onMounted } from 'vue';
-import BaseInput from '@/components/InputFields/BaseInput.vue';
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue';
 import { useUserInfoStore } from "@/stores/UserStore";
 import { UserService, ImageService } from '@/api';
 import type { UserUpdateDTO } from '@/api';
@@ -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";
@@ -101,35 +101,46 @@ onMounted(() => {
 
 <template>
   <div class="tab-pane active" id="profile">
-    <h6>YOUR PROFILE INFORMATION</h6>
+    <h6>DIN PROFILINFORMASJON</h6>
     <hr>
     <form @submit.prevent="handleSubmit" novalidate>
       <div class="user-avatar">
         <input type="file" ref="fileInputRef" @change="handleFileChange" accept=".jpg, .jpeg, .png"
           style="display: none;" />
-        <img :src="iconSrc" alt="User Avatar" 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"> Upload Image</button>
+              src="../../assets/icons/download.svg"> Last opp bilde</button>
         </div>
       </div>
       <div class="form-group">
-        <BaseInput :model-value="firstNameRef" @input-change-event="handleFirstNameInputEvent" id="firstNameInputChange"
-          input-id="first-name-new" type="text" label="First name" placeholder="Enter your first name"
-          invalid-message="Please enter your first name" />
+        <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 :model-value="surnameRef" @input-change-event="handleSurnameInputEvent" id="surnameInput-change"
-          input-id="surname-new" type="text" label="Surname" placeholder="Enter your surname"
-          invalid-message="Please enter your surname" />
+        <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 type="submit" class="btn btn-primary">Update Profile</button>
+      <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>
 
+
 <style scoped>
 #icon {
   width: 90px;
@@ -138,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/views/Settings/SettingsSecurityView.vue b/src/components/Settings/SettingsSecurity.vue
similarity index 53%
rename from src/views/Settings/SettingsSecurityView.vue
rename to src/components/Settings/SettingsSecurity.vue
index db55bb062446fec0738188c2da1a1c74e3e145b3..8eab51063b9684504beea4d6e375a1c4b536e3a4 100644
--- a/src/views/Settings/SettingsSecurityView.vue
+++ b/src/components/Settings/SettingsSecurity.vue
@@ -1,35 +1,41 @@
 <template>
     <div class="tab-pane active" id="security">
-        <h6>SECURITY SETTINGS</h6>
+        <h6>SIKKERHETSINNSTILLINGER</h6>
         <hr>
         <form @submit.prevent="handleSubmit" novalidate>
             <div class="form-group">
-                <label class="d-block">Change Password</label>
-                <BaseInput :model-value="oldPasswordRef" @input-change-event="handleOldPasswordInputEvent"
+                <label class="d-block">Endre passord</label>
+                <BaseInput data-cy="old-password-input" :model-value="oldPasswordRef"
+                            @input-change-event="handleOldPasswordInputEvent"
                     id="passwordInput-change" input-id="password-old" type="password"
-                    pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}" label="Old Password" placeholder="Enter password"
-                    invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number" />
+                    pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}" label="Gammelt passord" placeholder="Skriv inn passord"
+                    invalid-message="Passordet må være mellom 4 og 16 tegn og inneholde en stor bokstav, en liten bokstav og et tall" />
 
-                <BaseInput :model-value="newPasswordRef" @input-change-event="handleNewPasswordInputEvent"
+                <BaseInput data-cy="new-password-input" :model-value="newPasswordRef"
+                            @input-change-event="handleNewPasswordInputEvent"
                     id="passwordInput-change" input-id="password-new" type="password"
-                    pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}" label="New Password" placeholder="Enter password"
-                    invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number" />
+                    pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}" label="Nytt passord" placeholder="Skriv inn passord"
+                    invalid-message="Passordet må være mellom 4 og 16 tegn og inneholde en stor bokstav, en liten bokstav og et tall" />
 
-                <BaseInput :model-value="confirmPasswordRef" @input-change-event="handleConfirmPasswordInputEvent"
+                <BaseInput data-cy="confirm-password-input" :model-value="confirmPasswordRef"
+                            @input-change-event="handleConfirmPasswordInputEvent"
                     id="passwordInput-change" input-id="password-confirm" type="password"
-                    pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}" label="Confirm New Password" placeholder="Enter password"
-                    invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number" />
+                    pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}" label="Bekreft nytt passord" placeholder="Skriv inn passord"
+                    invalid-message="Passordet må være mellom 4 og 16 tegn og inneholde en stor bokstav, en liten bokstav og et tall" />
             </div>
-            <button type="submit" class="btn btn-primary">Update Password</button>
-            <button type="reset" class="btn btn-light">Reset Changes</button>
+            <button data-cy="update-password-btn" type="submit" class="btn btn-primary">Oppdater
+              passord</button>
+            <button data-cy="reset-fields-btn" type="reset" class="btn btn-light">Tilbakestill
+              endringer</button>
         </form>
         <hr>
     </div>
 </template>
 
+
 <script setup lang="ts">
     import { ref } from 'vue'
-    import BaseInput from '@/components/InputFields/BaseInput.vue'
+    import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue'
     import { type PasswordUpdateDTO, UserService } from '@/api'
 
     const oldPasswordRef = ref('');
diff --git a/src/views/ShopView.vue b/src/components/Shop/ItemShop.vue
similarity index 60%
rename from src/views/ShopView.vue
rename to src/components/Shop/ItemShop.vue
index 20739f15d353a92c7e6e0cbf49b566d944617afb..15f17c636da19d0e18deb7e1f627027ff310a7ac 100644
--- a/src/views/ShopView.vue
+++ b/src/components/Shop/ItemShop.vue
@@ -1,22 +1,24 @@
 <template>
-    <br>
+    <div id="background">
+        <br>
     <div id="dropdownContainer">
-        <h1 class="box">Shop</h1>
+        <h1 class="box">Butikk</h1>
     </div>
-    <div class="container">
-        <div class="row">
+    <div class="container d-flex justify-content-center">
+        <div class="row col-md-10">
             <div class="col-md-12">
                 <h1>Stash</h1>
                 <div class="category row justify-content-between mb-5 m-2">
                     <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/adfree.png" class="card-img-top" alt="...">
+                        <img src="../../assets/items/adfree.png" class="card-img-top" alt="...">
                         <div class="card-body">
                             <h5 class="card-title">Adfree</h5>
-                            <button type="button" class="btn btn-primary" id="buttonStyle" @click="buyNoAds"> +35kr</button>
+                            <button type="button" class="btn btn-primary" id="buttonStyle" @click="buyNoAds">
+                                +35kr</button>
                         </div>
                     </div>
                     <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/piggybank.webp" class="card-img-top" alt="...">
+                        <img src="../../assets/items/piggybank.webp" class="card-img-top" alt="...">
                         <div class="card-body">
                             <h5 class="card-title">Premium</h5>
                             <button type="button" class="btn btn-primary" id="buttonStyle"
@@ -26,59 +28,40 @@
                 </div>
             </div>
             <div class="col-md-12">
-                <h1>Fantacy</h1>
+                <h1>Items</h1>
                 <div class="category row justify-content-between mb-5 m-2">
-                    <!--<div class="col-md-4" v-for="product in products" :key="product.id">-->
-                    <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/galaxy.jpg" class="card-img-top" alt="...">
-                        <div class="card-body">
-                            <h5 class="card-title">The panda</h5>
-                            <ShopButton button-text="100"></ShopButton>
-                        </div>
-                    </div>
-                    <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/galaxy.jpg" class="card-img-top" alt="...">
-                        <div class="card-body">
-                            <h5 class="card-title">The panda</h5>
-                            <ShopButton button-text="100"></ShopButton>
-                        </div>
-                    </div>
-                    <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/galaxy.jpg" class="card-img-top" alt="...">
+                    <div v-for="product in products" :key="product.id" class="card text-center"
+                        style="width: 16rem; border: none">
+                        <img :src="`http://localhost:8080/api/images/${product.imageId}`" class="card-img-top"
+                            alt="..." />
                         <div class="card-body">
-                            <h5 class="card-title">The panda</h5>
-                            <ShopButton button-text="100"></ShopButton>
+                            <h5 class="card-title">{{ product.itemName }}</h5>
+                            <ShopButton v-if="!product.alreadyBought" :button-text="product.price"
+                                @click="buyItem(product.id)"></ShopButton>
+                            <p v-else>Owned</p>
                         </div>
                     </div>
-                    <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/galaxy.jpg" class="card-img-top" alt="...">
-                        <div class="card-body">
-                            <h5 class="card-title">The panda</h5>
-                            <ShopButton button-text="100"></ShopButton>
-                        </div>
-                    </div>
-                    <!--</div>-->
                 </div>
             </div>
             <div class="col-md-12">
                 <h1>Stash</h1>
                 <div class="category row justify-content-between mb-5 m-2">
                     <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/coffee.jpg" class="card-img-top" alt="...">
+                        <img src="../../assets/items/coffee.jpg" class="card-img-top" alt="...">
                         <div class="card-body">
                             <h5 class="card-title">Free Coffee</h5>
                             <ShopButton button-text="500"></ShopButton>
                         </div>
                     </div>
                     <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/viaplay.jpg" class="card-img-top" alt="...">
+                        <img src="../../assets/items/viaplay.jpg" class="card-img-top" alt="...">
                         <div class="card-body">
                             <h5 class="card-title">1 Month Viaplay</h5>
                             <ShopButton button-text="10000"></ShopButton>
                         </div>
                     </div>
                     <div class="card text-center" style="width: 16rem; border: none">
-                        <img src="@/assets/items/pirbad.png" class="card-img-top" alt="...">
+                        <img src="../../assets/items/pirbad.png" class="card-img-top" alt="...">
                         <div class="card-body">
                             <h5 class="card-title">-10% rabatt</h5>
                             <ShopButton button-text="1000"></ShopButton>
@@ -89,13 +72,34 @@
 
         </div>
     </div>
+    </div>
 </template>
 
 <script setup lang="ts">
-import ShopButton from '@/components/Buttons/ShopButton.vue';
-import { ref } from 'vue';
+import ShopButton from '@/components/Shop/ShopButton.vue';
+import { ref, onMounted } from 'vue';
 import { UserService } from '@/api';
 import { useUserInfoStore } from '@/stores/UserStore';
+import { ItemService } from '@/api';
+
+const products = ref([] as any);
+
+const getStore = async () => {
+    const response = await ItemService.getStore();
+    products.value = response;
+    console.log(response);
+}
+
+const buyItem = async (itemId: number) => {
+    try {
+        const response = await ItemService.buyItem({ itemId: itemId });
+        console.log(response);
+        const responseStore = await ItemService.getStore();
+        products.value = responseStore;
+    } catch (error) {
+        console.log(error);
+    }
+}
 
 const buyPremium = async () => {
     try {
@@ -118,6 +122,10 @@ const buyNoAds = async () => {
         console.log(error);
     }
 }
+
+onMounted(() => {
+    getStore();
+})
 </script>
 
 <style scoped>
@@ -132,6 +140,10 @@ const buyNoAds = async () => {
 
 .box {
     width: 90%;
+    justify-content: center;
+    text-align: center;
+    font-size: 5rem;
+    font-weight: 700;
 }
 
 .card:hover {
@@ -150,6 +162,10 @@ const buyNoAds = async () => {
 #dropdownContainer {
     display: flex;
     justify-content: center;
+    align-items: center;
     margin-bottom: 2rem;
 }
+
+#background {
+}
 </style>
\ No newline at end of file
diff --git a/src/components/Buttons/ShopButton.vue b/src/components/Shop/ShopButton.vue
similarity index 72%
rename from src/components/Buttons/ShopButton.vue
rename to src/components/Shop/ShopButton.vue
index 38f1ee04a792d43376635cd70f93d86e998e236a..843eeb1530c696b3ae8aca05ab310aae54aaf057 100644
--- a/src/components/Buttons/ShopButton.vue
+++ b/src/components/Shop/ShopButton.vue
@@ -1,5 +1,5 @@
 <template>
-    <button type="button" class="btn btn-primary" id="buttonStyle"><img src="@/assets/items/pigcoin.png" style="width: 2rem"> +{{ buttonText }}</button>
+    <button type="button" class="btn btn-primary" id="buttonStyle"><img src="../../assets/items/pigcoin.png" style="width: 2rem"> +{{ buttonText }}</button>
 </template>
 
 <script setup lang="ts">
diff --git a/src/components/Buttons/__tests__/ShopButton.spec.ts b/src/components/Shop/__tests__/ShopButton.spec.ts
similarity index 92%
rename from src/components/Buttons/__tests__/ShopButton.spec.ts
rename to src/components/Shop/__tests__/ShopButton.spec.ts
index 25858cb46e529322a5da1386f31aab636bff64f9..277e3521fe84175524d94d0f10bfdf5b7da851c3 100644
--- a/src/components/Buttons/__tests__/ShopButton.spec.ts
+++ b/src/components/Shop/__tests__/ShopButton.spec.ts
@@ -1,6 +1,6 @@
 import { describe, it, expect } from 'vitest'
 import { mount } from '@vue/test-utils'
-import ImageButtonComponent from '@/components/Buttons/ShopButton.vue'
+import ImageButtonComponent from '../ShopButton.vue'
 
 describe('ImageButtonComponent', () => {
   it('renders the button with the correct text and image', () => {
diff --git a/src/components/SignUp/SignUp.vue b/src/components/SignUp/SignUp.vue
index eb272c6f1966c45c9d61045a1375fc8dcfb14981..b0c7d67db691ba0be33be137210b6f580786e9c5 100644
--- a/src/components/SignUp/SignUp.vue
+++ b/src/components/SignUp/SignUp.vue
@@ -1,10 +1,10 @@
 <script setup lang="ts">
-
 import SignUpForm from '@/components/SignUp/SignUpForm.vue'
 </script>
 
 <template>
   <div class="containers">
+    <h1 class="title">SpareSti</h1>
     <div class="box">
       <SignUpForm />
     </div>
@@ -13,18 +13,28 @@ import SignUpForm from '@/components/SignUp/SignUpForm.vue'
 
 <style scoped>
 .containers {
-  background-color: #A2CC99;
+  background: url('@/assets/wave.svg');
+  background-repeat: no-repeat;
+  background-size: cover;
   height: 100vh;
   display: flex;
   justify-content: center;
+  align-items: center;
+  flex-direction: column;
 }
 
 .box {
-  width: 450px;
-  margin: 2rem;
   background-color: white;
-  border-radius: 3rem;
-  padding: 1rem 4rem;
-  box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
+  border-radius: 1rem;
+  max-width: 750px;
+  padding: 0 3rem 1rem 3rem;
+  box-shadow: rgba(57, 57, 63, 0.5) 0px 1px 20px 0px;
+}
+
+.title {
+  font-size: 60px;
+  color: white;
+  margin-bottom: 40px;
+  font-weight: 700;
 }
 </style>
\ No newline at end of file
diff --git a/src/components/SignUp/SignUpForm.vue b/src/components/SignUp/SignUpForm.vue
index b0b04ad2309aeaa1c82d1d86e651838a98decc68..6cf987d5b0e174520dad61c1205ad76cdc6a51cd 100644
--- a/src/components/SignUp/SignUpForm.vue
+++ b/src/components/SignUp/SignUpForm.vue
@@ -1,6 +1,6 @@
 <script setup lang="ts">
-import BaseInput from '@/components/InputFields/BaseInput.vue'
-import Button1 from '@/components/Buttons/Button1.vue'
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
 import { ref } from 'vue'
 import { useRouter } from 'vue-router'
 import { AuthenticationService } from '@/api'
@@ -19,6 +19,7 @@ const confirmPasswordRef = ref('')
 const formRef = ref()
 let samePasswords = ref(true)
 let errorMsg = ref('');
+const isSubmitting = ref(false);
 
 const handleFirstNameInputEvent = (newValue: any) => {
   firstNameRef.value = newValue
@@ -41,6 +42,8 @@ const handleConfirmPasswordInputEvent = (newValue: any) => {
 }
 
 const handleSubmit = async () => {
+  if (isSubmitting.value) return;
+  isSubmitting.value = true;
 
   samePasswords.value = (passwordRef.value === confirmPasswordRef.value)
   formRef.value.classList.add("was-validated")
@@ -62,59 +65,71 @@ const handleSubmit = async () => {
       }
     }
   }
+  isSubmitting.value = false;
 }
 
 </script>
 
 <template>
-  <div class="container">
-    <img src="@/assets/Sparesti-logo.png" style="width: 120px">
+  <div class="container-fluid">
+    <div class="container-fluid d-flex justify-content-center align-items-center flex-column mt-5">
+      <h1>Registrer deg</h1>
+    </div>
     <form ref="formRef" id="signUpForm" @submit.prevent="handleSubmit" novalidate>
-      <BaseInput :model-value=firstNameRef
-                 @input-change-event="handleFirstNameInputEvent"
-                 id="firstNameInput"
-                 input-id="first-name"
-                 type="text"
-                 label="First name"
-                 placeholder="Enter your first name"
-                 invalid-message="Please enter your first name"/>
-      <BaseInput :model-value="surnameRef"
-                 @input-change-event="handleSurnameInputEvent"
-                 id="surnameInput"
-                 input-id="surname"
-                 type="text"
-                 label="Surname"
-                 placeholder="Enter your surname"
-                 invalid-message="Please enter your surname"/>
-      <BaseInput :model-value="emailRef"
-                 @input-change-event="handleEmailInputEvent"
-                 id="emailInput"
-                 input-id="email"
-                 type="email"
-                 label="Email"
-                 placeholder="Enter your email"
-                 invalid-message="Invalid email"/>
-      <BaseInput :model-value="passwordRef"
-                 @input-change-event="handlePasswordInputEvent"
-                 id="passwordInput"
-                 input-id="password"
-                 type="password"
-                 pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
-                 label="Password"
-                 placeholder="Enter password"
-                 invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number"/>
-      <BaseInput :modelValue="confirmPasswordRef"
-                 @input-change-event="handleConfirmPasswordInputEvent"
-                 id="confirmPasswordInput"
-                 input-id="confirmPassword"
-                 type="password"
-                 pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
-                 label="Confirm Password"
-                 placeholder="Confirm password"
-                 invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number"/>
+      <div class="row">
+        <div class="col-sm">
+          <BaseInput :model-value=firstNameRef
+                     @input-change-event="handleFirstNameInputEvent"
+                     id="firstNameInput"
+                     input-id="first-name"
+                     type="text"
+                     pattern="^[^\d]+$"
+                     label="Fornavn"
+                     placeholder="Skriv inn ditt fornavn"
+                     invalid-message="Ugyldig fornavn, husk ingen tall"/>
+          <BaseInput :model-value="surnameRef"
+                     @input-change-event="handleSurnameInputEvent"
+                     id="surnameInput"
+                     input-id="surname"
+                     type="text"
+                     pattern="^[^\d]+$"
+                     label="Etternavn"
+                     placeholder="Skriv inn ditt etternavn"
+                     invalid-message="Ugyldig etternavn, husk ingen tall"/>
+          <BaseInput :model-value="emailRef"
+                     @input-change-event="handleEmailInputEvent"
+                     id="emailInput"
+                     input-id="email"
+                     type="email"
+                     label="E-post"
+                     placeholder="Skriv inn din e-post"
+                     invalid-message="Ugyldig e-post"/>
+        </div>
+        <div class="col-sm">
+          <BaseInput :model-value="passwordRef"
+                     @input-change-event="handlePasswordInputEvent"
+                     id="passwordInput"
+                     input-id="password"
+                     type="password"
+                     pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
+                     label="Passord"
+                     placeholder="Skriv inn passord"
+                     invalid-message="Passordet må være mellom 4 og 16 tegn og inneholde én stor bokstav, liten bokstav og et tall"/>
+          <BaseInput :modelValue="confirmPasswordRef"
+                     @input-change-event="handleConfirmPasswordInputEvent"
+                     id="confirmPasswordInput"
+                     input-id="confirmPassword"
+                     type="password"
+                     pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}"
+                     label="Bekreft Passord"
+                     placeholder="Bekreft passord"
+                     invalid-message="Passordet må være mellom 4 og 16 tegn og inneholde én stor bokstav, liten bokstav og et tall"
+          />
+        </div>
+      </div>
       <p class="text-danger">{{ errorMsg }}</p>
-      <p v-if="!samePasswords" class="text-danger">The passwords are not identical</p>
-      <button1 id="confirmButton" @click="handleSubmit" button-text="Sign up"></button1>
+      <p v-if="!samePasswords" class="text-danger">Passordene er ikke like</p>
+      <BaseButton id="confirmButton" @click="handleSubmit" :disabled="isSubmitting" button-text="Registrer deg"></BaseButton>
       <LoginLink/>
     </form>
   </div>
@@ -123,12 +138,8 @@ const handleSubmit = async () => {
 
 <style scoped>
 
-.container {
-  max-width: 450px;
-  display: flex;
-  justify-content: center;
-  align-items: center; 
-  flex-direction: column;
+.container-fluid {
+  max-width: 950px;
 }
 
 #signUpForm {
@@ -141,4 +152,9 @@ const handleSubmit = async () => {
 #firstNameInput, #surnameInput, #emailInput, #passwordInput, #confirmButton, #confirmPasswordInput {
   margin: 1rem 0;
 }
+
+h1 {
+  font-size: 2rem;
+  font-weight: bold;
+}
 </style>
\ No newline at end of file
diff --git a/src/components/SignUp/SignUpLink.vue b/src/components/SignUp/SignUpLink.vue
index e16871208dcc1d42fd4dc7783587772215d8e1c9..c53f6914dca776f7784c420472a4126328dbb2c2 100644
--- a/src/components/SignUp/SignUpLink.vue
+++ b/src/components/SignUp/SignUpLink.vue
@@ -3,9 +3,12 @@
 </script>
 
 <template>
-  <p>Don't have an account? <RouterLink to="/sign-up" id="signup">Sign up</RouterLink></p>
+  <p id="signupText">Ingen bruker? <RouterLink to="/sign-up" id="signup">Registrer deg</RouterLink></p>
 </template>
 
 <style scoped>
-
+#signupText {
+  font-size: 14px;
+  padding: 5px;
+}
 </style>
\ No newline at end of file
diff --git a/src/components/SignUp/__tests__/SignUpForm.spec.ts b/src/components/SignUp/__tests__/SignUpForm.spec.ts
index f2a653c9ea854ba0bbe29de03949ed26c983d3cf..1d66d74cc37f9f922d88123a76052b2bed2337c6 100644
--- a/src/components/SignUp/__tests__/SignUpForm.spec.ts
+++ b/src/components/SignUp/__tests__/SignUpForm.spec.ts
@@ -39,9 +39,9 @@ describe('Menu and Router Tests', () => {
                 },
             });
 
-            expect(wrapper.text()).toContain('First name');
-            expect(wrapper.text()).toContain('Surname');
-            expect(wrapper.text()).toContain('Email');
+            expect(wrapper.text()).toContain('Fornavn');
+            expect(wrapper.text()).toContain('Etternavn');
+            expect(wrapper.text()).toContain('E-post');
         });
     });
 
@@ -71,10 +71,10 @@ describe('Menu and Router Tests', () => {
         it('updates user credentials correctly', async () => {
             const { getByPlaceholderText } = render(MyComponent);
 
-            const firstInput = getByPlaceholderText('Enter your first name') as HTMLInputElement;
-            const lastInput = getByPlaceholderText('Enter your surname') as HTMLInputElement;
-            const emailInput = getByPlaceholderText('Enter your email') as HTMLInputElement;
-            const passwordInput = getByPlaceholderText('Enter password') as HTMLInputElement;
+            const firstInput = getByPlaceholderText('Skriv inn ditt fornavn') as HTMLInputElement;
+            const lastInput = getByPlaceholderText('Skriv inn ditt etternavn') as HTMLInputElement;
+            const emailInput = getByPlaceholderText('Skriv inn din e-post') as HTMLInputElement;
+            const passwordInput = getByPlaceholderText('Skriv inn passord') as HTMLInputElement;
 
             await fireEvent.update(firstInput, 'Alice');
             await fireEvent.update(lastInput, 'Alicon');
@@ -96,7 +96,7 @@ describe('Menu and Router Tests', () => {
             });
 
             const errorMsg = container.querySelector('#invalid'); // Use the actual ID here
-            expect(errorMsg?.textContent === "Password must be between 4 and 16 characters and contain one capital letter, small letter and a number")
+            expect(errorMsg?.textContent === "Passordet må være mellom 4 og 16 tegn og inneholde én stor bokstav, liten bokstav og et tall")
         });
 
         it('logout should have empty store at application start', () => {
diff --git a/src/components/SignUp/__tests__/SignUpLink.spec.ts b/src/components/SignUp/__tests__/SignUpLink.spec.ts
index f63128392efb73a8754daf65a62f0b57a4e61108..50e0aa0e4017db44b2113380dcdceaa9c5ed5bca 100644
--- a/src/components/SignUp/__tests__/SignUpLink.spec.ts
+++ b/src/components/SignUp/__tests__/SignUpLink.spec.ts
@@ -41,7 +41,7 @@ describe('LoginPrompt', () => {
             },
         });
 
-        const loginLink = getByText('Sign up');
+        const loginLink = getByText('Registrer deg');
         expect(loginLink).toBeDefined(); // Check if the 'Login' link is rendered
     });
 
diff --git a/src/components/UpdateUserComponents/UpdateUserLayout.vue b/src/components/UpdateUserComponents/UpdateUserLayout.vue
deleted file mode 100644
index 7c9e81cd0b2dff2477e0de17e93ca12982b9155a..0000000000000000000000000000000000000000
--- a/src/components/UpdateUserComponents/UpdateUserLayout.vue
+++ /dev/null
@@ -1,325 +0,0 @@
-<script setup lang="ts">
-import BaseInput from "@/components/InputFields/BaseInput.vue";
-import { onMounted, ref } from "vue";
-import { AuthenticationService, LeaderboardService, UserService, type UserUpdateDTO } from "@/api";
-import { useUserInfoStore } from "@/stores/UserStore";
-
-const firstNameRef = ref()
-const surnameRef = ref('')
-const emailRef = ref('')
-const passwordRef = ref('')
-const confirmPasswordRef = ref('')
-const formRef = ref()
-let samePasswords = ref(true)
-
-async function setupForm() {
-  try {
-    let response = await UserService.getUser();
-    console.log(response.firstName)
-
-    firstNameRef.value = response.firstName;
-    if (response.lastName != null) {
-      surnameRef.value = response.lastName;
-    }
-    if (response.email != null) {
-      emailRef.value = response.email
-    }
-  } catch (err) {
-    console.error(err)
-  }
-}
-
-
-
-const handleFirstNameInputEvent = (newValue: any) => {
-  firstNameRef.value = newValue
-}
-
-
-const handleSurnameInputEvent = (newValue: any) => {
-  surnameRef.value = newValue
-}
-
-const handleEmailInputEvent = (newValue: any) => {
-  emailRef.value = newValue
-}
-
-const handlePasswordInputEvent = (newValue: any) => {
-  passwordRef.value = newValue
-}
-
-const handleConfirmPasswordInputEvent = (newValue: any) => {
-  confirmPasswordRef.value = newValue
-}
-
-const handleSubmit = async () => {
-
-  samePasswords.value = (passwordRef.value === confirmPasswordRef.value)
-  console.log(samePasswords.value)
-  formRef.value.classList.add("was-validated")
-  const form = formRef.value;
-
-  const updateUserPayload: UserUpdateDTO = {
-    firstName: firstNameRef.value,
-    lastName: surnameRef.value,
-    email: emailRef.value,
-  };
-
-
-
-
-
-  if (form.checkValidity()) {
-    if (samePasswords.value) {
-      try {
-        UserService.update({ requestBody: updateUserPayload })
-        useUserInfoStore().setUserInfo({
-          email: emailRef.value,
-          firstname: firstNameRef.value,
-          lastname: surnameRef.value,
-          password: passwordRef.value
-        })
-
-      } catch (err) {
-        console.error(err)
-      }
-    }
-  } else {
-    console.log('Form is not valid');
-  }
-
-}
-onMounted(() => {
-  setupForm()
-})
-
-
-
-</script>
-
-<template>
-  <div class="containers">
-    <div class="row gutters">
-      <div class="col-xl-3 col-lg-3 col-md-12 col-sm-12 col-12">
-        <div class="card h-100">
-          <div class="card-body">
-            <div class="account-settings">
-              <div class="user-profile">
-                <div class="user-avatar">
-                  <img src="https://bootdey.com/img/Content/avatar/avatar7.png" alt="Maxwell Admin">
-                </div>
-                <div class="text-center">
-                  <div class="mt-2">
-                    <span class="btn btn-primary"><img src="@/assets/icons/download.svg"></span>
-                  </div>
-                </div>
-                <br>
-                <h3 class="user-name">Yuki Hayashi</h3>
-                <h6 class="user-email">yuki@Maxwell.com</h6>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-      <div class="col-xl-9 col-lg-9 col-md-12 col-sm-12 col-12">
-        <div class="card h-100">
-          <div class="card-body">
-            <div class="row gutters">
-              <div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12">
-                <h6 class="mb-2 text-primary">Personal Details <img src="@/assets/icons/black_person.svg"></h6>
-              </div>
-              <div class="col-xl-6 col-lg-6 col-md-6 col-sm-6 col-12">
-                <div class="form-group">
-                  <BaseInput :model-value="firstNameRef" @input-change-event="handleFirstNameInputEvent"
-                    id="firstNameInputChange" input-id="first-name-new" type="text" label="First name"
-                    placeholder="Enter your first name" invalid-message="Please enter your first name" />
-                </div>
-              </div>
-              <div class="col-xl-6 col-lg-6 col-md-6 col-sm-6 col-12">
-                <div class="form-group">
-                  <BaseInput :model-value="surnameRef" @input-change-event="handleSurnameInputEvent"
-                    id="surnameInput-change" input-id="surname-new" type="text" label="Surname"
-                    placeholder="Enter your surname" invalid-message="Please enter your surname" />
-
-                </div>
-              </div>
-              <div class="col-xl-6 col-lg-6 col-md-6 col-sm-6 col-12">
-                <div class="form-group">
-                  <BaseInput :model-value="emailRef" @input-change-event="handleEmailInputEvent" id="emailInput-change"
-                    input-id="email-new" type="email" label="Email" placeholder="Enter your email"
-                    invalid-message="Invalid email" />
-
-                </div>
-              </div>
-              <div class="col-xl-6 col-lg-6 col-md-6 col-sm-6 col-12">
-                <div class="form-group">
-                  <BaseInput :model-value="passwordRef" @input-change-event="handlePasswordInputEvent"
-                    id="passwordInput-change" input-id="password-new" type="password"
-                    pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}" label="Password" placeholder="Enter password"
-                    invalid-message="Password must be between 4 and 16 characters and contain one capital letter, small letter and a number" />
-
-                </div>
-              </div>
-            </div>
-
-            <div class="row gutters">
-              <div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12" style="margin-top: 10px;">
-                <h6 class="mb-2 text-primary">Personal Configuration <img src="@/assets/icons/black_person.svg"></h6>
-              </div>
-              <div class="accordion" id="accordionExample">
-                <div class="accordion-item">
-                  <h2 class="accordion-header">
-                    <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
-                      data-bs-target="#collapseThree" aria-expanded="true" aria-controls="collapseThree">
-                      Configuration
-                    </button>
-                  </h2>
-                  <div id="collapseThree" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
-                    <div class="accordion-body">
-                      Hallo
-                    </div>
-                  </div>
-                </div>
-              </div>
-            </div>
-            <div class="row gutters">
-              <div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12">
-                <h6 class="mt-3 mb-2 text-primary">Styles <img src="@/assets/icons/black_paintBrush.svg"></h6>
-              </div>
-              <div class="accordion" id="accordionExample">
-                <div class="accordion-item">
-                  <h2 class="accordion-header">
-                    <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
-                      data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
-                      Profile pictures
-                    </button>
-                  </h2>
-                  <div id="collapseOne" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
-                    <div class="accordion-body">
-                      Hallo
-                    </div>
-                  </div>
-                </div>
-                <div class="accordion-item">
-                  <h2 class="accordion-header">
-                    <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
-                      data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
-                      Road styles
-                    </button>
-                  </h2>
-                  <div id="collapseTwo" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
-                    <div class="accordion-body">
-                      Hallo
-                    </div>
-                  </div>
-                </div>
-              </div>
-            </div>
-            <div class="row gutters">
-              <div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12">
-                <div class="text-right">
-                  <button type="button" id="submit" name="submit" class="btn btn-secondary">Cancel</button>
-                  <button type="button" id="submit" name="submit" class="btn btn-primary">Update</button>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-
-</template>
-
-<style scoped>
-body {
-  margin: 0;
-  padding-top: 40px;
-  color: #2e323c;
-  background: #f5f6fa;
-  position: relative;
-  height: 100%;
-}
-
-.row {
-  margin: 0px;
-}
-
-.containers {
-  width: 100%;
-  justify-content: center;
-  display: flex;
-  align-items: center;
-  margin-top: 2rem;
-  margin-bottom: 4rem;
-}
-
-.account-settings .user-profile {
-  margin: 0 0 1rem 0;
-  padding-bottom: 1rem;
-  text-align: center;
-}
-
-.account-settings .user-profile .user-avatar {
-  margin: 0 0 1rem 0;
-}
-
-.account-settings .user-profile .user-avatar img {
-  width: 90px;
-  height: 90px;
-  -webkit-border-radius: 100px;
-  -moz-border-radius: 100px;
-  border-radius: 100px;
-}
-
-.account-settings .user-profile h3.user-name {
-  margin: 0 0 0.5rem 0;
-}
-
-.account-settings .user-profile h6.user-email {
-  margin: 0;
-  font-size: 0.8rem;
-  font-weight: 400;
-  color: #9fa8b9;
-}
-
-.account-settings .about {
-  margin: 2rem 0 0 0;
-  text-align: center;
-}
-
-.account-settings .about h5 {
-  margin: 0 0 15px 0;
-  color: #007ae1;
-}
-
-.account-settings .about p {
-  font-size: 0.825rem;
-}
-
-.form-control {
-  border: 1px solid #cfd1d8;
-  -webkit-border-radius: 2px;
-  -moz-border-radius: 2px;
-  border-radius: 2px;
-  font-size: .825rem;
-  background: #ffffff;
-  color: #2e323c;
-}
-
-.text-right {
-  display: flex;
-  justify-content: flex-end;
-  margin-top: 10px;
-}
-
-.card {
-  background: #efefef;
-  -webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  border-radius: 5px;
-  border: 0;
-  margin-bottom: 1rem;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
-}
-</style>
\ No newline at end of file
diff --git a/src/components/UserProfile/UserProfileForeignLayout.vue b/src/components/UserProfile/ExternalProfile.vue
similarity index 87%
rename from src/components/UserProfile/UserProfileForeignLayout.vue
rename to src/components/UserProfile/ExternalProfile.vue
index df6ea8befbd76da3b997b92105fb51f64ce09029..bedcaba232b66c355b80fb1e9a323bcedb4cdf8d 100644
--- a/src/components/UserProfile/UserProfileForeignLayout.vue
+++ b/src/components/UserProfile/ExternalProfile.vue
@@ -2,17 +2,23 @@
 import {useRoute, useRouter} from "vue-router";
 
 import {onMounted, ref} from "vue";
-import {UserService, type ProfileDTO} from "@/api";
+import {UserService, type ProfileDTO, GoalService} from "@/api";
 
 let numberOfHistory = 6;
 
 let cardTitles = ["Spain tour", "Food waste", "Coffee", "Concert", "New book", "Pretty clothes"]
 
+
+let hasHistory = ref(true)
+let firstname = ref();
+let lastname = ref();
+
 let username = ref()
 
 let friend = ref(false)
 
-let profile: ProfileDTO;;
+let profile: ProfileDTO;
+
 
 const imageUrl = ref(`../src/assets/userprofile.png`);
 
@@ -49,12 +55,29 @@ onMounted(async () => {
   }
 })
 
-function addFriend(){
+function addFriend() {
   friend.value = true
   console.log("Added friend")
 
-  //todo Send POST to backend when endpoints is made and add friend
 }
+async function getGoals() {
+  let response = await GoalService.getGoals();
+  console.log("number of goals: ", response.length )
+  if(response.length > 0) {
+    hasHistory.value = true
+  }else{
+    hasHistory.value = false
+    console.log('No history')
+  }
+}
+
+
+
+// Function to navigate to update user settings
+
+
+  //todo Send POST to backend when endpoints is made and add friend
+
 
 function removeFriend(){
   friend.value = false
@@ -64,10 +87,10 @@ function removeFriend(){
 
 }
 
+onMounted(() =>{
+  getGoals()
+})
 
-function toUpdateUserSettings(){
-  route.push('/update-user')
-}
 </script>
 
 
@@ -78,15 +101,15 @@ function toUpdateUserSettings(){
         <div class="card">
           <div class="rounded-top text-white d-flex flex-row bg-primary" style="height:200px;">
             <div class="ms-4 mt-5 d-flex flex-column" style="width: 150px;">
-              <img :src="imageUrl" alt="Generic placeholder image"
+              <img :src="imageUrl" alt="Generisk plassholderbilde"
                    class="img-fluid img-thumbnail mt-4 mb-2" style="width: 150px; z-index: 1">
               <button v-if="!friend" type="button" data-mdb-button-init data-mdb-ripple-init class="btn btn-outline-primary"
                       data-mdb-ripple-color="dark" style="z-index: 1;" @click="addFriend">
-                Add Friend
+                Legg til venn
               </button>
               <button v-if="friend" type="button" data-mdb-button-init data-mdb-ripple-init class="btn btn-outline-danger"
                       data-mdb-ripple-color="dark" style="z-index: 1;" @click="removeFriend">
-                Remove Friend
+                Fjern venn
               </button>
             </div>
             <div class="ms-3" style="margin-top: 130px;">
@@ -97,7 +120,7 @@ function toUpdateUserSettings(){
             <div class="d-flex justify-content-end text-center py-1">
               <div>
                 <p class="mb-1 h2">253 <img src="@/assets/items/pigcoin.png" style="width: 4rem"></p>
-                <p class="small text-muted mb-0">Points</p>
+                <p class="small text-muted mb-0">Poeng</p>
               </div>
               <div class="px-3">
                 <p class="mb-1 h2">1026 <img src="@/assets/icons/fire.png" style="width: 4rem"></p>
@@ -109,7 +132,7 @@ function toUpdateUserSettings(){
             <div class="row">
               <div class="col">
                 <div class="container-fluid">
-                  <h1 class="mt-5 text-start badges-text">Badges</h1>
+                  <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">
@@ -148,10 +171,10 @@ function toUpdateUserSettings(){
             </div>
             <div class="row">
               <div class="col">
-                <!-- Here is the history of saving target -->
+                <!-- Her er historikken over lagrede mål -->
                 <div class="container-fluid mb-5">
-                  <h1 class="mt-5 text-start history-text">History</h1>
-                  <div class="row scrolling-wrapper-history">
+                  <h1 class="mt-5 text-start history-text">Historie</h1>
+                  <div v-if="hasHistory" 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">
                       <div class="card history-block">
@@ -164,8 +187,8 @@ function toUpdateUserSettings(){
                             <div class="col-md-8">
                               <div class="card-body">
                                 <h5 class="card-title">{{ cardTitles[index - 1] }}</h5>
-                                <p class="card-text">Money saved: 200 <br />You are one challenge: 21</p>
-                                <p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
+                                <p class="card-text">Penger spart: 200 <br />Du har fullført en utfordring: 21</p>
+                                <p class="card-text"><small class="text-muted">Sist oppdatert for 3 minutter siden</small></p>
                                 <a href="#" class="btn  stretched-link" @click="toRoadmap"></a>
                               </div>
                             </div>
@@ -174,6 +197,7 @@ function toUpdateUserSettings(){
                       </div>
                     </div>
                   </div>
+                  <div v-if="!hasHistory">No History!</div>
 
                 </div>
               </div>
@@ -185,6 +209,7 @@ function toUpdateUserSettings(){
   </div>
 </template>
 
+
 <style scoped>
 .scrolling-wrapper-badges {
   overflow-x: auto;
diff --git a/src/components/UserProfile/UserProfileLayout.vue b/src/components/UserProfile/MyProfile.vue
similarity index 54%
rename from src/components/UserProfile/UserProfileLayout.vue
rename to src/components/UserProfile/MyProfile.vue
index 174e1eb4af9799ca23c2bf382e371e47f587c69b..94dff55239f3f36761477410422065d4bd9c79c1 100644
--- a/src/components/UserProfile/UserProfileLayout.vue
+++ b/src/components/UserProfile/MyProfile.vue
@@ -2,20 +2,37 @@
 import { ref, onMounted } from "vue";
 import { useRouter } from "vue-router";
 import { useUserInfoStore } from "../../stores/UserStore";
-import {GoalService, UserService} from "@/api";
-
+import {UserService, BadgeService, GoalService} from "@/api";
+import { ItemService } from "@/api";
 
 let numberOfHistory = 6;
-
 let cardTitles = ["Spain tour", "Food waste", "Coffee", "Concert", "New book", "Pretty clothes"]
-
-
-let hasHistory = ref(true)
 let firstname = ref();
 let lastname = ref();
 const imageUrl = ref(`../src/assets/userprofile.png`);
 
+let hasHistory = ref(true)
+
 const router = useRouter();
+const inventory = ref([] as any);
+const badges = ref([] as any);
+const backgroundName = ref("");
+
+
+async function getGoals() {
+  let response = await GoalService.getGoals();
+  console.log("number of goals: ", response.length )
+  console.log('The id of a goal: ', response[0])
+  if(response.length > 0) {
+    hasHistory.value = true
+
+
+
+  }else{
+    hasHistory.value = false
+    console.log('No history')
+  }
+}
 
 async function setupForm() {
   try {
@@ -24,12 +41,41 @@ async function setupForm() {
 
     firstname.value = response.firstName;
     lastname.value = response.lastName;
-    imageUrl.value = "http://localhost:8080/api/images/" + response.profileImage;
+    if (response.profileImage) {
+      imageUrl.value = "http://localhost:8080/api/images/" + response.profileImage;
+    }
+    getInventory();
+    getBadges();
   } catch (err) {
     console.error(err)
   }
 }
 
+const getInventory = async () => {
+  try {
+    const response = await ItemService.getInventory();
+    inventory.value = response;
+  } catch (error) {
+    console.log(error);
+  }
+}
+
+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({
+    roadBackground: item.imageId,
+  })
+}
+
 onMounted(() => {
   setupForm()
 })
@@ -38,16 +84,6 @@ const toRoadmap = () => {
   router.push('/');
 };
 
-async function getGoals() {
-  let response = await GoalService.getGoals();
-  if(response.length > 0) {
-    hasHistory.value = true
-  }else{
-    hasHistory.value = false
-    console.log('No history')
-  }
-}
-
 
 
 // Function to navigate to update user settings
@@ -55,10 +91,11 @@ const toUpdateUserSettings = () => {
   router.push('/settings/profile');
 };
 
-onMounted(() =>{
+onMounted(()=>{
   getGoals()
 })
 
+
 </script>
 
 <template>
@@ -66,77 +103,82 @@ onMounted(() =>{
     <div class="row d-flex justify-content-center align-items-center h-100">
       <div class="col 12">
         <div class="card">
-          <div class="rounded-top text-white d-flex flex-row bg-primary" style="height:200px;">
-            <div class="ms-4 mt-5 d-flex flex-column" style="width: 150px;">
-              <img :src="imageUrl" alt="Generic placeholder image"
-                class="img-fluid img-thumbnail mt-4 mb-2" style="width: 150px; z-index: 1">
-              <button type="button" data-mdb-button-init data-mdb-ripple-init class="btn btn-outline-primary"
-                data-mdb-ripple-color="dark" style="z-index: 1;" id="toUpdate" @click="toUpdateUserSettings">
-                Edit profile
-              </button>
-            </div>
-            <div class="ms-3" style="margin-top: 130px;">
-              <h1>{{ firstname }} {{ lastname }}</h1>
+          <div class="rounded-top text-white d-flex flex-row bg-primary" style="height:200px;" id="banner">
+            <div class=" d-flex flex-column align-items-center justify-content-center">
+              <img :src="imageUrl" alt="Generisk plassholderbilde" class="img-fluid img-thumbnail"
+                style="width: 150px; height:150px; margin-left: 25px; margin-right: 15px;">
             </div>
+              <h1 data-cy="firstname" style="display: flex; align-items: end; margin-bottom: 20px;">{{ firstname }} {{ lastname }}</h1>
           </div>
-          <div class="p-4 text-black" style="background-color: #f8f9fa;">
+          <div class="p-3 text-black" style="background-color: #f8f9fa;">
             <div class="d-flex justify-content-end text-center py-1">
+              <div style="width: 100%; display: flex; justify-content: start">
+                <button  data-cy="toUpdate" type="button" data-mdb-button-init data-mdb-ripple-init class="btn btn-outline-primary"
+                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">253 <img src="@/assets/items/pigcoin.png" style="width: 4rem"></p>
-                <p class="small text-muted mb-0">Points</p>
+                <p class="mb-1 h2" data-cy="points">253 <img src="@/assets/items/pigcoin.png" style="width: 4rem"></p>
+                <p class="small text-muted mb-0">Poeng</p>
               </div>
               <div class="px-3">
-                <p class="mb-1 h2">1026 <img src="@/assets/icons/fire.png" style="width: 4rem"></p>
+                <p class="mb-1 h2" data-cy="streak">1026 <img src="@/assets/icons/fire.png" style="width: 4rem"></p>
                 <p class="small text-muted mb-0">Streak</p>
               </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">Badges</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>
+                  <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"
+                            alt="..." />
+                        <div class="card-body">
+                            <h5 class="card-title">{{ product.itemName }}</h5>
+                        </div>
                     </div>
-                    <div class="col-5">
-                      <div class="card badges-block card-10"></div>
+                  </div>
+                  <div v-if="backgroundName" class="text-success">You selected the background: <strong>{{ backgroundName }}!</strong></div>
+                </div>
+              </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-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">
-                <!-- Here is the history of saving target -->
+                <!-- Her er historikken over lagrede mål -->
                 <div class="container-fluid mb-5">
-                  <h1 class="mt-5 text-start history-text">History</h1>
+                  <h1 class="mt-1 text-start history-text">Historie</h1>
                   <div v-if="hasHistory" 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">
@@ -150,8 +192,9 @@ onMounted(() =>{
                             <div class="col-md-8">
                               <div class="card-body">
                                 <h5 class="card-title">{{ cardTitles[index - 1] }}</h5>
-                                <p class="card-text">Money saved: 200 <br />You are one challenge: 21</p>
-                                <p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
+                                <p class="card-text">Penger spart: 200 <br />Du har fullført en utfordring: 21</p>
+                                <p class="card-text"><small class="text-muted">Sist oppdatert for 3 minutter
+                                    siden</small></p>
                                 <a href="#" class="btn  stretched-link" @click="toRoadmap"></a>
                               </div>
                             </div>
@@ -160,7 +203,9 @@ onMounted(() =>{
                       </div>
                     </div>
                   </div>
-                  <div v-if="!hasHistory">No History!</div>
+                  <div v-if="!hasHistory">
+                    No History!
+                  </div>
 
                 </div>
               </div>
@@ -172,6 +217,7 @@ onMounted(() =>{
   </div>
 </template>
 
+
 <style scoped>
 .scrolling-wrapper-badges {
   overflow-x: auto;
@@ -182,8 +228,6 @@ onMounted(() =>{
   overflow: auto;
 }
 
-
-
 .badges-text {
   font-weight: 500;
   font-size: 2.0em;
@@ -228,6 +272,10 @@ onMounted(() =>{
   }
 }
 
+#banner {
+  background-image: url('../src/assets/banners/stacked.svg');
+}
+
 .card-1 {
   background-color: #4158D0;
   background-image: linear-gradient(43deg, #4158D0 0%, #C850C0 46%, #FFCC70 100%);
diff --git a/src/components/UserProfile/__tests__/UserProfileLayout.spec.ts b/src/components/UserProfile/__tests__/MyProfile.spec.ts
similarity index 93%
rename from src/components/UserProfile/__tests__/UserProfileLayout.spec.ts
rename to src/components/UserProfile/__tests__/MyProfile.spec.ts
index ea5ed5fc8478886407332d09c04ffdba7ccb9156..306f0f13d39a6864b6947b57e86362399e1c1003 100644
--- a/src/components/UserProfile/__tests__/UserProfileLayout.spec.ts
+++ b/src/components/UserProfile/__tests__/MyProfile.spec.ts
@@ -3,7 +3,7 @@ import { mount } from '@vue/test-utils';
 import { createRouter, createMemoryHistory } from 'vue-router';
 import { createPinia, setActivePinia } from 'pinia';
 import { useUserInfoStore } from '@/stores/UserStore';
-import MyComponent from '@/components/UserProfile/UserProfileLayout.vue'; // Adjust path as needed
+import MyComponent from '../MyProfile.vue'; // Adjust path as needed
 import router from '@/router/index'; // Adjust path as needed
 
 describe('MyComponent and Router Tests', () => {
@@ -36,7 +36,7 @@ describe('MyComponent and Router Tests', () => {
           plugins: [mockRouter],
         },
       });
-      expect(wrapper.text()).toContain('Edit profile');
+      expect(wrapper.text()).toContain('Rediger profil');
     });
   });
 
diff --git a/src/router/index.ts b/src/router/index.ts
index e82992ba2009ebf7dcaa334c872c94596cfa9618..9c15ed459254e04ad1d80d1421619fe622ccf8c8 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -1,12 +1,6 @@
 // Import necessary dependencies from Vue Router and your views
 import { createRouter, createWebHistory } from 'vue-router';
-import LoginView from '../views/Authentication/LoginView.vue';
 import { useUserInfoStore } from '@/stores/UserStore';
-import UserProfileView from "@/views/User/UserProfileView.vue";
-import SignUp from '@/components/SignUp/SignUp.vue'
-import UpdateUserView from "@/views/UpdateUser/UpdateUserView.vue";
-
-
 const routes = [
   {
     path: '/',
@@ -17,79 +11,69 @@ const routes = [
       {
         path: '',
         name: 'home',
-        component: () => import('../views/SavingGoalView/RoadmapView.vue'),
+        component: () => import('@/views/SavingGoal/RoadmapView.vue'),
       },
       {
         path: 'news',
         name: 'news',
-        component: () => import('@/views/NewsView.vue'),
+        component: () => import('@/views/News/NewsView.vue'),
       },
       {
         path: 'leaderboard',
         name: 'leaderboard',
-        component: () => import('@/views/LeaderboardView.vue'),
-      },
-      {
-        path: 'test',
-        name: 'test',
-        component: () => import('@/views/TestView.vue'),
+        component: () => import('@/views/Leaderboard/LeaderboardView.vue'),
       },
       {
         path: 'profile',
         name: 'profile',
-        component: UserProfileView
-      },
-      {
-        path: 'update-user',
-        name: 'update-user',
-        component: UpdateUserView
+        component: () => import('@/views/User/MyProfileView.vue'),
       },
       {
         path: '/settings',
         name: 'settings',
-        component: () => import('@/views/SettingsView.vue'),
+        component: () => import('@/views/User/UserSettingsView.vue'),
         children: [
           {
             path: '/settings/account',
             name: 'account',
-            component: () => import('@/views/Settings/SettingsAccountView.vue'),
+            component: () => import('@/components/Settings/SettingsAccount.vue'),
           },
           {
             path: '/settings/profile',
             name: 'profilesettings',
-            component: () => import('@/views/Settings/SettingsProfileView.vue'),
+            component: () => import('@/components/Settings/SettingsProfile.vue'),
           },
           {
             path: '/settings/security',
             name: 'security',
-            component: () => import('@/views/Settings/SettingsSecurityView.vue'),
+            component: () => import('@/components/Settings/SettingsSecurity.vue'),
           },
           {
             path: '/settings/notification',
             name: 'notification',
-            component: () => import('@/views/Settings/SettingsNotificationView.vue'),
+            component: () => import('@/components/Settings/SettingsNotification.vue'),
           },
           {
             path: '/settings/bank',
             name: 'bank',
-            component: () => import('@/views/Settings/SettingsBankView.vue'),
+            component: () => import('@/components/Settings/SettingsBank.vue'),
           },
         ]
       },
       {
         path: 'roadmap',
         name: 'roadmap',
-        component: () => import('@/views/SavingGoalView/RoadmapView.vue'),
+        component: () => import('@/views/SavingGoal/RoadmapView.vue'),
       },
       {
         path: 'feedback',
         name: 'feedback',
-        component: () => import('@/views/FeedbackView.vue'),
+        component: () => import('@/views/User/UserFeedbackView.vue'),
       },
       {
         path: 'shop',
         name: 'shop',
-        component: () => import('@/views/ShopView.vue'),
+        component: () => import('@/views/Shop/ShopView.vue'),
       },
       {
         path: '/budget-overview',
@@ -106,40 +90,29 @@ const routes = [
       {
         path: '/profile/:id',
         name: 'friend-profile',
-        component: () => import('@/views/User/UserProfileForeignView.vue'),
+        component: () => import('@/views/User/ExternalProfileView.vue'),
       },
       {
         path: 'friends',
         name: 'friends',
         component: () => import('@/views/User/UserFriendsView.vue'),
       },
-      {
-        path: 'add-friend',
-        name: 'add-friend',
-        component: () => import('@/views/User/UserAddFriend.vue'),
-      },
-      {
-        path: 'admin',
-        name: 'admin',
-        component: () => import('@/views/TestView.vue'),
-        meta: { requiresAdmin: true },
-      },
       {
         path: 'unauthorized',
         name: 'unauthorized',
-        component: () => import('@/views/UnauthorizedView.vue'),
+        component: () => import('@/views/Exception/UnauthorizedView.vue'),
       },
       {
         path: '/:pathMatch(.*)*',
         name: 'not-found',
-        component: () => import('@/views/NotFoundView.vue'),
+        component: () => import('@/views/Exception/NotFoundView.vue'),
       },
     ]
   },
   {
     path: '/login',
     name: 'login',
-    component: LoginView,
+    component: () => import('@/views/Authentication/LoginView.vue'),
   },
   {
     path: '/forgotten-password',
@@ -156,25 +129,30 @@ const routes = [
     name: 'sign up',
     component: () => import('@/views/Authentication/SignUpView.vue'),
   },
+  {
+    path: '/redirect',
+    name: 'redirect',
+    component: () => import('@/views/BankID/RedirectView.vue'),
+  },
   {
     path: '/configuration',
     name: 'configuration',
-    component: () => import('@/views/ConfigurationView.vue'),
+    component: () => import('@/views/Configuration/ConfigurationView.vue'),
     children: [
       {
-        path: '/bank-id',
-        name: 'bankId',
-        component: () => import('@/components/Configuration/ConfigurationSteps/BankId.vue'),
+        path: '/bank-account',
+        name: 'bank account',
+        component: () => import('@/components/Configuration/ConfigurationSteps/BankAccount.vue'),
       },
       {
         path: '/commitment',
         name: 'commitment',
-        component: () => import('@/components/Configuration/ConfigurationSteps/Commitment.vue'),
+        component: () => import('@/components/Configuration/ConfigurationSteps/ConfigurationCommitment.vue'),
       },
       {
         path: '/experience',
         name: 'experience',
-        component: () => import('@/components/Configuration/ConfigurationSteps/Experience.vue'),
+        component: () => import('@/components/Configuration/ConfigurationSteps/ConfigurationExperience.vue'),
       },
       {
         path: '/suitable-challenges',
@@ -184,7 +162,7 @@ const routes = [
       {
         path: '/first-saving-goal',
         name: 'first saving goal',
-        component: () => import('@/components/Configuration/ConfigurationSteps/FirstSavingGoal.vue'),
+        component: () => import('@/components/Configuration/ConfigurationSteps/ConfigurationSavingGoal.vue'),
       }
     ]
   },
diff --git a/src/stores/ConfigurationStore.ts b/src/stores/ConfigurationStore.ts
index 951538aeed7c0153539c46042e4e82a5099c8245..465edde65849684c603a94dc25225fe6f037743a 100644
--- a/src/stores/ConfigurationStore.ts
+++ b/src/stores/ConfigurationStore.ts
@@ -1,11 +1,19 @@
 import { defineStore } from 'pinia'
 export const useConfigurationStore = defineStore('ConfigurationStore', {
   state: () => ({
+    spendingAccount: 0,
+    savingsAccount: 0,
     commitment: '',
     experience: '',
     challenges: [] as Array<string>,
   }),
   actions: {
+    setSpendingAccount(newValue: number) {
+      this.spendingAccount = newValue;
+    },
+    setSavingsAccount(newValue: number) {
+      this.savingsAccount = newValue
+    },
     setCommitment(commitment: string) {
       this.commitment = commitment
     },
@@ -22,6 +30,12 @@ export const useConfigurationStore = defineStore('ConfigurationStore', {
     }
   },
   getters: {
+    getSpendingAccount(): number {
+      return this.spendingAccount
+    },
+    getSavingsAccount(): number {
+      return this.savingsAccount
+    },
     getCommitment(): string {
       return this.commitment
     },
diff --git a/src/stores/UserStore.ts b/src/stores/UserStore.ts
index 9c852dbcca932782cdcab4ace9c6816b7f762cf7..a3fd5a3d7f772fd3133e3e7b1f98332708a44ee9 100644
--- a/src/stores/UserStore.ts
+++ b/src/stores/UserStore.ts
@@ -37,6 +37,7 @@ export type UserStoreInfo = {
   accessToken?: string;
   role?: string;
   subscriptionLevel?: string;
+  roadBackground?: number;
   profileImage?: number;
 };
 
@@ -50,6 +51,7 @@ export const useUserInfoStore = defineStore('UserInfoStore', {
     accessToken: '',
     role: '',
     subscriptionLevel: '',
+    roadBackground: 0,
     profileImage: 0,
   }),
   persist: {
@@ -71,6 +73,7 @@ export const useUserInfoStore = defineStore('UserInfoStore', {
       userinfo.accessToken && (OpenAPI.TOKEN = this.$state.accessToken);
       userinfo.role && (this.$state.role = userinfo.role);
       userinfo.subscriptionLevel && (this.$state.subscriptionLevel = userinfo.subscriptionLevel);
+      userinfo.roadBackground && (this.$state.roadBackground = userinfo.roadBackground);
       userinfo.profileImage && (this.$state.profileImage = userinfo.profileImage);
     },
     clearUserInfo() {
@@ -81,6 +84,7 @@ export const useUserInfoStore = defineStore('UserInfoStore', {
       this.$state.accessToken = '';
       this.$state.role = '';
       this.$state.subscriptionLevel = '';
+      this.$state.roadBackground = 0;
       this.$state.profileImage = 0;
       OpenAPI.TOKEN = undefined;
     },
diff --git a/src/stores/counter.ts b/src/stores/counter.ts
deleted file mode 100644
index b6757ba5723c5b89b35d011b9558d025bbcde402..0000000000000000000000000000000000000000
--- a/src/stores/counter.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { ref, computed } from 'vue'
-import { defineStore } from 'pinia'
-
-export const useCounterStore = defineStore('counter', () => {
-  const count = ref(0)
-  const doubleCount = computed(() => count.value * 2)
-  function increment() {
-    count.value++
-  }
-
-  return { count, doubleCount, increment }
-})
diff --git a/src/views/Authentication/ChangePasswordView.vue b/src/views/Authentication/ChangePasswordView.vue
index 3a50f55927afd22b84dd12e331b83960865a409a..53414e404c66a69ff7662b9fa187492ee613f151 100644
--- a/src/views/Authentication/ChangePasswordView.vue
+++ b/src/views/Authentication/ChangePasswordView.vue
@@ -1,86 +1,7 @@
 <template>
-    <div class="containers">
-        <div class="row justify-content-center">
-            <div class="col-lg-5">
-                <div class="card shadow-lg border-0 rounded-lg mt-5">
-                    <div class="card-header">
-                        <h3 class="text-center font-weight-light my-4">Password Recovery</h3>
-                    </div>
-                    <div class="card-body">
-                        <div class="small mb-3 text-muted">Enter the new password for your account</div>
-                        <form @submit.prevent="submitForm">
-                            <div class="form-floating mb-3">
-                                <input v-model="newPassword" class="form-control" id="newPassword" type="password"
-                                    placeholder="New Password" required>
-                                <label for="newPassword">Enter your new password</label>
-                            </div>
-                            <div class="form-floating mb-3">
-                                <input v-model="confirmPassword" class="form-control" id="confirmPassword"
-                                    type="password" placeholder="Confirm Password" required>
-                                <label for="confirmPassword">Confirm your new password</label>
-                            </div>
-                            <div class="errorMsg">{{ errormsg }}</div>
-                            <div class="d-flex align-items-center justify-content-between mt-4 mb-0">
-                                <router-link to="/login" class="small">Return to login</router-link>
-                                <button class="btn btn-primary" type="submit">Confirm Password</button>
-                            </div>
-                        </form>
-                    </div>
-                    <div class="card-footer text-center py-3">
-                        <div class="small"><router-link to="/sign-up">Need an account? Sign up!</router-link></div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
+  <ChangePassword/>
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue';
-import { useRouter, useRoute } from 'vue-router';
-import axios from 'axios';
-import { UserService } from '@/api';
-
-const router = useRouter();
-const route = useRoute();
-
-const token = route.params.token;
-
-const newPassword = ref('');
-const confirmPassword = ref('');
-
-let errormsg = ref('');
-
-const submitForm = async () => {
-    if (newPassword.value !== confirmPassword.value) {
-        errormsg.value = 'The passwords do not match';
-        return;
-    }
-    errormsg.value = '';
-    try {
-        const resetPassword = {
-            password: newPassword.value,
-            token: token as string,
-        };
-        const response = await UserService.confirmPasswordReset({ requestBody: resetPassword });
-        console.log(response);
-        router.push('/login');
-    } catch (error) {
-        console.error('Error:', error);
-    }
-};
-
-</script>
-
-<style scoped>
-    .containers {
-        width: 100%;
-        background-color: #A2CC99;
-        height: 100vh;
-    }
-
-    .row {
-        margin-right: 0px;
-        margin-left: 0px;
-    }
-</style>
\ No newline at end of file
+import ChangePassword from '@/components/Login/ChangePassword.vue'
+</script>
\ No newline at end of file
diff --git a/src/views/Authentication/ForgottenPasswordView.vue b/src/views/Authentication/ForgottenPasswordView.vue
index 07501b6f6593a120c171fc99bc72a7bbf0bfe893..ef2cd9f18081b53d8943d238cb8ad6a827f27d1d 100644
--- a/src/views/Authentication/ForgottenPasswordView.vue
+++ b/src/views/Authentication/ForgottenPasswordView.vue
@@ -1,72 +1,7 @@
 <template>
-    <div class="containers">
-        <div class="row justify-content-center">
-            <div class="col-lg-5">
-                <div class="card shadow-lg border-0 rounded-lg mt-5">
-                    <div class="card-header">
-                        <h3 class="text-center font-weight-light my-4">Password Recovery</h3>
-                    </div>
-                    <div class="card-body">
-                        <div class="small mb-3 text-muted">Enter your email address and we will send you a link to reset
-                            your password.</div>
-                        <form @submit.prevent="submitForm">
-                            <div class="form-floating mb-3">
-                                <input v-model="email" class="form-control" id="inputEmail" type="email"
-                                    placeholder="name@example.com" required>
-                                <label for="inputEmail">Enter email address</label>
-                            </div>
-                            <div class="d-flex align-items-center justify-content-between mt-4 mb-0">
-                                <router-link to="/login" class="small">Return to login</router-link>
-                                <button class="btn btn-primary" type="submit">Reset Password</button>
-                            </div>
-                            <div class="text-success">
-                                {{ confirmationMessage }}
-                            </div>
-                        </form>
-                    </div>
-                    <div class="card-footer text-center py-3">
-                        <div class="small"><router-link to="/sign-up">Need an account? Sign up!</router-link></div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
+  <ForgottenPassword/>
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue';
-import { useRouter, useRoute } from 'vue-router';
-import axios from 'axios';
-import { UserService } from '@/api';
-
-const router = useRouter();
-
-const email = ref('');
-let confirmationMessage = ref('');
-
-const submitForm = async () => {
-    try {
-        const response = await UserService.resetPassword({
-            requestBody: email.value 
-        });
-        console.log('Success:', response.data);
-        confirmationMessage.value = 'An email has been sent to your email address with a link to reset your password.';
-    } catch (error) {
-        console.error('Error:', error);
-    }
-};
-
-</script>
-
-<style scoped>
-    .containers {
-        width: 100%;
-        background-color: #A2CC99;
-        height: 100vh;
-    }
-
-    .row {
-        margin-right: 0px;
-        margin-left: 0px;
-    }
-</style>
\ No newline at end of file
+import ForgottenPassword from '@/components/Login/ForgottenPassword.vue'
+</script>
\ No newline at end of file
diff --git a/src/views/Authentication/LoginView.vue b/src/views/Authentication/LoginView.vue
index 92ff4ea8f2288a9e61950c797add14dfd0e20ac7..8e98a1cec4e1285528b46c7b5aa96604d45ef030 100644
--- a/src/views/Authentication/LoginView.vue
+++ b/src/views/Authentication/LoginView.vue
@@ -1,13 +1,7 @@
-<script setup lang="ts">
-import Footer from '@/components/BaseComponents/Footer.vue'
-import Menu from '@/components/BaseComponents/Menu.vue'
-import Login from '@/components/Login/Login.vue'
-</script>
-
 <template>
   <Login/>
 </template>
 
-<style scoped>
-
-</style>
\ No newline at end of file
+<script setup lang="ts">
+import Login from '@/components/Login/LoginParent.vue'
+</script>
\ No newline at end of file
diff --git a/src/views/Authentication/SignUpView.vue b/src/views/Authentication/SignUpView.vue
index b6b2f2e951c3c776ae746a3779e73301bb6c6f48..7fdad6614a10dccd5b45a80c1786cfa928cd89f0 100644
--- a/src/views/Authentication/SignUpView.vue
+++ b/src/views/Authentication/SignUpView.vue
@@ -1,11 +1,7 @@
-<script setup lang="ts">
-import SignUp from '@/components/SignUp/SignUp.vue'
-</script>
-
 <template>
   <SignUp/>
 </template>
 
-<style scoped>
-
-</style>
\ No newline at end of file
+<script setup lang="ts">
+import SignUp from '@/components/SignUp/SignUp.vue'
+</script>
\ No newline at end of file
diff --git a/src/views/BankID/RedirectView.vue b/src/views/BankID/RedirectView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..93e690d2e9aef70d6f2fa374d997ee1cc5909309
--- /dev/null
+++ b/src/views/BankID/RedirectView.vue
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import { onMounted } from 'vue'
+import { type AuthenticationResponse, OpenAPI } from '@/api'
+import { useUserInfoStore } from '@/stores/UserStore'
+import axios from 'axios'
+import router from '@/router'
+
+onMounted(() => {
+  const query = new URLSearchParams(window.location.search);
+  const code = query.get('code');
+  const state = query.get('state');
+
+  if (code && state) {
+    exchangeCodeForToken(code, state);
+  } else {
+    console.error("Authorization code or state missing.");
+  }
+});
+
+async function exchangeCodeForToken(code: string, state: string) {
+  axios.post<AuthenticationResponse>('http://localhost:8080/api/auth/bank-id', { code: code, state: state })
+    .then(response => {
+      OpenAPI.TOKEN = response.data.token;
+      useUserInfoStore().setUserInfo({
+        accessToken: response.data.token,
+        role: response.data.role,
+        firstname: response.data.firstName,
+        lastname: response.data.lastName,
+      });
+      router.push({ name: 'home' });
+    })
+    .catch(error => {
+      console.error("Authentication error:", error);
+      router.push({ name: 'login' });
+    });
+}
+</script>
\ No newline at end of file
diff --git a/src/views/BasePageView.vue b/src/views/BasePageView.vue
index 312242fa196f91ac4a2def0a9c793f2b82b65c2c..4aebb55972d017af7c1469446acd9a9cb4ef8d61 100644
--- a/src/views/BasePageView.vue
+++ b/src/views/BasePageView.vue
@@ -1,8 +1,7 @@
 <script setup lang="ts">
 import { RouterView } from 'vue-router'
-import Footer from '@/components/BaseComponents/Footer.vue'
-import Menu from '@/components/BaseComponents/Menu.vue'
-import FooterAlternative from "@/components/BaseComponents/FooterAlternative.vue";
+import Footer from '@/components/BaseComponents/BaseFooter.vue'
+import Menu from '@/components/BaseComponents/NavBar.vue'
 import { useUserInfoStore } from '@/stores/UserStore';
 </script>
 
@@ -11,11 +10,17 @@ import { useUserInfoStore } from '@/stores/UserStore';
     <div v-if="!useUserInfoStore().isPremium && !useUserInfoStore().isNoAds" style="display: flex; flex-direction: row;">
       <img v-for="item in 7" src="@/assets/coca.webp" style="width: 100%; height: 100px; margin: 5px; border-radius: 1rem;" alt="picture">
     </div>
-    <div>
+    <div id="minHeight">
       <RouterView />
     </div>
    <div v-if="!useUserInfoStore().isPremium && !useUserInfoStore().isNoAds" style="display: flex; flex-direction: row;">
       <img v-for="item in 7" src="@/assets/coca.webp" style="width: 100%; height: 100px; margin: 5px; border-radius: 1rem;" alt="picture">
     </div>
-    <FooterAlternative></FooterAlternative>
-</template>
\ No newline at end of file
+  <Footer></Footer>
+</template>
+
+<style scoped>
+#minHeight {
+  min-height: 700px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/Budget/BudgetOverview.vue b/src/views/Budget/BudgetOverview.vue
index 3219b788013ccb0b54318572cab0401f8a259a84..1eea4fe5ce22bf6b5d7599b353f45612e6730409 100644
--- a/src/views/Budget/BudgetOverview.vue
+++ b/src/views/Budget/BudgetOverview.vue
@@ -1,10 +1,10 @@
 <script setup lang="ts">
-import Button1 from '@/components/Buttons/Button1.vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
 import BudgetBox from '@/components/Budget/BudgetBox.vue'
 import { onMounted, ref } from 'vue'
 import handleUnknownError from '@/components/Exceptions/unkownErrorHandler'
 import { useBudgetStore } from '@/stores/BudgetStore'
-import { type BudgetRequestDTO, type BudgetResponseDTO, UserService } from '@/api'
+import { type BudgetRequestDTO, type BudgetResponseDTO, BudgetService } from '@/api'
 import { useRouter } from 'vue-router'
 
 const router = useRouter();
@@ -23,7 +23,7 @@ let budgetListKey = ref(0);
  */
 onMounted(async () => {
   try {
-    budgetList.value = await UserService.getBudgetsByUser()
+    budgetList.value = await BudgetService.getBudgetsByUser()
     console.log(budgetList.value)
   } catch (error) {
     errorMsg.value = handleUnknownError(error);
@@ -42,7 +42,7 @@ const createNewBudget = async() => {
       expenseAmount: 0
     }
     // Creates new budget with the budget request body
-    await UserService.createBudget({requestBody: request})
+    await BudgetService.createBudget({requestBody: request})
     // Updates displayed budget list after creation
     await updateBudgetList()
   } catch (error) {
@@ -54,7 +54,7 @@ const createNewBudget = async() => {
  * Updates the displayed budget list.
  */
 const updateBudgetList = async () => {
-  budgetList.value = await UserService.getBudgetsByUser()
+  budgetList.value = await BudgetService.getBudgetsByUser()
   budgetListKey.value++
 }
 
@@ -71,20 +71,17 @@ const goToBudget = (id: number) => {
 
 <template>
   <div class="container">
-    <h1 class="text-center">Your Budgets</h1>
-    <button1 id="createBudgetButton" button-text="Create new budget" class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample"/>
-
+    <h1 class="text-center">Dine Budsjetter</h1>
+    <BaseButton id="createBudgetButton" button-text="Opprett nytt budsjett" class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample"/>
     <div class="collapse" id="collapseExample">
       <div class="container collapse-container">
         <div class="input-group">
-          <input id="collapseInput" class="form-control" type="text" placeholder="Enter name of budget" v-model="budgetNameInput">
-          <button1 id="collapseButton" button-text="Create" data-bs-dismiss="modal" @click="createNewBudget"/>
+          <input id="collapseInput" class="form-control" type="text" placeholder="Skriv inn navn på budsjettet" v-model="budgetNameInput">
+          <BaseButton id="collapseButton" button-text="Opprett" data-bs-dismiss="modal" @click="createNewBudget"/>
         </div>
       </div>
     </div>
-
     <p class="text-danger">{{ errorMsg }}</p>
-
     <ul class="budgetContainer" :key="budgetListKey">
       <li v-for="(item, index) in budgetList">
         <budget-box
@@ -99,11 +96,10 @@ const goToBudget = (id: number) => {
         ></budget-box>
       </li>
     </ul>
-
-    <nav id="navbar" aria-label="Page navigation example">
+    <nav id="navbar" aria-label="Sidenavigasjon eksempel">
       <ul class="pagination">
         <li class="page-item">
-          <a class="page-link" href="#" aria-label="Previous">
+          <a class="page-link" href="#" aria-label="Forrige">
             <span aria-hidden="true">&laquo;</span>
           </a>
         </li>
@@ -111,17 +107,16 @@ const goToBudget = (id: number) => {
         <li class="page-item"><a class="page-link" href="#">2</a></li>
         <li class="page-item"><a class="page-link" href="#">3</a></li>
         <li class="page-item">
-          <a class="page-link" href="#" aria-label="Next">
+          <a class="page-link" href="#" aria-label="Neste">
             <span aria-hidden="true">&raquo;</span>
           </a>
         </li>
       </ul>
     </nav>
-
   </div>
-
 </template>
 
+
 <style scoped>
 .collapse-container {
   align-content: center;
diff --git a/src/views/Budget/BudgetView.vue b/src/views/Budget/BudgetView.vue
index 7e4f8c44641ff0601a876c9788144815c7604178..e06214ebd9bccb12b5370a936974462a7901ceab 100644
--- a/src/views/Budget/BudgetView.vue
+++ b/src/views/Budget/BudgetView.vue
@@ -1,11 +1,10 @@
 <script setup lang="ts">
 import { onMounted, ref } from 'vue'
-import Button1 from '@/components/Buttons/Button1.vue'
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
 import ExpenseBox from '@/components/Budget/ExpenseBox.vue'
 import { useRouter } from 'vue-router'
 import { useBudgetStore } from '@/stores/BudgetStore'
-import type { BudgetResponseDTO, ExpenseRequestDTO, ExpenseResponseDTO } from '@/api'
-import { UserService } from '@/api'
+import { type BudgetResponseDTO, BudgetService, type ExpenseRequestDTO, type ExpenseResponseDTO } from '@/api'
 import handleUnknownError from '@/components/Exceptions/unkownErrorHandler'
 import ConfirmDeleteModal from '@/components/Budget/Modal/ConfirmDeleteModal.vue'
 import ImportBudgetModal from '@/components/Budget/Modal/ImportBudgetModal.vue'
@@ -43,7 +42,7 @@ onMounted(async () => {
     await updateExpenses();
     await updateBalance();
     // Gets budgets which can be imported
-    budgetDTOList.value = await UserService.getBudgetsByUser();
+    budgetDTOList.value = await BudgetService.getBudgetsByUser();
     budgetDTOList.value = budgetDTOList.value.filter(item => item.id !== useBudgetStore().getActiveBudgetId);
   } catch (error) {
     errorMsg.value = handleUnknownError(error);
@@ -56,7 +55,7 @@ onMounted(async () => {
  * budget amount, and expense amount accordingly.
  */
 const updateHeader = async () => {
-  const budgetResponse: BudgetResponseDTO = await UserService.getBudget({budgetId: useBudgetStore().getActiveBudgetId});
+  const budgetResponse: BudgetResponseDTO = await BudgetService.getBudget({budgetId: useBudgetStore().getActiveBudgetId});
   if (budgetResponse.budgetName != null) {
     title.value = budgetResponse.budgetName;
   }
@@ -73,7 +72,7 @@ const updateHeader = async () => {
  * Fetches the expenses associated with the active budget using the UserService.
  */
 const updateExpenses = async () => {
-  expenseDTOList.value = await UserService.getExpenses({budgetId: useBudgetStore().getActiveBudgetId});
+  expenseDTOList.value = await BudgetService.getExpenses({budgetId: useBudgetStore().getActiveBudgetId});
   // Resets expenses and then re-calculates it
   expenses.value = 0;
   for (let expenseDTO of expenseDTOList.value) {
@@ -113,7 +112,7 @@ const updateBudget = async (newBudget: number, newBudgetName: string) => {
       expenseAmount: expenses.value
     }
     // Send request to update budget information
-    await UserService.updateBudget({budgetId: useBudgetStore().getActiveBudgetId, requestBody: request})
+    await BudgetService.updateBudget({budgetId: useBudgetStore().getActiveBudgetId, requestBody: request})
   } catch (error) {
     errorMsg.value = handleUnknownError(error)
   }
@@ -135,7 +134,7 @@ const addNewExpense = async (expenseDescription: string, expenseValue: number) =
       amount: expenseValue
     }
     // Send request to update expense information
-    await UserService.updateExpense({budgetId: useBudgetStore().getActiveBudgetId, requestBody: request});
+    await BudgetService.updateExpense({budgetId: useBudgetStore().getActiveBudgetId, requestBody: request});
     // Trigger updates of expenses and balance and budget
     await updateExpenses();
     await updateBudget(budget.value, title.value)
@@ -154,7 +153,7 @@ const addNewExpense = async (expenseDescription: string, expenseValue: number) =
  */
 const deleteExpense = async (id: number) => {
   try {
-    await UserService.deleteExpense({expenseId: id});
+    await BudgetService.deleteExpense({expenseId: id});
     await updateExpenses();
     await updateBudget(budget.value, title.value)
     await updateBalance();
@@ -181,7 +180,7 @@ const editExpense = async (id: number, newDescription: string, newAmount: number
       amount: newAmount
     }
     // Send request to update the expense using the UserService
-    await UserService.updateExpense({budgetId: useBudgetStore().getActiveBudgetId, requestBody: request});
+    await BudgetService.updateExpense({budgetId: useBudgetStore().getActiveBudgetId, requestBody: request});
     await updateExpenses();
     await updateBudget(budget.value, title.value)
     await updateBalance();
@@ -198,18 +197,18 @@ const editExpense = async (id: number, newDescription: string, newAmount: number
 const importBudget = async (budgetId: number) => {
   try {
     // Update current budget value from the imported budget
-    const budgetResponse: BudgetResponseDTO = await UserService.getBudget({budgetId: budgetId});
+    const budgetResponse: BudgetResponseDTO = await BudgetService.getBudget({budgetId: budgetId});
     if (budgetResponse.budgetAmount != null) {
       budget.value += budgetResponse.budgetAmount;
     }
     // Get all the expenses from imported budget, and copy them to current budget
-    const expenses: ExpenseResponseDTO[] = await UserService.getExpenses({budgetId: budgetId})
+    const expenses: ExpenseResponseDTO[] = await BudgetService.getExpenses({budgetId: budgetId})
     for (let expense of expenses) {
       const expenseRequest: ExpenseRequestDTO = {
         description: expense.description,
         amount: Number(expense.amount) || 0
       }
-      await UserService.updateExpense({budgetId: useBudgetStore().getActiveBudgetId, requestBody: expenseRequest});
+      await BudgetService.updateExpense({budgetId: useBudgetStore().getActiveBudgetId, requestBody: expenseRequest});
     }
     // Update display and budget
     await updateExpenses();
@@ -226,8 +225,8 @@ const importBudget = async (budgetId: number) => {
     <h1 class="text-center">{{ title }}</h1>
 
     <div class="button-container">
-      <button1 id="goBack" @click="router.push('/budget-overview')" button-text="Go back"/>
-      <button1 id="optionButton" button-text="Options" data-bs-toggle="modal" data-bs-target="#modal"/>
+      <BaseButton id="goBack" @click="router.push('/budsjett-oversikt')" button-text="Gå tilbake"/>
+      <BaseButton id="optionButton" button-text="Alternativer" data-bs-toggle="modal" data-bs-target="#modal"/>
     </div>
 
     <p class="text-danger">{{ errorMsg }}</p>
@@ -236,23 +235,23 @@ const importBudget = async (budgetId: number) => {
       <div class="modal-dialog">
         <div class="modal-content">
           <div class="modal-header">
-            <h3>Options</h3>
+            <h3>Alternativer</h3>
             <button class="btn btn-close" data-bs-dismiss="modal"></button>
           </div>
           <div class="modal-body">
-            <button id="importButton" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#import-modal"><img src="../../assets/icons/import.svg" height="20" width="20" alt="picture">Import budget</button>
-            <button id="editBudget" class="btn btn-primary" data-bs-toggle="collapse" data-bs-target="#editBudgetCollapse" aria-expanded="false" aria-controls="editBudgetCollapse"><img src="../../assets/icons/edit-button.svg" alt="editButton">Rename budget</button>
+            <button id="importButton" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#import-modal"><img src="../../assets/icons/import.svg" height="20" width="20" alt="bilde">Importer budsjett</button>
+            <button id="editBudget" class="btn btn-primary" data-bs-toggle="collapse" data-bs-target="#editBudgetCollapse" aria-expanded="false" aria-controls="editBudgetCollapse"><img src="../../assets/icons/edit-button.svg" alt="redigerKnapp">Endre navn på budsjett</button>
             <div class="collapse" id="editBudgetCollapse">
               <div class="container collapse-container">
                 <form ref="renameFormRef" @submit.prevent="updateBudget(budget, budgetTitle)">
                   <div class="input-group">
-                    <input id="collapseInput" class="col-5 form-control" type="text" required minlength="1" placeholder="Enter new name of budget" v-model="budgetTitle">
-                    <button1 id="collapseButton" type="submit" button-text="Confirm" data-bs-dismiss="modal"/>
+                    <input id="collapseInput" class="col-5 form-control" type="text" required minlength="1" placeholder="Skriv inn nytt navn på budsjettet" v-model="budgetTitle">
+                    <BaseButton id="collapseButton" type="submit" button-text="Bekreft" data-bs-dismiss="modal"/>
                   </div>
                 </form>
               </div>
             </div>
-            <button id="deleteButton" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#confirm-modal"><img src="../../assets/icons/trash-can.svg" height="20" width="20" alt="picture">Delete budget</button>
+            <button id="deleteButton" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#confirm-modal"><img src="../../assets/icons/trash-can.svg" height="20" width="20" alt="bilde">Slett budsjett</button>
           </div>
         </div>
       </div>
@@ -261,7 +260,7 @@ const importBudget = async (budgetId: number) => {
     <confirm-delete-modal :budget-id="useBudgetStore().getActiveBudgetId"
                           modal-id="confirm-modal"
                           :budgetTitle="title"
-                          @deletedEvent="router.push('/budget-overview')"/>
+                          @deletedEvent="router.push('/budsjett-oversikt')"/>
 
     <import-budget-modal modal-id="import-modal"
                          :listOfBudgetResponseDTO="budgetDTOList"
@@ -269,26 +268,26 @@ const importBudget = async (budgetId: number) => {
 
     <div class="budget-info-container">
       <div class="info budget-container">
-        <i><img src="../../assets/icons/money2.svg" width="48px" height="48px" alt="picture"></i>
+        <i><img src="../../assets/icons/money2.svg" width="48px" height="48px" alt="bilde"></i>
         <div class="budget-text-container">
           <h5>{{budget}} kr</h5>
-          <p>Budget</p>
+          <p>Budsjett</p>
         </div>
       </div>
 
       <div class="info expenses-container">
-        <i><img src="../../assets/icons/credit-card.svg" width="48px" height="48px" alt="picture"></i>
+        <i><img src="../../assets/icons/credit-card.svg" width="48px" height="48px" alt="bilde"></i>
         <div class="expenses-text-container">
           <h5>{{expenses}} kr</h5>
-          <p>Expenses</p>
+          <p>Utgifter</p>
         </div>
       </div>
 
       <div class="info balance-container">
-        <i ref="iRef"><img src="../../assets/icons/scale.svg" width="48px" height="48px" alt="picture"></i>
+        <i ref="iRef"><img src="../../assets/icons/scale.svg" width="48px" height="48px" alt="bilde"></i>
         <div class="balance-text-container">
           <h5>{{balance}} kr</h5>
-          <p>Balance</p>
+          <p>Balanse</p>
         </div>
       </div>
     </div>
@@ -297,24 +296,24 @@ const importBudget = async (budgetId: number) => {
     <div class="budget-content-container">
       <form class="budget-from" @submit.prevent="updateBudget(budgetValue, title)">
         <div class="input-group">
-          <span class="input-group-text">Your budget </span>
-          <input type="text" class="form-control" placeholder="Enter your budget" required v-model="budgetValue">
-          <button type="submit" class="btn btn-primary">Calculate</button>
+          <span class="input-group-text">Ditt budsjett </span>
+          <input type="text" class="form-control" placeholder="Skriv inn ditt budsjett" required v-model="budgetValue">
+          <button type="submit" class="btn btn-primary">Beregn</button>
         </div>
       </form>
 
       <form class="expenses-form" @submit.prevent="addNewExpense(expenseDescription, expenseAmount)">
         <div class="input-group">
-          <span class="input-group-text">Add new expense </span>
-          <input type="text" class="form-control" placeholder="Name of expense" required v-model="expenseDescription">
-          <input type="number" min="0" class="form-control" placeholder="Amount (kr)" required v-model="expenseAmount">
-          <button type="submit" class="btn btn-primary">Calculate</button>
+          <span class="input-group-text">Legg til ny utgift </span>
+          <input type="text" class="form-control" placeholder="Navn på utgift" required v-model="expenseDescription">
+          <input type="number" min="0" class="form-control" placeholder="Beløp (kr)" required v-model="expenseAmount">
+          <button type="submit" class="btn btn-primary">Beregn</button>
         </div>
       </form>
     </div>
 
     <div v-if="expenseDTOList.length != 0" class="expenses-details-container">
-      <h3>Expenses details</h3>
+      <h3>Utgiftsdetaljer</h3>
       <div class="expense-box-container">
         <expense-box v-for="(expenseDTO, index) in expenseDTOList"
                      :id="Number(expenseDTO.expenseId) || 0"
@@ -330,6 +329,7 @@ const importBudget = async (budgetId: number) => {
   </div>
 </template>
 
+
 <style scoped>
 
 .button-container {
diff --git a/src/views/ConfigurationView.vue b/src/views/Configuration/ConfigurationView.vue
similarity index 90%
rename from src/views/ConfigurationView.vue
rename to src/views/Configuration/ConfigurationView.vue
index 2c375e5d6c494d84822eb53e84684aba09572356..426224bfc413d2c59ac8443f701771ed77889022 100644
--- a/src/views/ConfigurationView.vue
+++ b/src/views/Configuration/ConfigurationView.vue
@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import Configuration from '@/components/Configuration/Configuration.vue'
+import Configuration from '@/components/Configuration/ConfigurationParent.vue'
 </script>
 
 <template>
diff --git a/src/views/Exception/NotFoundView.vue b/src/views/Exception/NotFoundView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d86aab5d9cc9a72056091020e461f416b11639f6
--- /dev/null
+++ b/src/views/Exception/NotFoundView.vue
@@ -0,0 +1,7 @@
+<template>
+    <NotFoundPage/>
+</template>
+
+<script setup lang="ts">
+    import NotFoundPage from '@/components/Exceptions/NotFoundPage.vue';
+</script>
\ No newline at end of file
diff --git a/src/views/Exception/UnauthorizedView.vue b/src/views/Exception/UnauthorizedView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..412c8d2319480ed0c12661441cd85db78f8e8f75
--- /dev/null
+++ b/src/views/Exception/UnauthorizedView.vue
@@ -0,0 +1,7 @@
+<template>
+    <UnauthorizedPage/>
+</template>
+
+<script setup lang="ts">
+    import UnauthorizedPage from '@/components/Exceptions/UnauthorizedPage.vue';
+</script>
\ No newline at end of file
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
deleted file mode 100644
index 70c5e6456e7f882ebbea3fa1476b4cae2fb52aa2..0000000000000000000000000000000000000000
--- a/src/views/HomeView.vue
+++ /dev/null
@@ -1,9 +0,0 @@
-<script setup lang="ts">
-
-</script>
-
-<template>
-  <RouterLink to="login">Login</RouterLink>
-  <br/>
-  <RouterLink to="sign-up">Sign up</RouterLink>
-</template>
diff --git a/src/views/Leaderboard/LeaderboardView.vue b/src/views/Leaderboard/LeaderboardView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a57d059cbe3584e5192bc907c0cf2ed614331782
--- /dev/null
+++ b/src/views/Leaderboard/LeaderboardView.vue
@@ -0,0 +1,7 @@
+<template>
+    <ItemShop/>
+</template>
+
+<script setup lang="ts">
+    import ItemShop from '@/components/Leaderboard/LeaderboardRank.vue';
+</script>
\ No newline at end of file
diff --git a/src/views/NewsView.vue b/src/views/News/NewsView.vue
similarity index 55%
rename from src/views/NewsView.vue
rename to src/views/News/NewsView.vue
index bdfb7c611f43f0301e460f56b150a97213393a9d..2c309f722ba054b6b188401b997631ab6673bb94 100644
--- a/src/views/NewsView.vue
+++ b/src/views/News/NewsView.vue
@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import NewsComponent from "@/components/NewsComponents/NewsComponent.vue";
+import NewsComponent from "@/components/News/NewsFeed.vue";
 </script>
 
 
diff --git a/src/views/SavingGoalView/RoadmapView.vue b/src/views/SavingGoal/RoadmapView.vue
similarity index 53%
rename from src/views/SavingGoalView/RoadmapView.vue
rename to src/views/SavingGoal/RoadmapView.vue
index cdf655318efd24b40aab9b9e8fa1b82c3d30d3df..67921dc5416487704834d0f84c5cbe07cbf0eebd 100644
--- a/src/views/SavingGoalView/RoadmapView.vue
+++ b/src/views/SavingGoal/RoadmapView.vue
@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import SavingGoal from "@/components/SavingGoalComponents/SavingGoal.vue";
+import SavingGoal from "@/components/SavingGoal/SavingGoal.vue";
 </script>
 
 <template>
diff --git a/src/views/Settings/SettingsAccountView.vue b/src/views/Settings/SettingsAccountView.vue
deleted file mode 100644
index 82de6a01832d7a05c48da68eabf3b71dd0e8b313..0000000000000000000000000000000000000000
--- a/src/views/Settings/SettingsAccountView.vue
+++ /dev/null
@@ -1,75 +0,0 @@
-<script setup lang="ts">
-import { ref, onMounted } from 'vue';
-import BaseInput from '@/components/InputFields/BaseInput.vue';
-import { useUserInfoStore } from "@/stores/UserStore";
-import { UserService } from '@/api';
-import type { UserUpdateDTO } from '@/api';
-
-const emailRef = ref('')
-const errorMsg = ref('')
-const confirmationMsg = ref('')
-
-const handleEmailInputEvent = (newValue: any) => {
-  emailRef.value = newValue
-}
-
-async function setupForm() {
-  try {
-    let response = await UserService.getUser();
-    if (response.email != null) {
-      emailRef.value = response.email
-    }
-    confirmationMsg.value = '';
-    errorMsg.value = '';
-  } catch (err) {
-    errorMsg.value = 'Error fetching email, try again!'
-    confirmationMsg.value = ''
-  }
-}
-
-const handleSubmit = async () => {
-  console.log('Yoooo')
-  const updateUserPayload: UserUpdateDTO = {
-    email: emailRef.value,
-  };
-  try {
-    UserService.update({ requestBody: updateUserPayload })
-    useUserInfoStore().setUserInfo({
-        email: emailRef.value,
-    })
-    confirmationMsg.value = 'Email updated successfully!'
-    errorMsg.value = '';
-  } catch (err) {
-    errorMsg.value = "Error updating email, try again!";
-    confirmationMsg.value = ''
-  }
-}
-onMounted(() => {
-  setupForm()
-})
-</script>
-
-<template>
-    <div class="tab-pane active" id="account">
-        <h6>ACCOUNT SETTINGS</h6>
-        <hr>
-        <form  @submit.prevent="handleSubmit">
-            <div class="form-group">
-                <BaseInput :model-value="emailRef" @input-change-event="handleEmailInputEvent" id="emailInput-change"
-                    input-id="email-new" type="email" label="Email" placeholder="Enter your email"
-                    invalid-message="Invalid email"/>
-            </div>
-            <p class="text-danger">{{ errorMsg }}</p>
-            <p class="text-success">{{ confirmationMsg }}</p>
-            <br>
-            <button type="submit" class="btn btn-primary">Update Profile</button>
-            <hr>
-            <div class="form-group">
-                <label class="d-block text-danger">Delete Account</label>
-                <p class="text-muted font-size-sm">Once you delete your account, there is no going
-                    back. Please be certain.</p>
-            </div>
-            <button class="btn btn-danger" type="button">Delete Account</button>
-        </form>
-    </div>
-</template>
\ No newline at end of file
diff --git a/src/views/Shop/ShopView.vue b/src/views/Shop/ShopView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..667f6802ec2e019af1144e975e9924c542dd3c61
--- /dev/null
+++ b/src/views/Shop/ShopView.vue
@@ -0,0 +1,7 @@
+<template>
+    <ItemShop/>
+</template>
+
+<script setup lang="ts">
+    import ItemShop from '@/components/Shop/ItemShop.vue';
+</script>
\ No newline at end of file
diff --git a/src/views/TestView.vue b/src/views/TestView.vue
deleted file mode 100644
index a7fce444288c4df4c5f9f531c3e92e3da43935a4..0000000000000000000000000000000000000000
--- a/src/views/TestView.vue
+++ /dev/null
@@ -1,11 +0,0 @@
-<template>
-    <div>
-        <Button1 :buttonText="hallo"></Button1>
-    </div>
-</template>
-
-<script setup lang="ts">
-    import Button1 from '@/components/Buttons/Button1.vue'
-
-    const hallo = 'Hallo'
-</script>
\ No newline at end of file
diff --git a/src/views/UnauthorizedView.vue b/src/views/UnauthorizedView.vue
deleted file mode 100644
index b17b84045310f0de340a09e5c3c60d91e8ddfb7b..0000000000000000000000000000000000000000
--- a/src/views/UnauthorizedView.vue
+++ /dev/null
@@ -1,32 +0,0 @@
-<template>
-    <body class="bg-dark text-white py-5">
-        <div class="container py-5">
-            <div class="row">
-                <div class="col-md-2 text-center">
-                    <p><img src="@/assets/icons/danger.svg" alt="danger"> <br/>Status Code: 403</p>
-                </div>
-                <div class="col-md-10">
-                    <h3>OPPSSS!!!! Sorry...</h3>
-                    <p>Sorry, your access is refused due to security reasons of our server and also our sensitive data.<br/>Please go back to the home page to continue browsing.</p>
-                    <Button1 :button-text="'Take Me Home'" @click="home" />
-                </div>
-            </div>
-        </div>
-    </body>
-</template>
-
-<script setup lang="ts">
-import { useRouter } from 'vue-router';
-import Button1 from '@/components/Buttons/Button1.vue';
-
-const router = useRouter();
-
-const home = () => {
-    router.push('/'); 
-};
-</script>
-
-
-<style scoped>
-
-</style>
\ No newline at end of file
diff --git a/src/views/UpdateUser/UpdateUserView.vue b/src/views/UpdateUser/UpdateUserView.vue
deleted file mode 100644
index aae915c1e1225dca1b3f6ac4b34e5b987c765515..0000000000000000000000000000000000000000
--- a/src/views/UpdateUser/UpdateUserView.vue
+++ /dev/null
@@ -1,12 +0,0 @@
-<script setup lang="ts">
-
-import UpdateUserLayout from "@/components/UpdateUserComponents/UpdateUserLayout.vue";
-</script>
-
-<template>
-<UpdateUserLayout></UpdateUserLayout>
-</template>
-
-<style scoped>
-
-</style>
\ No newline at end of file
diff --git a/src/views/User/UserProfileForeignView.vue b/src/views/User/ExternalProfileView.vue
similarity index 68%
rename from src/views/User/UserProfileForeignView.vue
rename to src/views/User/ExternalProfileView.vue
index 0662a2c06dc7a47cea608f4172a11d009aafdefe..67951edd79a50af254b995e802c041708a7083b5 100644
--- a/src/views/User/UserProfileForeignView.vue
+++ b/src/views/User/ExternalProfileView.vue
@@ -1,6 +1,6 @@
 <script setup lang="ts">
 
-import UserProfileForeignLayout from "@/components/UserProfile/UserProfileForeignLayout.vue";
+import UserProfileForeignLayout from "@/components/UserProfile/ExternalProfile.vue";
 </script>
 <!-- The path to a foreign user is /{userId} || /profile/{userId}-->
 <template>
diff --git a/src/views/User/UserProfileView.vue b/src/views/User/MyProfileView.vue
similarity index 60%
rename from src/views/User/UserProfileView.vue
rename to src/views/User/MyProfileView.vue
index 85e9882866797433edfa76cc3fbf4368796432cf..f8ec753f18e393bf30db04d063c0b7026906dd02 100644
--- a/src/views/User/UserProfileView.vue
+++ b/src/views/User/MyProfileView.vue
@@ -1,6 +1,6 @@
 <script setup lang="ts">
 
-import UserProfileLayout from "@/components/UserProfile/UserProfileLayout.vue";
+import UserProfileLayout from "@/components/UserProfile/MyProfile.vue";
 </script>
 
 <template>
diff --git a/src/views/User/UserAddFriend.vue b/src/views/User/UserAddFriend.vue
deleted file mode 100644
index 585f5f8c7ec6f69bebe290fe917e46cad1f8eb5e..0000000000000000000000000000000000000000
--- a/src/views/User/UserAddFriend.vue
+++ /dev/null
@@ -1,238 +0,0 @@
-<script setup lang="ts">
-import { ref } from 'vue'
-import { FriendService } from '@/api';
-
-async function addFriend(friendID: number) {
-    const response = await FriendService.addFriendRequest({ userId: friendID });
-    console.log(response);
-}
-</script>
-
-
-<template>
-    <div class="container">
-        <h1>Add Friend</h1>
-        <div class="row">
-            <form class="col-md-5" id="searchBox" role="search">
-                <input class="form-control me-2 custom-border" type="search" placeholder="Search" aria-label="Search">
-                <button class="btn btn-success" type="submit">Search</button>
-            </form>
-            <div class="col-md-8">
-                <div class="people-nearby">
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar7.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Sophia Page</a></h5>
-                                <p>Software Engineer</p>
-                                <p class="text-muted">500m away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right" @click="addFriend(1)">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar6.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Emma Johnson</a></h5>
-                                <p>Model at Fashion</p>
-                                <p class="text-muted">800m away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar5.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Nora Wilson</a></h5>
-                                <p>Writer at Newspaper</p>
-                                <p class="text-muted">2.5km away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar4.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Diana Amber</a></h5>
-                                <p>Student</p>
-                                <p class="text-muted">700m away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar3.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Addison Thomas</a></h5>
-                                <p>Barber at Fashion</p>
-                                <p class="text-muted">1.5km away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar2.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Jonathon Thompson</a></h5>
-                                <p>Fashion Designer</p>
-                                <p class="text-muted">2km away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar7.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Olivia Steward</a></h5>
-                                <p>Creative Director</p>
-                                <p class="text-muted">2km away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar6.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Elena Foster</a></h5>
-                                <p>Executive Officer</p>
-                                <p class="text-muted">4km away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar1.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Brian Walton</a></h5>
-                                <p>Designer at Designer</p>
-                                <p class="text-muted">3km away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="nearby-user">
-                        <div class="row">
-                            <div class="col-md-2 col-sm-2">
-                                <img src="https://bootdey.com/img/Content/avatar/avatar7.png" alt="user"
-                                    class="profile-photo-lg">
-                            </div>
-                            <div class="col-md-7 col-sm-7">
-                                <h5><a href="#" class="profile-link">Cris Haris</a></h5>
-                                <p>General Manager at Manager</p>
-                                <p class="text-muted">1km away</p>
-                            </div>
-                            <div class="col-md-3 col-sm-3">
-                                <button class="btn btn-primary pull-right">Add Friend</button>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-</template>
-
-<style scoped>
-body {
-    margin-top: 20px;
-    background: #FAFAFA;
-}
-
-.people-nearby .google-maps {
-    background: #f8f8f8;
-    border-radius: 4px;
-    border: 1px solid #f1f2f2;
-    padding: 20px;
-    margin-bottom: 20px;
-}
-
-.people-nearby .google-maps .map {
-    height: 300px;
-    width: 100%;
-    border: none;
-}
-
-.people-nearby .nearby-user {
-    padding: 20px 0;
-    border-top: 1px solid #f1f2f2;
-    border-bottom: 1px solid #f1f2f2;
-    margin-bottom: 20px;
-}
-
-img.profile-photo-lg {
-    height: 80px;
-    width: 80px;
-    border-radius: 50%;
-}
-
-#searchBox {
-    margin-bottom: 20px;
-    display: flex;
-    text-wrap: nowrap;
-}
-
-.row {
-    width: 100%;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-}
-
-.form-control.custom-border {
-    border-color: #222223;
-    /* Change to your desired color */
-}
-</style>
\ No newline at end of file
diff --git a/src/views/FeedbackView.vue b/src/views/User/UserFeedbackView.vue
similarity index 83%
rename from src/views/FeedbackView.vue
rename to src/views/User/UserFeedbackView.vue
index 6eef349d66eda4e3145a12372e9061ccf2cecedb..3c28adbed9221b1b24edd8a33a6638531c293ffd 100644
--- a/src/views/FeedbackView.vue
+++ b/src/views/User/UserFeedbackView.vue
@@ -2,14 +2,14 @@
     <main>
       <div class="wrapper">
       <div id="formFrame">
-          <h1>Feedback</h1>
+          <h1>TIlbakemelding</h1>
       <form @submit.prevent="submitForm">
         <BaseInput v-model="email" label="Email" type="email" placeholder="Enter your email" inputId="email" required />
         <br>
-        <label for="feedback">Your feedback:</label>
+        <label for="feedback">Din tilbakemelding:</label>
         <textarea v-model="message" placeholder="Write here" rows="5" name="comment[text]" id="comment_text" cols="33"
           required></textarea>
-        <Button1 button-text="Send" @click="submitForm">Submit</Button1>
+        <BaseButton button-text="Send" @click="submitForm">Send inn</BaseButton>
         <p v-if="submissionStatus">{{ submissionStatus }}</p>
       </form>
     </div>
@@ -19,8 +19,8 @@
 
 <script setup lang="ts">
 import { ref } from 'vue';
-import BaseInput from '@/components/InputFields/BaseInput.vue';
-import Button1 from '@/components/Buttons/Button1.vue';
+import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue';
+import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue';
 
 const email = ref("");
 const message = ref("");
diff --git a/src/views/User/UserFriendsView.vue b/src/views/User/UserFriendsView.vue
index b6b3ed3c46805bed9cd0dbb7e507ef83796bebce..075b06aeae3091f5fa45091845882a2c6cd59225 100644
--- a/src/views/User/UserFriendsView.vue
+++ b/src/views/User/UserFriendsView.vue
@@ -1,570 +1,7 @@
 <template>
-    <div class="container">
-        <h1>Your Friends</h1>
-        <div>
-            <button class="btn btn-primary pull-right" @click="addNewFriends">+ Add Friend</button>
-            <div class="my-3">
-                <button class="btn pages" @click="setupFriends">Your Friends</button>
-                <button class="btn pages" @click="requestFriend">Friend Requests</button>
-            </div>
-        </div>
-        <div v-if="showFriends">
-            <div v-if="elementsInFriends">
-                <div class="row">
-                    <div class="col-lg-3" v-for="friend in friends" :key="friend.id">
-                        <div class="card card-one">
-                            <div class="header">
-                                <div v-if="friend.profileImage" class="avatar">
-                                    <img :src="'http://localhost:8080/api/images/' + friend.profileImage" alt="">
-                                </div>
-                                <div v-else class="avatar">
-                                    <img :src="'../src/assets/userprofile.png'" alt="">
-                                </div>
-                            </div>
-                            <h3><a href="#" class="btn stretched-link" id="profileName"
-                                    @click="navigateToFriend(friend.id)">{{
-                friend.firstName }}</a></h3>
-                            <div class="desc">{{ friend.firstName }} {{ friend.lastName }}</div>
-                            <div class="contacts">
-                                <a class="text removeFriend" data-bs-toggle="collapse"
-                                    :href="'#collapseExample' + friend.id" role="button" aria-expanded="false"
-                                    :aria-controls="'collapseExample' + friend.id">
-                                    See more
-                                </a>
-                                <div class="collapse" :id="'collapseExample' + friend.id">
-                                    <button class="btn btn-danger" @click="removeFriend(friend.id)">
-                                        <h5><img src="@/assets/icons/remove-white.svg" style="width: 30px"> Remove
-                                            friend
-                                        </h5>
-                                    </button>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-            <div v-else>No Friends</div>
-        </div>
-        <div v-else-if="showRequests" class="row">
-            <div class="content-body">
-                <div v-if="elementsInFriendRequest" id="requests">
-                    <div class="request" v-for="(friend) in friendRequests" :key="friend.id">
-                        <div v-if="friend.profileImage !== null"><img id="profilePicture"
-                                :src="'http://localhost:8080/api/images/' + friend.profileImage" alt="user"
-                                class="profile-photo-lg"></div>
-                        <div v-else><img id="profilePicture" :src="'../src/assets/userprofile.png'" alt="user"
-                                class="profile-photo-lg"></div>
-                        <h2>{{ friend.firstName }}</h2> - <button class="btn btn-success mx-2"
-                            @click="acceptRequest(friend.id)">Accept</button>
-                        <button class="btn btn-danger" @click="rejectRequest(friend.id)">Reject</button>
-                    </div>
-                </div>
-                <div v-else>No friend requests</div>
-            </div>
-        </div>
-        <div v-if="showAddFriend" class="modal" tabindex="-1" role="dialog"
-            style="display:block; background-color: rgba(0,0,0,0.5);">
-            <div class="modal-dialog" role="document">
-                <div class="modal-content">
-                    <div class="modal-header">
-                        <h5 class="modal-title">Add Friend</h5>
-                        <button type="button" class="close" @click="showAddFriend = false">
-                            <span aria-hidden="true">&times;</span>
-                        </button>
-                    </div>
-                    <div class="modal-body d-flex justify-content-center align-items-center flex-column">
-                        <form class="col-md-10 d-flex justify-content-center align-items-center flex-row my-4"
-                            id="searchBox" role="search" @submit.prevent="searchProfile(searchWord)">
-                            <input class="form-control me-2 custom-border" type="search" placeholder="Search"
-                                aria-label="Search" v-model="searchWord">
-                            <button class="btn btn-success" type="submit">Search</button>
-                        </form>
-                        <div class="col-md-12">
-                            <div class="people-nearby">
-                                <div v-for="user in searchedUsers" :key="user.id" class="nearby-user">
-                                    <div class="row d-flex align-items-center">
-                                        <div class="col-md-2 col-sm-2">
-                                            <div v-if="user.profileImage !== null"><img id="profilePicture"
-                                                    :src="'http://localhost:8080/api/images/' + user.profileImage"
-                                                    alt="user" class="profile-photo-lg"></div>
-                                            <div v-else><img id="profilePicture" :src="'../src/assets/userprofile.png'"
-                                                    alt="user" class="profile-photo-lg"></div>
-
-                                        </div>
-                                        <div class="col-md-7 col-sm-7">
-                                            <h5><a href="#" class="profile-link" @click="toUserProfile(user.id)">{{
-                                                    user.firstName }}</a>
-                                            </h5>
-                                        </div>
-                                        <div class="col-md-3 col-sm-3">
-                                            <button class="btn btn-primary pull-right" @click="addFriend(user.id)">Add
-                                                Friend</button>
-                                        </div>
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
+    <UserFriends/>
 </template>
 
-
-
 <script setup lang="ts">
-import { ref, onMounted } from 'vue';
-import { useRouter } from 'vue-router';
-import { FriendService, UserService } from '@/api';
-import type { UserDTO } from '@/api';
-
-const router = useRouter();
-const friends = ref();
-const showFriends = ref(true);
-const showRequests = ref(false);
-const showAddFriend = ref(false);
-const friendRequests = ref([] as any);
-const addFriends = ref([] as any);
-const searchedUsers = ref([] as any);
-
-const searchWord = ref("");
-
-const elementsInFriendRequest = ref(false);
-const elementsInFriends = ref(false);
-
-const toUserProfile = (userId: number) => {
-    router.push('/profile/' + userId);
-};
-
-const searchProfile = async (searchTerm: string) => {
-    const userPayload = {
-        searchTerm: searchTerm as string,
-        filter: 'NON_FRIENDS' as string,
-    };
-    try {
-        const response = await UserService.getUsersByNameAndFilter(userPayload);
-        searchedUsers.value = response;
-        console.log(response);
-    } catch (error) {
-        console.error('Failed to search for profile', error);
-    }
-};
-
-const addNewFriends = async () => {
-    const userPayload = {
-        amount: 6 as number,
-        filter: 'NON_FRIENDS' as string,
-    };
-    try {
-        const response = await UserService.getRandomUsers(userPayload);
-        searchedUsers.value = response;
-        showAddFriend.value = true;
-    } catch (error) {
-        console.error('Failed to add friend', error);
-    }
-};
-
-async function addFriend(friendID: number) {
-    const response = await FriendService.addFriendRequest({ userId: friendID });
-}
-
-async function requestFriend() {
-    showRequests.value = true;
-    showFriends.value = false;
-    try {
-        const response = await FriendService.getFriendRequests();
-        friendRequests.value = response;
-        elementsInFriendRequest.value = response.length > 0;
-        console.log("Friend requests: " + response);
-    } catch (error) {
-        console.error('Failed to fetch friend requests', error);
-    }
-}
-
-const navigateToFriend = (friendID: number) => {
-    router.push('/profile/' + friendID);
-};
-
-const removeFriend = async (friendID: number) => {
-    try {
-        await FriendService.deleteFriendOrFriendRequest({ friendId: friendID });
-        const responseFriends = await FriendService.getFriends();
-        friends.value = responseFriends;
-    } catch (error) {
-        console.error('Failed to remove friend', error);
-    }
-};
-
-const setupFriends = async () => {
-    showFriends.value = true;
-    showRequests.value = false;
-    try {
-        const response = await FriendService.getFriends();
-        friends.value = response;
-        elementsInFriends.value = response.length > 0;
-        console.log(response);
-    } catch (error) {
-        console.error('Failed to fetch friends', error);
-    }
-};
-
-const acceptRequest = async (requestID: number) => {
-    try {
-        await FriendService.acceptFriendRequest({ friendId: requestID });
-        const responseRequest = await FriendService.getFriendRequests();
-        friendRequests.value = responseRequest;
-        const responseFriends = await FriendService.getFriends();
-        friends.value = responseFriends;
-    } catch (error) {
-        console.error('Failed to accept friend request', error);
-    }
-};
-
-const rejectRequest = async (requestID: number) => {
-    try {
-        await FriendService.deleteFriendOrFriendRequest({ friendId: requestID });
-        const response = await FriendService.getFriendRequests();
-        friendRequests.value = response;
-    } catch (error) {
-        console.error('Failed to reject friend request', error);
-    }
-};
-
-onMounted(() => {
-    setupFriends();
-});
-</script>
-
-
-<style scoped>
-body {
-    background-color: #f0f6ff;
-    color: #28384d;
-
-}
-
-/*social */
-.card-one {
-    position: relative;
-    width: 300px;
-    background: #fff;
-    box-shadow: 0 10px 7px -5px rgba(0, 0, 0, 0.4);
-}
-
-.card {
-    margin-bottom: 35px;
-    padding-bottom: 1rem;
-    box-shadow: 0 10px 20px 0 rgba(26, 44, 57, 0.14);
-    border: none;
-}
-
-.follower-wrapper li {
-    list-style-type: none;
-    color: #fff;
-    display: inline-block;
-    float: left;
-    margin-right: 20px;
-}
-
-.social-profile {
-    color: #fff;
-}
-
-.social-profile a {
-    color: #fff;
-}
-
-.social-profile {
-    position: relative;
-    margin-bottom: 150px;
-}
-
-.social-profile .user-profile {
-    position: absolute;
-    bottom: -75px;
-    width: 150px;
-    height: 150px;
-    border-radius: 50%;
-    left: 50px;
-}
-
-.social-nav {
-    position: absolute;
-    bottom: 0;
-}
-
-.social-prof {
-    color: #333;
-    text-align: center;
-}
-
-.social-prof .wrapper {
-    width: 70%;
-    margin: auto;
-    margin-top: -100px;
-}
-
-.social-prof img {
-    width: 150px;
-    height: 150px;
-    border-radius: 50%;
-    margin-bottom: 20px;
-    border: 5px solid #fff;
-    /*border: 10px solid #70b5e6ee;*/
-}
-
-.social-prof h3 {
-    font-size: 36px;
-    font-weight: 700;
-    margin-bottom: 0;
-}
-
-.social-prof p {
-    font-size: 18px;
-}
-
-.social-prof .nav-tabs {
-    border: none;
-}
-
-.card .nav>li {
-    position: relative;
-    display: block;
-}
-
-.card .nav>li>a {
-    position: relative;
-    display: block;
-    padding: 10px 15px;
-    font-weight: 300;
-    border-radius: 4px;
-}
-
-.card .nav>li>a:focus,
-.card .nav>li>a:hover {
-    text-decoration: none;
-    background-color: #eee;
-}
-
-.card .s-nav>li>a.active {
-    text-decoration: none;
-    background-color: #3afe;
-    color: #fff;
-}
-
-.text-blue {
-    color: #3afe;
-}
-
-ul.friend-list {
-    margin: 0;
-    padding: 0;
-}
-
-ul.friend-list li {
-    list-style-type: none;
-    display: flex;
-    align-items: center;
-}
-
-ul.friend-list li:hover {
-    background: rgba(0, 0, 0, .1);
-    cursor: pointer;
-}
-
-ul.friend-list .left img {
-    width: 45px;
-    height: 45px;
-    border-radius: 50%;
-    margin-right: 20px;
-}
-
-ul.friend-list li {
-    padding: 10px;
-}
-
-ul.friend-list .right h3 {
-    font-size: 16px;
-    font-weight: 700;
-    margin-bottom: 0;
-}
-
-ul.friend-list .right p {
-    font-size: 11px;
-    color: #6c757d;
-    margin: 0;
-}
-
-.social-timeline-card .dropdown-toggle::after {
-    display: none;
-}
-
-.info-card h4 {
-    font-size: 15px;
-}
-
-.info-card h2 {
-    font-size: 18px;
-    margin-bottom: 20px;
-}
-
-.social-about .social-info {
-    font-size: 16px;
-    margin-bottom: 20px;
-}
-
-.social-about p {
-    margin-bottom: 20px;
-}
-
-.info-card i {
-    color: #3afe;
-}
-
-.card-one {
-    position: relative;
-    width: 300px;
-    background: #fff;
-    box-shadow: 0 10px 7px -5px rgba(0, 0, 0, 0.4);
-}
-
-.card-one .header {
-    position: relative;
-    width: 100%;
-    height: 60px;
-    background-color: #3afe;
-}
-
-.card-one .header::before,
-.card-one .header::after {
-    content: '';
-    position: absolute;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    background: inherit;
-}
-
-.card-one .header::before {
-    -webkit-transform: skewY(-8deg);
-    transform: skewY(-8deg);
-    -webkit-transform-origin: 100% 100%;
-    transform-origin: 100% 100%;
-}
-
-.card-one .header::after {
-    -webkit-transform: skewY(8deg);
-    transform: skewY(8deg);
-    -webkit-transform-origin: 0 100%;
-    transform-origin: 0 100%;
-}
-
-.card-one .header .avatar {
-    position: absolute;
-    left: 50%;
-    top: 30px;
-    margin-left: -50px;
-    z-index: 5;
-    width: 100px;
-    height: 100px;
-    border-radius: 50%;
-    overflow: hidden;
-    background: #ccc;
-    border: 3px solid #fff;
-}
-
-.card-one .header .avatar img {
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    -webkit-transform: translate(-50%, -50%);
-    transform: translate(-50%, -50%);
-    width: 100px;
-    height: auto;
-}
-
-.card-one h3 {
-    position: relative;
-    margin: 80px 0 30px;
-    text-align: center;
-}
-
-.card-one h3::after {
-    content: '';
-    position: absolute;
-    bottom: -15px;
-    left: 50%;
-    margin-left: -15px;
-    width: 30px;
-    height: 1px;
-    background: #000;
-}
-
-.card-one .desc {
-    padding: 0 1rem 2rem;
-    text-align: center;
-    line-height: 1.5;
-    color: #777;
-}
-
-#gallery li {
-    width: 24%;
-    float: left;
-    margin: 6px;
-
-}
-
-.removeFriend {
-    text-wrap: nowrap;
-}
-
-.contacts {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    flex-direction: column;
-}
-
-#profileName {
-    font-size: 1.5rem;
-    font-weight: 600;
-    width: 100%;
-}
-
-#requests {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-}
-
-.request {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    margin: 1rem;
-}
-
-#profilePicture {
-    width: 70px;
-    height: 70px;
-    border-radius: 50%;
-    margin-right: 1rem;
-    border: 2px solid #000;
-}
-
-.modal-content {
-    padding: 1rem;
-}
-
-.modal-header {
-    margin-bottom: 5px;
-}
-
-.pages {
-    border-bottom: 1px solid #000;
-    border-radius: 0px;
-    margin: 0px 5px;
-}
-</style>
\ No newline at end of file
+    import UserFriends from '@/components/Friends/UserFriends.vue';
+</script>
\ No newline at end of file
diff --git a/src/views/SettingsView.vue b/src/views/User/UserSettingsView.vue
similarity index 92%
rename from src/views/SettingsView.vue
rename to src/views/User/UserSettingsView.vue
index bfacde14fc84fd679ba5dd74411c03c60bf5a219..485d8dd73014ae413f73fdebc29dd676b6ce578e 100644
--- a/src/views/SettingsView.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,19 +45,19 @@ 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">
                                     <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
                                     <circle cx="12" cy="7" r="4"></circle>
                                 </svg>
-                                Profile
+                                Profil
                             </a>
 
 
                             <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">
@@ -63,33 +66,33 @@ function toBilling() {
                                         d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z">
                                     </path>
                                 </svg>
-                                Account
+                                Konto
                             </a>
 
 
                             <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">
                                     <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
                                 </svg>
-                                Security
+                                Sikkerhet
                             </a>
 
 
                             <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">
                                     <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
                                     <path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
-                                </svg>Notification
+                                </svg>Varsel
                             </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">
@@ -174,6 +177,7 @@ function toBilling() {
 
 </template>
 
+
 <style scoped>
 .container {
     margin-top: 2rem;