diff --git a/package-lock.json b/package-lock.json
index 4d84981ffc0ea20655b4480a4eaf37d1585b272a..6545ddf362172e977f30659857ffaa00ac1d6809 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
         "jwt-decode": "^3.1.2",
         "pinia": "^2.0.35",
         "pinia-plugin-persistedstate": "^3.1.0",
+        "sass": "^1.62.0",
         "vue": "^3.2.45",
         "vue-router": "^4.1.6"
       },
@@ -1330,9 +1331,6 @@
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
       "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "normalize-path": "^3.0.0",
         "picomatch": "^2.0.4"
@@ -1539,9 +1537,6 @@
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
       "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "engines": {
         "node": ">=8"
       }
@@ -1571,9 +1566,6 @@
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
       "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "fill-range": "^7.0.1"
       },
@@ -1831,15 +1823,12 @@
       "version": "3.5.3",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
       "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
-      "dev": true,
       "funding": [
         {
           "type": "individual",
           "url": "https://paulmillr.com/funding/"
         }
       ],
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "anymatch": "~3.1.2",
         "braces": "~3.0.2",
@@ -2742,9 +2731,6 @@
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
       "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "to-regex-range": "^5.0.1"
       },
@@ -2851,7 +2837,6 @@
       "version": "2.3.2",
       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
       "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-      "dev": true,
       "hasInstallScript": true,
       "optional": true,
       "os": [
@@ -2995,9 +2980,6 @@
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
       "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "is-glob": "^4.0.1"
       },
@@ -3279,10 +3261,7 @@
     "node_modules/immutable": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
-      "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
-      "dev": true,
-      "optional": true,
-      "peer": true
+      "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg=="
     },
     "node_modules/imurmurhash": {
       "version": "0.1.4",
@@ -3349,9 +3328,6 @@
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
       "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "binary-extensions": "^2.0.0"
       },
@@ -3387,9 +3363,6 @@
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
       "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "engines": {
         "node": ">=0.10.0"
       }
@@ -3407,9 +3380,6 @@
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
       "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "is-extglob": "^2.1.1"
       },
@@ -3443,9 +3413,6 @@
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
       "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "engines": {
         "node": ">=0.12.0"
       }
@@ -4644,9 +4611,6 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
       "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "engines": {
         "node": ">=0.10.0"
       }
@@ -4893,9 +4857,6 @@
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
       "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "engines": {
         "node": ">=8.6"
       },
@@ -5236,9 +5197,6 @@
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
       "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "picomatch": "^2.2.1"
       },
@@ -5440,9 +5398,6 @@
       "version": "1.62.0",
       "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz",
       "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "chokidar": ">=3.0.0 <4.0.0",
         "immutable": "^4.0.0",
@@ -6237,9 +6192,6 @@
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
       "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-      "dev": true,
-      "optional": true,
-      "peer": true,
       "dependencies": {
         "is-number": "^7.0.0"
       },
diff --git a/package.json b/package.json
index 07c86518e9c5cca96054dc4a5190ccb9e2a4807d..3763423fcce1bfff961a04258f6ad2607f61d14a 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
     "jwt-decode": "^3.1.2",
     "pinia": "^2.0.35",
     "pinia-plugin-persistedstate": "^3.1.0",
+    "sass": "^1.62.0",
     "vue": "^3.2.45",
     "vue-router": "^4.1.6"
   },
diff --git a/src/App.vue b/src/App.vue
index 1358b7e3e414d1466e1288bbfed8cdcabdafb3fc..d9988e4a1832293fff956f9976fd7782c97b76ec 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,19 +1,15 @@
 <script setup>
-import { RouterLink, RouterView } from 'vue-router'
-import Navbar from "@/components/Navbar.vue";
-
+  import { RouterView } from 'vue-router'
+  import Navbar from "@/components/Navbar.vue";
 
 </script>
 
 <template>
-    <Navbar></Navbar>
-    <body>
-    <RouterView />
-    </body>
-
+  <Navbar v-if="$route.name !== 'login' && $route.name !== 'selectProfile'" />
+  <RouterView />
 </template>
 
-<style scoped>
+<style lang=scss scoped>
 header {
   line-height: 1.5;
   max-height: 100vh;
@@ -52,7 +48,7 @@ nav a:first-of-type {
   border: 0;
 }
 
-@media (min-width: 1024px) {
+@media (min-width: base.$desktop-min) {
   header {
     display: flex;
     place-items: center;
diff --git a/src/assets/main.css b/src/assets/main.css
index 2d624bc8d97520029335b1976f166e1a46c461b1..c417db8ebe95a78dcdf6bb8c362b0a6cb4dc518b 100644
--- a/src/assets/main.css
+++ b/src/assets/main.css
@@ -25,10 +25,14 @@ a,
   body {
     display: flex;
     place-items: center;
+    justify-content: center;
+    align-items: center;
   }
 
   #app {
     display: grid;
-    padding: 0 2rem;
+    padding: 2rem 2rem;
+
+    
   }
 }
diff --git a/src/components/FridgeItem.vue b/src/components/FridgeItem.vue
index 46f03ed381f06adc678daada431ffab509f8d376..a23603f03c0e965368cda1ebea78fdf8865bb36f 100644
--- a/src/components/FridgeItem.vue
+++ b/src/components/FridgeItem.vue
@@ -12,7 +12,6 @@
     </div>
 
 </div>
-    <hr>
 </template>
 
 <script>
@@ -110,13 +109,17 @@ export default {
 #item {
     background-color: base.$white;
     color: black;
-    qborder-radius: 10px;
     padding: 1em;
     padding-left: 2em;
     padding-right:2em;
     display:flex;
     align-items: center;
     justify-content: space-between;
+    border-bottom: solid 1px base.$grey;
+}
+
+#item:last-child {
+    border-bottom: none;
 }
 
 #fridgeItemName {
diff --git a/src/components/GroceryOffers.vue b/src/components/GroceryOffers.vue
index c970238dc31d8463b342f7f404db08c9988d6014..cbc668647d78b1a3fae6125cd7f1c68dceb2c945 100644
--- a/src/components/GroceryOffers.vue
+++ b/src/components/GroceryOffers.vue
@@ -1,6 +1,6 @@
 <template>
     <div>
-        <h2>Tilbudaviser</h2>
+        <h2>Lenker til tilbudsaviser</h2>
     </div>
 
   <div id="list">
diff --git a/src/components/ItemSearch.vue b/src/components/ItemSearch.vue
index cfa6e6c5d551e11c2a17317003dafdd9055ef909..10805ce1e1e4a2edb9f9eeda83e3e4b11650ac73 100644
--- a/src/components/ItemSearch.vue
+++ b/src/components/ItemSearch.vue
@@ -1,9 +1,9 @@
 <template>
     <div v-if="showSearch" id="wrapper">
-        <h3>SØK ETTER VARE</h3>
+        <h3>Søk etter vare</h3>
         <div id="searchBoxDiv">
             <input type="text" id="searchBox" v-model="itemSearch">
-            <button @click="search">Søk</button>
+            <button id="search-button" @click="search">Søk</button>
         </div>
 
         <p>Resultater: ({{searchResult.length}})</p>
@@ -12,9 +12,10 @@
             <option v-for ="item in searchResult" :value="item" :key="item.ean">{{item.name}} ({{item.amount.quantity}}{{item.amount.unit}})</option>
         </select>
         <p>Antall varer: <span v-if="numOfItemsToAdd>1 && selectedItem!=null">(totalt: {{this.totalNumOfItems}} {{selectedItem.amount.unit}})</span></p>
-        <input type="number" min='1' v-model="numOfItemsToAdd"><br>
+        <input id="items-input" type="number" min='1' v-model="numOfItemsToAdd"><br>
 
-        <button id = "addToFridgeBtn" @click="addToFridge">Legg i kjøleskap</button>
+        <button v-if="addsToFridge" id = "addToFridgeBtn" @click="addToFridge">Legg i kjøleskap</button>
+        <button v-else id = "addToFridgeBtn" @click="addToShoppingList">Legg i handleliste</button>
 
 
     </div>
@@ -22,10 +23,17 @@
 
 <script>
 import {API} from "@/util/API";
+import { useAuthStore } from "@/stores/authStore.js";
 
 
 export default {
     name: "itemSearch",
+    props: {
+        addsToFridge: {
+            type: Boolean,
+            default: false
+        }
+    },
     data(){
         return{
             itemSearch:'',
@@ -55,7 +63,25 @@ export default {
                         {
                             "quantity": this.selectedItem.amount.quantity*num,
                             "unit": this.selectedItem.amount.unit}}
-            ).then(() => this.$emit('itemsAdded',this.selectedItem)).catch((_)=> console.log("No items were added to the fridge"))
+            ).then((_) => {
+                this.$emit('itemsAdded',this.selectedItem)
+            }).catch((_)=> console.log("No items were added to the fridge"))
+        },
+        async addToShoppingList() {
+            const num = this.numOfItemsToAdd;
+            const authStore = useAuthStore();
+
+            if (authStore.profile.restricted) {
+                await API.addSuggestion(this.selectedItem.id, num)
+                    .then((ingredient) => {this.$emit('itemsAdded', ingredient)})
+                    .catch(err => console.log(err));
+            } else {
+                await API.addItemToShoppingList(this.selectedItem.id, num)
+                    .then((ingredient) => {
+                        console.log(ingredient)
+                        this.$emit('itemsAdded', ingredient)
+                    }).catch(err => console.log(err));
+            }
         }
     }
 }
@@ -74,6 +100,14 @@ select {
 
 }
 
+#items-input {
+    margin-bottom: 1em;
+}
+
+#search-button {
+    margin-left: 0.5em;
+}
+
 #searchBoxDiv {
     display:flex;
     width:100%;
@@ -91,14 +125,17 @@ button {
     padding: .5em;
     background-color: base.$light-green;
     border-radius: 5%;
-
+    background-color: base.$green;
+    color: white;
+    font-weight: bold;
     border: 1px solid base.$green;
+    height: 30px;
 
 }
 
 button:hover {
     border: 1px solid base.$grey;
-    background-color: base.$light-green-hover;
+    background-color: base.$light-green;
     cursor: pointer;
 
 
diff --git a/src/components/Navbar.vue b/src/components/Navbar.vue
index b3f9d0433378866d59f82cebe2d65d336405d630..10d7e10ab9c318905ccc11056c64963d6d86ca50 100644
--- a/src/components/Navbar.vue
+++ b/src/components/Navbar.vue
@@ -18,7 +18,7 @@
                     </RouterLink>
                 </li>
                 <li>
-                    <RouterLink :to="'/'" :aria-label="'link to shopping list'">
+                    <RouterLink :to="'/shoppingList'" :aria-label="'link to shopping list'">
                       <Icon icon="material-symbols:event-list-outline" :color="iconColor" :style="{ fontSize: iconSize }" />
                     </RouterLink>
                 </li>
diff --git a/src/components/ShoppingListItem.vue b/src/components/ShoppingListItem.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e69e730e4f3910a5c67711a2320c95eca2a82b84
--- /dev/null
+++ b/src/components/ShoppingListItem.vue
@@ -0,0 +1,166 @@
+<template>
+    <div class="content">
+        <div class="item">
+            <div class="check">
+                <input v-model="isChecked" @click="this.updateChecked()" class="checkbox" type="checkbox">
+            </div>
+
+            <p> {{ this.index }}</p>
+
+            <div class="item-label">
+                <label for="checkbox" class="checkbox-label">{{ this.amount }}x {{ this.itemName }}</label>
+            </div>
+        </div>
+     
+        <div class="delete">
+            <img @click="deleteItem" src="./icons/trash.svg" alt="delete">
+        </div>
+    </div>
+</template>
+
+<script>
+    let uuid = 0;
+
+    export default {
+        beforeCreate() {
+            this.uuid = uuid.toString();
+            console.log(this.itemName + " + " + this.uuid)
+
+            uuid += 1;
+        },
+
+
+        name: "ShoppingListItem",
+        props: {
+            itemName: {
+                type: String,
+                default: "",
+                required: true
+            },
+            amount: {
+                type: Number,
+                default: 1,
+                required: false
+            },
+            propValue: {
+                type: Boolean,
+                default: false,
+                required: false
+            },
+            index: {
+                type: Number,
+                required: true
+
+            }
+        },
+        data() {
+            return {
+                isChecked: this.propValue,
+                uuid: ""
+            }
+        },
+        methods: {
+            updateChecked() {
+                this.$emit('updateItem', {id: this.uuid, isChecked: !this.isChecked})
+            }
+        }
+
+
+    }
+</script>
+
+<style lang="scss" scoped>
+
+    .content {
+        display: flex;
+        flex-direction: row;
+        gap: 10px;
+        justify-content: space-between;
+        background-color: white;
+        padding: 5px;
+        border-top-right-radius: 10px;
+        border-top-left-radius: 10px;
+        //border-bottom: base.$grey solid 1px;
+
+    }
+
+    .content:not(:first-child) {
+        border-radius: 0px;
+    }
+
+    .content:last-child {
+        border-radius: 0px;
+        border-bottom-left-radius: 10px;
+        border-bottom-right-radius: 10px;
+    }
+
+    .content:not(:last-child)::after {
+        content: '';
+        height: 1px; /* this works like a border-width */
+        width: 70%; /* percentage of border shown */
+        background: base.$grey; /* the color of border */
+        position: absolute;
+        bottom: 0;
+        margin: 0 auto; left: 0; right: 0; /* horizontal centering */
+    }
+
+    .item {
+        display: flex;
+        flex-direction: row;
+        gap: 10px;
+    }
+
+    input[type="checkbox"] {
+        -webkit-appearance: none;
+        -moz-appearance: none;
+        appearance: none;
+        width: 35px;
+        height: 35px;
+        border-radius: 50%;
+        border: 2px solid #ccc;
+        
+    }
+
+    input[type="checkbox"]:checked {
+        background-color: base.$light-green;
+    }
+
+    input[type="checkbox"]:checked:after {
+        content: "\2713"; /* Unicode code for checkmark symbol */
+        font-size: 24px;
+        font-weight: bold;
+        color: white;
+        text-align: center;
+        line-height: 35px;
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%, -50%);
+    }
+
+    label {
+        font-size: 20px;
+    }
+
+    img {
+        width: 30px;
+        height: 30px;
+        padding: 5px;
+
+        max-height: 100%;
+        max-width: 100%;
+        
+    
+    }
+
+    .check {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+    }
+
+    .delete {
+        align-self: flex-end;
+    }
+
+</style>
\ No newline at end of file
diff --git a/src/components/__tests__/ShoppingListItem.spec.js b/src/components/__tests__/ShoppingListItem.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..8d61f2b68f7ed420666faf8e071de41c9191fd22
--- /dev/null
+++ b/src/components/__tests__/ShoppingListItem.spec.js
@@ -0,0 +1,23 @@
+import { describe, it, expect, vi} from 'vitest'
+import { createTestingPinia } from '@pinia/testing'
+import { mount } from '@vue/test-utils'
+import ShoppingListItem from "@/components/ShoppingListItem.vue";
+
+
+
+describe('ShoppingListItem', () => {
+    it('mounts correctly', () => {
+        const wrapper = mount(ShoppingListItem, {
+            global: {
+              plugins: [createTestingPinia({
+                createSpy: vi.fn,
+              })],
+            },
+            props: {
+              itemName: "Test",
+              amount: 99
+            }
+          })
+        expect(wrapper.text()).toMatch("99x Test")
+    })
+})
diff --git a/src/components/icons/tips.png b/src/components/icons/tips.png
new file mode 100644
index 0000000000000000000000000000000000000000..7547b26b1bcbb2f138729714bd68dd5b20c5be29
Binary files /dev/null and b/src/components/icons/tips.png differ
diff --git a/src/components/icons/trash.svg b/src/components/icons/trash.svg
new file mode 100644
index 0000000000000000000000000000000000000000..d6a7d41dcee741cd4596a2738a0e4fa5b7b70440
--- /dev/null
+++ b/src/components/icons/trash.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" id="Outline" viewBox="0 0 24 24" width="512" height="512"><path d="M21,4H17.9A5.009,5.009,0,0,0,13,0H11A5.009,5.009,0,0,0,6.1,4H3A1,1,0,0,0,3,6H4V19a5.006,5.006,0,0,0,5,5h6a5.006,5.006,0,0,0,5-5V6h1a1,1,0,0,0,0-2ZM11,2h2a3.006,3.006,0,0,1,2.829,2H8.171A3.006,3.006,0,0,1,11,2Zm7,17a3,3,0,0,1-3,3H9a3,3,0,0,1-3-3V6H18Z"/><path d="M10,18a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,10,18Z"/><path d="M14,18a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,14,18Z"/></svg>
diff --git a/src/router/index.js b/src/router/index.js
index 5ebfef204d1472a8a26f5a4be3f7739a4256cd11..aa8efdeb78b72d4e113c4613dbd546c9c8632f8a 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -6,9 +6,11 @@ import LoginView from '../views/LoginView.vue'
 import SelectProfileView from '../views/SelectProfileView.vue'
 import ProfileCreationView from '../views/ProfileCreationView.vue'
 import RegisterAccountView from '../views/RegisterAccountView.vue'
-
+import PinCodeView from "@/views/PinCodeView.vue";
 import FridgeView from "@/views/FridgeView.vue";
+import RecipeView from "@/views/RecipeView.vue";
 
+import ShoppingListView from '../views/ShoppingListView.vue'
 
 const router = createRouter({
   history: createWebHistory(import.meta.env.BASE_URL),
@@ -37,11 +39,27 @@ const router = createRouter({
       path: '/registerAccount',
       name: 'registerAccount',
       component: RegisterAccountView
-    },{
+    },
+    {
+      path: '/pincode',
+      name: 'pincode',
+      component: PinCodeView
+    },
+    {
       path: '/myFridge',
       name: 'myFridge',
       component: FridgeView
     },
+    {
+      path: '/recipe/:id',
+      name: 'recipe',
+      component: RecipeView
+    },
+    {
+      path: '/shoppingList',
+      name: 'shoppingList',
+      component: ShoppingListView
+    },
     {
       path: '/profileSettings',
       name: 'profileSettings',
diff --git a/src/stores/authStore.js b/src/stores/authStore.js
index 1c7e561ca6628fa4b8d4275d22186cf98201afd0..db029beb454bad9b49dcfc0c1ac658915888f9fa 100644
--- a/src/stores/authStore.js
+++ b/src/stores/authStore.js
@@ -5,7 +5,9 @@ export const useAuthStore = defineStore("auth", {
       token: "",
       account: {},
       profile: {},
-      profiles: []
+      profiles: [],
+      items: {ingredientList: [], suggestionList: []},
+      fridgeItems: [],
     };
   },
   persist: {
@@ -32,6 +34,18 @@ export const useAuthStore = defineStore("auth", {
     setProfiles(profiles) {
       this.profiles = profiles;
     },
+    setItems(items) {
+      this.items = items;
+    },
+    setItem(item) {
+      this.items.push(item);
+    },
+    setFridge(fridgeItems){
+      this.fridgeItems = fridgeItems;
+    },
+    addItemToFridge(fridgeItem){
+      this.fridgeItems.push(fridgeItem);
+    },
     updateProfile(name, image, isRestricted){
       this.profile.name = name;
       this.profile.profileImageUrl = image;
diff --git a/src/style.scss b/src/style.scss
index 3142bce63de8907d0511e5f6fb2b243594c15834..9cc6bdcfdd7f3e718539c048fd98eaf01b6bffb0 100644
--- a/src/style.scss
+++ b/src/style.scss
@@ -3,6 +3,7 @@ $green: #00663C;
 $light-green: hsla(160, 100%, 37%, 1);
 $white:#FFFFFF;
 $grey:#D9D9D9;
+$light-grey: #F3F4F9;
 $red:#EE6D6D;
 $darkred: darkred;
 
@@ -10,8 +11,39 @@ $red-hover: darken( $red, 5% );
 $green-hover: darken( $green, 8% );
 $light-green-hover: darken( $light-green, 10% );
 $darkred-hover: darken(darkred, 10%);
+$indigo: #2c3e50;
 
-
-$desktop-min: 800px;
+$desktop-min: 1024px;
 $phone-min : 360px;
 
+.add-button {
+    border-radius: 50%;
+    border-style: none;
+    width: 70px;
+    height: 70px;
+    font-size: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: $light-green;
+    color: white;
+    transition: .25s ease-in-out;
+    line-height: 1;
+    padding: 0;
+}
+
+.add-button:hover {
+    background-color: $green;
+}
+
+.plus-sign:before {
+  content: '\FF0B';
+}
+.plus-sign {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  margin: 0;
+  height: 100%;
+}
\ No newline at end of file
diff --git a/src/util/API.js b/src/util/API.js
index c4653e1603597569628fd5224faa1b3db643fd09..48507b710f51989fa41da77523087c1abb8abe0f 100644
--- a/src/util/API.js
+++ b/src/util/API.js
@@ -5,129 +5,165 @@ import router from "@/router/index";
 
 export const API = {
 
-    /**
-     * API method to send a login request.
-     * If login succeeds, the logged in User and their token
-     * is saved to the Pinia AuthStore
-     *
-     * @param email email address of the user to log in as
-     * @param password password to log in with
-     * @returns a Result with whether the login attempt succeeded
-     */
-    login: async (request) => {
-        const authStore = useAuthStore();
-        let token;
-        authStore.logout(); //in case someone for some reason is logged in
-
-        return axios.post(
-            `${import.meta.env.VITE_BACKEND_URL}/login`,
-            request,
-          )
-            .then(async (response) => {
-              token = response.data;
-              const id = (jwt_decode(token)).id;
-
-              return API.getAccount(id, token)
-                .then((user) => {
-                  authStore.setAccount(user);
-                  authStore.setToken(token);
-                  API.getProfiles()
-                    .then(response => {authStore.setProfiles(response)})
-                    .catch(() => {throw new Error()})
-                  return;
-                })
-                .catch(() => {
-                  throw new Error();
-                });
-            })
-            .catch(() => {
-              throw new Error();
-            });
-        },
-
-
-    /**
-     * API method to get a account by their ID
-     * @param id ID number of the account to retrieve
-     * @returns A promise that resolves to a User if the API call succeeds,
-     * or is rejected if the API call fails
-     */
-    getAccount: async (id, token) => {
-        return axios.get(`${import.meta.env.VITE_BACKEND_URL}/account/${id}`, {
-            headers: { Authorization: `Bearer ${token}` },
-          })
-          .then((response) => {
-            return response.data;
+  /**
+   * API method to send a login request.
+   * If login succeeds, the logged in User and their token
+   * is saved to the Pinia AuthStore
+   *
+   * @param email email address of the user to log in as
+   * @param password password to log in with
+   * @returns a Result with whether the login attempt succeeded
+   */
+  login: async (request) => {
+    const authStore = useAuthStore();
+    let token;
+    authStore.logout(); //in case someone for some reason is logged in
+
+    return axios.post(
+      `${import.meta.env.VITE_BACKEND_URL}/login`,
+      request,
+    )
+      .then(async (response) => {
+        token = response.data;
+        const id = (jwt_decode(token)).id;
+
+        return API.getAccount(id, token)
+          .then((user) => {
+            authStore.setAccount(user);
+            authStore.setToken(token);
+            API.getProfiles()
+              .then(response => { authStore.setProfiles(response) })
+              .catch(() => { throw new Error() })
+            return;
           })
           .catch(() => {
-            throw new Error("Account not found or not accessible");
+            throw new Error();
           });
-      },
-
-    // Sends the user into the home page logged in as the profile they clicked on
-    selectProfile: async (id) => {
-        const authStore = useAuthStore()
-        return axios.get(`${import.meta.env.VITE_BACKEND_URL}/profile/${id}`, {
-            headers: { Authorization: `Bearer ${authStore.token}` },
-          })
-          .then((response) => {
-            authStore.setProfile(response.data)
-            router.push("/")
-
-          })
-          .catch(() => {
-            throw new Error("Profile not found or not accessible")
-          })
-
+      })
+      .catch(() => {
+        throw new Error();
+      });
+  },
+
+
+  /**
+   * API method to get a account by their ID
+   * @param id ID number of the account to retrieve
+   * @returns A promise that resolves to a User if the API call succeeds,
+   * or is rejected if the API call fails
+   */
+  getAccount: async (id, token) => {
+    return axios.get(`${import.meta.env.VITE_BACKEND_URL}/account/${id}`, {
+      headers: { Authorization: `Bearer ${token}` },
+    })
+      .then((response) => {
+        return response.data;
+      })
+      .catch(() => {
+        throw new Error("Account not found or not accessible");
+      });
+  },
 
-    },
 
-    /**
-     * Sends a request to create a new profile on the currently logged in account
-     *
-     * @typedef {{name: string, profileImageUrl: string, isRestricted: boolean}} ProfileType
-     * @param {ProfileType} profile
-     * @returns
+  /**
+     * Sends the user into the home page logged in as the profile specified
+     * @param id ID of the profile that the user will log in as
      */
-    addProfile: async (profile) => {
-      const authStore = useAuthStore();
-      if (!authStore.isLoggedIn) {
-          throw new Error();
-      }
+  selectProfile: async (id) => {
+    const authStore = useAuthStore()
+    return axios.get(`${import.meta.env.VITE_BACKEND_URL}/profile/${id}`, {
+      headers: { Authorization: `Bearer ${authStore.token}` },
+    })
+      .then((response) => {
+          authStore.setProfile(response.data)
+          if (!response.data.restricted) {
+              router.push('pincode')
+          } else {
+              router.push("/")
+          }
 
-      return axios.post(import.meta.env.VITE_BACKEND_URL + '/profile', {
-        headers: { Authorization: "Bearer " + authStore.token },
-        body: profile
       })
+      .catch(() => {
+        throw new Error("Profile not found or not accessible")
+      })
+  },
+
+  /**
+   * Upload profile image
+   *
+   * @param {Blob} image - the image file contents to upload. Must be a JPEG no bigger than 512kB
+   * @param {Number} profileId - the ID of the profile to upload this image to
+   * @returns {Promise<String>} A Promise that resolves to the URL of the uploaded image
+   */
+  uploadProfileImage: async (image, profileId) => {
+    const authStore = useAuthStore();
+
+    let fd = new FormData();
+    fd.append("file", image);
+    fd.append("profileId", profileId);
+
+    return axios.post(`${import.meta.env.VITE_BACKEND_URL}/img`, fd, {
+      headers: {
+        Authorization: `Bearer ${authStore.token}`,
+      }
+    })
+      .then((response) => {
+        return response.data;
+      })
+      .catch(() => {
+        throw new Error();
+      })
+  },
+
+  /**
+   * Sends a request to create a new profile on the currently logged in account
+   *
+   * @typedef {{name: string, id?: number, accountId?: number, profileImageUrl: string, isRestricted: boolean}} ProfileType
+   * @param {ProfileType} profile  - the partial data of profile to create
+   * @returns {Promise<ProfileType>} the full profile after saving, with id and account ID set
+   */
+  addProfile: async (profile) => {
+    const authStore = useAuthStore();
+    if (!authStore.isLoggedIn) {
+      throw new Error();
+    }
+
+    return axios.post(import.meta.env.VITE_BACKEND_URL + '/profile', profile,  {
+      headers: { Authorization: "Bearer " + authStore.token },
+    })
       .then((response) => {
         return response.data;
       }).catch(() => {
         throw new Error();
       })
-    },
+  },
 
-    // Returns all profiles to the logged in user
+    /**
+     * @returns all profiles to the logged in user
+     */
     getProfiles: async () => {
         const authStore = useAuthStore();
         if (!authStore.isLoggedIn) {
             throw new Error();
         }
 
-        return axios.get(import.meta.env.VITE_BACKEND_URL + '/profile', {
-            headers: { Authorization: "Bearer " + authStore.token },
-          },
-        )
-          .then(response => {
-            return response.data
-          }).catch(() => {
-            throw new Error();
-          });
+    return axios.get(import.meta.env.VITE_BACKEND_URL + '/profile', {
+      headers: { Authorization: "Bearer " + authStore.token },
     },
+    )
+      .then(response => {
+        return response.data
+      }).catch(() => {
+        throw new Error();
+      });
+  },
 
-    // Registers a new account and logs into it
+    /**
+     * Registers a new account and logs into it
+     * @param email the email of the new account
+     * @param password the password of the new account
+     */
     addAccount: async (request) => {
-        const authStore = useAuthStore();
-
         axios.post(import.meta.env.VITE_BACKEND_URL + '/account', request)
         .then(() => {
             API.login({email: request.email, password: request.password})
@@ -147,6 +183,7 @@ export const API = {
             headers: { Authorization: `Bearer ${authStore.token}` },
         })
             .then((response) => {
+                authStore.setFridge(response.data)
                 return response.data;
             }).catch(() => {
                 throw new Error("Could not fetch fridge items");
@@ -159,11 +196,11 @@ export const API = {
      * @returns {Promise<void>}
      */
     addToFridge: async(request) =>{
-
         const authStore = useAuthStore();
         axios.post(`${import.meta.env.VITE_BACKEND_URL}/fridge/items`, request,{
             headers: { Authorization: `Bearer ${authStore.token}` },
         }).then((response) => {
+            authStore.setFridge(response.data)
             return response.data;
         }).catch(()=> {
             throw new Error("Could not add item to fridge: ");
@@ -220,20 +257,137 @@ export const API = {
         })
     },
 
+    /**
+     * Getter for the shopping list of a logged in account
+     * @returns a promise that resolves to an array of Ingredient objects representing the shopping list, or an error if it fails
+     */
+    getShoppingList: async () => {
+      const authStore = useAuthStore();
+
+      return axios.get(import.meta.env.VITE_BACKEND_URL + '/shoppinglist',
+      {
+        headers: { Authorization: "Bearer " + authStore.token },
+      })
+      .then((response) => {
+        authStore.setItems(response.data)
+        return response.data
+      })
+      .catch(() => {throw new Error()})
+    },
+
 
-    //returns fridgeItem of specific id
-    getFridgeItem: async (id) =>{
-        const authStore = useAuthStore();
+    /**
+     * Adds an item to the logged in account's shopping list
+     * @param itemId the id of the item that will be added
+     * @param amount the amount of the specified item that will be added
+     */
+    addItemToShoppingList: async (itemId, amount) => {
+      const authStore = useAuthStore();
+      return axios.put(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/items/' + itemId + '/' + amount, "",
+      {
+        headers: { Authorization: "Bearer " + authStore.token }
+      },
+      )
+      .then(response => {
+        return response.data
+      })
+      .catch(err => {console.log(err)})
+    },
 
-        axios.get(`${import.meta.env.VITE_BACKEND_URL}/fridge/${id}`, {
-            headers: { Authorization: `Bearer ${authStore.token}` },
+    /**
+     * Deletes an ingredient(item with amount) from the logged in account's shopping list
+     * @param ingredientId the id of the ingredient that will be removed
+     */
+    deleteItemFromShoppingList: async (ingredientId) => {
+      const authStore = useAuthStore();
+      return axios.delete(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/items/' + ingredientId,
+      {
+        headers: {Authorization: "Bearer " + authStore.token }
+      })
+      .then(response => { return response.data; })
+      .catch(err => {console.log(err)})
+    },
+
+    /**
+     * Adds a suggestion to the logged in account's shopping list
+     * @param itemId the id of the item that will be suggested
+     * @param amount the amount of the specified item that will be suggested
+     */
+    addSuggestion: async (itemId, amount) => {
+      const authStore = useAuthStore();
+      return axios.put(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/suggestions/' + itemId + '/' + amount, "",
+      {
+        headers: { Authorization: "Bearer " + authStore.token }
+      })
+      .then(response => { return response.data; })
+      .catch(err => {console.log(err)})
+    },
+
+
+    /**
+     * Accepts a suggestion and adds it to the shopping list, removing it from the suggestions list
+     * @param id the id of the ingredient that will be added to the list
+     */
+    acceptSuggestion: async (id) => {
+      const authStore = useAuthStore();
+      return axios.put(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/suggestions/accept/' + id, "",
+      {
+        headers: { Authorization: "Bearer " + authStore.token }
+      })
+      .then(response => { return response.data; })
+      .catch(err => {console.log(err)})
+    },
+
+     /**
+     * Declines a suggestion and removes it from the suggestions list
+     * @param id the id of the ingredient that will be declined
+     */
+    declineSuggestion: async (id) => {
+      const authStore = useAuthStore();
+      return axios.delete(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/suggestions/' + id,
+      {
+        headers: { Authorization: "Bearer " + authStore.token }
+      })
+      .then(response => { return response.data; })
+      .catch(err => {console.log(err)})
+    },
+
+
+      // addIngredientsToFridge: async (ingredientIds) => {
+      //   const authStore = useAuthStore();
+      //   return axios.delete(`${import.meta.env.VITE_BACKEND_URL}/shoppinglist/purchased`, {
+      //     headers: { Authorization: `Bearer ${authStore.token}`},
+      //     data: { ingredientIds }
+      //   })
+      //   .then((response) => {return response.data})
+      //   .catch(err => {console.log(err)})
+
+      // },
+
+      addIngredientsToFridge: async (ingredients) => {
+        const authStore = useAuthStore();
+        return axios.put(`${import.meta.env.VITE_BACKEND_URL}/shoppinglist/purchased`, ingredients, {
+          headers: { Authorization: `Bearer ${authStore.token}`}
         })
+        .then((response) => {return response.data})
+        .catch(err => {console.log(err)})
+
+      },
+
+    /**
+     * Get recipe based on id
+     * @param id
+     * @returns {Promise<*>}
+     */
+    getRecipe: async (id) => {
+        return axios.get(`${import.meta.env.VITE_BACKEND_URL}/recipe/${id}`)
             .then((response) => {
+                console.log(response.data);
                 return response.data;
             })
-            .catch(() => {
-                throw new Error("Could not fetch fridge item");
-            });
+            .catch((error) => {
+                throw new Error(error);
+            })
     },
 
 
diff --git a/src/views/FridgeView.vue b/src/views/FridgeView.vue
index a9af9a5f70f906ee75717baaedbf3527b94c56ff..6ee345d55cce6d76d913784118d191047ede2ab7 100644
--- a/src/views/FridgeView.vue
+++ b/src/views/FridgeView.vue
@@ -1,8 +1,8 @@
-<template><h1>Kjøleskap</h1><br><br>
+<template><h1>Kjøleskap</h1>
     <main>
-        <ItemSearch v-if="searchVisible" @itemsAdded="updateFridge"></ItemSearch>
+        <ItemSearch :adds-to-fridge="true" v-if="searchVisible" @itemsAdded="updateFridge"></ItemSearch>
 
-        <div id = "fridgeMsg"><p>Melding fra kjøleskapet:</p><span>{{this.fridgeMsg}}</span></div>
+        <div id = "fridgeMsg"><p v-if="this.fridgeMsg != ''">Melding fra kjøleskapet:</p><span>{{this.fridgeMsg}}</span></div>
         <eat-fridge-item-modal @closeModal="hideModal" v-if="visible" :fridge-item="selectedItem"></eat-fridge-item-modal>
 
         <div id = "itemContainer" >
@@ -10,8 +10,8 @@
         </div>
 
         <div id="addItemBtn-container">
-          <button @click="showItemSearch" id="addItemBtn">
-            <span class="plus">+</span>
+          <button :class="{ rotate: this.searchVisible }" @click="showItemSearch" class="add-button">
+            <span class="plus-sign"></span>
           </button>
         </div>
     </main>
@@ -31,14 +31,13 @@ export default {
     name: "FridgeView",
     components: {ItemSearch, EatFridgeItemModal, FridgeItem},
     computed:{
-      ...mapState(useAuthStore, ['account']),
-      ...mapStores(useFridgeStore),
+      ...mapState(useAuthStore, ['account', 'fridgeItems']),
     },
   data() {
       return {
           visible: false, //is the useitemModal visible
           selectedItem: null,
-          fridgeItems: [],
+          //fridgeItems: [],
           searchVisible: false,
           fridgeMsg: ""
       }
@@ -62,17 +61,15 @@ export default {
           this.fridgeMsg=msg;
       },
       async updateFridge(addedItem) {
-          this.fridgeItems = await API.getFridgeItems();
-          this.fridgeItems = await API.getFridgeItems();
           this.hideItemSearch();
           this.updateFridgeMessage(addedItem.name + " ble lagt i kjøleskapet.")
       },
 
   },
   async mounted() {
-      this.fridgeItems = await API.getFridgeItems();
+      await API.getFridgeItems()
       if(this.fridgeItems.length===0){
-          this.fridgeMsg="Kjøleskapet ditt er tomt. Legg inn varer ved å trykke på pluss-knappen nederst i høyre hjørne"
+          this.fridgeMsg="Kjøleskapet ditt er tomt."
       }
   }
 }
@@ -82,21 +79,24 @@ export default {
 main {
 
     color:black;
-    background-color: base.$grey;
-    padding: 2em;
+    //background-color: base.$grey;
+    padding: 1em 1em;
     min-height: 600px;
 }
 
 h1 {
   width:100%;
-  padding-left: 1em;
+  padding-left: 0.5em;
   padding-top: 2em;
-  font-weight: bold;
 }
 
 #itemContainer {
-    background-color: base.$grey;
-    padding-bottom: 5em;
+    padding-bottom: 170px;
+
+}
+
+.rotate {
+    -webkit-transform: rotate(45deg);
 }
 
 #addItemBtn {
@@ -118,16 +118,16 @@ h1 {
 }
 
 #addItemBtn-container {
-  padding-bottom: 3em;
-  z-index: 9999;
   position: fixed;
-  bottom: 15px;
-  right: 1em;
+  bottom: 75px;
+  right: 10px;
+  float: right;
 }
 
 #fridgeMsg {
   background-color: base.$light-green;
   padding: 1em;
+  min-height: 3em;
 }
 
 #fridgeMsg span, #fridgeMsg p{
@@ -135,4 +135,8 @@ h1 {
   font-weight: bolder;
   font-size: 1.2em;
 }
+
+p, span {
+  color: white;
+}
 </style>
\ No newline at end of file
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 1bd7463494c91b036111d7a97d4983d6e3395c12..3cf09945743a39413906a51730ebe43d5644685b 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -30,12 +30,15 @@
         </div>
 
         <div class="tips">
-          <img id="tips-img" src="../components/icons/logo.png" alt="Logo">
-          <p id="tips-text">Her kommer tips du kanskje kan ha nytte av, trykk på meg for å gå til neste tips!</p>
+          <img id="tips-img" src="../components/icons/tips.png" alt="Logo">
+          <p id="tips-text">Frys ned rester, så kan du ta opp en porsjon senere når du trenger et raskt måltid, i stedet for å kaste restene.</p>
         </div>
 
+        <div class="grocery">
           <grocery-offers></grocery-offers>
 
+        </div>
+
 
       </div>
   </main>
@@ -67,8 +70,8 @@
 }
 
 #tips-img {
-  width: 40px;
-  height: 40px;
+  width: 55px;
+  height: 55px;
   margin: auto 0;
 }
 
@@ -81,6 +84,7 @@
   background-color: rgb(232, 232, 232);
   margin-left: 10px;
   margin-right: 10px;
+  margin-bottom: 1.5em;
 
 
 }
diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue
index 77618971030bf7cf0ff025bf08d5e7e49e20fcef..7572c9a1d41d64d7e86a5b262ee8c4a3f3f2fc27 100644
--- a/src/views/LoginView.vue
+++ b/src/views/LoginView.vue
@@ -80,6 +80,12 @@ form {
   flex-direction: column;
 }
 
+#error-message {
+  text-align: center;
+  width: 80%;
+
+}
+
 input {
   height: 40px;
   font-size: 16px;
diff --git a/src/views/PinCodeView.vue b/src/views/PinCodeView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3fc4116508005935b5be9317ead74fd0d38d32bd
--- /dev/null
+++ b/src/views/PinCodeView.vue
@@ -0,0 +1,54 @@
+<script>
+import router from '@/router/index.js';
+
+export default {
+    methods: {
+        sendToHomePage() {
+            router.push("/");
+        }
+    }
+}
+</script>
+
+<template>
+    <main>
+        <h1>PIN</h1>
+        <div class="pincode-container">
+            <input id="pincode-field" type="tel" maxlength="4" placeholder="0000"/>
+            <button id="pincode-button" type="button" @click="sendToHomePage">OK</button>
+        </div>
+    </main>
+</template>
+
+<style scoped lang="scss">
+h1 {
+    font-size: 50px;
+}
+main {
+    padding: 50px 10px;
+    text-align: center;
+}
+
+.pincode-container {
+    width: 100%;
+    display: flex;
+    justify-content: center;
+    padding: 10px;
+    input {
+        border-radius: 0;
+        border: 1px solid black;
+        height: 50px;
+        width: 100px;
+        margin: 0 5px;
+        font-size: 38px;
+        padding: 5px;
+    }
+}
+
+
+button {
+    border-radius: 0;
+    border: 1px solid black;
+    width: 50px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/ProfileCreationView.vue b/src/views/ProfileCreationView.vue
index 22cb341b164554dd4416834a341b895504de2bde..560f3c5d29264e61c614ce618b6cf56f8e162220 100644
--- a/src/views/ProfileCreationView.vue
+++ b/src/views/ProfileCreationView.vue
@@ -1,6 +1,8 @@
 <script>
-import Toggle from '../components/Toggle.vue';
+import { mapStores } from 'pinia';
+import router from '../router'
 import { API } from '../util/API';
+import { useAuthStore } from '../stores/authStore'
 
 export default {
     data: () => {
@@ -14,20 +16,33 @@ export default {
         };
     },
     methods: {
-        submit() {
-            this.profile.isRestricted = this.$refs.toggle.state;
-            API.addProfile(this.profile);
+        async submit() {
+            await API.addProfile(this.profile)
+            .then((profile) => {
+                let id = profile.id;
+
+                let image = document.getElementById("profile_img").files[0];
+                
+                API.uploadProfileImage(image, id)
+                .then((updatedProfile) => {
+                    this.authStore.profile = updatedProfile;                     
+                    router.push("/");
+                });
+
+            })
         },
         updateImg() {
-            let file = document.getElementById("avatar").files[0];
+            let file = document.getElementById("profile_img").files[0];
             let reader = new FileReader();
             reader.onload = function (ev) {
-                document.getElementById("avatar_preview").src = ev.target.result;
+                document.getElementById("profile_img_preview").src = ev.target.result;
             };
             reader.readAsDataURL(file);
         }
     },
-    components: { Toggle }
+    computed: {
+        ...mapStores(useAuthStore)
+    }
 }
 </script>
 
@@ -35,21 +50,22 @@ export default {
     <main>
         <h1>Ny profil</h1>
 
-        <form action="todo" method="post">
-            <label for="avatar" id="avatar_label">
+        <form @submit.prevent="submit">
+            <label for="profile_img" id="profile_img_label">
                 <div class="img_hover">
-                    <img :src="image" alt="fjes" id="avatar_preview">
+                    <img :src="image" alt="fjes" id="profile_img_preview">
                     <p class="hover_text">
                         Klikk for å endre
                     </p>
                 </div>
             </label>
-            <input type="file" name="avatar" id="avatar" @change="updateImg">
+            <input @change="updateImg" type="file"
+                accept=".jpeg, .jpg" id="profile_img" name="profile_img">
             <label for="name">Navn</label>
             <input name="name" type="text" v-model="profile.name">
             <div class="check_container">
-                <label for="child">Begrenset:</label>
-                <Toggle ref="toggle" />
+                <label for="limited">Begrenset:</label>
+                <input type="checkbox" name="limited" id="limited">
             </div>
         </form>
         <button @click="submit">Opprett</button>
@@ -84,7 +100,7 @@ main {
     }
 }
 
-#avatar_label {
+#profile_img_label {
     display: flex;
     justify-content: center;
     width: 100%;
diff --git a/src/views/RecipeView.vue b/src/views/RecipeView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..88fd6572f4de41dae6c0a44719f0a0255f2b3dc1
--- /dev/null
+++ b/src/views/RecipeView.vue
@@ -0,0 +1,86 @@
+<script>
+
+import {API} from "@/util/API";
+
+export default {
+    name: "RecipeView",
+    data() {
+        return {
+            recipe: {},
+            id: this.$route.params.id,
+            title: "",
+            description: "",
+            time: "",
+            ingredients: [],
+            instructions: "",
+        }
+    },
+    methods: {
+        async loadData() {
+            await API.getRecipe(this.id)
+                .then((recipe) => {
+                  this.title = recipe.title;
+                  this.description = recipe.description;
+                  this.time = recipe.time;
+                  this.ingredients = recipe.ingredient;
+                  this.instructions = recipe.instructions;
+                })
+        },
+        addIngredientsShoppingList() {
+            //TODO add ingredients to shopping list
+        },
+        removeIngredientsFromFridge() {
+            //TODO remove used ingredients from fridge
+        }
+    },
+    async mounted() {
+        await this.loadData();
+    }
+}
+
+</script>
+
+<template>
+  <main>
+      <h1>{{this.title}}</h1><br>
+      <p>{{this.description}}</p><br>
+      <div class="ingredients">
+          <h2>Ingredienser</h2>
+          <ul>
+              <li v-for="ingredient in this.ingredients">{{ ingredient.item.name }} {{ ingredient.amount.quantity }} {{ingredient.amount.unit}}</li>
+          </ul>
+          <button @click="addIngredientsShoppingList">Legg til ingrediensene i handlekurven</button>
+      </div>
+      <div class="instructions">
+          <h2>Instruksjoner</h2>
+          {{this.instructions}}
+      </div>
+      <button @click="removeIngredientsFromFridge">Fjern varene fra kjøleskapet</button>
+
+  </main>
+
+</template>
+
+<style scoped lang="scss">
+@media(min-width: base.$desktop-min) {
+  main {
+    padding-top: 45px !important;
+  }
+}
+
+main {
+  padding: 20px 10px;
+  .ingredients {
+    margin-bottom: 20px;
+  }
+    button {
+        min-height: 40px;
+        border-radius: 0;
+        border: 1px solid;
+        cursor: pointer;
+        padding: 5px;
+    }
+}
+
+
+</style>
\ No newline at end of file
diff --git a/src/views/SelectProfileView.vue b/src/views/SelectProfileView.vue
index 01ed39912f2343e22898718b05ac76d21a551b00..8dd7991f2720672dfb0ca46f75a8cb1bdd0fab1b 100644
--- a/src/views/SelectProfileView.vue
+++ b/src/views/SelectProfileView.vue
@@ -2,6 +2,7 @@
     import { API } from '@/util/API.js';
     import { useAuthStore } from "@/stores/authStore.js";
     import { mapState } from 'pinia'
+    import router from '../router';
 
     export default {
         data() {
@@ -22,7 +23,7 @@
             
             // Sends the user into the "register profile" view 
             addProfile() {
-                API.addProfile();
+                router.push('/newProfile')
             },
 
             // Receives all profiles from this user
@@ -55,7 +56,7 @@
         </div>
 
         <div class="add">
-            <button @click="addProfile">+</button>
+            <button class="add-button" @click="addProfile"><span class="plus-sign"></span></button>
         </div>
     </div>
 </template>
@@ -104,19 +105,6 @@
         padding: 10px;
     }
 
- 
-    button {
-        border-radius: 50%;
-        border-style: none;
-        width: 50px;
-        height: 50px;
-        font-size: 50px;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        padding-bottom: 10px;
-    }
-
     #selectProfileBtn {
         background-color: transparent;
         border:none;
diff --git a/src/views/ShoppingListView.vue b/src/views/ShoppingListView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7501e1ad2c5feab9e15f678a8c07acfacbe99a87
--- /dev/null
+++ b/src/views/ShoppingListView.vue
@@ -0,0 +1,372 @@
+<template>
+    <div class="container">
+        <h1 v-if="this.items.suggestionList.length === 0">Handleliste</h1>
+
+        <ItemSearch v-if="this.showAddMenu && this.profile.restricted"
+            @itemsAdded="(ingredient) => updateSuggestionList(ingredient)" :addsToFridge="false"></ItemSearch>
+        <ItemSearch v-else-if="this.showAddMenu && !this.profile.restricted"
+            @itemsAdded="(ingredient) => updateShoppingList(ingredient)" :addsToFridge="false"></ItemSearch>
+
+        <div class="list">
+            <div class="items">
+
+                <div v-if="items.suggestionList.length > 0" class="suggestions-wrapper">
+                    <h2>Forslag</h2>
+                    <div v-for="(item, index) in items.suggestionList" :key="index" :item="item" class="item">
+
+                        <div class="item-wrapper">
+                            <div class="item-label">
+                                <label v-if="item.amount.quantity === 1" for="checkbox" class="checkbox-label">{{
+                                    item.item.name }}</label>
+                                <label v-else for="checkbox" class="checkbox-label">{{ item.amount.quantity }}x {{
+                                    item.item.name }}</label>
+                            </div>
+                        </div>
+
+                        <div class="buttons">
+                            <button v-if="!this.profile.restricted" class="accept-button"
+                                @click="acceptItem(item.ingredient_id)">Godta</button>
+                            <button class="decline-button" @click="declineItem(item.ingredient_id)">Avslå</button>
+                        </div>
+
+                    </div>
+                </div>
+
+
+                <h2 v-if="this.items.ingredientList.length > 0 && this.items.suggestionList > 0">Handleliste</h2>
+                <div v-for="(item, index) in items.ingredientList" :key="index" :item="item" class="item">
+
+                    <div class="item-wrapper">
+                        <div class="check">
+                            <input v-model="item.isChecked" @change="sortList" class="checkbox" type="checkbox">
+                        </div>
+
+                        <div class="item-label">
+                            <label v-if="item.amount.quantity === 1" for="checkbox" class="checkbox-label">{{ item.item.name
+                            }}</label>
+                            <label v-else for="checkbox" class="checkbox-label">{{ item.amount.quantity }}x {{
+                                item.item.name }}</label>
+                        </div>
+                    </div>
+
+                    <div class="buttons">
+                        <img id="delete-button" @click="deleteItem(item.ingredient_id)" src="../components/icons/trash.svg" alt="delete">
+                    </div>
+
+                </div>
+            </div>
+
+        </div>
+        <div class="add">
+            <button :class="{ rotate: this.showAddMenu }" class="add-button" @click="addItem"><span class="plus-sign"></span></button>
+        </div>
+    </div>
+</template>
+
+<script>
+import { API } from '../util/API.js';
+import { mapState } from 'pinia';
+import { useAuthStore } from "@/stores/authStore.js";
+import ItemSearch from '../components/ItemSearch.vue'
+
+
+export default {
+    data() {
+        return {
+            testItems: [{ itemName: "banan", amount: 2, isChecked: false }, { itemName: "ost", amount: 1, isChecked: false }, { itemName: "eple", amount: 4, isChecked: false }, { itemName: "brus", amount: 1, isChecked: false }],
+            ingredients: [],
+            showAddMenu: false,
+        }
+    },
+    components: {
+        ItemSearch
+    },
+    methods: {
+        sortList() {
+            this.items.ingredientList.sort((a, b) => a.isChecked - b.isChecked)
+        },
+        async getShoppingList() {
+            await API.getShoppingList()
+                .catch(err => { console.log(err) })
+        },
+        async addItem() {
+            this.showAddMenu = !this.showAddMenu;
+            window.scrollTo({ top: 0, behavior: 'smooth' });
+
+        },
+        async acceptItem(id) {
+            await API.acceptSuggestion(id)
+                .then((response) => {
+                    this.items.suggestionList.forEach((ingredient, index) => {
+                        if (ingredient.ingredient_id === response.ingredient_id) {
+                            this.items.suggestionList.splice(index, 1);
+                        }
+                    })
+                    this.updateShoppingList(response)
+                })
+
+        },
+        async declineItem(id) {
+            await API.declineSuggestion(id)
+                .then((response) => {
+                    this.items.suggestionList.forEach((ingredient, index) => {
+                        if (ingredient.ingredient_id === response.ingredient_id) {
+                            this.items.suggestionList.splice(index, 1);
+                        }
+                    })
+                })
+        },
+        async deleteItem(id) {
+            await API.deleteItemFromShoppingList(id)
+                .then(() => {
+                    this.items.ingredientList.forEach((ingredient, index) => {
+                        if (ingredient.ingredient_id === id) {
+                            this.items.ingredientList.splice(index, 1);
+                        }
+                    })
+                })
+
+        },
+        addIsCheckedToIngredient() {
+            this.items.ingredientList.forEach(ingredient => {
+                if (!ingredient.hasOwnProperty('isChecked')) {
+                    ingredient.isChecked = false;
+                }
+            })
+        },
+        updateShoppingList(ingredient) {
+            ingredient.isChecked = false;
+            this.items.ingredientList.push(ingredient);
+            this.showAddMenu = false;
+        },
+        updateSuggestionList(ingredient) {
+            ingredient.isChecked = false;
+            this.items.suggestionList.push(ingredient)
+            this.showAddMenu = false;
+        },
+        sendIngredientsToFridge() {
+            const boughtIngredients = []
+
+            this.items.ingredientList.forEach(ingredient => {
+                if (ingredient.isChecked) {
+                    boughtIngredients.push(ingredient)
+                }
+            })
+            console.log(boughtIngredients)
+            API.addIngredientsToFridge(boughtIngredients)
+        }
+
+    },
+    computed: {
+        ...mapState(useAuthStore, ['items', 'profile'])
+    },
+    async mounted() {
+        await this.getShoppingList()
+            .then(() => {
+                this.items.ingredientList.forEach(item => {
+                    item.isChecked = false
+                })
+            })
+    },
+    beforeRouteLeave (to, from) {
+        this.sendIngredientsToFridge()
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.container {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    margin: auto;
+
+    max-width: 550px;
+    margin-top: 4em;
+    height: 100%;
+}
+
+h1 {
+
+  width:100%;
+  padding-left: 0.5em;
+
+}
+
+
+
+.rotate {
+    -webkit-transform: rotate(45deg);
+}
+
+.accept-button {
+    border-radius: 10px;
+    background-color: base.$light-green;
+    color: white;
+    font-weight: bold;
+    border-style: none;
+    height: 27px;
+    padding: 0 10px;
+}
+
+.decline-button {
+    border-radius: 10px;
+    background-color: base.$grey;
+    color: base.$indigo;
+    font-weight: bold;
+    border-style: none;
+    height: 27px;
+    padding: 0 10px;
+    margin: 0 auto;
+
+}
+
+.buttons {
+    display: flex;
+    gap: 5px;
+    align-self: center
+}
+
+
+h2 {
+    padding: 5px 15px
+}
+
+
+
+.add {
+    position: fixed;
+    bottom: 75px;
+    right: 10px;
+    float: right;
+}
+
+.header {
+    display: flex;
+    align-items: left;
+    justify-content: left;
+    padding-left: 15px;
+    width: 100%;
+    border-bottom: 1px solid base.$grey;
+}
+
+.list {
+    min-width: 300px;
+    min-height: 100vh;
+    height: 100%;
+    /* background-color: #F3F4F9; */
+    width: 100%;
+    // padding: 15px;
+    // border-radius: 10px;
+}
+
+.items {
+    padding-bottom: 170px;
+}
+
+.suggestions-wrapper {
+    border-bottom: 1px solid base.$grey;
+    border-width: 100%;
+    padding-bottom: 15px;
+
+
+}
+
+.item {
+    display: flex;
+    flex-direction: row;
+    gap: 10px;
+    justify-content: space-between;
+    background-color: white;
+    padding: 5px 15px;
+    padding: 0.5em 1em;
+    border-top-right-radius: 10px;
+    border-top-left-radius: 10px;
+
+}
+
+.item:not(:first-child) {
+    border-radius: 0px;
+}
+
+.item:last-child {
+    border-radius: 0px;
+    border-bottom-left-radius: 10px;
+    border-bottom-right-radius: 10px;
+}
+
+// .item:not(:last-child)::after {
+//     content: '';
+//     /* this works like a border-width */
+//     height: 1px;
+//     /* percentage of border shown */
+//     width: 70%;
+//     /* the color of border */
+//     background: base.$grey; 
+//     position: absolute;
+//     bottom: 0;
+//     margin: 0 auto;
+//     left: 0;
+//     /* horizontal centering */
+//     right: 0;
+// }
+
+.item-wrapper {
+    display: flex;
+    flex-direction: row;
+    gap: 10px;
+
+}
+
+input[type="checkbox"] {
+    -webkit-appearance: none;
+    -moz-appearance: none;
+    appearance: none;
+    width: 35px;
+    height: 35px;
+    border-radius: 50%;
+    border: 2px solid #ccc;
+
+}
+
+input[type="checkbox"]:checked {
+    background-color: base.$light-green;
+}
+
+input[type="checkbox"]:checked:after {
+    content: "\2713";
+    /* Unicode code for checkmark symbol */
+    font-size: 24px;
+    font-weight: bold;
+    color: white;
+    text-align: center;
+    line-height: 35px;
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+}
+
+label {
+    font-size: 20px;
+}
+
+img {
+    width: 30px;
+    height: 30px;
+    padding: 5px;
+
+    max-height: 100%;
+    max-width: 100%;
+}
+
+.check {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+.delete {
+    align-self: flex-end;
+}</style>
\ No newline at end of file
diff --git a/src/views/__tests__/FridgeView.spec.js b/src/views/__tests__/FridgeView.spec.js
index 4790f4ad2639935f3da4a5694dafcb3a27738181..4312e6a5f91ac7d53812647c27bb300461c284b0 100644
--- a/src/views/__tests__/FridgeView.spec.js
+++ b/src/views/__tests__/FridgeView.spec.js
@@ -38,7 +38,7 @@ describe('Fridge', () => {
 
         })
         expect(wrapper.find('ItemSearch').exists()).toBe(false);
-        await wrapper.find('#addItemBtn').trigger('click');
+        await wrapper.find('.add-button').trigger('click');
 
         setTimeout(() => {
             expect(wrapper.find('ItemSearch').exists()).toBe(true);
diff --git a/src/views/__tests__/SelectProfileView.spec.js b/src/views/__tests__/SelectProfileView.spec.js
index 858b394a2c36720176fd2f1cf9e157e4b6673907..c0b9d55f0f528f4c4f3d4cbe65a125804b500fad 100644
--- a/src/views/__tests__/SelectProfileView.spec.js
+++ b/src/views/__tests__/SelectProfileView.spec.js
@@ -13,7 +13,6 @@ describe('Select profile', () => {
       },
     })
     expect(wrapper.text()).toContain('Hvem bruker appen?')
-    expect(wrapper.text()).toContain('+')
   })
 
   it('loads with one profile', () => {
diff --git a/src/views/__tests__/ShoppingListView.spec.js b/src/views/__tests__/ShoppingListView.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..97988ad4314e26355b1a35af1ea4c27b25874b62
--- /dev/null
+++ b/src/views/__tests__/ShoppingListView.spec.js
@@ -0,0 +1,211 @@
+import { describe, it, expect, vi} from 'vitest'
+import { mount } from '@vue/test-utils'
+import { createTestingPinia } from '@pinia/testing'
+import ShoppingListView from '../ShoppingListView.vue'
+
+
+  
+  describe('Shopping list', () => {
+    const wrapper = mount(ShoppingListView, 
+        { computed: {
+            items() {
+                return {
+                    id: 1,
+                    ingredientList: [
+                    {
+                        ingredient_id: 1,
+                        amount: {
+                        quantity: 1,
+                        unit: "stk"
+                        },
+                        item: {
+                        id: 1,
+                        name: "Vegansk Krone-Is Jordbær",
+                        ean: "7041012550001",
+                        shelfLife: 30,
+                        image_url: "https://bilder.ngdata.no/7041012550001/meny/large.jpg",
+                        amount: {
+                            quantity: 4,
+                            unit: "stk"
+                        },
+                        store: null,
+                        allergens: [
+                            {
+                            name: "Nøtter (kan inneholde spor)"
+                            },
+                            {
+                            name: "Peanøtter (kan inneholde spor)"
+                            },
+                            {
+                            name: "Soya (kan inneholde spor)"
+                            }
+                        ],
+                        nutrition: [
+                            {
+                            name: "Kalorier",
+                            amount: {
+                                quantity: 264,
+                                unit: "stk"
+                            }
+                            },
+                            {
+                            name: "Energi",
+                            amount: {
+                                quantity: 1106,
+                                unit: "stk"
+                            }
+                            },
+                            {
+                            name: "Fett",
+                            amount: {
+                                quantity: 11.2,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Karbohydrater",
+                            amount: {
+                                quantity: 38.7,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Mettet fett",
+                            amount: {
+                                quantity: 9.5,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Protein",
+                            amount: {
+                                quantity: 1.5,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Salt",
+                            amount: {
+                                quantity: 0.11,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Sukkerarter",
+                            amount: {
+                                quantity: 23.6,
+                                unit: "g"
+                            }
+                            }
+                        ]
+                        },
+                        exp_date: null
+                    },
+                    {
+                        ingredient_id: 2,
+                        amount: {
+                        quantity: 1,
+                        unit: "stk"
+                        },
+                        item: {
+                        id: 2,
+                        name: "Jarlsberg Gulost",
+                        ean: "7038010053368",
+                        shelfLife: 14,
+                        image_url: "https://bilder.ngdata.no/7038010053368/kmh/large.jpg",
+                        amount: {
+                            quantity: 700,
+                            unit: "g"
+                        },
+                        store: null,
+                        allergens: [
+                            {
+                            name: "Melk"
+                            }
+                        ],
+                        nutrition: [
+                            {
+                            name: "Kalorier",
+                            amount: {
+                                quantity: 351,
+                                unit: "kcal"
+                            }
+                            },
+                            {
+                            name: "Energi",
+                            amount: {
+                                quantity: 1458,
+                                unit: "kj"
+                            }
+                            },
+                            {
+                            name: "Fett",
+                            amount: {
+                                quantity: 27,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Karbohydrater",
+                            amount: {
+                                quantity: 0,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Mettet fett",
+                            amount: {
+                                quantity: 17,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Protein",
+                            amount: {
+                                quantity: 27,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Salt",
+                            amount: {
+                                quantity: 1.1,
+                                unit: "g"
+                            }
+                            },
+                            {
+                            name: "Sukkerarter",
+                            amount: {
+                                quantity: 0,
+                                unit: "g"
+                            }
+                            }
+                        ]
+                        },
+                        exp_date: null
+                    }
+                    ],
+                    suggestionList: []
+                }    
+            }
+            },
+            global: {
+                plugins: [createTestingPinia({
+                    createSpy: vi.fn,
+                })],
+                },
+        
+        })
+
+  it('renders properly', () => {
+
+    expect(wrapper.text()).toContain('Handleliste')
+    expect(wrapper.text()).not.toContain('Forslag')
+  })
+
+  it('items gets shown', () => {
+    expect(wrapper.text()).toContain('Vegansk Krone-Is Jordbær')
+    expect(wrapper.text()).toContain('Jarlsberg Gulost')
+  })
+
+})