diff --git a/src/components/__tests__/NavBarTest.spec.ts b/src/components/__tests__/NavBarTest.spec.ts
index b31870d5340b4f2fe9642c8b74116ced1360c96f..ea7c2814a609abe8a0e43501fa558e7f45f70dc5 100644
--- a/src/components/__tests__/NavBarTest.spec.ts
+++ b/src/components/__tests__/NavBarTest.spec.ts
@@ -2,7 +2,7 @@ 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'
 
 vi.stubGlobal('scrollTo', vi.fn())
 
diff --git a/src/components/__tests__/savingsPathTest.spec.ts b/src/components/__tests__/savingsPathTest.spec.ts
index af21d03c1b80df3ae2e90e8b92bd8e1782df544f..dea8650e2ad5d6ced6b43bfd45ce7bc012319875 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'
diff --git a/src/router/index.ts b/src/router/index.ts
index c80ad8b511e430bf1f1a6bec2b83e82e929f4641..e88ce03d04665ab80cdf5a41c5724d526a36b32c 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',
diff --git a/src/stores/accountStore.ts b/src/stores/accountStore.ts
index d0d7715190bedd53d676fa1193145768037f2774..b80263eafa362581f6c2e235d544456ad887274c 100644
--- a/src/stores/accountStore.ts
+++ b/src/stores/accountStore.ts
@@ -1,7 +1,7 @@
 import { defineStore } from 'pinia'
 import { ref } from 'vue'
 import authInterceptor from '@/services/authInterceptor'
-import axios, { AxiosError } from 'axios'
+import { AxiosError } from 'axios'
 
 export const useAccountStore = defineStore('account', {
     state: () => ({
diff --git a/src/stores/userConfigStore.ts b/src/stores/userConfigStore.ts
index 3b5661531c91b403d1fb631dc6959fa513065285..6f1e0f1ccbe25f90f463aed9ef97ec9b63ac4319 100644
--- a/src/stores/userConfigStore.ts
+++ b/src/stores/userConfigStore.ts
@@ -1,7 +1,7 @@
 import { defineStore } from 'pinia'
 import { ref } from 'vue'
 import authInterceptor from '@/services/authInterceptor'
-import axios, { AxiosError } from 'axios'
+import { AxiosError } from 'axios'
 
 export const useUserConfigStore = defineStore('userConfig', {
     state: () => ({
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/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/ConfigAccountNumberView.vue b/src/views/ConfigAccountNumberView.vue
index ef650a7178ad5b1ec25644fbe3193b9822e83e91..652cf0d11ba68e92f47d8b6e14171faa565cf321 100644
--- a/src/views/ConfigAccountNumberView.vue
+++ b/src/views/ConfigAccountNumberView.vue
@@ -46,7 +46,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, computed } from 'vue'
+import { computed, ref } from 'vue'
 import { useAccountStore } from '@/stores/accountStore'
 import ContinueButtonComponent from '@/components/ContinueButtonComponent.vue'
 import router from '@/router'
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>