diff --git a/Makefile b/Makefile
index 693ef9b2aaec37942c81b422312ea0b5f0751ac4..c483e0b12516af8ea4d80e3cf72efbf340d9a9a1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,19 @@
-.PHONY: build run
+.PHONY: build run run-dev unit e2e clean-docker
 
 build-docker:
 	docker build -t sparesti_frontend .
 
 run-docker:
-	docker run -p 5173:5173 sparesti_frontend
+	docker run --rm --name sparesti_frontend_container -p 5173:5173 sparesti_frontend
+
+clean-docker:
+	-docker stop sparesti_frontend_container
+	-docker rm sparesti_frontend_container
+
+run:
+	make build-docker
+	make clean-docker
+	make run-docker
 
 run-dev:
 	npm run dev
@@ -13,4 +22,4 @@ unit:
 	npm run test:unit
 
 e2e:
-	npm run test:e2e
\ No newline at end of file
+	npm run test:e2e
diff --git a/cypress/e2e/homeView.cy.ts b/cypress/e2e/homeView.cy.ts
index c36a497515644ec32fde9cce49a6e3f78850b3ae..8ddc7675b8e2f8c39782ff114013650c1f9a9138 100644
--- a/cypress/e2e/homeView.cy.ts
+++ b/cypress/e2e/homeView.cy.ts
@@ -14,6 +14,13 @@ describe('Goals and Challenges Page Load', () => {
         ],
       },
     }).as('fetchGoals');
+    // Mock the POST request for renewing the token if it's not implemented in the backend
+    cy.intercept('POST', '/auth/renewToken', {
+      statusCode: 200,
+      body: {
+        accessToken: 'newlyRenewedAccessToken'
+      }
+    }).as('renewToken');
 
     cy.intercept('GET', '/challenges', {
       statusCode: 200,
@@ -24,6 +31,14 @@ describe('Goals and Challenges Page Load', () => {
       },
     }).as('fetchChallenges');
 
+    cy.intercept('GET', '/profile/streak', {
+      statusCode: 200,
+      body: {
+        content: [
+          { streak: 1, startDate: "2026-04-29T12:10:38.308Z" },
+        ],
+      },
+    }).as('fetchChallenges');
     // Visit the component that triggers these requests in `onMounted`
     cy.visit('/hjem');
   });
@@ -31,6 +46,13 @@ describe('Goals and Challenges Page Load', () => {
   it('loads and displays goals and challenges after onMounted', () => {
     // Wait for API calls made during `onMounted` to complete
     cy.wait(['@fetchGoals', '@fetchChallenges']);
+    // Mock the POST request for renewing the token if it's not implemented in the backend
+    cy.intercept('POST', '/auth/renewToken', {
+      statusCode: 200,
+      body: {
+        accessToken: 'newlyRenewedAccessToken'
+      }
+    }).as('renewToken');
 
     // Check console logs for any errors or warnings that might indicate issues
     cy.window().then((win) => {
diff --git a/package-lock.json b/package-lock.json
index 962f0ccbb36ff69aa08fc85c6ff4ba24d66f855f..cdbcb6f750f1327fdc33e3e3d5fc21a2a8970dbd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
         "pinia": "^2.1.7",
         "vue": "^3.4.21",
         "vue-router": "^4.3.1",
+        "vue3-flip-countdown": "^0.1.6",
         "vuedraggable": "^4.1.0"
       },
       "devDependencies": {
@@ -7252,6 +7253,14 @@
         "typescript": "*"
       }
     },
+    "node_modules/vue3-flip-countdown": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/vue3-flip-countdown/-/vue3-flip-countdown-0.1.6.tgz",
+      "integrity": "sha512-RRz+iZ7Zvr1U9mrZRya7I5815jboDyRJz9vzgILq8ZCc2fQ6SxZPYwOr3pD5oWCDBprAEsPF9x4fsTtEitSmXw==",
+      "dependencies": {
+        "vue": "^3.0.0"
+      }
+    },
     "node_modules/vuedraggable": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
diff --git a/package.json b/package.json
index be13c2a5d3e4a0451de2749309b751fd1a3e17b4..3d1c8853a603f9b7c4fb8d0e0f161bdd8d57c335 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
     "pinia": "^2.1.7",
     "vue": "^3.4.21",
     "vue-router": "^4.3.1",
+    "vue3-flip-countdown": "^0.1.6",
     "vuedraggable": "^4.1.0"
   },
   "devDependencies": {
diff --git a/src/assets/archerSpare.gif b/src/assets/archerSpare.gif
new file mode 100644
index 0000000000000000000000000000000000000000..ef0e3fa6fd0fcdd700e0e8cb233c4195b90b1355
Binary files /dev/null and b/src/assets/archerSpare.gif differ
diff --git a/src/assets/backgroundSavingsPath.png b/src/assets/backgroundSavingsPath.png
new file mode 100644
index 0000000000000000000000000000000000000000..43cfde5161f862f862f14f8612077b10bbcfb4e2
Binary files /dev/null and b/src/assets/backgroundSavingsPath.png differ
diff --git a/src/assets/bioAuthFace.png b/src/assets/bioAuthFace.png
new file mode 100644
index 0000000000000000000000000000000000000000..b03bb5d400029bcbc6d7bea9f5657da31e3e63a0
Binary files /dev/null and b/src/assets/bioAuthFace.png differ
diff --git a/src/assets/bioAuthTouch.png b/src/assets/bioAuthTouch.png
new file mode 100644
index 0000000000000000000000000000000000000000..363627b9c744b2a8dcabc9d2a69485d055045f43
Binary files /dev/null and b/src/assets/bioAuthTouch.png differ
diff --git a/src/assets/boatSpare.gif b/src/assets/boatSpare.gif
new file mode 100644
index 0000000000000000000000000000000000000000..f0aaaa991168e07de3f56e5b129ae082094499f3
Binary files /dev/null and b/src/assets/boatSpare.gif differ
diff --git a/src/assets/borderImage.png b/src/assets/borderImage.png
new file mode 100644
index 0000000000000000000000000000000000000000..1c0ac6cdc5e2ef366679ecd0fb85f51c73ccc65f
Binary files /dev/null and b/src/assets/borderImage.png differ
diff --git a/src/assets/farmerSpare.gif b/src/assets/farmerSpare.gif
new file mode 100644
index 0000000000000000000000000000000000000000..0f471d607f720952491c22b815486d4b58425b76
Binary files /dev/null and b/src/assets/farmerSpare.gif differ
diff --git a/src/assets/finishLine.png b/src/assets/finishLine.png
index f30b5a30213062013638f6e275673d65d0640777..9394bd3c85fed058ab7862e207667d0c9df00ff7 100644
Binary files a/src/assets/finishLine.png and b/src/assets/finishLine.png differ
diff --git a/src/assets/flower.png b/src/assets/flower.png
new file mode 100644
index 0000000000000000000000000000000000000000..c7481c94d5c7f137f0bfaad68fbf20b4d9396f9c
Binary files /dev/null and b/src/assets/flower.png differ
diff --git a/src/assets/infoIcon.png b/src/assets/infoIcon.png
new file mode 100644
index 0000000000000000000000000000000000000000..1aef35a260e16d428c804b38c584651fe42a1487
Binary files /dev/null and b/src/assets/infoIcon.png differ
diff --git a/src/assets/pengesekkStreak.png b/src/assets/pengesekkStreak.png
new file mode 100644
index 0000000000000000000000000000000000000000..54565d0fd1ad2795edeaab7eeb614e538d618dc2
Binary files /dev/null and b/src/assets/pengesekkStreak.png differ
diff --git a/src/assets/savingsPathBg.png b/src/assets/savingsPathBg.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb1994e981fffba4df9736cd50ccd71d00e70340
Binary files /dev/null and b/src/assets/savingsPathBg.png differ
diff --git a/src/components/ButtonDIsplayStreak.vue b/src/components/ButtonDIsplayStreak.vue
deleted file mode 100644
index e5043e4fb746882e19dac98ed5cb8c42de707c1e..0000000000000000000000000000000000000000
--- a/src/components/ButtonDIsplayStreak.vue
+++ /dev/null
@@ -1,76 +0,0 @@
-<template>
-    <div class="flex flex-col items-center">
-        <Span class="text-sm text-bold">STREAK</Span>
-        <button @click="toggleStreakCard" class="bg-transparent">
-            <img src="@/assets/streak.png" alt="streak" class="mx-auto w-12 h-12" />
-        </button>
-
-        <div
-            v-if="displayStreakCard"
-            class="w-96 h-64 duration-500 group overflow-hidden absolute top-32 rounded bg-white-800 text-neutral-50 p-4 flex flex-col justify-evenly"
-        >
-            <div
-                class="absolute blur opacity-40 duration-500 group-hover:blur-none w-72 h-72 rounded-full group-hover:translate-x-12 group-hover:translate-y-12 bg-green-100 right-1 -bottom-24"
-            ></div>
-            <div
-                class="absolute blur opacity-40 duration-500 group-hover:blur-none w-12 h-12 rounded-full group-hover:translate-x-12 group-hover:translate-y-2 bg-green-300 right-12 bottom-12"
-            ></div>
-            <div
-                class="absolute blur opacity-40 duration-500 group-hover:blur-none w-36 h-36 rounded-full group-hover:translate-x-12 group-hover:-translate-y-12 bg-green-500 right-1 -top-12"
-            ></div>
-            <div
-                class="absolute blur opacity-40 duration-500 group-hover:blur-none w-24 h-24 bg-green-400 rounded-full group-hover:-translate-x-12"
-            ></div>
-            <div class="z-10 flex flex-col justify-evenly w-full h-full px-4">
-                <span class="text-2xl font-bold text-black"
-                    >{{ currentStreak }}{{ currentStreak === 1 ? ' dag' : ' dager' }} streak</span
-                >
-                <p class="text-black text-1xl font-bold">
-                    {{
-                        currentStreak > 0
-                            ? 'Bra jobba du har spart i ' + currentStreak + ' dager!'
-                            : 'Du har ikke gjort noe i dag. Gjør noe nå for å starte en streak!'
-                    }}
-                </p>
-                <!-- Row component with horizontal padding and auto margins for centering -->
-                <div
-                    class="flex flex-row justify-content-between items-center h-20 w-full mx-auto bg-black-400 gap-4"
-                >
-                    <div class="flex flex-1 overflow-x-auto">
-                        <div v-for="index in 6" :key="index" class="min-w-max mx-auto">
-                            <div class="flex flex-col items-center">
-                                <span class="text-black"
-                                    >Dag {{ currentStreak - ((currentStreak % 7) - index) }}</span
-                                >
-                                <!-- Conditional rendering for streak images -->
-                                <img
-                                    v-if="index - 1 < currentStreak % 7"
-                                    src="@/assets/streak.png"
-                                    alt="challenge completed"
-                                    class="max-h-8 max-w-8"
-                                />
-                                <img
-                                    v-else
-                                    src="@/assets/streak.png"
-                                    alt="challenge not completed"
-                                    class="max-h-8 max-w-8 grayscale"
-                                />
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-
-const displayStreakCard = ref(false)
-const currentStreak = ref(20)
-
-function toggleStreakCard() {
-    displayStreakCard.value = !displayStreakCard.value
-}
-</script>
diff --git a/src/components/ButtonDisplayStreak.vue b/src/components/ButtonDisplayStreak.vue
new file mode 100644
index 0000000000000000000000000000000000000000..50ff4e445c0db7b234538d27824d34a65954824c
--- /dev/null
+++ b/src/components/ButtonDisplayStreak.vue
@@ -0,0 +1,134 @@
+<template>
+    <div class="flex flex-col items-center absolute">
+        <span class="text-sm text-bold">STREAK</span>
+        <button
+            @mouseover="display"
+            @mouseleave="hide"
+            class="cursor-pointer bg-transparent hover:bg-transparent hover:scale-150"
+        >
+            <img
+                src="@/assets/pengesekkStreak.png"
+                alt="streak"
+                class="mx-auto w-6 h-6 md:w-12 md:h-12"
+            />
+        </button>
+
+        <div
+            v-if="displayStreakCard"
+            class="w-[30vh] h-[20vh] md:w-auto md:h-auto group z-50 bg-opacity-50 overflow-hidden absolute left-0 top-14 md:top-20 flex flex-col justify-evenly text-wrap"
+        >
+            <div
+                class="flex flex-col justify-evenly w-full h-full py-2 px-4 md:py-0 bg-white rounded-2xl border-4 border-green-300"
+            >
+                <span class="text-xs md:text-2xl font-bold text-black"
+                    >{{ currentStreak
+                    }}{{
+                        currentStreak === 1 ? ' utfodring fullført' : ' utfodringer fullført'
+                    }}
+                    streak</span
+                >
+                <p class="text-black text-xs md:text-1xl md:font-bold">
+                    {{
+                        currentStreak! > 0
+                            ? 'Bra jobba du har fullført ' + currentStreak + ' utfordringer på rad!'
+                            : 'Du har ikke fullført en utfordring det siste. Fullfør en nå for å starte en streak!'
+                    }}
+                </p>
+                <Countdown
+                    v-if="screenSize > 768 && currentStreak! > 0"
+                    class="flex flex-row"
+                    countdownSize="1rem"
+                    labelSize=".5rem"
+                    mainColor="white"
+                    secondFlipColor="white"
+                    mainFlipBackgroundColor="#30ab0e"
+                    secondFlipBackgroundColor="#9af781"
+                    :labels="{ days: 'dager', hours: 'timer', minutes: 'min', seconds: 'sek' }"
+                    :deadlineISO="deadline"
+                ></Countdown>
+                <!-- Row component with horizontal padding and auto margins for centering -->
+                <div
+                    class="flex flex-row items-center mx-auto h-20 w-4/5 md:w-full bg-black-400 gap-4"
+                >
+                    <div class="flex flex-1 overflow-x-auto">
+                        <div v-for="index in 6" :key="index" class="min-w-max mx-auto">
+                            <div class="flex flex-col justify-around items-center">
+                                <span class="text-black text-xs md:text-1xl font-bold">{{
+                                    currentStreak! - ((currentStreak! % 7) - index)
+                                }}</span>
+                                <!-- Conditional rendering for streak images -->
+                                <img
+                                    v-if="index - 1 < currentStreak! % 7"
+                                    src="@/assets/pengesekkStreak.png"
+                                    alt="challenge completed"
+                                    class="max-h-6 max-w-6 md:max-h-10 md:max-w-10"
+                                />
+                                <img
+                                    v-else
+                                    src="@/assets/pengesekkStreak.png"
+                                    alt="challenge not completed"
+                                    class="max-h-6 max-w-6 md:max-h-10 md:max-w-10 grayscale"
+                                />
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, onUnmounted, ref, watch } from 'vue'
+import { useUserStore } from '@/stores/userStore'
+// @ts-ignore
+import { Countdown } from 'vue3-flip-countdown'
+
+const userStore = useUserStore()
+const currentStreak = ref<number>()
+const streakStart = ref<string>()
+const deadline = ref<string>()
+onMounted(async () => {
+    await userStore.getUserStreak()
+    if (userStore.streak) {
+        currentStreak.value = userStore.streak?.streak
+        streakStart.value = userStore.streak?.streakStart
+        deadline.value = userStore.streak?.streakStart
+    }
+    console.log('Streak:', currentStreak.value)
+    if (typeof window !== 'undefined') {
+        window.addEventListener('resize', handleWindowSizeChange)
+    }
+    handleWindowSizeChange()
+})
+
+const screenSize = ref<number>(window.innerWidth)
+
+onUnmounted(() => {
+    window.removeEventListener('resize', handleWindowSizeChange)
+})
+const handleWindowSizeChange = () => {
+    screenSize.value = window.innerWidth
+}
+
+watch(
+    () => currentStreak.value,
+    (newStreak, oldStreak) => {
+        if (newStreak !== oldStreak) {
+            currentStreak.value = newStreak
+            console.log('Updated Steak:', currentStreak)
+        }
+    },
+    { immediate: true }
+)
+
+const displayStreakCard = ref(false)
+
+const display = () => {
+    displayStreakCard.value = true
+}
+
+const hide = () => {
+    displayStreakCard.value = false
+}
+</script>
diff --git a/src/components/DisplayInfoForChallengeOrGoal.vue b/src/components/DisplayInfoForChallengeOrGoal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b20221e248f67478e41e6df76fd9e8459645cc7d
--- /dev/null
+++ b/src/components/DisplayInfoForChallengeOrGoal.vue
@@ -0,0 +1,87 @@
+<template>
+    <button @click="display" class="bg-transparent relative p-0 hover:bg-transparent">
+        <img src="@/assets/infoIcon.png" alt="i" class="max-h-4 max-w-4 ml-1" />
+    </button>
+    <div
+        v-if="displayInfoCard"
+        class="w-[40vh] h-[20vh]md:w-60 md:h-40 group z-50 bg-opacity-50 overflow-hidden absolute mt-8 md:mt-4 md:mr-0 flex flex-col justify-evenly text-wrap"
+    >
+        <div
+            class="flex flex-col justify-around w-3/4 md:w-full h-[80%] py-2 px-4 md:py-0 bg-white rounded-2xl border-4 border-green-300 overflow-auto"
+        >
+            <p class="text-base md:text-lg text-wrap text-bold">{{ title.toUpperCase() }}</p>
+            <p class="text-xs md:text-sm text-wrap mb-2">Beskrivelse: {{ description }}</p>
+            <p v-if="completion !== 100" class="text-xs md:text-sm text-nowrap text-green-800">
+                Utløper om:
+            </p>
+            <Countdown
+                v-if="completion !== 100 && screenSize > 763"
+                class="flex flex-row"
+                countdownSize="1.3rem"
+                labelSize=".8rem"
+                mainColor="white"
+                secondFlipColor="white"
+                mainFlipBackgroundColor="#30ab0e"
+                secondFlipBackgroundColor="#9af781"
+                :labels="{ days: 'dager', hours: 'timer', minutes: 'min', seconds: 'sek' }"
+                :deadlineISO="deadline"
+            ></Countdown>
+            <Countdown
+                v-else-if="completion !== 100 && screenSize <= 763"
+                class="flex flex-row"
+                countdownSize="1.0rem"
+                labelSize=".6rem"
+                mainColor="white"
+                secondFlipColor="white"
+                mainFlipBackgroundColor="#30ab0e"
+                secondFlipBackgroundColor="#9af781"
+                :labels="{ days: 'dager', hours: 'timer', minutes: 'min', seconds: 'sek' }"
+                :deadlineISO="deadline"
+            ></Countdown>
+            <p class="text-nowrap text-xs md:text.sm" v-else>
+                Utfordring fullført.<br />
+                Totalt spart: {{ amountSaved }}kr
+            </p>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import type { Challenge } from '@/types/challenge'
+import type { Goal } from '@/types/goal'
+import { onUnmounted, ref } from 'vue'
+// @ts-ignore
+import { Countdown } from 'vue3-flip-countdown'
+
+interface Props {
+    challenge: Challenge | null | undefined
+    goal: Goal | null | undefined
+    isChallenge: boolean
+}
+const props = defineProps<Props>()
+
+const description = ref<string>(
+    props.isChallenge ? props.challenge!.description : props.goal!.description
+)
+const title = ref<string>(props.isChallenge ? props.challenge!.title : props.goal!.title)
+const amountSaved = ref<number>(props.isChallenge ? props.challenge!.saved : props.goal!.saved)
+const completion = ref<number>(
+    props.isChallenge ? props.challenge?.completion ?? 0 : props.goal?.completion ?? 0
+)
+const deadline = ref<string>(props.isChallenge ? props.challenge!.due : props.goal!.due)
+
+const displayInfoCard = ref(false)
+
+const display = () => {
+    displayInfoCard.value = !displayInfoCard.value
+}
+
+const screenSize = ref<number>(window.innerWidth)
+
+onUnmounted(() => {
+    window.removeEventListener('resize', handleWindowSizeChange)
+})
+const handleWindowSizeChange = () => {
+    screenSize.value = window.innerWidth
+}
+</script>
diff --git a/src/components/FormLogin.vue b/src/components/FormLogin.vue
index 731e224e722324e37fb36ffd35f3bfe4ee2344f7..363580072249635f9a74c6a5e1e9ec0eac6cbdc3 100644
--- a/src/components/FormLogin.vue
+++ b/src/components/FormLogin.vue
@@ -15,11 +15,18 @@ const emailRegex = /^[a-zA-Z0-9_+&*-]+(?:\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\
 const userStore = useUserStore()
 
 const isEmailValid = computed(() => emailRegex.test(resetEmail.value))
+const isSendingEmail = ref(false)
+const successMessage = ref<string>('')
+const modalErrorMessage = ref<string>('')
 
 const submitForm = () => {
     userStore.login(username.value, password.value)
 }
 
+const bioLogin = () => {
+    userStore.bioLogin(username.value)
+}
+
 const toggleShowPassword = () => {
     showPassword.value = !showPassword.value
 }
@@ -30,17 +37,36 @@ const openForgotPasswordModal = (event: MouseEvent) => {
 }
 
 const submitReset = async () => {
-    await axios.post('http://localhost:8080/forgotPassword/changePasswordRequest', {
-        email: resetEmail.value
-    })
-
-    resetEmail.value = ''
-    isModalOpen.value = false
+    isSendingEmail.value = true
+    modalErrorMessage.value = ''
+    successMessage.value = ''
+    try {
+        const response = await axios.post(
+            'http://localhost:8080/forgotPassword/changePasswordRequest',
+            {
+                email: resetEmail.value
+            }
+        )
+        successMessage.value =
+            'E-posten er sendt. Vennligst sjekk innboksen din for instrukser. OBS: E-posten kan havne i spam-mappen'
+        isSendingEmail.value = false
+        setTimeout(() => {
+            isModalOpen.value = false
+            successMessage.value = ''
+        }, 5000)
+    } catch (error) {
+        console.error(error)
+        modalErrorMessage.value = 'Noe gikk galt. Vennligst prøv igjen.'
+        isSendingEmail.value = false
+    }
 }
 
 const closeModal = () => {
-    resetEmail.value = ''
     isModalOpen.value = false
+    isSendingEmail.value = false
+    modalErrorMessage.value = ''
+    resetEmail.value = ''
+    successMessage.value = ''
 }
 
 watch(
@@ -95,36 +121,58 @@ watch(
                 Logg inn
             </button>
             <p>{{ errorMessage }}</p>
+            <button @click="bioLogin">biologin</button>
         </div>
     </div>
     <modal-component
         :title="'Glemt passord'"
         :message="'Vennligst skriv inn e-posten din for å endre passordet.'"
         :is-modal-open="isModalOpen"
-        @close="isModalOpen = false"
+        @close="closeModal"
     >
         <template v-slot:input>
-            <input
-                type="email"
-                v-model="resetEmail"
-                class="border border-gray-300 p-2 w-full mb-7"
-                placeholder="Skriv e-postadressen din her"
-            />
-        </template>
-        <template v-slot:buttons>
-            <button
-                :disabled="!isEmailValid"
-                @click="submitReset"
-                class="active-button font-bold py-2 px-4 w-1/2 border-2 disabled:border-transparent"
-            >
-                Send mail
-            </button>
-            <button
-                @click="closeModal"
-                class="active-button font-bold py-2 px-4 w-1/2 border-2 disabled:border-transparent"
-            >
-                Lukk
-            </button>
+            <div v-if="isSendingEmail" class="flex justify-center items-center">
+                <div
+                    class="p-3 animate-spin drop-shadow-2xl bg-gradient-to-r from-lime-500 from-30% to-green-600 to-90% md:w-18 md:h-20 h-20 w-20 aspect-square rounded-full"
+                >
+                    <div class="rounded-full h-full w-full bg-slate-100 background-blur-md"></div>
+                </div>
+            </div>
+            <div v-else-if="successMessage">
+                <p class="text-green-500 text-center">{{ successMessage }}</p>
+            </div>
+            <div v-else-if="modalErrorMessage">
+                <p class="text-red-500 text-center">{{ modalErrorMessage }}</p>
+                <button
+                    @click="closeModal"
+                    class="active-button font-bold py-2 px-4 w-1/2 mt-4 border-2 disabled:border-transparent"
+                >
+                    Lukk
+                </button>
+            </div>
+            <div v-else>
+                <input
+                    type="email"
+                    v-model="resetEmail"
+                    class="border border-gray-300 p-2 w-full mb-7"
+                    placeholder="Skriv e-postadressen din her"
+                />
+                <div class="flex gap-5 mt-4">
+                    <button
+                        :disabled="!isEmailValid"
+                        @click="submitReset"
+                        class="active-button font-bold py-2 px-4 w-1/2 border-2 disabled:border-transparent"
+                    >
+                        Send mail
+                    </button>
+                    <button
+                        @click="closeModal"
+                        class="active-button font-bold py-2 px-4 w-1/2 border-2 disabled:border-transparent"
+                    >
+                        Lukk
+                    </button>
+                </div>
+            </div>
         </template>
     </modal-component>
 </template>
diff --git a/src/components/ImgGifTemplate.vue b/src/components/ImgGifTemplate.vue
new file mode 100644
index 0000000000000000000000000000000000000000..46fecc79efe8cca7f8427a1a1e851e0c0ca15b79
--- /dev/null
+++ b/src/components/ImgGifTemplate.vue
@@ -0,0 +1,20 @@
+<template>
+    <div class="hover:scale-125">
+        <img
+            v-if="index % 6 === modValue"
+            :src="url"
+            alt="could not load"
+            class="h-32 w-32 border-2 rounded-lg border-stale-400 shadow-md shadow-black"
+        />
+    </div>
+</template>
+
+<script setup lang="ts">
+interface Props {
+    url: string
+    index: number
+    modValue: number
+}
+
+defineProps<Props>()
+</script>
diff --git a/src/components/NavBarComponent.vue b/src/components/NavBarComponent.vue
index f73a9e94cf8f39d898f8641c099b9ccc91f0506c..d801c739ea7ab26801c7215d1fee8fe05070c038 100644
--- a/src/components/NavBarComponent.vue
+++ b/src/components/NavBarComponent.vue
@@ -10,8 +10,7 @@
             </router-link>
 
             <div class="flex flex-row justify-center">
-                <img alt="streak" class="w-8 h-8" src="@/assets/streakFlame.png" />
-                <p class="font-bold">Streak</p>
+                <ButtonDisplayStreak></ButtonDisplayStreak>
             </div>
         </div>
         <div v-if="!isHamburger" class="flex flex-row gap-10">
@@ -68,6 +67,7 @@ import { RouterLink } from 'vue-router'
 import { onMounted, ref } from 'vue'
 import { useUserStore } from '@/stores/userStore'
 import ModalComponent from '@/components/ModalComponent.vue'
+import ButtonDisplayStreak from '@/components/ButtonDisplayStreak.vue'
 
 const userStore = useUserStore()
 
@@ -95,7 +95,9 @@ const updateWindowWidth = () => {
 }
 
 onMounted(() => {
-    window.addEventListener('resize', updateWindowWidth)
+    if (typeof window !== 'undefined') {
+        window.addEventListener('resize', updateWindowWidth)
+    }
     updateWindowWidth()
 })
 
diff --git a/src/components/SavingsPath.vue b/src/components/SavingsPath.vue
index b71a11bb1b657160eea30453ff91600acded5f0f..5e82a770cc22e2a37bab3fa8752ce7a4b0e858b1 100644
--- a/src/components/SavingsPath.vue
+++ b/src/components/SavingsPath.vue
@@ -1,6 +1,6 @@
 <template>
     <div
-        class="flex flex-col basis-2/3 max-h-full mx-auto max-w-5/6 md:basis-3/4 md:pr-20 md:max-mr-20"
+        class="flex flex-col basis-2/3 max-h-full mx-auto md:ml-20 md:mr-2 max-w-5/6 md:basis-3/4 md:max-pr-20 md:pr-10 md:max-mr-20"
     >
         <div class="flex justify-center align-center">
             <span
@@ -9,18 +9,28 @@
                 Din Sparesti
             </span>
         </div>
+        <button
+            class="h-auto w-auto absolute flex text-center self-end mr-10 md:mr-20 text-wrap shadow-sm shadow-black sm:top-50 sm:text-xs sm:mr-20 lg:mr-32 top-60 z-50 p-2 text-xs md:text-sm"
+            @click="scrollToFirstUncompleted"
+            v-show="!isAtFirstUncompleted"
+        >
+            Ufullførte utfordringer<br />↓
+        </button>
         <div class="h-1 w-4/6 mx-auto my-2 opacity-10"></div>
         <div
             ref="containerRef"
-            class="container relative mx-auto pt-6 w-4/5 md:w-3/5 no-scrollbar h-full max-h-[60vh] md:max-h-[60v] overflow-y-auto border-2 border-slate-300 rounded-lg bg-white shadow-lg"
+            class="container relative pt-6 w-4/5 bg-cover bg-[center] md:[background-position: center;] mx-auto md:w-4/5 no-scrollbar h-full max-h-[60vh] md:max-h-[60vh] md:min-w-2/5 overflow-y-auto border-2 border-transparent rounded-xl bg-white shadow-lg shadow-slate-400"
+            style="background-image: url('src/assets/backgroundSavingsPath.png')"
         >
             <div>
                 <img src="@/assets/start.png" alt="Spare" class="md:w-1/6 md:h-auto h-20" />
             </div>
+
             <div
                 v-for="(challenge, index) in challenges"
-                :key="challenge.title"
+                :key="challenge.id"
                 class="flex flex-col items-center"
+                :ref="(el) => assignRef(el, challenge, index)"
             >
                 <!-- Challenge Row -->
                 <div
@@ -31,31 +41,44 @@
                     class="flex flex-row w-4/5 gap-8"
                 >
                     <div class="right-auto just">
-                        <img
-                            v-if="index === 3"
-                            src="@/assets/sleepingSpare.gif"
-                            alt="could not load"
-                            class="w-32 h-32 border-2 rounded-lg border-stale-400"
-                        />
-                        <img
-                            v-else-if="index === 1"
-                            src="@/assets/golfSpare.gif"
-                            alt="could not load"
-                            class="w-32 h-32 border-2 rounded-lg border-stale-400"
-                        />
+                        <img-gif-template
+                            :index="index"
+                            :mod-value="1"
+                            url="src/assets/golfSpare.gif"
+                        ></img-gif-template>
+                        <img-gif-template
+                            :index="index"
+                            :mod-value="3"
+                            url="src/assets/sleepingSpare.gif"
+                        ></img-gif-template>
+                        <img-gif-template
+                            :index="index"
+                            :mod-value="5"
+                            url="src/assets/archerSpare.gif"
+                        ></img-gif-template>
                     </div>
                     <!-- Challenge Icon and Details -->
                     <div class="flex">
                         <!-- Challenge Icon -->
-                        <div class="flex flex-col items-center">
-                            <p class="text-center" data-cy="challenge-title">
-                                {{ challenge.title }}
-                            </p>
+                        <div class="flex flex-col items-center gap-4">
+                            <div class="flex flex-row flex-nowrap">
+                                <p
+                                    class="text-center text-wrap text-xs md:text-lg"
+                                    data-cy="challenge-title"
+                                >
+                                    {{ challenge.title }}
+                                </p>
+                                <display-info-for-challenge-or-goal
+                                    :goal="goal"
+                                    :challenge="challenge"
+                                    :is-challenge="true"
+                                ></display-info-for-challenge-or-goal>
+                            </div>
                             <img
                                 @click="editChallenge(challenge)"
                                 :data-cy="'challenge-icon-' + challenge.id"
                                 :src="getChallengeIcon(challenge)"
-                                class="max-w-20 max-h-20 cursor-pointer"
+                                class="max-w-20 max-h-20 cursor-pointer hover:scale-125"
                                 :alt="challenge.title"
                             />
                             <!-- Progress Bar, if the challenge is not complete -->
@@ -65,7 +88,7 @@
                                 "
                                 class="flex-grow w-full mt-2"
                             >
-                                <div class="flex flex-row">
+                                <div class="flex flex-row ml-5 md:ml-10 justify-center">
                                     <div class="flex flex-col">
                                         <div
                                             class="bg-gray-200 rounded-full h-2.5 dark:bg-gray-700"
@@ -80,7 +103,7 @@
                                                 }"
                                             ></div>
                                         </div>
-                                        <div class="text-center">
+                                        <div class="text-center text-xs md:text-base">
                                             {{ challenge.saved }}kr / {{ challenge.target }}kr
                                         </div>
                                     </div>
@@ -95,12 +118,14 @@
                                     </button>
                                 </div>
                             </div>
-                            <span v-else class="text-center">Ferdig: {{ challenge.saved }}</span>
+                            <span v-else class="text-center text-xs md:text-base"
+                                >Ferdig: {{ challenge.saved }}</span
+                            >
                         </div>
                         <!-- Check Icon -->
                         <div
                             v-if="challenge.completion !== undefined && challenge.completion >= 100"
-                            class="max-w-10 max-h-10"
+                            class="md:max-w-10 min-w-4 max-w-6 max-h-6 w-full h-auto md:max-h-10 min-h-4"
                         >
                             <img src="@/assets/completed.png" alt="" />️
                         </div>
@@ -109,18 +134,21 @@
                         </div>
                     </div>
                     <div class="">
-                        <img
-                            v-if="index === 0"
-                            src="@/assets/cowboySpare.gif"
-                            alt="could not load"
-                            class="h-32 w-32 border-2 rounded-lg border-stale-400"
-                        />
-                        <img
-                            v-else-if="index === 2"
-                            src="@/assets/hotAirBalloonSpare.gif"
-                            class="h-32 w-32 border-stale-400 border-2 rounded-lg"
-                            alt="could not load"
-                        />
+                        <img-gif-template
+                            :index="index"
+                            :mod-value="0"
+                            url="src/assets/cowboySpare.gif"
+                        ></img-gif-template>
+                        <img-gif-template
+                            :index="index"
+                            :mod-value="2"
+                            url="src/assets/hotAirBalloonSpare.gif"
+                        ></img-gif-template>
+                        <img-gif-template
+                            :index="index"
+                            :mod-value="4"
+                            url="src/assets/farmerSpare.gif"
+                        ></img-gif-template>
                     </div>
                 </div>
                 <!-- Piggy Steps, centered -->
@@ -155,9 +183,17 @@
         </div>
         <!-- Goal -->
         <div v-if="goal" class="flex flex-row justify-around m-t-2 pt-6 w-full mx-auto">
-            <div class="flex flex-col items-start cursor-pointer" @click="editGoal(goal)">
-                <img :src="getGoalIcon(goal)" class="w-12 h-12 mx-auto" :alt="goal.title" />
-                <div class="text-lg font-bold" data-cy="goal-title">{{ goal.title }}</div>
+            <div class="grid grid-rows-2 grid-flow-col gap 4">
+                <div class="row-span-3 cursor-pointer" @click="editGoal(goal)">
+                    <img :src="getGoalIcon(goal)" class="w-12 h-12 mx-auto" :alt="goal.title" />
+                    <div class="text-lg font-bold" data-cy="goal-title">{{ goal.title }}</div>
+                </div>
+                <display-info-for-challenge-or-goal
+                    class="col-span-2"
+                    :goal="goal"
+                    :challenge="null"
+                    :is-challenge="false"
+                ></display-info-for-challenge-or-goal>
             </div>
             <div class="flex flex-col items-end">
                 <div @click="goToEditGoal" class="cursor-pointer">
@@ -182,7 +218,16 @@
 </template>
 
 <script setup lang="ts">
-import { nextTick, onMounted, type Ref, ref, watch } from 'vue'
+import {
+    type ComponentPublicInstance,
+    nextTick,
+    onMounted,
+    onUnmounted,
+    reactive,
+    type Ref,
+    ref,
+    watch
+} from 'vue'
 import anime from 'animejs'
 import type { Challenge } from '@/types/challenge'
 import type { Goal } from '@/types/goal'
@@ -190,6 +235,8 @@ import confetti from 'canvas-confetti'
 import { useRouter } from 'vue-router'
 import { useGoalStore } from '@/stores/goalStore'
 import { useChallengeStore } from '@/stores/challengeStore'
+import DisplayInfoForChallengeOrGoal from '@/components/DisplayInfoForChallengeOrGoal.vue'
+import ImgGifTemplate from '@/components/ImgGifTemplate.vue'
 
 const router = useRouter()
 const goalStore = useGoalStore()
@@ -204,6 +251,110 @@ const props = defineProps<Props>()
 const challenges = ref<Challenge[]>(props.challenges)
 const goal = ref<Goal | null | undefined>(props.goal)
 
+onMounted(async () => {
+    await goalStore.getUserGoals()
+    window.addEventListener('resize', handleWindowSizeChange)
+    handleWindowSizeChange()
+    sortChallenges()
+})
+
+const sortChallenges = () => {
+    challenges.value.sort((a, b) => {
+        // First, sort by completion status: non-completed (less than 100) before completed (100)
+        if (a.completion !== 100 && b.completion === 100) {
+            return 1 // 'a' is not completed and 'b' is completed, 'a' should come first
+        } else if (a.completion === 100 && b.completion !== 100) {
+            return -1 // 'a' is completed and 'b' is not, 'b' should come first
+        } else {
+            // Explicitly convert dates to numbers for subtraction
+            const dateA = new Date(a.due).getTime()
+            const dateB = new Date(b.due).getTime()
+            return dateA - dateB
+        }
+    })
+}
+
+const screenSize = ref<number>(window.innerWidth)
+
+onUnmounted(() => {
+    window.removeEventListener('resize', handleWindowSizeChange)
+})
+const handleWindowSizeChange = () => {
+    screenSize.value = window.innerWidth
+}
+
+interface ElementRefs {
+    [key: string]: HTMLElement | undefined
+}
+
+const elementRefs = reactive<ElementRefs>({})
+
+const isAtFirstUncompleted = ref(false) // This state tracks visibility of the button
+const firstUncompletedRef: Ref<HTMLElement | undefined> = ref()
+
+function scrollToFirstUncompleted() {
+    let found = false
+    for (let i = 0; i < challenges.value.length; i++) {
+        if (challenges.value[i].completion! < 100) {
+            const refKey = `uncompleted-${i}`
+            if (elementRefs[refKey]) {
+                elementRefs[refKey]!.scrollIntoView({ behavior: 'smooth', block: 'start' })
+                firstUncompletedRef.value = elementRefs[refKey] // Store the reference
+                found = true
+                isAtFirstUncompleted.value = true
+                break
+            }
+        }
+    }
+    if (!found) {
+        isAtFirstUncompleted.value = false
+    }
+}
+
+onMounted(() => {
+    const container = containerRef.value
+    if (container) {
+        container.addEventListener('scroll', () => {
+            if (!firstUncompletedRef.value) return
+            const containerRect = container.getBoundingClientRect()
+            const firstUncompletedRect = firstUncompletedRef.value.getBoundingClientRect()
+            isAtFirstUncompleted.value = !(
+                firstUncompletedRect.top > containerRect.bottom ||
+                firstUncompletedRect.bottom < containerRect.top
+            )
+        })
+    }
+    scrollToFirstUncompleted()
+})
+
+onUnmounted(() => {
+    const container = containerRef.value
+    if (container) {
+        container.removeEventListener('scroll', () => {
+            // Clean up the scroll listener
+        })
+    }
+})
+
+const assignRef = (
+    el: Element | ComponentPublicInstance | null,
+    challenge: Challenge,
+    index: number
+) => {
+    const refKey = `uncompleted-${index}`
+    if (el instanceof HTMLElement) {
+        // Ensure that el is an HTMLElement
+        if (challenge.completion! < 100) {
+            elementRefs[refKey] = el
+        }
+    } else {
+        // Cleanup if the element is unmounted or not an HTMLElement
+        if (elementRefs[refKey]) {
+            delete elementRefs[refKey]
+        }
+    }
+}
+
 // Utilizing watch to specifically monitor for changes in the props
 watch(
     () => props.goal,
@@ -221,6 +372,7 @@ watch(
     (newChallenges, oldChallenges) => {
         if (newChallenges !== oldChallenges) {
             challenges.value = newChallenges
+            sortChallenges()
             console.log('Updated challenges:', challenges.value)
         }
     },
@@ -243,15 +395,13 @@ const addSpareUtfordring = () => {
 
 // Increment saved amount
 const incrementSaved = async (challenge: Challenge) => {
-    // Set a default increment amount per purchase
-    challenge.perPurchase = 20
-
     // Safely increment the saved amount, ensuring it exists
     challenge.saved += challenge.perPurchase
 
     // Check if the saved amount meets or exceeds the target
     if (challenge.saved >= challenge.target) {
         challenge.completion = 100
+        await challengeStore.completeUserChallenge(challenge)
     }
 
     console.log('Incrementing saved amount for:', challenge)
diff --git a/src/components/__tests__/NavBarTest.spec.ts b/src/components/__tests__/NavBarTest.spec.ts
index b31870d5340b4f2fe9642c8b74116ced1360c96f..a04985617f5d080bd2997f743beab7723f2a47e5 100644
--- a/src/components/__tests__/NavBarTest.spec.ts
+++ b/src/components/__tests__/NavBarTest.spec.ts
@@ -2,9 +2,30 @@ import { mount, VueWrapper } from '@vue/test-utils'
 import NavBar from '@/components/NavBarComponent.vue'
 import router from '@/router'
 import { createPinia, setActivePinia } from 'pinia'
-import { describe, it, expect, beforeEach, vi } from 'vitest'
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { nextTick } from 'vue'
 
 vi.stubGlobal('scrollTo', vi.fn())
+// Mocking Axios correctly using `importOriginal`
+const mocks = vi.hoisted(() => ({
+    get: vi.fn(),
+    post: vi.fn()
+}))
+
+vi.mock('axios', async (importActual) => {
+    const actual = await importActual<typeof import('axios')>()
+
+    return {
+        default: {
+            ...actual.default,
+            create: vi.fn(() => ({
+                ...actual.default.create(),
+                get: mocks.get,
+                post: mocks.post
+            }))
+        }
+    }
+})
 
 describe('NavBar Routing', () => {
     let wrapper: VueWrapper<any>
@@ -21,6 +42,7 @@ describe('NavBar Routing', () => {
 
         await router.push('/')
         await router.isReady()
+        await nextTick()
     })
 
     it('renders without errors', () => {
diff --git a/src/components/__tests__/savingsPathTest.spec.ts b/src/components/__tests__/savingsPathTest.spec.ts
index af21d03c1b80df3ae2e90e8b92bd8e1782df544f..40739f5a4e0a9b042239fadd17c40fe3ae9c6a61 100644
--- a/src/components/__tests__/savingsPathTest.spec.ts
+++ b/src/components/__tests__/savingsPathTest.spec.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it, beforeEach, vi } from 'vitest'
+import { beforeEach, describe, expect, it, vi } from 'vitest'
 import { mount } from '@vue/test-utils'
 import { createPinia, setActivePinia } from 'pinia'
 import SavingsPath from '@/components/SavingsPath.vue'
@@ -11,12 +11,32 @@ vi.mock('canvas-confetti', () => ({
         clear: vi.fn()
     }))
 }))
+const mocks = vi.hoisted(() => ({
+    get: vi.fn(),
+    post: vi.fn()
+}))
+
+vi.mock('axios', async (importActual) => {
+    const actual = await importActual<typeof import('axios')>()
+
+    return {
+        default: {
+            ...actual.default,
+            create: vi.fn(() => ({
+                ...actual.default.create(),
+                get: mocks.get,
+                post: mocks.post
+            }))
+        }
+    }
+})
 
 describe('SavingsPath Component', () => {
     let wrapper: any
     const pinia = createPinia()
 
     beforeEach(() => {
+        window.HTMLElement.prototype.scrollIntoView = function () {}
         setActivePinia(pinia)
         wrapper = mount(SavingsPath, {
             global: {
@@ -94,6 +114,7 @@ describe('SavingsPath Component', () => {
                 ]
             })
             await wrapper.vm.$nextTick()
+            await wrapper.vm.$nextTick()
 
             progressBar = wrapper.find('.bg-green-600')
             expect(progressBar.element.style.width).toBe('90%')
diff --git a/src/router/index.ts b/src/router/index.ts
index c80ad8b511e430bf1f1a6bec2b83e82e929f4641..5f32e18fa4bcb61cf7ad48446e11dea346712c49 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -33,6 +33,11 @@ const router = createRouter({
             name: 'profile',
             component: () => import('@/views/ProfileView.vue')
         },
+        {
+            path: '/profil/rediger',
+            name: 'edit-profile',
+            component: () => import('@/views/EditProfileView.vue')
+        },
         {
             path: '/sparemaal',
             name: 'goals',
@@ -117,6 +122,11 @@ const router = createRouter({
             path: '/:pathMatch(.*)*',
             name: 'not-found',
             component: () => import('@/views/NotFoundView.vue')
+        },
+        {
+            path: '/addAlternativeLogin',
+            name: 'addAlternativeLogin',
+            component: () => import('@/views/AddAlternativeLogin.vue')
         }
     ],
     scrollBehavior() {
diff --git a/src/stores/challengeStore.ts b/src/stores/challengeStore.ts
index 8e4529c5cd004d75a741cd132bc35fa7d7e80310..a8417aa62bf51495a6a06b401145b0fe06f34a06 100644
--- a/src/stores/challengeStore.ts
+++ b/src/stores/challengeStore.ts
@@ -41,10 +41,31 @@ export const useChallengeStore = defineStore('challenge', () => {
             console.error('Error updating challenge:', error)
         }
     }
+    const completeUserChallenge = async (challenge: Challenge) => {
+        try {
+            const response = await authInterceptor.put(
+                `/challenges/${challenge.id}/complete`,
+                challenge
+            )
+            if (response.data) {
+                // Update local challenge state to reflect changes
+                const index = challenges.value.findIndex((c) => c.id === challenge.id)
+                if (index !== -1) {
+                    challenges.value[index] = { ...challenges.value[index], ...response.data }
+                    console.log('Updated Challenge:', response.data)
+                }
+            } else {
+                console.error('No challenge content found in response data')
+            }
+        } catch (error) {
+            console.error('Error updating challenge:', error)
+        }
+    }
 
     return {
         challenges,
         getUserChallenges,
-        editUserChallenge
+        editUserChallenge,
+        completeUserChallenge
     }
 })
diff --git a/src/stores/userStore.ts b/src/stores/userStore.ts
index fe31bd1a782e8feadd79d12e5fc3338ade7f9f93..eff4fd1479cd1bf9b70c10e6650a054ae0b6321c 100644
--- a/src/stores/userStore.ts
+++ b/src/stores/userStore.ts
@@ -4,6 +4,11 @@ import type { User } from '@/types/user'
 import router from '@/router'
 import type { AxiosError } from 'axios'
 import axios from 'axios'
+import authInterceptor from '@/services/authInterceptor'
+import type { Streak } from '@/types/streak'
+import type { CredentialRequestOptions } from '@/types/CredentialRequestOptions'
+import { base64urlToUint8array, initialCheckStatus, uint8arrayToBase64url } from '@/util'
+import type { CredentialCreationOptions } from '@/types/CredentialCreationOptions'
 
 export const useUserStore = defineStore('user', () => {
     const defaultUser: User = {
@@ -14,6 +19,7 @@ export const useUserStore = defineStore('user', () => {
 
     const user = ref<User>(defaultUser)
     const errorMessage = ref<string>('')
+    const streak = ref<Streak>()
 
     const register = async (
         firstname: string,
@@ -38,7 +44,7 @@ export const useUserStore = defineStore('user', () => {
                 user.value.lastname = lastname
                 user.value.username = username
 
-                router.push({ name: 'configurations1' })
+                router.push({ name: 'addAlternativeLogin' })
             })
             .catch((error) => {
                 const axiosError = error as AxiosError
@@ -75,11 +81,163 @@ export const useUserStore = defineStore('user', () => {
         user.value = defaultUser
         router.push({ name: 'login' })
     }
+    const getUserStreak = async () => {
+        try {
+            const response = await authInterceptor('/profile/streak')
+            if (response.data) {
+                streak.value = response.data
+                console.log('Fetched Challenges:', streak.value)
+            } else {
+                streak.value = undefined
+                console.error('No challenge content found:', response.data)
+            }
+        } catch (error) {
+            console.error('Error fetching challenges:', error)
+            streak.value = undefined // Ensure challenges is always an array
+        }
+    }
+
+    const bioRegister = async () => {
+        try {
+            const response = await authInterceptor.post('/auth/bioRegistration')
+            initialCheckStatus(response)
+
+            const credentialCreateJson: CredentialCreationOptions = response.data
+
+            const credentialCreateOptions: CredentialCreationOptions = {
+                publicKey: {
+                    ...credentialCreateJson.publicKey,
+                    challenge: base64urlToUint8array(
+                        credentialCreateJson.publicKey.challenge as unknown as string
+                    ),
+                    user: {
+                        ...credentialCreateJson.publicKey.user,
+                        id: base64urlToUint8array(
+                            credentialCreateJson.publicKey.user.id as unknown as string
+                        )
+                    },
+                    excludeCredentials: credentialCreateJson.publicKey.excludeCredentials?.map(
+                        (credential) => ({
+                            ...credential,
+                            id: base64urlToUint8array(credential.id as unknown as string)
+                        })
+                    ),
+                    extensions: credentialCreateJson.publicKey.extensions
+                }
+            }
+
+            const publicKeyCredential = (await navigator.credentials.create(
+                credentialCreateOptions
+            )) as PublicKeyCredential
+
+            const publicKeyResponse =
+                publicKeyCredential.response as AuthenticatorAttestationResponse
+            const encodedResult = {
+                type: publicKeyCredential.type,
+                id: publicKeyCredential.id,
+                response: {
+                    attestationObject: uint8arrayToBase64url(publicKeyResponse.attestationObject),
+                    clientDataJSON: uint8arrayToBase64url(publicKeyResponse.clientDataJSON),
+                    transports: publicKeyResponse.getTransports?.() || []
+                },
+                clientExtensionResults: publicKeyCredential.getClientExtensionResults()
+            }
+
+            await authInterceptor
+                .post('/auth/finishBioRegistration', { credential: JSON.stringify(encodedResult) })
+                .then((response) => {
+                    router.push({ name: 'configurations1' })
+                })
+        } catch (error) {
+            router.push({ name: 'configurations1' })
+            console.error(error)
+        }
+    }
+
+    const bioLogin = async (username: string) => {
+        try {
+            const request = await axios.post(`http://localhost:8080/auth/bioLogin/${username}`)
+
+            initialCheckStatus(request)
+            console.log(request)
+
+            const credentialGetJson: CredentialRequestOptions = request.data
+            console.log(credentialGetJson)
+
+            const credentialGetOptions: CredentialRequestOptions = {
+                publicKey: {
+                    ...credentialGetJson.publicKey,
+                    allowCredentials:
+                        credentialGetJson.publicKey.allowCredentials &&
+                        credentialGetJson.publicKey.allowCredentials.map((credential) => ({
+                            ...credential,
+                            id: base64urlToUint8array(credential.id as unknown as string)
+                        })),
+                    challenge: base64urlToUint8array(
+                        credentialGetJson.publicKey.challenge as unknown as string
+                    ),
+                    extensions: credentialGetJson.publicKey.extensions
+                }
+            }
+
+            const publicKeyCredential = (await navigator.credentials.get(
+                credentialGetOptions
+            )) as PublicKeyCredential
+
+            // Extract response data based on the type of credential
+            const response = publicKeyCredential.response as AuthenticatorAssertionResponse
+
+            const encodedResult = {
+                type: publicKeyCredential.type,
+                id: publicKeyCredential.id,
+                response: {
+                    authenticatorData:
+                        response.authenticatorData &&
+                        uint8arrayToBase64url(response.authenticatorData),
+                    clientDataJSON:
+                        response.clientDataJSON && uint8arrayToBase64url(response.clientDataJSON),
+
+                    signature: response.signature && uint8arrayToBase64url(response.signature),
+                    userHandle: response.userHandle && uint8arrayToBase64url(response.userHandle)
+                },
+                clientExtensionResults: publicKeyCredential.getClientExtensionResults()
+            }
+            console.log(encodedResult)
+
+            await axios
+                .post(`http://localhost:8080/auth/finishBioLogin/${username}`, {
+                    credential: JSON.stringify(encodedResult)
+                })
+                .then((response) => {
+                    sessionStorage.setItem('accessToken', response.data.accessToken)
+                    localStorage.setItem('refreshToken', response.data.refreshToken)
+
+                    user.value.firstname = response.data.firstName
+                    user.value.lastname = response.data.lastName
+                    user.value.username = response.data.username
+
+                    router.push({ name: 'home' })
+                })
+                .catch((error) => {
+                    const axiosError = error as AxiosError
+                    errorMessage.value =
+                        (axiosError.response?.data as string) || 'An error occurred'
+                    console.log('hei :' + errorMessage.value)
+                })
+        } catch (error) {
+            // Handle errors
+            console.log(error)
+        }
+    }
 
     return {
         register,
         login,
         logout,
-        errorMessage
+        bioLogin,
+        bioRegister,
+        errorMessage,
+        getUserStreak,
+        streak
     }
 })
diff --git a/src/types/CredentialCreationOptions.ts b/src/types/CredentialCreationOptions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b6fdd7a76510ca4033a1c763a2ca9545797ab1b5
--- /dev/null
+++ b/src/types/CredentialCreationOptions.ts
@@ -0,0 +1,3 @@
+export interface CredentialCreationOptions {
+    publicKey: PublicKeyCredentialCreationOptions
+}
diff --git a/src/types/CredentialRequestOptions.ts b/src/types/CredentialRequestOptions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4349a83cdfde9e60fe294adeef87dd4f1792087c
--- /dev/null
+++ b/src/types/CredentialRequestOptions.ts
@@ -0,0 +1,3 @@
+export interface CredentialRequestOptions {
+    publicKey: PublicKeyCredentialRequestOptions
+}
diff --git a/src/types/profile.ts b/src/types/profile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..392aee69615beff857dc324e85cc4f77ea1f7911
--- /dev/null
+++ b/src/types/profile.ts
@@ -0,0 +1,19 @@
+export interface Profile {
+    id: number
+    firstName: string
+    lastName: string
+    email: string
+    username: string
+    password?: string
+    spendingAccount: {
+        accNumber?: number
+        accountType?: string
+        balance?: number
+    }
+    savingAccount: {
+        accNumber?: number
+        accountType?: string
+        balance?: number
+    }
+    badges?: object[]
+}
diff --git a/src/types/streak.ts b/src/types/streak.ts
new file mode 100644
index 0000000000000000000000000000000000000000..61dafae24c954c7ca99a3596ca43a659f1ef122c
--- /dev/null
+++ b/src/types/streak.ts
@@ -0,0 +1,4 @@
+export interface Streak {
+    streakStart?: string
+    streak?: number
+}
diff --git a/src/util.ts b/src/util.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7f6cbfc818ab356135d6acf232024019ea4fafe0
--- /dev/null
+++ b/src/util.ts
@@ -0,0 +1,33 @@
+import base64js from 'base64-js'
+import { type AxiosResponse } from 'axios'
+
+export function base64urlToUint8array(base64Bytes: string): Uint8Array {
+    const padding = '===='.substring(0, (4 - (base64Bytes.length % 4)) % 4)
+    return base64js.toByteArray((base64Bytes + padding).replace(/\//g, '_').replace(/\+/g, '-'))
+}
+
+export function uint8arrayToBase64url(bytes: Uint8Array | ArrayBuffer | number[]): string {
+    if (bytes instanceof Uint8Array) {
+        return base64js
+            .fromByteArray(bytes)
+            .replace(/\+/g, '-')
+            .replace(/\//g, '_')
+            .replace(/=/g, '')
+    } else {
+        return uint8arrayToBase64url(new Uint8Array(bytes))
+    }
+}
+
+export function checkStatus(response: AxiosResponse<any>): AxiosResponse<any> | undefined {
+    if (response.status !== 200) {
+        console.log('an error occurred: ', response.statusText)
+        return undefined
+    } else {
+        return response
+    }
+}
+
+export function initialCheckStatus(response: AxiosResponse<any>): any {
+    checkStatus(response)
+    return response.data
+}
diff --git a/src/utilo.js b/src/utilo.js
new file mode 100644
index 0000000000000000000000000000000000000000..4125c85af520a7d429032a90f80c9a4611f07740
--- /dev/null
+++ b/src/utilo.js
@@ -0,0 +1,28 @@
+import base64js from 'base64-js'
+
+export function base64urlToUint8array(base64Bytes) {
+    const padding = '===='.substring(0, (4 - (base64Bytes.length % 4)) % 4)
+    return base64js.toByteArray((base64Bytes + padding).replace(/\//g, '_').replace(/\+/g, '-'))
+}
+export function uint8arrayToBase64url(bytes) {
+    if (bytes instanceof Uint8Array) {
+        return base64js
+            .fromByteArray(bytes)
+            .replace(/\+/g, '-')
+            .replace(/\//g, '_')
+            .replace(/=/g, '')
+    } else {
+        return uint8arrayToBase64url(new Uint8Array(bytes))
+    }
+}
+export function checkStatus(response) {
+    if (response.status !== 200) {
+        console.log('an error occurred: ', response.body)
+    } else {
+        return response
+    }
+}
+export function initialCheckStatus(response) {
+    checkStatus(response)
+    return response.data
+}
diff --git a/src/views/AddAlternativeLogin.vue b/src/views/AddAlternativeLogin.vue
new file mode 100644
index 0000000000000000000000000000000000000000..554f09f25915282f5675244784a6bb212457d036
--- /dev/null
+++ b/src/views/AddAlternativeLogin.vue
@@ -0,0 +1,48 @@
+<template>
+    <div class="alt-login-main">
+        <h1>Alternativ innlogging</h1>
+        <div class="img-div">
+            <img src="@/assets/bioAuthTouch.png" alt="bioAuthTouch" />
+            <img src="@/assets/bioAuthFace.png" alt="bioAuthFace" />
+        </div>
+        <h2>Vil du logge på med touch eller face id?</h2>
+        <div class="btn-div">
+            <button @click="router.push('konfigurasjonSteg1')">Senere</button>
+            <button @click="userStore.bioRegister()">OK</button>
+        </div>
+    </div>
+</template>
+<script setup lang="ts">
+import { useUserStore } from '@/stores/userStore'
+import router from '@/router'
+
+const userStore = useUserStore()
+</script>
+
+<style scoped>
+.alt-login-main {
+    max-width: 800px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.img-div {
+    display: flex;
+    justify-content: center;
+}
+
+img {
+    width: 30%;
+}
+
+img:first-child {
+    margin-right: 20px;
+}
+
+button {
+    margin: 10px;
+    width: 100px;
+    height: 40px;
+}
+</style>
diff --git a/src/views/CardTemplate.vue b/src/views/CardTemplate.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6fa731e67776d9e923ea99427b9a23893f3de385
--- /dev/null
+++ b/src/views/CardTemplate.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup></script>
+
+<template>
+    <div class="border rounded-xl shadow-lg overflow-hidden">
+        <slot></slot>
+    </div>
+</template>
+
+<style scoped></style>
diff --git a/src/views/ConfigHabitChangeView.vue b/src/views/ConfigHabitChangeView.vue
index 5ee730d582b413003907a7061f11affe2792a103..a1e8b37350d385d2c3f31db77f2b8c81b56b6e41 100644
--- a/src/views/ConfigHabitChangeView.vue
+++ b/src/views/ConfigHabitChangeView.vue
@@ -47,7 +47,7 @@
 </template>
 
 <script setup lang="ts">
-import { onMounted, ref } from 'vue'
+import { ref } from 'vue'
 import ContinueButtonComponent from '@/components/ContinueButtonComponent.vue'
 import router from '@/router'
 import { useUserConfigStore } from '@/stores/userConfigStore'
diff --git a/src/views/EditProfileView.vue b/src/views/EditProfileView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..82da35481c774c789baffd3264b4a36cbbe45614
--- /dev/null
+++ b/src/views/EditProfileView.vue
@@ -0,0 +1,254 @@
+<script lang="ts" setup>
+import authInterceptor from '@/services/authInterceptor'
+import { computed, onMounted, ref } from 'vue'
+import type { Profile } from '@/types/profile'
+import CardTemplate from '@/views/CardTemplate.vue'
+import router from '@/router'
+import ToolTip from '@/components/ToolTip.vue'
+import InteractiveSpare from '@/components/InteractiveSpare.vue'
+
+const profile = ref<Profile>({
+    id: 0,
+    firstName: '',
+    lastName: '',
+    email: '',
+    username: '',
+    password: '',
+    spendingAccount: {
+        accNumber: undefined,
+        balance: 0
+    },
+    savingAccount: {
+        accNumber: undefined,
+        balance: 0
+    }
+})
+
+const updatePassword = ref<boolean>(false)
+const confirmPassword = ref<string>('')
+const errorMessage = ref<string>('')
+
+const nameRegex = /^[æÆøØåÅa-zA-Z,.'-][æÆøØåÅa-zA-Z ,.'-]{1,29}$/
+const emailRegex =
+    /^[æÆøØåÅa-zA-Z0-9_+&*-]+(?:\.[æÆøØåÅa-zA-Z0-9_+&*-]+)*@(?:[æÆøØåÅa-zA-Z0-9-]+\.)+[æÆøØåÅa-zA-Z]{2,7}$/
+const usernameRegex = /^[ÆØÅæøåA-Za-z][æÆøØåÅA-Za-z0-9_]{2,29}$/
+const passwordRegex = /^(?=.*[0-9])(?=.*[a-zæøå])(?=.*[ÆØÅA-Z])(?=.*[@#$%^&+=!])(?=\S+$).{8,30}$/
+const accountNumberRegex = /^\d{11}$/
+
+const isFirstNameValid = computed(
+    () => nameRegex.test(profile.value.firstName) && profile.value.firstName
+)
+const isLastNameValid = computed(
+    () => nameRegex.test(profile.value.lastName) && profile.value.lastName
+)
+const isEmailValid = computed(() => emailRegex.test(profile.value.email))
+const isUsernameValid = computed(() => usernameRegex.test(profile.value.username))
+const isPasswordValid = computed(() => passwordRegex.test(profile.value.password || ''))
+const isSpendingAccountValid = computed(() =>
+    accountNumberRegex.test(profile.value.spendingAccount.accNumber?.toString() || '')
+)
+const isSavingAccountValid = computed(() =>
+    accountNumberRegex.test(profile.value.savingAccount.accNumber?.toString() || '')
+)
+
+const isFormInvalid = computed(
+    () =>
+        [
+            isFirstNameValid,
+            isLastNameValid,
+            isEmailValid,
+            isUsernameValid,
+            isSpendingAccountValid,
+            isSavingAccountValid
+        ].some((v) => !v.value) ||
+        (updatePassword.value
+            ? profile.value.password !== confirmPassword.value || profile.value.password === ''
+            : false)
+)
+
+onMounted(async () => {
+    await authInterceptor('/profile')
+        .then((response) => {
+            profile.value = response.data
+            console.log(profile.value)
+        })
+        .catch((error) => {
+            return console.log(error)
+        })
+})
+
+const saveChanges = async () => {
+    if (isFormInvalid.value) {
+        errorMessage.value = 'Vennligst fyll ut alle feltene riktig'
+        return
+    }
+
+    if (!updatePassword.value) {
+        delete profile.value.password
+    }
+
+    await authInterceptor
+        .put('/profile', profile.value)
+        .then(() => {
+            router.back()
+        })
+        .catch((error) => {
+            errorMessage.value = error.response.data.message
+        })
+}
+</script>
+
+<template>
+    <div class="w-full flex px-10 justify-center">
+        <div class="flex flex-row flex-wrap justify-center w-full max-w-screen-xl gap-20">
+            <div class="flex flex-col max-w-96 w-full gap-5">
+                <h1>Rediger profil</h1>
+                <div class="w-full flex flex-row gap-5 justify-between justify-items-end">
+                    <div class="flex flex-col justify-center">
+                        <button class="h-min bg-transparent text-4xl" v-text="'⬅️'" />
+                    </div>
+                    <div class="w-32 h-32 border-black border-2 rounded-full shrink-0" />
+                    <div class="flex flex-col justify-center">
+                        <button class="h-min bg-transparent text-4xl" v-text="'➡️'" />
+                    </div>
+                </div>
+
+                <div class="flex flex-col">
+                    <div class="flex flex-row justify-between mx-4">
+                        <p>Fornavn*</p>
+                        <ToolTip
+                            :message="'Must include only letters, spaces, commas, apostrophes, periods, and hyphens. 1-30 characters long'"
+                        />
+                    </div>
+                    <input
+                        v-model="profile.firstName"
+                        :class="{ 'bg-green-200': isFirstNameValid }"
+                        name="firstname"
+                        placeholder="Skriv inn fornavn"
+                        type="text"
+                    />
+                </div>
+                <div class="flex flex-col">
+                    <div class="flex flex-row justify-between mx-4">
+                        <p>Etternavn*</p>
+                        <ToolTip
+                            :message="'Must include only letters, spaces, commas, apostrophes, periods, and hyphens. 1-30 characters long'"
+                        />
+                    </div>
+                    <input
+                        v-model="profile.lastName"
+                        :class="{ 'bg-green-200': isLastNameValid }"
+                        name="lastname"
+                        placeholder="Skriv inn etternavn"
+                        type="text"
+                    />
+                </div>
+                <div class="flex flex-col">
+                    <div class="flex flex-row justify-between mx-4">
+                        <p>E-post*</p>
+                        <ToolTip
+                            :message="'Valid email: Starts with Norwegian letters, numbers, or special characters. Includes \@\ followed by a domain. Ends with 2-7 letters.'"
+                        />
+                    </div>
+                    <input
+                        v-model="profile.email"
+                        :class="{ 'bg-green-200': isEmailValid }"
+                        name="email"
+                        placeholder="Skriv inn e-post"
+                        type="text"
+                    />
+                </div>
+                <div class="flex flex-col">
+                    <div class="flex flex-row justify-between mx-4">
+                        <p>Brukernavn*</p>
+                        <ToolTip
+                            :message="'Must start with a letter and can include numbers and underscores. 3-30 characters long.'"
+                        />
+                    </div>
+                    <input
+                        v-model="profile.username"
+                        :class="{ 'bg-green-200': isUsernameValid }"
+                        name="username"
+                        placeholder="Skriv inn brukernavn"
+                        type="text"
+                    />
+                </div>
+                <div class="flex flex-col">
+                    <div class="flex flex-row justify-between mx-4">
+                        <div class="flex flex-row gap-2">
+                            <p>Endre passord</p>
+                            <input v-model="updatePassword" type="checkbox" />
+                        </div>
+                        <ToolTip
+                            v-if="updatePassword"
+                            :message="'Must be at least 8 characters, including at least one number, one lowercase letter, one uppercase letter, one special character (@#$%^&+=!), and no spaces.'"
+                        />
+                    </div>
+                    <input
+                        v-if="updatePassword"
+                        v-model="profile.password"
+                        :class="{ 'bg-green-200': isPasswordValid }"
+                        class="w-full"
+                        name="password"
+                        placeholder="Skriv inn passord"
+                    />
+                    <input
+                        v-if="updatePassword"
+                        v-model="confirmPassword"
+                        :class="{ 'bg-red-200': profile.password !== confirmPassword }"
+                        class="mt-2"
+                        name="confirm"
+                        placeholder="Bekreft passord"
+                        type="password"
+                    />
+                </div>
+
+                <p v-if="errorMessage" class="text-red-500" v-text="errorMessage" />
+            </div>
+            <div class="flex flex-col justify-end max-w-96 w-full gap-5">
+                <InteractiveSpare
+                    :png-size="10"
+                    :speech="['Her kan du endre på profilen din!']"
+                    direction="left"
+                />
+
+                <CardTemplate>
+                    <div class="bg-red-300">
+                        <p class="font-bold mx-3" v-text="'Brukskonto'" />
+                    </div>
+                    <input
+                        v-model="profile.spendingAccount.accNumber"
+                        :class="{ 'bg-green-200': isSpendingAccountValid }"
+                        class="border-2 rounded-none rounded-b-xl w-full"
+                        placeholder="Kontonummer"
+                        type="number"
+                    />
+                </CardTemplate>
+
+                <CardTemplate>
+                    <div class="bg-red-300">
+                        <p class="font-bold mx-3" v-text="'Sparekonto'" />
+                    </div>
+                    <input
+                        v-model="profile.savingAccount.accNumber"
+                        :class="{ 'bg-green-200': isSavingAccountValid }"
+                        class="border-2 rounded-none rounded-b-xl w-full"
+                        placeholder="Kontonummer"
+                        type="number"
+                    />
+                </CardTemplate>
+
+                <div class="flex flex-row justify-between">
+                    <button class="bg-button-other" @click="router.back()" v-text="'Avbryt'" />
+                    <button
+                        :disabled="isFormInvalid"
+                        @click="saveChanges"
+                        v-text="'Lagre endringer'"
+                    />
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style scoped></style>
diff --git a/src/views/ProfileView.vue b/src/views/ProfileView.vue
index 255824275b207f62108888007491f385b3b8e1d2..436e522c7c815ad6cb5725724b76a8f76779d75d 100644
--- a/src/views/ProfileView.vue
+++ b/src/views/ProfileView.vue
@@ -1,21 +1,115 @@
 <script lang="ts" setup>
 import authInterceptor from '@/services/authInterceptor'
-import { onMounted } from 'vue'
+import { computed, onMounted, ref } from 'vue'
+import type { Profile } from '@/types/profile'
+import CardTemplate from '@/views/CardTemplate.vue'
+import InteractiveSpare from '@/components/InteractiveSpare.vue'
+import type { Challenge } from '@/types/challenge'
+import type { Goal } from '@/types/goal'
+import CardGoal from '@/components/CardGoal.vue'
+import router from '@/router'
+
+const profile = ref<Profile>()
+const completedGoals = ref<Goal[]>([])
+const completedChallenges = ref<Challenge[]>([])
 
 onMounted(async () => {
-    await authInterceptor
-        .get('/config')
+    await authInterceptor('/profile')
+        .then((response) => {
+            profile.value = response.data
+            console.log(profile.value)
+        })
+        .catch((error) => {
+            return console.log(error)
+        })
+
+    await authInterceptor(`/goals/completed?page=0&size=3`)
         .then((response) => {
-            console.log(response.data)
+            completedGoals.value = response.data.content
         })
         .catch((error) => {
-            console.log(error)
+            return console.log(error)
         })
+
+    await authInterceptor('/challenges/completed?page=0&size=3')
+        .then((response) => {
+            completedChallenges.value = response.data.content
+        })
+        .catch((error) => {
+            return console.log(error)
+        })
+})
+
+const welcome = computed(() => {
+    return [`Velkommen, ${profile.value?.firstName} ${profile.value?.lastName} !`]
 })
 </script>
 
 <template>
-    <h1>Din profil</h1>
+    <div class="w-full flex px-10 justify-center">
+        <div class="flex flex-row flex-wrap justify-center w-full max-w-screen-xl gap-20">
+            <div class="flex flex-col max-w-96 w-full gap-5">
+                <h1>Profile</h1>
+                <div class="flex flex-row gap-5">
+                    <div class="w-32 h-32 border-black border-2 rounded-full shrink-0" />
+                    <div class="w-full flex flex-col justify-between">
+                        <h3 class="font-thin my-0">{{ profile?.username }}</h3>
+                        <h3 class="font-thin my-0">
+                            {{ profile?.firstName + ' ' + profile?.lastName }}
+                        </h3>
+                        <h3 class="font-thin my-0">{{ profile?.email }}</h3>
+                    </div>
+                </div>
+
+                <h3 class="font-bold" v-text="'Du har spart ' + '< totalSaved >' + 'kr'" />
+
+                <CardTemplate>
+                    <div class="bg-red-300">
+                        <p class="font-bold mx-3" v-text="'Brukskonto'" />
+                    </div>
+                    <p
+                        class="mx-3"
+                        v-text="profile?.spendingAccount.accNumber || 'Ingen brukskonto oppkoblet'"
+                    />
+                </CardTemplate>
+
+                <CardTemplate>
+                    <div class="bg-red-300">
+                        <p class="font-bold mx-3" v-text="'Sparekonto'" />
+                    </div>
+                    <p
+                        class="mx-3"
+                        v-text="profile?.savingAccount.accNumber || 'Ingen sparekonto oppkoblet'"
+                    />
+                </CardTemplate>
+
+                <button @click="router.push({ name: 'edit-profile' })" v-text="'Rediger bruker'" />
+            </div>
+
+            <div class="flex flex-col">
+                <InteractiveSpare :png-size="10" :speech="welcome" direction="left" />
+                <div class="flex flex-row justify-between mx-4">
+                    <p class="font-bold">Fullførte sparemål</p>
+                    <a class="hover:p-0 cursor-pointer" v-text="'Se alle'" />
+                </div>
+                <CardTemplate class="p-4 flex flex-row flex-wrap justify-center gap-2 mb-4 mt-2">
+                    <CardGoal v-for="goal in completedGoals" :key="goal.id" :goal-instance="goal" />
+                </CardTemplate>
+
+                <div class="flex flex-row justify-between mx-4">
+                    <p class="font-bold">Fullførte utfordringer</p>
+                    <a class="hover:p-0 cursor-pointer" v-text="'Se alle'" />
+                </div>
+                <CardTemplate class="p-4 flex flex-row flex-wrap justify-center gap-2 mb-4 mt-2">
+                    <CardGoal
+                        v-for="challenge in completedChallenges"
+                        :key="challenge.id"
+                        :goal-instance="challenge"
+                    />
+                </CardTemplate>
+            </div>
+        </div>
+    </div>
 </template>
 
 <style scoped></style>