diff --git a/cypress/e2e/login.cy.js b/cypress/e2e/login.cy.js index 50b8b978bca4f56e07c750efe52a48a66910ad9b..f0a2e1fb843a2ed27ec2167dfb9a6a4b6de7f7ac 100644 --- a/cypress/e2e/login.cy.js +++ b/cypress/e2e/login.cy.js @@ -13,4 +13,4 @@ describe('Login fails with wrong credentials', () => { cy.get('#error-message').contains("Kunne ikke logge inn!") }) -}) \ No newline at end of file +}) diff --git a/cypress/e2e/navbar.cy.js b/cypress/e2e/navbar.cy.js deleted file mode 100644 index 9e227781986c499d749fd2f66f66d95f56a4ee32..0000000000000000000000000000000000000000 --- a/cypress/e2e/navbar.cy.js +++ /dev/null @@ -1,5 +0,0 @@ -describe('Correct navigation links', () => { -}) -describe('Navbar on all pages', () => { - -}) diff --git a/src/App.vue b/src/App.vue index d9988e4a1832293fff956f9976fd7782c97b76ec..0ee5e4f7eab741a76f4aa11de4819c67f32814f2 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,11 +1,12 @@ <script setup> import { RouterView } from 'vue-router' import Navbar from "@/components/Navbar.vue"; - + import { useAuthStore } from "@/stores/authStore.js"; + import router from "@/router"; </script> <template> - <Navbar v-if="$route.name !== 'login' && $route.name !== 'selectProfile'" /> + <Navbar v-if="$route.name !== 'login' && $route.name !== 'selectProfile' && $route.name !== 'registerAccount'"/> <RouterView /> </template> diff --git a/src/assets/main.css b/src/assets/main.css index c417db8ebe95a78dcdf6bb8c362b0a6cb4dc518b..190d9256732aaed000ed88ac91a644c72f4e5921 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -3,11 +3,28 @@ #app { max-width: 1280px; margin: 0 auto; - qpadding: 2rem; font-weight: normal; } +button:hover { + cursor: pointer; +} + +main { + margin-bottom: 4em; + margin-top: 0; + +} + +@media (min-width: 1024px) { + main { + + margin-top: 4em; + margin-bottom: 0; + } +} + a, .green { text-decoration: none; diff --git a/src/components/EatFridgeItemModal.vue b/src/components/EatFridgeItemModal.vue index af451315946af362d35ca6d677378c5596c668c1..490c6f3f87bea180bee45d02e4553475852b13fd 100644 --- a/src/components/EatFridgeItemModal.vue +++ b/src/components/EatFridgeItemModal.vue @@ -160,6 +160,7 @@ export default { } + #exitBtn button { width:2em; height:2em; @@ -175,7 +176,7 @@ button { width: 50%; padding:1em; background-color: base.$red; - color:white; + color:black; border:none; } button:hover { @@ -187,6 +188,7 @@ button:hover { } #eatenBtn { background-color: base.$green; + color: white; } #itemHasExpiredMessage { diff --git a/src/components/EditAccount.vue b/src/components/EditAccount.vue index 564f678621ce2e4e4873b4ea42d473d54184630d..cb5f59c1099cbfd66056c19aa496a8a9547b2900 100644 --- a/src/components/EditAccount.vue +++ b/src/components/EditAccount.vue @@ -11,26 +11,31 @@ <label for="password">Endre passord</label><br> <input type="password" id="password" v-model="updatedAccount.upPassword"> - <button class="greenBtn" @click="saveAccountSettings">Lagre profilendringer</button> + <div class="submit"> + <button class="greenBtn submitBtn" @click="saveAccountSettings">Lagre profilendringer</button> + </div> <p id="alert">{{alertMsg}}</p> </form> <div id="logout"> <p class="infoText">Logger deg ut fra din SmartMat-konto</p> - <button class ="redBtn" @click="logOut">Logg ut</button> + <button id="logOut" class ="redBtn" @click="logOut">Logg ut</button> </div> <br> <br> - <hr> + <form @submit.prevent="submit" id = "dangerZone"> <h1>🔺FARESONE🔺</h1> <p class="infoText">Ved å trykke på knappen nedenfor, vil du slette din SmartMat-konto</p> <input type="checkbox" id="deletionCheckbox" v-model="deletionConfirmation"> <label for="deletionCheckbox"> Jeg bekrefter jeg skjønner dette, og ønsker å slette kontoen min SmartMat-konto for alltid.</label><br> - <button class="darkRedBtn" id ="delAccount" @click="deleteAccount">SLETT KONTO</button> + <div class="submit"> + <button class="darkRedBtn" id ="delAccount" @click="deleteAccount">SLETT KONTO</button> + + </div> <p id="alert">{{delAlertMsg}}</p> </form> </template> @@ -116,13 +121,16 @@ export default { } #logout{ - background-color: base.$grey; + background-color: base.$light-grey; color: black; padding: 2em; margin-top: 2em; margin-bottom: 2em; display: flex; flex-direction: column; + align-items: center; + justify-content: center; + width: 90%; } input[type="checkbox"] { @@ -130,16 +138,29 @@ input[type="checkbox"] { height: 2.5em; } +.submitBtn { + width: 80%; + max-width: 220px; + +} + +.submit { + display: flex; + justify-content: center; + align-items: center; +} /*--General--*/ form { - background-color: base.$grey; + background-color: base.$light-grey; color: black; align-content: end; padding: 2em; - margin-top: 2em; + margin-top: .5em; margin-bottom: 2em; + width: 90%; + } input[type="text"], @@ -154,11 +175,13 @@ button { margin: 1em; padding:.9em; font-weight: bold; + } .redBtn { background-color: base.$red; border:none; - color:white; + color:black; + width: 10em; } .redBtn:hover { diff --git a/src/components/EditProfile.vue b/src/components/EditProfile.vue index 76b5e5dcd1539a8576d7c442a75835881a27525f..c4b01186eda5b200a4e10288a22ad83f41963e5b 100644 --- a/src/components/EditProfile.vue +++ b/src/components/EditProfile.vue @@ -6,7 +6,7 @@ <h3>{{this.profile.name}}</h3> - <button @click="changeProfile" id="changeUserBtn" class="redBtn">Bytt bruker</button> + <button @click="changeProfile" id="changeUserBtn" class="greenBtn">Bytt bruker</button> <form @submit.prevent="submit"> <label for="brukernavn">Profilnavn</label><br> @@ -34,8 +34,8 @@ </div> <br><br> <div id = "submitbuttonBox"> - <button class="greenBtn" @click=" saveUserSettings">Lagre profilendringer</button> - <button class="darkRedBtn" @click="deleteProfile">Slett brukerprofil</button> + <button class="greenBtn submitBtn" @click=" saveUserSettings">Lagre profilendringer</button> + <button class="darkRedBtn submitBtn" id="delete" @click="deleteProfile">Slett brukerprofil</button> </div> <p id="alert">{{alertMsg}}</p> @@ -177,9 +177,15 @@ input[type="radio"] { } #changeUserBtn { - border: 1px solid black; + +} + +#changeUserBtn:hover { + } + + #profilepicture-container { display:flex; border-radius:50%; @@ -193,6 +199,7 @@ input[type="radio"] { #changeUserImage { display:flex; + gap: 10px; } img { @@ -206,12 +213,21 @@ img { #submitbuttonBox { display:flex; + flex-direction: column; justify-content: space-between; + align-items: center; + +} + +.submitBtn { + width: 80%; + max-width: 220px; } input[type=file]::file-selector-button { - background-color: base.$light-green; - color: base.$white; + + background-color: base.$grey; + color: black; border: none; font-weight: bold; padding: 8px 14px; @@ -223,25 +239,27 @@ input[type=file]::file-selector-button { } input[type=file]::file-selector-button:hover { - background-color: base.$light-green-hover; + background-color: base.$grey-hover; } /*--General--*/ form { - background-color: base.$grey; - color: black; - align-content: end; - padding: 2em; - margin-top: 2em; - margin-bottom: 2em; - } + background-color: base.$light-grey; + color: black; + align-content: end; + padding: 2em; + margin-top: 2em; + margin-bottom: 2em; + width: 90%; +} input[type="text"], input[type="password"]{ width: 100%; padding: .5em; + } button { @@ -250,11 +268,12 @@ button { margin: 1em; padding:.9em; font-weight: bold; + } .redBtn { background-color: base.$red; border:none; - color:white; + color:black; } .redBtn:hover { diff --git a/src/components/Logo.vue b/src/components/Logo.vue deleted file mode 100644 index 79fb2736956cb8da14271e6531689e6b8d377895..0000000000000000000000000000000000000000 --- a/src/components/Logo.vue +++ /dev/null @@ -1,14 +0,0 @@ -<template> - <div> - <img src="../components/icons/logo.png" alt="logo" :style="{ width: logoSize }"> - </div> -</template> -<script> -export default { - name: "Logo" -} -</script> - -<style scoped> - -</style> \ No newline at end of file diff --git a/src/components/Navbar.vue b/src/components/Navbar.vue index 85fab9a5359794a132898c825f849579f0c930ef..88979ec5cc61fbe25948fb5859f83f20746956c0 100644 --- a/src/components/Navbar.vue +++ b/src/components/Navbar.vue @@ -33,11 +33,10 @@ </template> <script> import { Icon } from '@iconify/vue'; -import Logo from "@/components/Logo.vue"; export default { name: "Navbar", - components: {Logo, Icon}, + components: {Icon}, computed: { iconColor() { return '#ffffff'; diff --git a/src/router/index.js b/src/router/index.js index cafcdb0fe603b7e6e922b8371db71585eb7a1309..864b43512c941df533098611e9f71da924d11a61 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -12,6 +12,7 @@ import FridgeView from "@/views/FridgeView.vue"; import RecipeView from "@/views/RecipeView.vue"; import ShoppingListView from '../views/ShoppingListView.vue' +import { useAuthStore } from "@/stores/authStore.js"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -79,4 +80,12 @@ const router = createRouter({ ] }) +router.beforeEach (async (to, from) => { + const authStore = useAuthStore(); + if (!authStore.isLoggedIn && to.name !== 'login' && to.name !== 'registerAccount') { + return { name: 'login'}; + } +}) + + export default router diff --git a/src/style.scss b/src/style.scss index e863df96777166400722ef6bffb56936c321ff1d..982960a9b2295496f306bd7da4e2b1f79b1504fb 100644 --- a/src/style.scss +++ b/src/style.scss @@ -11,6 +11,7 @@ $red-hover: darken( $red, 5% ); $green-hover: darken( $green, 8% ); $light-green-hover: darken( $light-green, 10% ); $darkred-hover: darken(darkred, 10%); +$grey-hover: darken( $grey, 10%); $indigo: #2c3e50; $desktop-min: 1024px; @@ -30,10 +31,12 @@ $phone-min : 360px; transition: .25s ease-in-out; line-height: 1; padding: 0; + cursor: pointer; } .add-button:hover { background-color: $green; + } .plus-sign:before { diff --git a/src/util/API.js b/src/util/API.js index 20b02ff45532e066564639ab7869eaffdac578da..3fb7d159fd31176b70cac34ebb3b7cfa6b5634b6 100644 --- a/src/util/API.js +++ b/src/util/API.js @@ -108,8 +108,9 @@ export const API = { } }) .then((response) => { - return response.data; - }) + authStore.profiles = API.getProfiles(); + return response.data; + }) .catch(() => { throw new Error(); }) @@ -132,6 +133,7 @@ export const API = { headers: { Authorization: "Bearer " + authStore.token }, }) .then((response) => { + authStore.profiles.push(response.data) return response.data; }).catch(() => { throw new Error(); @@ -152,6 +154,7 @@ export const API = { }, ) .then(response => { + authStore.profiles = response.data; return response.data }).catch(() => { throw new Error(); @@ -215,7 +218,6 @@ export const API = { searchItems: async(searchPhrase)=> { return axios.get(`${import.meta.env.VITE_BACKEND_URL}/item/search?name=${searchPhrase}`, { }).then((response) => { - console.log(response.data.content); return response.data.content; }).catch(()=> { throw new Error("Error when searching for item "); @@ -490,6 +492,7 @@ export const API = { headers: { Authorization: `Bearer ${authStore.token}` }, }) .then(() => { + authStore.profiles = API.getProfiles(); router.push('/selectProfile') }) .catch(() => { diff --git a/src/views/FridgeView.vue b/src/views/FridgeView.vue index 0025e636d186917bca41b65d777a616864a3044b..5acfd2d8e50bf1d05cebb6e07056a4df67bcbeb5 100644 --- a/src/views/FridgeView.vue +++ b/src/views/FridgeView.vue @@ -1,5 +1,6 @@ -<template><h1>Kjøleskap</h1> + <template> <main> + <h1>Kjøleskap</h1> <ItemSearch :adds-to-fridge="true" v-if="searchVisible" @itemsAdded="updateFridge"></ItemSearch> <div id = "fridgeMsg"><p v-if="this.fridgeMsg != ''">Melding fra kjøleskapet:</p><span>{{this.fridgeMsg}}</span></div> @@ -84,17 +85,15 @@ export default { <style scoped lang="scss"> main { - color:black; //background-color: base.$grey; - padding: 1em 1em; + padding: 0 1em; min-height: 600px; } + h1 { width:100%; - padding-left: 0.5em; - padding-top: 2em; } #itemContainer { @@ -141,9 +140,10 @@ h1 { font-weight: bolder; font-size: 1.2em; + color: black; } -p, span { - color: white; +p { + color: black; } </style> \ No newline at end of file diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 3cf09945743a39413906a51730ebe43d5644685b..e101541d9e642ca11c2e4df848adc58e068e5af8 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -25,10 +25,6 @@ <h1>Velkommen, {{ this.profile.name }}!</h1> </div> - <div class="gamification"> - - </div> - <div class="tips"> <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> @@ -63,6 +59,10 @@ padding: 20px; } +h1 { + text-align: center; +} + #logo { width: 75px; @@ -100,6 +100,8 @@ display: flex; flex-direction: column; align-items: center; + justify-content: center; } } + </style> diff --git a/src/views/RegisterAccountView.vue b/src/views/RegisterAccountView.vue index 2a5b360e64494f39cc0c804b18dc16f43500fa8b..e0da403e0c7599c8e52e62af84b22787b54cb1cc 100644 --- a/src/views/RegisterAccountView.vue +++ b/src/views/RegisterAccountView.vue @@ -39,12 +39,12 @@ } }, methods: { - register() { + async register() { if (this.name === "" || this.password === "") { this.errormsg = "Vennligst fyll inn alle feltene" } else { - API.addAccount({firstname: this.name, email: this.email, password: this.password}).then(() => { + await API.addAccount({firstname: this.name, email: this.email, password: this.password}).then(() => { router.push("/selectProfile") }) .catch(() => { diff --git a/src/views/ShoppingListView.vue b/src/views/ShoppingListView.vue index 7501e1ad2c5feab9e15f678a8c07acfacbe99a87..c5ab482412fc174ac58eeb8e4fa7301241f7af7d 100644 --- a/src/views/ShoppingListView.vue +++ b/src/views/ShoppingListView.vue @@ -1,66 +1,68 @@ <template> - <div class="container"> - <h1 v-if="this.items.suggestionList.length === 0">Handleliste</h1> + <main> + <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> - <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> + </div> - <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"> + <h2 v-if="this.items.ingredientList.length > 0 && this.items.suggestionList.length > 0">Handleliste</h2> + <div v-for="(item, index) in items.ingredientList" :key="index" :item="item" class="item"> <div class="item-wrapper"> + <div v-if="!this.profile.restricted" 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-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 v-if="!this.profile.restricted" class="buttons"> + <img id="delete-button" @click="deleteItem(item.ingredient_id)" src="../components/icons/trash.svg" alt="delete"> </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 class="add"> + <button :class="{ rotate: this.showAddMenu }" class="add-button" @click="addItem"><span class="plus-sign"></span></button> + </div> </div> - </div> + </main> </template> <script> @@ -91,6 +93,7 @@ export default { }, async addItem() { this.showAddMenu = !this.showAddMenu; + console.log(this.profile) window.scrollTo({ top: 0, behavior: 'smooth' }); }, @@ -152,7 +155,6 @@ export default { boughtIngredients.push(ingredient) } }) - console.log(boughtIngredients) API.addIngredientsToFridge(boughtIngredients) } @@ -183,7 +185,6 @@ export default { margin: auto; max-width: 550px; - margin-top: 4em; height: 100%; } @@ -203,13 +204,21 @@ h1 { .accept-button { border-radius: 10px; background-color: base.$light-green; - color: white; + color: black; font-weight: bold; border-style: none; height: 27px; padding: 0 10px; } +.accept-button:hover { + background-color: base.$light-green-hover; +} + +.decline-button:hover { + background-color: base.$grey-hover ; +} + .decline-button { border-radius: 10px; background-color: base.$grey; @@ -225,7 +234,13 @@ h1 { .buttons { display: flex; gap: 5px; - align-self: center + align-self: center; + cursor: pointer; +} + +.buttons:hover { + background-color: base.$light-grey; + border-radius: 10px; } diff --git a/src/views/__tests__/ShoppingListView.spec.js b/src/views/__tests__/ShoppingListView.spec.js index 97988ad4314e26355b1a35af1ea4c27b25874b62..8e0dd7e32bb61e176e077646a908fa17ee52f405 100644 --- a/src/views/__tests__/ShoppingListView.spec.js +++ b/src/views/__tests__/ShoppingListView.spec.js @@ -187,7 +187,30 @@ import ShoppingListView from '../ShoppingListView.vue' ], suggestionList: [] } - } + }, + profile() { + return { + + id: 1, + email: "ola@ola.no", + firstname: "Ola", + shoppingList: { + id: 1, + ingredientList: [], + suggestionList: [] + }, + fridge: { + id: 1, + ingredientList: [] + }, + username: "ola@ola.no", + authorities: [], + accountNonExpired: true, + accountNonLocked: true, + credentialsNonExpired: true, + enabled: true + } + } }, global: { plugins: [createTestingPinia({ @@ -208,4 +231,13 @@ import ShoppingListView from '../ShoppingListView.vue' expect(wrapper.text()).toContain('Jarlsberg Gulost') }) + it('pressing the plus button makes search visible', async () => { + expect(wrapper.find('ItemSearch').exists()).toBe(false); + await wrapper.find('.add-button').trigger('click'); + + setTimeout(() => { + expect(wrapper.find('ItemSearch').exists()).toBe(true); + }, 1000); +}); + })