From 905f98c8226b4f3ed6c47a9a98527a3d07b6bba8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Valdemar=20=C3=85storp=20Beere?= <valdemb@stud.ntnu.no>
Date: Mon, 22 Apr 2024 15:19:56 +0200
Subject: [PATCH] Fix(type):

Fix type check
---
 package-lock.json                             |  86 +++++------
 package.json                                  |   2 +
 src/components/ButtonAddGoalOrChallange.vue   |   7 +-
 src/components/InteractiveSpare.vue           |  15 +-
 src/components/__tests__/HomeViewTest.spec.ts |  44 ++++--
 .../__tests__/InteractiveSpareTest.spec.ts    |  17 ++-
 src/types/goal.ts                             |  44 ++++++
 src/views/HomeView.vue                        | 134 ++++++++----------
 8 files changed, 195 insertions(+), 154 deletions(-)
 create mode 100644 src/types/goal.ts

diff --git a/package-lock.json b/package-lock.json
index f146b6a..e033404 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,8 @@
         "@types/animejs": "^3.1.12",
         "@types/jsdom": "^21.1.6",
         "@types/node": "^20.12.5",
+        "@typescript-eslint/eslint-plugin": "^7.7.0",
+        "@typescript-eslint/parser": "^7.7.0",
         "@vitejs/plugin-vue": "^5.0.4",
         "@vitest/coverage-v8": "^1.5.0",
         "@vue/eslint-config-prettier": "^9.0.0",
@@ -1218,16 +1220,16 @@
       }
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz",
-      "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz",
+      "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==",
       "dev": true,
       "dependencies": {
         "@eslint-community/regexpp": "^4.10.0",
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/type-utils": "7.6.0",
-        "@typescript-eslint/utils": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@typescript-eslint/scope-manager": "7.7.0",
+        "@typescript-eslint/type-utils": "7.7.0",
+        "@typescript-eslint/utils": "7.7.0",
+        "@typescript-eslint/visitor-keys": "7.7.0",
         "debug": "^4.3.4",
         "graphemer": "^1.4.0",
         "ignore": "^5.3.1",
@@ -1253,15 +1255,15 @@
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz",
-      "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz",
+      "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/typescript-estree": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@typescript-eslint/scope-manager": "7.7.0",
+        "@typescript-eslint/types": "7.7.0",
+        "@typescript-eslint/typescript-estree": "7.7.0",
+        "@typescript-eslint/visitor-keys": "7.7.0",
         "debug": "^4.3.4"
       },
       "engines": {
@@ -1281,13 +1283,13 @@
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz",
-      "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz",
+      "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0"
+        "@typescript-eslint/types": "7.7.0",
+        "@typescript-eslint/visitor-keys": "7.7.0"
       },
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -1298,13 +1300,13 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz",
-      "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz",
+      "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "7.6.0",
-        "@typescript-eslint/utils": "7.6.0",
+        "@typescript-eslint/typescript-estree": "7.7.0",
+        "@typescript-eslint/utils": "7.7.0",
         "debug": "^4.3.4",
         "ts-api-utils": "^1.3.0"
       },
@@ -1325,9 +1327,9 @@
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz",
-      "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz",
+      "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -1338,13 +1340,13 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz",
-      "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz",
+      "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@typescript-eslint/types": "7.7.0",
+        "@typescript-eslint/visitor-keys": "7.7.0",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
@@ -1366,17 +1368,17 @@
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz",
-      "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz",
+      "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
         "@types/json-schema": "^7.0.15",
         "@types/semver": "^7.5.8",
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/typescript-estree": "7.6.0",
+        "@typescript-eslint/scope-manager": "7.7.0",
+        "@typescript-eslint/types": "7.7.0",
+        "@typescript-eslint/typescript-estree": "7.7.0",
         "semver": "^7.6.0"
       },
       "engines": {
@@ -1391,12 +1393,12 @@
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz",
-      "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz",
+      "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
+        "@typescript-eslint/types": "7.7.0",
         "eslint-visitor-keys": "^3.4.3"
       },
       "engines": {
diff --git a/package.json b/package.json
index f15dbce..53e12f2 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,8 @@
     "@types/animejs": "^3.1.12",
     "@types/jsdom": "^21.1.6",
     "@types/node": "^20.12.5",
+    "@typescript-eslint/eslint-plugin": "^7.7.0",
+    "@typescript-eslint/parser": "^7.7.0",
     "@vitejs/plugin-vue": "^5.0.4",
     "@vitest/coverage-v8": "^1.5.0",
     "@vue/eslint-config-prettier": "^9.0.0",
diff --git a/src/components/ButtonAddGoalOrChallange.vue b/src/components/ButtonAddGoalOrChallange.vue
index 5ca7b20..820233b 100644
--- a/src/components/ButtonAddGoalOrChallange.vue
+++ b/src/components/ButtonAddGoalOrChallange.vue
@@ -1,6 +1,6 @@
 <template>
     <button
-        class="w-full max-w-60 max-h-12 bg-green-500 text-white font-bold py-2 rounded-full flex items-center justify-start pl-4 pl-4 space-x-2 hover:bg-green-600 drop-shadow-lg focus:outline-none focus:ring-2 focus:ring-green-700 focus:ring-opacity-50 shadow-md transition duration-300 ease-in-out text-xs md:text-sm lg:text-base"
+        class="w-full max-w-60 max-h-12 bg-green-500 text-white font-bold py-2 rounded-full flex items-center justify-start pl-4 space-x-2 hover:bg-green-600 drop-shadow-lg focus:outline-none focus:ring-2 focus:ring-green-700 focus:ring-opacity-50 shadow-md transition duration-300 ease-in-out text-xs md:text-sm lg:text-base"
     >
         <svg
             xmlns="http://www.w3.org/2000/svg"
@@ -24,10 +24,7 @@
 import { defineProps, ref } from 'vue'
 
 interface Props {
-    buttonText: {
-        type: String
-        required: true
-    }
+    buttonText: string
 }
 
 const props = defineProps<Props>()
diff --git a/src/components/InteractiveSpare.vue b/src/components/InteractiveSpare.vue
index 5002069..5d50f1e 100644
--- a/src/components/InteractiveSpare.vue
+++ b/src/components/InteractiveSpare.vue
@@ -25,21 +25,14 @@ import { ref, defineProps, computed } from 'vue'
 import spareImageSrc from '@/assets/spare.png'
 
 interface Props {
-    speech?: Array<String>
-    // direction string should be either 'left' or 'right'
-    direction: {
-        type: String
-        required: true
-    }
-    pngSize: {
-        type: Number
-        default: 20
-    }
+    speech?: string[] // Using TypeScript's type for speech as an array of strings
+    direction: 'left' | 'right' // This restricts direction to either 'left' or 'right'
+    pngSize: number // Just declaring the type directly since it's simple
 }
 
 const props = defineProps<Props>()
 
-const speech = ref<string[]>(props.speech || [])
+const speech = ref<String[]>(props.speech || [])
 
 const currentSpeechIndex = ref(0)
 const currentSpeech = computed(() => speech.value[currentSpeechIndex.value])
diff --git a/src/components/__tests__/HomeViewTest.spec.ts b/src/components/__tests__/HomeViewTest.spec.ts
index d887807..a241e46 100644
--- a/src/components/__tests__/HomeViewTest.spec.ts
+++ b/src/components/__tests__/HomeViewTest.spec.ts
@@ -2,27 +2,37 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'
 import { mount } from '@vue/test-utils'
 import HomeView from '@/views/HomeView.vue' // Adjust the import path as needed.
 import anime from 'animejs'
+import type {Challenge} from "../../types/challenge";
 
 // Setup localStorage mock
 const localStorageMock = (function () {
-    let store = {}
+    let store = {} as { [key: string]: string };
     return {
-        getItem: vi.fn((key) => store[key] || null),
-        setItem: vi.fn((key, value) => {
-            store[key] = value.toString()
+        getItem: vi.fn((key: string) => store[key] || null),
+        setItem: vi.fn((key: string, value: any) => {
+            store[key] = value.toString();
         }),
         clear: vi.fn(() => {
-            store = {}
+            store = {};
         }),
-        removeItem: vi.fn((key) => {
-            delete store[key]
+        removeItem: vi.fn((key: string) => {
+            delete store[key];
+        }),
+        get length() {
+            return Object.keys(store).length;
+        },
+        key: vi.fn((index: number): string | null => {
+            const keys = Object.keys(store);
+            return keys[index] || null;
         }),
         __store: store // expose store for assertions
-    }
-})()
+    };
+})();
+Object.defineProperty(global, 'localStorage', {
+    value: localStorageMock,
+    writable: true
+});
 
-// Apply the mock
-global.localStorage = localStorageMock
 
 // Mocking animejs with a default export
 vi.mock('animejs', () => ({
@@ -35,7 +45,7 @@ vi.mock('animejs', () => ({
 }))
 
 describe('HomeView', () => {
-    let wrapper
+    let wrapper: any
 
     beforeEach(() => {
         // Clear localStorage and reset all mocks
@@ -58,16 +68,20 @@ describe('HomeView', () => {
     })
 
     it('handles incrementSaved correctly', async () => {
-        const challenge = { title: 'Kaffe', saved: 90, target: 100, completion: 90 }
+        const challenge: Challenge = {
+            createdOn: new Date(),
+            description: "",
+            title: 'Kaffe', saved: 90, target: 100, completion: 90 }
         wrapper.vm.incrementSaved(challenge)
         expect(challenge.saved).toBe(100)
         expect(challenge.completion).toBe(100)
     })
 
     it('animates on challenge completion', async () => {
-        const challenge = {
+        const challenge: Challenge = {
+            createdOn: new Date(), description: "",
             title: 'Mat og Drikke',
-            challengeType: 'SNACKS',
+            type: 'SNACKS',
             saved: 100,
             target: 100,
             completion: 100
diff --git a/src/components/__tests__/InteractiveSpareTest.spec.ts b/src/components/__tests__/InteractiveSpareTest.spec.ts
index 947a5ae..5a523d9 100644
--- a/src/components/__tests__/InteractiveSpareTest.spec.ts
+++ b/src/components/__tests__/InteractiveSpareTest.spec.ts
@@ -4,10 +4,11 @@ import SpeechBubbleComponent from '@/components/InteractiveSpare.vue' // Adjust
 
 describe('SpeechBubbleComponent', () => {
     it('renders correctly with default props', () => {
-        const wrapper = mount(SpeechBubbleComponent, {
+        const wrapper:any = mount(SpeechBubbleComponent, {
             props: {
                 direction: 'left',
-                speech: ['Hello', 'World']
+                speech: ['Hello', 'World'],
+                pngSize: 100
             }
         })
         expect(wrapper.exists()).toBeTruthy()
@@ -17,14 +18,16 @@ describe('SpeechBubbleComponent', () => {
         const wrapper = mount(SpeechBubbleComponent, {
             props: {
                 direction: 'right',
-                speech: ['Hello', 'World']
+                speech: ['Hello', 'World'],
+                pngSize:100
             }
         })
         expect(wrapper.find('div').classes()).toContain('flex-row')
         const wrapperReverse = mount(SpeechBubbleComponent, {
             props: {
                 direction: 'left',
-                speech: ['Hello', 'World']
+                speech: ['Hello', 'World'],
+                pngSize: 100,
             }
         })
         expect(wrapperReverse.find('div').classes()).toContain('flex-row-reverse')
@@ -34,7 +37,8 @@ describe('SpeechBubbleComponent', () => {
         const wrapper = mount(SpeechBubbleComponent, {
             props: {
                 direction: 'right',
-                speech: ['Hello', 'World']
+                speech: ['Hello', 'World'],
+                pngSize:100,
             }
         })
         expect(wrapper.find('img').classes()).toContain('scale-x-[-1]')
@@ -44,7 +48,8 @@ describe('SpeechBubbleComponent', () => {
         const wrapper = mount(SpeechBubbleComponent, {
             props: {
                 direction: 'left',
-                speech: ['First speech', 'Second speech']
+                speech: ['First speech', 'Second speech'],
+                pngSize: 100
             }
         })
         expect(wrapper.find('span').text()).toBe('First speech')
diff --git a/src/types/goal.ts b/src/types/goal.ts
new file mode 100644
index 0000000..f1bbd1b
--- /dev/null
+++ b/src/types/goal.ts
@@ -0,0 +1,44 @@
+export interface Goal {
+  /** The unique identifier for the Goal, must not be null. */
+  id: number;
+
+  /**
+   * The title of the Goal, must not be null, empty, or only whitespace.
+   */
+  title: string;
+
+  /**
+   * The amount saved towards the Goal so far. Must not be null and must be zero or positive.
+   */
+  saved: number;
+
+  /**
+   * The target amount to achieve for the Goal. Must not be null and must be positive.
+   */
+  target: number;
+
+  /**
+   * Completion percentage of the Goal. Must not be null and must be zero or positive.
+   */
+  completion: number;
+
+  /**
+   * A description of the Goal, must not be null, empty, or only whitespace.
+   */
+  description: string;
+
+  /**
+   * The priority of the Goal, must not be null and must be zero or positive.
+   */
+  priority: number;
+
+  /**
+   * The date and time when the Goal was created. Must be a date in the past.
+   */
+  createdOn: Date;
+
+  /**
+   * The date and time by which the Goal is due. Must be a date in the future.
+   */
+  due: Date;
+}
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 5913a09..89f6cf4 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -51,7 +51,7 @@
                                 />
                                 <!-- Progress Bar, if the challenge is not complete -->
                                 <div
-                                    v-if="challenge.completion < 100"
+                                    v-if="challenge.completion !=undefined &&  challenge.completion< 100"
                                     class="flex-grow w-full mt-2"
                                 >
                                     <div class="flex flex-row">
@@ -88,8 +88,9 @@
                                 >
                             </div>
                             <!-- Check Icon -->
-                            <div v-if="challenge.completion >= 100" class="max-w-16 max-h-16">
-                                <img src="@/assets/completed.png" alt="" />️
+                          <div v-if="challenge.completion !== undefined && challenge.completion >= 100" class="max-w-16 max-h-16">
+
+                          <img src="@/assets/completed.png" alt="" />️
                             </div>
                             <div v-else class="max-w-16 max-h-16">
                                 <img src="@/assets/pending.png" alt="" />️
@@ -137,21 +138,21 @@
             <img src="@/assets/finishLine.png" class="w-1/2 max-h-4 mx-auto" alt="Finish Line" />
 
             <!-- Goal -->
-            <div v-if="currentGoal" class="flex flex-row gap-24 m-t-2 pt-6 mx-auto">
+            <div v-if="goal" class="flex flex-row gap-24 m-t-2 pt-6 mx-auto">
                 <div class="flex flex-col items-start">
                     <img
-                        :src="getGoalIcon(currentGoal)"
+                        :src="getGoalIcon(goal)"
                         class="w-12 h-12 mx-auto"
-                        :alt="currentGoal.title"
+                        :alt="goal.title"
                     />
-                    <div class="text-lg font-bold">{{ currentGoal.title }}</div>
+                    <div class="text-lg font-bold">{{ goal.title }}</div>
                 </div>
                 <div class="flex flex-col items-end">
                     <div @click="goToEditGoal" class="cursor-pointer">
                         <h3 class="text-blue-500 text-base">Endre mål</h3>
                     </div>
                     <div ref="targetRef" class="bg-yellow-400 px-4 py-1 rounded-full text-black">
-                        {{ currentGoal.saved }}kr / {{ currentGoal.target }}kr
+                        {{ goal.saved }}kr / {{ goal.target }}kr
                     </div>
                 </div>
             </div>
@@ -168,11 +169,13 @@
 </template>
 
 <script setup lang="ts">
-import { computed, nextTick, onMounted, ref, watch } from 'vue'
+import { nextTick, onMounted, ref, watch } from 'vue'
 import anime from 'animejs'
 import InteractiveSpare from '@/components/InteractiveSpare.vue'
 import ButtonAddGoalOrChallenge from '@/components/ButtonAddGoalOrChallange.vue'
 import router from '@/router'
+import type {Challenge} from "@/types/challenge";
+import type {Goal} from "@/types/goal"
 
 // Define your speech array
 const speechArray = [
@@ -188,66 +191,44 @@ const iconRef = ref<HTMLElement | null>(null)
 const containerRef = ref<HTMLElement | null>(null)
 const targetRef = ref<HTMLElement | null>(null)
 
-const goals = ref([
-    {
-        title: 'Gaming',
-        saved: 280,
-        target: 100,
-        description: 'Gaming console',
-        priority: 1,
-        completion: 0
-    }
-    // Other goals...
-])
-const challenges = ref([
-    {
-        title: 'Kaffe',
-        challengeType: 'COFFEE',
-        saved: 100,
-        target: 100,
-        description: 'Morning boost',
-        completion: 100
-    },
-    {
-        title: 'Mat og Drikke',
-        challengeType: 'SNACKS',
-        saved: 80,
-        target: 100,
-        description: 'Morning boost',
-        completion: 80
-    },
-    {
-        title: 'Gaming',
-        challengeType: 'GAMING',
-        saved: 20,
-        target: 100,
-        description: 'Morning boost',
-        completion: 20
-    },
-    {
-        title: 'Kaffe',
-        challengeType: 'COFFEE',
-        saved: 90,
-        target: 100,
-        description: 'Morning boost',
-        completion: 90
-    },
-    {
-        title: 'Mat og Drikke',
-        challengeType: 'SNACKS',
-        saved: 80,
-        target: 100,
-        description: 'Morning boost',
-        completion: 80
-    }
-    // Other challenges...
-])
 
-// Computed current goal
-const currentGoal = computed(() => {
-    // Logic to determine the current goal
-    return goals.value.find((goal) => goal.completion < 100)
-})
+const goal: Goal ={
+  id: 1,
+  title: "gaming",
+  saved: 200,
+  description: "none",
+  target: 400,
+  completion: 50,
+  priority: 0,
+  createdOn: new Date(),
+  due: new Date,
+}
+
+const challenge: Challenge = {
+  title: "Coffe",
+  saved: 1200.50,
+  target: 3000,
+  description: "Saving monthly for a year-end vacation to Bali",
+  createdOn: new Date('2023-01-01T00:00:00Z'),
+  dueDate: new Date('2023-12-31T23:59:59Z'),
+  type: "COFFE",
+  completion: 40,
+  completedOn: undefined // Not yet completed
+};
+const challenge1: Challenge = {
+  title: "Snacks",
+  saved: 200,
+  target: 400,
+  description: "Saving monthly for a year-end vacation to Bali",
+  createdOn: new Date('2023-01-01T00:00:00Z'),
+  dueDate: new Date('2023-12-31T23:59:59Z'),
+  type: "SNACKS",
+  completion: 50,
+  completedOn: undefined // Not yet completed
+};
+
+const challenges = ref([challenge, challenge1]);
+
 
 // AddSpareUtfordring
 function addSpareUtfordring() {
@@ -255,7 +236,7 @@ function addSpareUtfordring() {
 }
 
 // Increment saved amount
-function incrementSaved(challenge) {
+function incrementSaved(challenge: Challenge) {
     challenge.saved += 10
     if (challenge.saved >= challenge.target) {
         challenge.completion = 100
@@ -279,13 +260,13 @@ const loadAnimatedStates = () => {
     animatedChallenges.value = animated ? new Set(JSON.parse(animated)) : new Set()
 }
 
-const saveAnimatedState = (title) => {
+const saveAnimatedState = (title: String) => {
     animatedChallenges.value.add(title)
     localStorage.setItem('animatedChallenges', JSON.stringify([...animatedChallenges.value]))
 }
 
-const animateChallenge = (challenge) => {
-    if (challenge.completion >= 100 && !animatedChallenges.value.has(challenge.title)) {
+const animateChallenge = (challenge: Challenge) => {
+    if (challenge.completion !== undefined && challenge.completion >= 100 && !animatedChallenges.value.has(challenge.title)) {
         console.log('Animating for:', challenge.title)
         recalculateAndAnimate() // Assumes this function triggers the actual animation
         saveAnimatedState(challenge.title)
@@ -383,11 +364,14 @@ function animateIcon() {
 }
 
 // Helper methods to get icons
-function getChallengeIcon(challenge) {
-    return `src/assets/${challenge.challengeType.toLowerCase()}.png`
+function getChallengeIcon(challenge: Challenge): string {
+  if (challenge.type === undefined) {
+    throw new Error("Challenge type is undefined");
+  }
+  return `src/assets/${challenge.type.toLowerCase()}.png`
 }
 
-function getGoalIcon(goal) {
+function getGoalIcon(goal: Goal): string {
     return `src/assets/${goal.title.toLowerCase()}.png`
 }
 function getPigStepsIcon() {
-- 
GitLab