diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a50b3b132633e6dddaf8a8c26664adf4f4d16277..e757a909259f83ab7a49cbed5dac6b15ab115061 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,41 +1,43 @@ image: node:16 stages: - - setup +# - setup - test -variables: - npm_config_cache: "$CI_PROJECT_DIR/.npm" +#variables: +# npm_config_cache: "$CI_PROJECT_DIR/.npm" # Define a hidden job to be used with extends # Better than default to avoid activating cache for all jobs -.dependencies_cache: - cache: - key: - files: - - package-lock.json - paths: - - .npm - policy: pull +#.dependencies_cache: +# cache: +# key: +# files: +# - package-lock.json +# paths: +# - .npm +# policy: pull -setup: - stage: setup - script: - - npm ci - extends: .dependencies_cache - cache: - policy: pull-push - artifacts: - expire_in: 3 days #delete cache after 3 days to conserve space - paths: - - node_modules +#setup: +# stage: setup +# script: +# - npm ci +# extends: .dependencies_cache +# cache: +# policy: pull-push +# artifacts: +# expire_in: 3 days #delete cache after 3 days to conserve space +# paths: +# - node_modules -lint_test: +test: stage: test script: + - npm ci - npm run lint - -unit_test: - stage: test - script: - npm run test:unit + +#unit_test: +# stage: test +# script: +# - npm run test:unit diff --git a/package-lock.json b/package-lock.json index c091f74324b213d6b61eb1d8a3e3c4c51fa17fe2..8128c7cae624745f25207e7ac2bf07f290c690ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "frontend", "version": "0.1.0", "dependencies": { + "@heroicons/vue": "^1.0.6", "@mdi/font": "5.9.55", "@vuelidate/core": "^2.0.0-alpha.40", "@vuelidate/validators": "^2.0.0-alpha.28", @@ -1707,6 +1708,14 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@heroicons/vue": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@heroicons/vue/-/vue-1.0.6.tgz", + "integrity": "sha512-ng2YcCQrdoQWEFpw+ipFl2rZo8mZ56v0T5+MyfQQvNqfKChwgP6DMloZLW+rl17GEcHkE3H82UTAMKBKZr4+WA==", + "peerDependencies": { + "vue": ">= 3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", "dev": true, @@ -16108,6 +16117,12 @@ "@hapi/hoek": "^9.0.0" } }, + "@heroicons/vue": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@heroicons/vue/-/vue-1.0.6.tgz", + "integrity": "sha512-ng2YcCQrdoQWEFpw+ipFl2rZo8mZ56v0T5+MyfQQvNqfKChwgP6DMloZLW+rl17GEcHkE3H82UTAMKBKZr4+WA==", + "requires": {} + }, "@humanwhocodes/config-array": { "version": "0.5.0", "dev": true, diff --git a/package.json b/package.json index 42be29cb212bd2a0f546fa362f15f5d482baa322..4b4f06e87feea6cbf22be72ac5bacc3aed4b4eaf 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "vue-cli-service lint" }, "dependencies": { + "@heroicons/vue": "^1.0.6", "@mdi/font": "5.9.55", "@vuelidate/core": "^2.0.0-alpha.40", "@vuelidate/validators": "^2.0.0-alpha.28", diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2bbee9c7589aa7943fe472849934b7f220ed43cd Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000000000000000000000000000000000000..41235286563508e0feb4c451a34b598ef822ec21 --- /dev/null +++ b/public/index.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width,initial-scale=1.0"> + <link rel="icon" href="<%= BASE_URL %>favicon.ico"> + <title><%= htmlWebpackPlugin.options.title %></title> + </head> + <body> + <noscript> + <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> + </noscript> + <div id="app"></div> + <!-- built files will be auto injected --> + </body> +</html> diff --git a/src/App.vue b/src/App.vue index 91695eb7395ebb9a45774a95415215684ce798b7..8b981fa82ba0894398770b4837b3acf32161f24b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -9,14 +9,18 @@ import { defineComponent } from "vue"; // Components - -import NavBar from "./components/NavigationComponents/NavBar.vue"; +import NavBar from "./components/BaseComponents/NavBar.vue"; export default defineComponent({ name: "App", - components: { NavBar, }, }); </script> + +<style global> +@tailwind base; +@tailwind components; +@tailwind utilities; +</style> diff --git a/src/assets/members.png b/src/assets/members.png new file mode 100644 index 0000000000000000000000000000000000000000..51775f6bead51014d3143631c292421752d024b6 Binary files /dev/null and b/src/assets/members.png differ diff --git a/src/assets/newCommunity.png b/src/assets/newCommunity.png new file mode 100644 index 0000000000000000000000000000000000000000..73bfba9f8000cecabb461394d7fe2f6b90c02b56 Binary files /dev/null and b/src/assets/newCommunity.png differ diff --git a/src/components/BaseComponents/ColoredButton.vue b/src/components/BaseComponents/ColoredButton.vue new file mode 100644 index 0000000000000000000000000000000000000000..74091bb360a25e7d489994c4aded8e59544445e5 --- /dev/null +++ b/src/components/BaseComponents/ColoredButton.vue @@ -0,0 +1,16 @@ +<template> + <button + class="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" + > + {{ text }} + </button> +</template> + +<script> +export default { + name: "ColoredButton", + props: { + text: String, + }, +}; +</script> diff --git a/src/components/BaseComponents/CommunityHeader.vue b/src/components/BaseComponents/CommunityHeader.vue new file mode 100644 index 0000000000000000000000000000000000000000..6e2b31a722f7401e93c6d9d640ca911b85d1f251 --- /dev/null +++ b/src/components/BaseComponents/CommunityHeader.vue @@ -0,0 +1,94 @@ +<template> + <div class="flex items-center justify-between mx-4"> + <div class="flex-1 min-w-0"> + <h2 + class="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate" + > + {{ community.name }} + </h2> + <div + class="mt-1 flex flex-col sm:flex-row sm:flex-wrap sm:mt-0 sm:space-x-6" + > + <div class="mt-2 flex items-center text-sm text-gray-500"> + <svg + class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 20 20" + fill="currentColor" + aria-hidden="true" + > + <path + fill-rule="evenodd" + d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" + clip-rule="evenodd" + /> + </svg> + {{ community.location }} + </div> + </div> + </div> + <div> + <span class="hidden sm:block"> + <!-- Legg dette til i button: v-if="adminStatus" --> + + <svg + @click="toggle" + xmlns="http://www.w3.org/2000/svg" + class="w-9 h-9 cursor-pointer" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor" + > + <path + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M4 6h16M4 12h16M4 18h16" + /> + </svg> + + <CommunityHamburger + v-if="hamburgerOpen" + class="origin-top-right absolute right-0" + :community-i-d="community.communityId" + /> + <!-- class="absolute" --> + </span> + </div> + </div> +</template> + +<script> +import CommunityHamburger from "@/components/CommunityComponents/CommunityHamburger"; +export default { + name: "CommunityHeader", + components: { + CommunityHamburger, + }, + data() { + return { + hamburgerOpen: false, + }; + }, + props: { + adminStatus: Boolean, + community: { + communityId: Number, + name: String, + description: String, + visibility: Number, + location: String, + picture: String, + }, + }, + methods: { + toggle: function () { + if (this.hamburgerOpen) { + this.hamburgerOpen = false; + } else { + this.hamburgerOpen = true; + } + }, + }, +}; +</script> diff --git a/src/components/BaseComponents/CustomFooterModal.vue b/src/components/BaseComponents/CustomFooterModal.vue new file mode 100644 index 0000000000000000000000000000000000000000..8a6e57ca1707d02d53ab57a00b3c2626587f146d --- /dev/null +++ b/src/components/BaseComponents/CustomFooterModal.vue @@ -0,0 +1,65 @@ +<template> + <!-- Main modal --> + <div + v-if="visible" + class="fixed grid place-items-center bg-gray-600 bg-opacity-50 top-0 left-0 right-0 z-50 w-full overflow-x-hidden overflow-y-auto md:inset-0 h-modal md:h-full" + > + <div class="relative w-full h-full max-w-2xl p-4 md:h-auto"> + <!-- Modal content --> + <div class="relative bg-white rounded-lg shadow dark:bg-gray-700"> + <!-- Modal header --> + <div + class="flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600" + > + <h3 class="text-xl font-semibold text-gray-900 dark:text-white"> + {{ title }} + </h3> + <button + @click="close()" + class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" + > + <svg + class="w-5 h-5" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + fill-rule="evenodd" + d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" + clip-rule="evenodd" + ></path> + </svg> + </button> + </div> + <!-- Modal body --> + <div class="p-6 space-y-6"> + <p class="text-base leading-relaxed text-gray-500 dark:text-gray-400"> + {{ message }} + </p> + </div> + <!-- Modal footer --> + <div class="rounded-b border-t border-gray-200 dark:border-gray-600"> + <!-- Slot: Add any html you want here --> + <slot /> + </div> + </div> + </div> + </div> +</template> + +<script> +export default { + name: "CustomFooterModal", + props: { + visible: Boolean, + title: String, + message: String, + }, + methods: { + close() { + this.$emit("close"); + }, + }, +}; +</script> diff --git a/src/components/BaseComponents/IconButton.vue b/src/components/BaseComponents/IconButton.vue new file mode 100644 index 0000000000000000000000000000000000000000..4bacbdf64c9f36c6ce5e9bc29146e24737f55ea4 --- /dev/null +++ b/src/components/BaseComponents/IconButton.vue @@ -0,0 +1,30 @@ +<template> + <!-- Icon button --> + <button + class="block w-fit text-white text-base bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" + > + <div class="flex flex-row px-5 py-2.5 h-10"> + <!-- Icon slot: Default content "Ban"-icon --> + <div class="h-6 w-6"> + <slot> + <BanIcon /> + </slot> + </div> + <p>{{ text }}</p> + </div> + </button> +</template> + +<script> +import { BanIcon } from "@heroicons/vue/outline"; + +export default { + name: "IconButton", + props: { + text: String, + }, + components: { + BanIcon, + }, +}; +</script> diff --git a/src/components/NavigationComponents/NavBar.vue b/src/components/BaseComponents/NavBar.vue similarity index 95% rename from src/components/NavigationComponents/NavBar.vue rename to src/components/BaseComponents/NavBar.vue index c440c3555f76aae08a30cb70d29002fdf3bf718a..a14c390128eea359968f895e823ecc620be36645 100644 --- a/src/components/NavigationComponents/NavBar.vue +++ b/src/components/BaseComponents/NavBar.vue @@ -1,6 +1,6 @@ <template> <nav - class="flex items-center justify-between bg-white h-14 border-1 border-b border-gray-300 border-solid" + class="flex items-center justify-between bg-white h-14 border-1 border-b border-gray-300 border-solid sticky top-0 z-50" > <div class="logo"> <img diff --git a/src/components/BaseComponents/NotificationModal.vue b/src/components/BaseComponents/NotificationModal.vue new file mode 100644 index 0000000000000000000000000000000000000000..5883ed10714253ab7a6ffe1f0416c5af75f5166a --- /dev/null +++ b/src/components/BaseComponents/NotificationModal.vue @@ -0,0 +1,60 @@ +<template> + <!-- Main modal --> + <div + v-if="visible" + class="fixed grid place-items-center bg-gray-600 bg-opacity-50 top-0 left-0 right-0 z-50 w-full overflow-x-hidden overflow-y-auto md:inset-0 h-modal md:h-full" + > + <div class="relative w-full h-full max-w-2xl p-4 md:h-auto"> + <!-- Modal content --> + <div class="relative bg-white rounded-lg shadow dark:bg-gray-700"> + <!-- Modal header --> + <div + class="flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600" + > + <h3 class="text-xl font-semibold text-gray-900 dark:text-white"> + {{ title }} + </h3> + <button + @click="close()" + class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" + > + <svg + class="w-5 h-5" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + fill-rule="evenodd" + d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" + clip-rule="evenodd" + ></path> + </svg> + </button> + </div> + <!-- Modal body --> + <div class="p-6 space-y-6"> + <p class="text-base leading-relaxed text-gray-500 dark:text-gray-400"> + {{ message }} + </p> + </div> + </div> + </div> + </div> +</template> + +<script> +export default { + name: "NotificationModal", + props: { + visible: Boolean, + title: String, + message: String, + }, + methods: { + close() { + this.$emit("close"); + }, + }, +}; +</script> diff --git a/src/components/NavigationComponents/NotificationsForm.vue b/src/components/BaseComponents/NotificationsForm.vue similarity index 100% rename from src/components/NavigationComponents/NotificationsForm.vue rename to src/components/BaseComponents/NotificationsForm.vue diff --git a/src/components/ChatComponents/ChatMessage.vue b/src/components/ChatComponents/ChatMessage.vue index 58720e89792b63889b4de9db9f870e47fc4eeeeb..d3e016a3d4b947d0b90cedb3ea9e07093a47a206 100644 --- a/src/components/ChatComponents/ChatMessage.vue +++ b/src/components/ChatComponents/ChatMessage.vue @@ -47,7 +47,7 @@ export default { calculateTime() { //let time = this.message.from; // Calculate time when message was sent - let date = new Date(Date.now()); + let date = new Date(this.message.timestamp); let hours = date.getHours(); let minutes = "0" + date.getMinutes(); let formattedTime = hours + ":" + minutes.substr(-2); diff --git a/src/components/CommunityComponents/CommunityHamburger.vue b/src/components/CommunityComponents/CommunityHamburger.vue new file mode 100644 index 0000000000000000000000000000000000000000..e060566e73a400fbe368f168136a2e1cff1f8a7b --- /dev/null +++ b/src/components/CommunityComponents/CommunityHamburger.vue @@ -0,0 +1,46 @@ +<template> + <div + id="dropdown" + class="z-10 w-44 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700" + > + <ul class="py-1"> + <li id="newItem"> + <router-link + to="/addNewItem" + class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white" + >Opprett Utleie</router-link + > + </li> + <li id="getMembers"> + <router-link + :to="'/group/' + communityID + '/memberlist'" + class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white" + >Se Medlemmer + </router-link> + </li> + <li id="adminGroup"> + <router-link + :to="'/group/' + communityID + '/memberlist'" + class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white" + >Administrer Gruppe</router-link + > + </li> + <li id="leaveGroup"> + <div + class="cursor-pointer block py-2 px-4 text-sm text-red-600 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white" + > + Forlat Gruppe + </div> + </li> + </ul> + </div> +</template> + +<script> +export default { + name: "CommunityHamburger", + props: { + communityID: Number, + }, +}; +</script> diff --git a/src/components/CommunityComponents/CommunityHome.vue b/src/components/CommunityComponents/CommunityHome.vue index 1d973afa3cb94e1519b55b29ff5e81b14c53a4c0..e6cf391a30732b1b29ac542848fe4cfac2c58b8c 100644 --- a/src/components/CommunityComponents/CommunityHome.vue +++ b/src/components/CommunityComponents/CommunityHome.vue @@ -1,8 +1,12 @@ <template> - <section class="relative w-full max-w-md px-5 py-4 mx-auto rounded-md"> - <div class="mb-5 mt-5 border-b-2 border-blue-900"> - <label class="text-xl font-bold">Tøyenhus borettslag</label> - </div> + <section class="w-full px-5 py-4 mx-auto rounded-md"> + <CommunityHeader + :admin-status="false" + :community="community" + class="mb-5" + /> + + <!-- Search field --> <div class="relative" id="searchComponent"> <span class="absolute inset-y-0 left-0 flex items-center pl-3"> <svg class="w-5 h-5 text-gray-400" viewBox="0 0 24 24" fill="none"> @@ -25,9 +29,17 @@ /> </div> - <div class="absolute inset-x-0 px-6 py-3 mt-4"> - <div class="grid grid-cols-2"> - <ItemCard v-for="item in searchedItems" :key="item" :item="item" /> + <!-- Item cards --> + <div class="absolute inset-x-0 px-6 py-3"> + <div + class="grid grid-flow-row-dense grid-cols-2 md:grid-cols-4 lg:grid-cols-5 w-full place-items-center" + > + <ItemCard + v-for="item in searchedItems" + :key="item" + :item="item" + @click="goToItemInfoPage(item.listingID)" + /> </div> </div> </section> @@ -35,10 +47,13 @@ <script> import ItemCard from "@/components/CommunityComponents/ItemCard"; +import CommunityHeader from "@/components/BaseComponents/CommunityHeader"; +import { GetCommunity, GetListingsInCommunity } from "@/utils/apiutil"; export default { name: "SearchItemListComponent", components: { + CommunityHeader, ItemCard, }, @@ -49,37 +64,51 @@ export default { filteredItems = this.items.filter( (p) => p.title.toLowerCase().includes(this.search.toLowerCase()) || - p.adresse.toLowerCase().includes(this.search.toLowerCase()) || - p.price === Number(this.search) + p.address.toLowerCase().includes(this.search.toLowerCase()) || + p.pricePerDay === Number(this.search) ); return filteredItems; }, }, - - /** - * Her må det lages en metode som henter alle items (i en gruppe) fra databasen. - * De kan deretter bli pusha inn i items array, og da burde de bli displayet i lista. - * Når denne metoden er på plass kan items[] i data tømmes. Da vil alt dataen komme fra db. - */ - + created() { + if (this.$store.state.user.token !== null) { + this.isLoggedIn = true; + } + }, data() { return { - items: [ - { img: "", adresse: "Oslo", title: "Dyson", price: 1000 }, - - { img: "", adresse: "Trondheim", title: "Gressklipper", price: 500 }, - - { img: "", adresse: "Bergen", title: "Bil", price: 500 }, - ], + items: [], item: { + listingID: 0, img: "", - adresse: "", + address: "", title: "", - price: 0, + pricePerDay: 0, }, search: "", + communityID: -1, + community: {}, }; }, + methods: { + getCommunityFromAPI: async function () { + this.communityID = await this.$router.currentRoute.value.params + .communityID; + this.community = await GetCommunity(this.communityID); + }, + getListingsOfCommunityFromAPI: async function () { + this.communityID = await this.$router.currentRoute.value.params + .communityID; + this.items = await GetListingsInCommunity(this.communityID); + }, + goToItemInfoPage(item) { + this.$router.push("/itempage/" + item); + }, + }, + beforeMount() { + this.getCommunityFromAPI(); //To get the id of the community before mounting the view + this.getListingsOfCommunityFromAPI(); + }, }; </script> diff --git a/src/components/CommunityComponents/CommunityList.vue b/src/components/CommunityComponents/CommunityList.vue index 045eeadf16730ecd725b4e0c9990fbad0ee3d9ca..859e69d3e7f96c56935f64dd7b16beca2f403188 100644 --- a/src/components/CommunityComponents/CommunityList.vue +++ b/src/components/CommunityComponents/CommunityList.vue @@ -1,21 +1,22 @@ <template> <ul> - <li v-for="(group, index) in groupList" :key="index"> - <group-list-item :group="group" /> + <li v-for="community in communities" :key="community"> + <CommunityListItem :community="community" :member="member" /> </li> </ul> </template> <script> -import GroupListItem from "@/components/CommunityComponents/CommunityListItem.vue"; +import CommunityListItem from "@/components/CommunityComponents/CommunityListItem.vue"; export default { - name: "GroupList", + name: "CommunityList", props: { - groupList: Array, + communities: Array, + member: Boolean, }, components: { - GroupListItem, + CommunityListItem, }, }; </script> diff --git a/src/components/CommunityComponents/CommunityListItem.vue b/src/components/CommunityComponents/CommunityListItem.vue index 81d2b7dee530d7eae79f97e954ff19a52936bd34..d75938f456c1ed61aad0ebc89db8e04a2282bc2f 100644 --- a/src/components/CommunityComponents/CommunityListItem.vue +++ b/src/components/CommunityComponents/CommunityListItem.vue @@ -1,46 +1,66 @@ <template> + <CustomFooterModal + @close="this.dialogOpen = false" + :visible="dialogOpen" + :title="community.name" + :message="community.description" + > + <div class="flex justify-center p-2"> + <ColoredButton + v-if="!member" + :text="'Bli med'" + @click="goToJoin(community.communityId)" + /> + <ColoredButton + v-if="member" + :text="'Gå til'" + @click="goToGroup(community.communityId)" + /> + </div> + </CustomFooterModal> <div + @click="toggleDialog()" class="bg-white shadow dark:bg-gray-800 select-none cursor-pointer hover:bg-gray-50 flex items-center p-4" > <div class="h-10 w-10 flex flex-col justify-center items-center mr-4"> - <img alt="groupIMG" src="../../assets/group.png" /> + <UserGroupIcon v-if="!community.image" alt="Felleskapets bilde" /> + <!-- TODO: USE COMMUNITY IMAGE <img alt="Felleskapets bilde" src="@/assets/group.png" /> --> </div> - <div class="flex-1 pl-1"> - <div class="font-medium dark:text-white"> - {{ group.name }} + <div class="flex-1 pl-1 overflow-hidden"> + <div class="font-medium dark:text-white truncate"> + {{ community.name }} </div> </div> - <div class="flex flex-row justify-center"> - <button - @click="goToJoin(group.communityId)" - v-if="!isMember" - class="px-4 py-2 w-24 font-medium tracking-wide text-white capitalize transition-colors duration-200 transform bg-blue-600 rounded-md hover:bg-blue-500 focus:outline-none focus:ring focus:ring-blue-300 focus:ring-opacity-80" - > - Bli med - </button> - <button - v-if="isMember" - @click="goToGroup(group.communityId)" - class="px-4 py-2 w-24 font-medium tracking-wide text-white capitalize transition-colors duration-200 transform bg-blue-600 rounded-md hover:bg-blue-500 focus:outline-none focus:ring focus:ring-blue-300 focus:ring-opacity-80" - > - Gå til - </button> + <div class="flex flex-row justify-center items-center"> + <LockClosedIcon + v-if="community.visibility === 0" + class="max-h-6 max-w-6 shrink m-2" + /> </div> </div> </template> <script> -import { getMyGroups } from "@/utils/apiutil"; +import CustomFooterModal from "@/components/BaseComponents/CustomFooterModal.vue"; +import ColoredButton from "@/components/BaseComponents/ColoredButton.vue"; +import { UserGroupIcon, LockClosedIcon } from "@heroicons/vue/outline"; export default { - name: "GroupListItem", + name: "CommunityListItem", + components: { + CustomFooterModal, + ColoredButton, + UserGroupIcon, + LockClosedIcon, + }, data() { return { - myGroups: [], + dialogOpen: false, }; }, props: { - group: Object, + community: Object, + member: Boolean, }, methods: { goToGroup(id) { @@ -49,15 +69,9 @@ export default { goToJoin(id) { this.$router.push("/community/" + id + "/join"); }, - async getMyGroups() { - this.myGroups = await getMyGroups(); + toggleDialog() { + this.dialogOpen = !this.dialogOpen; }, - isMember(group) { - return this.myGroups.includes(group); - }, - }, - beforeMount() { - this.getMyGroups(); }, }; </script> diff --git a/src/components/CommunityComponents/ItemCard.vue b/src/components/CommunityComponents/ItemCard.vue index 44abedf3ca02f74998e51ae0816ea00c1bdf3293..4f4b52526a96f32d29ed839245254a5c12228f1e 100644 --- a/src/components/CommunityComponents/ItemCard.vue +++ b/src/components/CommunityComponents/ItemCard.vue @@ -1,6 +1,6 @@ <template> <div class="mt-5"> - <div class="w-4/5 rounded bg-gray-200"> + <div class="w-52 rounded bg-gray-200"> <img class="w-full" :src="item.img || require('../../assets/default-product.png')" @@ -8,10 +8,12 @@ /> <div class="p-1 m-1"> <p class="text-gray-700 text-xs font-bold" id="adress"> - {{ item.adresse }} + {{ item.address }} </p> <p class="font-bold text-sm" id="title">{{ item.title }}</p> - <p class="text-gray-700 text-xs" id="price">{{ item.price }} kr</p> + <p class="text-gray-700 text-xs" id="price"> + {{ item.pricePerDay }} kr + </p> </div> </div> </div> @@ -22,9 +24,9 @@ export default { props: { item: { img: String, - adresse: String, + address: String, title: String, - price: Number, + pricePerDay: Number, }, }, }; diff --git a/src/components/CommunityComponents/MemberList.vue b/src/components/CommunityComponents/MemberList.vue index 7b44f5fa5a3fa3ba4ef464e0400a22613eb6c819..b8360de5851fd26e86d6e9c5925f68eec3011e31 100644 --- a/src/components/CommunityComponents/MemberList.vue +++ b/src/components/CommunityComponents/MemberList.vue @@ -1,4 +1,9 @@ <template> + <CommunityHeader + :admin-status="false" + :community="community" + class="mb-5 mt-5" + /> <ul> <li v-for="member in memberlist" :key="member.userId"> <user-list-item-card :admin="admin" :user="member" /> @@ -8,29 +13,38 @@ <script> import UserListItemCard from "../UserProfileComponents/UserListItemCard.vue"; +import { GetMembersOfCommunity, GetCommunity } from "@/utils/apiutil"; +import CommunityHeader from "@/components/BaseComponents/CommunityHeader"; export default { data() { return { - memberlist: [ - { - userId: 2, - firstName: "erik", - lastName: "hansen", - }, - { - userId: 1, - firstName: "Test", - lastName: "Testesen", - }, - ], + memberlist: [], + community: {}, }; }, components: { + CommunityHeader, UserListItemCard, }, props: { admin: Boolean, }, + methods: { + getAllMembersOfCommunity: async function () { + this.memberlist = await GetMembersOfCommunity( + this.$router.currentRoute.value.params.id + ); + }, + getCommunity: async function () { + this.community = await GetCommunity( + this.$router.currentRoute.value.params.id + ); + }, + }, + beforeMount() { + this.getAllMembersOfCommunity(); + this.getCommunity(); + }, }; </script> diff --git a/src/components/CommunityComponents/NewCommunityForm.vue b/src/components/CommunityComponents/NewCommunityForm.vue index e322ce2c043a9a1349d7fa0e9cb7757150ea6595..bb3a4d8edfd877b35648111b8b9a28d4ab2c9575 100644 --- a/src/components/CommunityComponents/NewCommunityForm.vue +++ b/src/components/CommunityComponents/NewCommunityForm.vue @@ -101,42 +101,6 @@ </div> </div> - <!-- Select category --> - <div class="mt-6"> - <label - class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400" - id="selectCategoryLabel" - >Kategori</label - > - <select - v-model="v$.group.select.$model" - id="categories" - class="bg-gray-200 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" - > - <option class="text-gray-400" value="" disabled selected> - Select a category - </option> - <option - v-for="category in group.categories" - :key="category" - class="text-gray-900 text-sm" - > - {{ category }} - </option> - </select> - - <!-- error message for select box --> - <div - class="text-red" - v-for="(error, index) of v$.group.select.$errors" - :key="index" - > - <div class="text-red-600 text-sm"> - {{ error.$message }} - </div> - </div> - </div> - <!-- Description --> <div class="mt-6" :class="{ error: v$.group.description.$errors.length }"> <label @@ -184,13 +148,16 @@ <!-- Button for adding an image --> <div class="inline-flex rounded-md shadow-sm"> - <button + <div class="text-red-500 uppercase text-center"> + midlertidig fjernet + </div> + <!-- <button @click="$refs.file.click()" - class="text-black bg-gray-200 hover:bg-grey-800 focus:ring-4 focus:outline-none focus:ring-grey-300 font-medium rounded-lg text-sm sm:w-auto px-5 py-2.5 text-center dark:bg-grey-600 dark:hover:bg-grey-700 dark:focus:ring-grey-800 disabled:opacity-50 cursor-not-allowed" + class="text-black bg-gray-200 hover:bg-grey-800 focus:ring-4 focus:outline-none focus:ring-grey-300 font-medium rounded-lg text-sm sm:w-auto px-5 py-2.5 text-center dark:bg-grey-600 dark:hover:bg-grey-700 dark:focus:ring-grey-800 disabled:opacity-50" :disabled="imageAdded" > Velg bilde - </button> + </button> --> <!-- Button for removing an image --> <button @@ -266,9 +233,6 @@ export default { maxLength(200) ), }, - select: { - required: helpers.withMessage(() => `Velg en kategori`, required), - }, }, }; }, @@ -276,10 +240,8 @@ export default { return { group: { name: "", - select: null, description: "", images: [], - categories: ["Borettslag", "Idrettsklubb", "Fritidsklubb"], radio: null, place: "", visibility: 1, @@ -300,45 +262,26 @@ export default { removeImage: function () { this.group.images.pop(); this.imageThere = false; - console.log("Bilder nå: " + this.group.images.length); }, checkRadioButton: function (event) { this.group.radio = event.target.value; - console.log(this.group.radio); if (this.group.radio == null || this.group.radio == "Åpen") { this.group.visibility = 1; } else { this.group.visibility = 0; } - - console.log("visibility: " + this.group.visibility); }, checkValidation: function () { - console.log("sjekker validering"); - this.v$.group.$touch(); if (this.v$.group.$invalid) { - console.log("Invalid, avslutter..."); return false; } - - console.log("validert!"); return true; }, async saveClicked() { - console.log("Attempting to save item"); - if (this.checkValidation()) { - console.log("validert, videre..."); - console.log("Navn: " + this.group.name); - console.log("Sted: " + this.group.place); - console.log("Synlighet: " + this.group.radio); - console.log("Kategori: " + this.group.select); - console.log("Beskrivelse: " + this.group.description); - console.log("bilder: " + this.group.images); - const groupInfo = { name: this.group.name, description: this.group.description, @@ -347,18 +290,13 @@ export default { picture: "", }; - console.log(groupInfo); - const postCreatedGroup = await postNewgroup(groupInfo); - console.log(postCreatedGroup); + await postNewgroup(groupInfo); } }, addImage: function (event) { - console.log(event.target.files); this.group.images.push(URL.createObjectURL(event.target.files[0])); - console.log("antall bilder: " + this.group.images.length); this.imageThere = true; - console.log("image: " + this.imageThere); }, }, }; diff --git a/src/components/FormComponents/RegisterForm.vue b/src/components/FormComponents/RegisterForm.vue index 240895bffbe2fe98be228f19e2d7549f3bc24227..3f4551a3e677e01b48cfcc29cb889b21d9bf04c1 100644 --- a/src/components/FormComponents/RegisterForm.vue +++ b/src/components/FormComponents/RegisterForm.vue @@ -182,15 +182,15 @@ export default { const loginResponse = await doLogin(loginRequest); - if (loginResponse === "Failed login") { + if (loginResponse.isLoggedIn === false) { this.errorMessage = "Failed to log in with new user"; this.$store.commit("logout"); - this.$router.push("/login"); + await this.$router.push("/login"); return; } - this.$store.commit("saveToken", loginResponse); - this.$router.push("/"); + this.$store.commit("saveToken", loginResponse.token); + await this.$router.push("/"); }, async sendRegisterRequest() { const registerInfo = { diff --git a/src/components/RentingComponents/ImageCarousel.vue b/src/components/RentingComponents/ImageCarousel.vue index 704c83cedf0a1a5f56f9f09b33c96a6cfd5149c0..aef0e652e6609273c2505025287c152ece3d10d4 100644 --- a/src/components/RentingComponents/ImageCarousel.vue +++ b/src/components/RentingComponents/ImageCarousel.vue @@ -1,71 +1,78 @@ <template> - <div id="carouselIndicators" class="carousel slide relative" data-bs-ride="carousel"> - <div class="carousel-indicators absolute right-0 bottom-0 left-0 flex justify-center p-0 mb-4"> - <button - v-for="(image, i) in images" - :key="i" - type="button" - data-bs-target="#carouselIndicators" - :data-bs-slide-to="i" - :class="{'active': i === 0}" - :aria-current="i === 0 ? 'true' : 'false'" - :aria-label="'Slide ' + (i+1)" - ></button> - </div> - <div class="carousel-inner relative w-full overflow-hidden"> - <div v-for="(image, i) in images" :key="i" :class="'carousel-item float-left w-full'+ (i == 0 ? ' active' : '')" > - <img - :src="image.src" - class="block w-full" - :alt="image.alt" - /> - </div> - </div> - <button - class="carousel-control-prev absolute top-0 bottom-0 flex items-center justify-center p-0 text-center border-0 hover:outline-none hover:no-underline focus:outline-none focus:no-underline left-0" - type="button" - data-bs-target="#carouselIndicators" - data-bs-slide="prev" - > - <span class="carousel-control-prev-icon inline-block bg-no-repeat" aria-hidden="true"></span> - <span class="visually-hidden">Previous</span> - </button> - <button - class="carousel-control-next absolute top-0 bottom-0 flex items-center justify-center p-0 text-center border-0 hover:outline-none hover:no-underline focus:outline-none focus:no-underline right-0" - type="button" - data-bs-target="#carouselIndicators" - data-bs-slide="next" - > - <span class="carousel-control-next-icon inline-block bg-no-repeat" aria-hidden="true"></span> - <span class="visually-hidden">Next</span> - </button> + <div + id="carouselIndicators" + class="carousel slide relative" + data-bs-ride="carousel" + > + <div + class="carousel-indicators absolute right-0 bottom-0 left-0 flex justify-center p-0 mb-4" + > + <button + v-for="(image, i) in images" + :key="i" + type="button" + data-bs-target="#carouselIndicators" + :data-bs-slide-to="i" + :class="{ active: i === 0 }" + :aria-current="i === 0 ? 'true' : 'false'" + :aria-label="'Slide ' + (i + 1)" + ></button> </div> + <div class="carousel-inner relative w-full overflow-hidden"> + <div + v-for="(image, i) in images" + :key="i" + :class="'carousel-item float-left w-full' + (i == 0 ? ' active' : '')" + > + <img :src="image.src" class="block w-full" :alt="image.alt" /> + </div> + </div> + <button + class="carousel-control-prev absolute top-0 bottom-0 flex items-center justify-center p-0 text-center border-0 hover:outline-none hover:no-underline focus:outline-none focus:no-underline left-0" + type="button" + data-bs-target="#carouselIndicators" + data-bs-slide="prev" + > + <span + class="carousel-control-prev-icon inline-block bg-no-repeat" + aria-hidden="true" + ></span> + <span class="visually-hidden">Previous</span> + </button> + <button + class="carousel-control-next absolute top-0 bottom-0 flex items-center justify-center p-0 text-center border-0 hover:outline-none hover:no-underline focus:outline-none focus:no-underline right-0" + type="button" + data-bs-target="#carouselIndicators" + data-bs-slide="next" + > + <span + class="carousel-control-next-icon inline-block bg-no-repeat" + aria-hidden="true" + ></span> + <span class="visually-hidden">Next</span> + </button> + </div> </template> <script> - /* { src: "imageURL", alt: "IMAGE ALT TEXT" } */ - import 'tw-elements'; - export default { - props: { - images: { - type: Array, - required: true, - }, - }, - data() { - return { - - } - } - } +import "tw-elements"; +export default { + props: { + images: { + type: Array, + required: true, + }, + }, + data() { + return {}; + }, +}; </script> -<style scoped> - -</style> \ No newline at end of file +<style scoped></style> diff --git a/src/components/RentingComponents/ItemInfo.vue b/src/components/RentingComponents/ItemInfo.vue new file mode 100644 index 0000000000000000000000000000000000000000..61c4e6099a972322c1e05b475af8421e75cb92b1 --- /dev/null +++ b/src/components/RentingComponents/ItemInfo.vue @@ -0,0 +1,142 @@ +<template> + <div> + <div> + <ImageCarousel :images="pictures"></ImageCarousel> + </div> + <!-- Product info --> + <div + class="max-w-2xl mx-auto pt-10 pb-16 px-4 sm:px-6 lg:max-w-7xl lg:pt-16 lg:pb-24 lg:px-8 lg:grid lg:grid-cols-3 lg:grid-rows-[auto,auto,1fr] lg:gap-x-8" + > + <div class="lg:col-span-2 lg:border-r lg:border-gray-200 lg:pr-8"> + <h1 + class="text-2xl font-extrabold tracking-tight text-gray-900 sm:text-3xl" + > + {{ item.title }} + </h1> + </div> + <div + class="py-10 lg:pt-6 lg:pb-16 lg:col-start-1 lg:col-span-2 lg:border-r lg:border-gray-200 lg:pr-8" + > + <!-- Description and details --> + <div> + <h3 class="text-base font-semibold text-gray-900">Pris per dag</h3> + + <div class="space-y-6"> + <p class="text-2xl font-medium text-gray-900"> + {{ item.pricePerDay }} kr + </p> + </div> + </div> + <div class="mt-4"> + <h3 class="text-base font-base text-gray-900">Ledige tidspunkter</h3> + + <div> + <p class="text-sm text-gray-900"> + (placeholder skal byttes ut med date-picker) + </p> + </div> + </div> + <div class="mt-10"> + <div class="mt-4 space-y-6"> + <p class="text-sm text-gray-600">{{ item.description }}</p> + </div> + </div> + <div class="mt-6"> + <!-- Add in method for displaying user card. Use item.userID on the method --> + (Placeholder) Add usercard here + <UserListItemCard :admin="false" :user="this.item.userID"></UserListItemCard> + </div> + <div> + <div class="mt-4 space-y-6"> + <p class="text-base font-semibold text-gray-900"> + {{ item.address }} + </p> + </div> + </div> + <div class="mt-10"> + <h3 class="text-base font-semibold text-gray-900">Totalprisen er</h3> + + <div class="mt-2 space-y-2"> + <p class="text-xl font-medium text-gray-900"> + mye (Change with tot price from calc method) + </p> + <button> + <!-- This button should send you to the rent page --> + Rent page + </button> + </div> + </div> + </div> + </div> + </div> +</template> + +<script> +import { getItem } from "@/utils/apiutil"; +import { getItemPictures } from "@/utils/apiutil"; +import ImageCarousel from "@/components/RentingComponents/ImageCarousel.vue"; +import UserListItemCard from "@/components/UserProfileComponents/UserListItemCard.vue"; + +export default { + name: "ItemInfo", + data() { + return { + item: { + listingID: 0, + title: "", + description: "", + pricePerDay: 0, + address: "", + userID: 0, + categoryNames: [], + communityIDs: [], + }, + images: [ + { + listingID: 0, + picture: "", + }, + ], + pictures: [], + }; + }, + components: { + ImageCarousel, + UserListItemCard, + }, + methods: { + async getItem() { + let id = this.$router.currentRoute.value.params.id; + this.item = await getItem(id); + }, + async getItemPictures() { + let id = this.$router.currentRoute.value.params.id; + this.images = await getItemPictures(id); + + if(this.images.length < 1) { + let noImage = { + src: require('@/assets/default-product.png'), + alt: "No image found", + }; + this.pictures.push(noImage); + } else { + for (let i = 0; i < this.images.length; i++) { + let oneImage = { + src: this.images[i].picture, + //How do i make this accurate to the image? + alt: "An image", + }; + this.pictures.push(oneImage); + } + } + //TODO fixs so each image get a correct alt text. + }, + }, + async beforeMount() { + await this.getItemPictures(); + this.getItem(); + }, +}; +</script> + +<style></style> diff --git a/src/index.css b/src/index.css deleted file mode 100644 index bd6213e1dfe6b0a79ce7d8b37d0d2dc70f0250bb..0000000000000000000000000000000000000000 --- a/src/index.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; \ No newline at end of file diff --git a/src/main.js b/src/main.js index da2685dca10f402e327223ae32fee373b9a0c8c1..32764da4a55678ff6ed1fbf6e21819a55990f716 100644 --- a/src/main.js +++ b/src/main.js @@ -2,7 +2,6 @@ import { createApp } from "vue"; import App from "./App.vue"; import router from "./router"; import store from "./store"; -import "./index.css"; import ws from "./services/ws"; createApp(App).use(router).use(store).mount("#app"); diff --git a/src/router/index.js b/src/router/index.js index 163dc85a54a6abf12fd6f9e988fd8079d48c9185..bf6239a2db9c859369a2eed02bfc2bd12b7d0a0f 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -84,7 +84,8 @@ const routes = [ { path: "/notifications", name: "notifications", - component: () => import("../views/NavigationViews/NotificationView.vue"), + component: () => + import("../components/BaseComponents/NotificationsForm.vue"), beforeEnter: guardRoute, }, { @@ -93,10 +94,19 @@ const routes = [ component: () => import("../views/CommunityViews/MyCommunitiesView.vue"), }, { - path: "/groupHomePage", + path: "/community/:communityID", name: "GroupHome", component: () => import("../views/CommunityViews/CommunityHomeView.vue"), - beforeEnter: guardRoute, + }, + { + path: "/test", + name: "test", + component: () => import("../views/TestView.vue"), + }, + { + path: "/itempage/:id", + name: "ItemInfo", + component: () => import("../views/RentingViews/ItemInfoPageView.vue"), }, ]; diff --git a/src/utils/apiutil.js b/src/utils/apiutil.js index 36cc5d98091d38e0707974782c5f5f0bab692c51..c37d6d77e52847898f2017130607e85c2dc22b6f 100644 --- a/src/utils/apiutil.js +++ b/src/utils/apiutil.js @@ -147,3 +147,69 @@ export function getVisibleGroups() { console.error(error); }); } + +export function getItem(itemid) { + return axios + .get(API_URL + "listing/" + itemid, { + headers: tokenHeader(), + }) + .then((response) => { + return response.data; + }) + .catch((error) => { + console.error(error); + }); +} + +export async function getItemPictures(itemid) { + let res = await axios + .get(API_URL + "listing/" + itemid + "/pictures", { + headers: tokenHeader(), + }) + .then((response) => { + return response.data; + }) + .catch((error) => { + console.error(error); + }); + return res; +} + +export async function GetCommunity(communityID) { + return axios + .get(API_URL + "community/" + communityID, { + headers: tokenHeader(), + }) + .then((response) => { + return response.data; + }) + .catch((error) => { + console.error(error); + }); +} + +export async function GetListingsInCommunity(communityID) { + return axios + .get(API_URL + "community/" + communityID + "/listings", { + headers: tokenHeader(), + }) + .then((response) => { + return response.data; + }) + .catch((error) => { + console.error(error); + }); +} + +export async function GetMembersOfCommunity(communityID) { + return axios + .get(API_URL + "community/" + communityID + "/members", { + headers: tokenHeader(), + }) + .then((response) => { + return response.data; + }) + .catch((error) => { + console.error(error); + }); +} diff --git a/src/views/CommunityViews/CommunityHomeView.vue b/src/views/CommunityViews/CommunityHomeView.vue index cabfd1b6ed2ea1e5775868f160484ddd9fa99b06..40886b3feb0816f305ee4a5045f180478677c8bb 100644 --- a/src/views/CommunityViews/CommunityHomeView.vue +++ b/src/views/CommunityViews/CommunityHomeView.vue @@ -1,15 +1,13 @@ <template> - <GroupHome></GroupHome> + <CommunityHome /> </template> <script> -import GroupHome from "@/components/CommunityComponents/CommunityHome"; +import CommunityHome from "@/components/CommunityComponents/CommunityHome.vue"; export default { - name: "GroupHomeView.vue", + name: "CommunityHomeView", components: { - GroupHome, + CommunityHome, }, }; </script> - -<style scoped></style> diff --git a/src/views/CommunityViews/CommunityView.vue b/src/views/CommunityViews/CommunityView.vue index d608f4bb50feb03376484b7f79de4685868b7977..9fd39f5f305a7592f633795254899fa3cf3883a8 100644 --- a/src/views/CommunityViews/CommunityView.vue +++ b/src/views/CommunityViews/CommunityView.vue @@ -1,42 +1,49 @@ <template> - <div> - <div id="myGroups"> - <div>Mine grupper:</div> - <group-list :groupList="myGroups" /> - </div> - <div id="localGroups"> - <div>Offentlige grupper:</div> - <group-list :groupList="localGroups" /> + <div v-if="loggedIn"> + <div class="flex flex-row p-4 relative"> + <p class="capitalize font-bold w-full">Mine felleskap</p> + <PlusIcon + class="cursor-pointer max-h-6 max-w-6 float-right grow" + @click="$router.push('/createNewGroup')" + v-if="loggedIn" + alt="Lag ett nytt felleskap" + /> </div> + <CommunityList :communities="myCommunities" :member="true" /> </div> + <p class="capitalize font-bold w-full p-4">Offentlige felleskap</p> + <CommunityList :communities="publicCommunities" :member="false" /> </template> <script> -import GroupList from "@/components/CommunityComponents/CommunityList.vue"; +import CommunityList from "@/components/CommunityComponents/CommunityList.vue"; import { getMyGroups, getVisibleGroups } from "@/utils/apiutil"; +import { PlusIcon } from "@heroicons/vue/outline"; export default { name: "HomeView", data() { return { - myGroups: [], - localGroups: [], + loggedIn: false, + myCommunities: [], + publicCommunities: [], }; }, components: { - GroupList, - }, - methods: { - async getMyGroups() { - this.myGroups = await getMyGroups(); - }, - async getPotentialGroups() { - this.localGroups = await getVisibleGroups(); - }, + CommunityList, + PlusIcon, }, async created() { - await this.getMyGroups(); - await this.getPotentialGroups(); + this.publicCommunities = await getVisibleGroups(); + this.loggedIn = this.$store.state.user.token !== null; + if (!this.loggedIn) return; + + this.myCommunities = await getMyGroups(); + + // Remove all of the user's communities from the public communities arrays + this.publicCommunities = this.publicCommunities.filter( + (val) => !this.myCommunities.includes(val) + ); }, }; </script> diff --git a/src/views/CommunityViews/MemberListView.vue b/src/views/CommunityViews/MemberListView.vue index d250c0d86d6909e6813594be74e75f2616f29fec..9f63b476d52810f37e88b726803ca54b6ccc9266 100644 --- a/src/views/CommunityViews/MemberListView.vue +++ b/src/views/CommunityViews/MemberListView.vue @@ -1,83 +1,13 @@ <template> - <div class="flex items-center justify-between mx-4"> - <div class="flex-1 min-w-0"> - <h2 - class="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate" - > - {{ groupe.name }} - </h2> - <div - class="mt-1 flex flex-col sm:flex-row sm:flex-wrap sm:mt-0 sm:space-x-6" - > - <div class="mt-2 flex items-center text-sm text-gray-500"> - <svg - class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" - > - <path - fill-rule="evenodd" - d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" - clip-rule="evenodd" - /> - </svg> - {{ groupe.address }} - </div> - </div> - </div> - <div class="flex"> - <span class="hidden sm:block"> - <button - v-if="adminStatus" - @click="edit()" - type="button" - class="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" - > - <!-- Heroicon name: solid/pencil --> - <svg - class="-ml-1 mr-2 h-5 w-5 text-gray-500" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" - > - <path - d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" - /> - </svg> - Edit - </button> - </span> - </div> - </div> - <div class="h-screen bg-gray-200 content-top grid place-items-top"> - <member-list :admin="editing" /> - </div> + <MemberList /> </template> <script> import MemberList from "@/components/CommunityComponents/MemberList.vue"; export default { - data() { - return { - groupe: { - name: "Solsikken borettslag", - address: "Sollia 6, 7033 Trondheim", - }, - adminStatus: false, - editing: false, - }; - }, components: { MemberList, }, - methods: { - edit() { - this.editing = !this.editing; - }, - }, }; </script> diff --git a/src/views/NavigationViews/NavBarView.vue b/src/views/NavigationViews/NavBarView.vue deleted file mode 100644 index c15762550bcfa1763085a8adca42ac5f39dd4983..0000000000000000000000000000000000000000 --- a/src/views/NavigationViews/NavBarView.vue +++ /dev/null @@ -1,17 +0,0 @@ -<template> - <div> - <Navbar /> - </div> -</template> - -<script> -import Navbar from "@/components/NavigationComponents/NavBar"; -export default { - name: "NavBarView", - components: { - Navbar, - }, -}; -</script> - -<style scoped></style> diff --git a/src/views/NavigationViews/NotificationView.vue b/src/views/NavigationViews/NotificationView.vue deleted file mode 100644 index 91eda3ca2fcf81963a368d41e3a9f466c4ba48da..0000000000000000000000000000000000000000 --- a/src/views/NavigationViews/NotificationView.vue +++ /dev/null @@ -1,18 +0,0 @@ -<template> - <div> - <NotificationsForm /> - </div> -</template> - -<script> -import NotificationsForm from "@/components/NavigationComponents/NotificationsForm"; - -export default { - name: "NotificationView.vue", - components: { - NotificationsForm, - }, -}; -</script> - -<style scoped></style> diff --git a/src/views/RentingViews/ItemInfoPageView.vue b/src/views/RentingViews/ItemInfoPageView.vue new file mode 100644 index 0000000000000000000000000000000000000000..c08362fb9094c59ca4b1419893314bc609648c38 --- /dev/null +++ b/src/views/RentingViews/ItemInfoPageView.vue @@ -0,0 +1,15 @@ +<template> + <ItemInfo></ItemInfo> +</template> + +<script> +import ItemInfo from "@/components/RentingComponents/ItemInfo"; +export default { + name: "ItemInfoPage.vue", + components: { + ItemInfo, + }, +}; +</script> + +<style scoped></style> diff --git a/src/views/TestView.vue b/src/views/TestView.vue new file mode 100644 index 0000000000000000000000000000000000000000..7537e2d18769293327ccda2e2357aefe9973c58e --- /dev/null +++ b/src/views/TestView.vue @@ -0,0 +1,19 @@ +<template> + <div /> +</template> + +<script> +export default { + data() { + return { + show: false, + }; + }, + components: {}, + methods: { + toggleModal() { + this.show = !this.show; + }, + }, +}; +</script> diff --git a/tailwind.config.js b/tailwind.config.js index ff5434c5421ba46ec13418cfd1118b574be60819..d92b980ab15ed8d8de1d9e631b62ea2085bd8705 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,10 +1,12 @@ module.exports = { darkMode: "class", - content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}", './node_modules/tw-elements/dist/js/**/*.js'], + content: [ + "./index.html", + "./src/**/*.{vue,js,ts,jsx,tsx}", + "./node_modules/tw-elements/dist/js/**/*.js", + ], theme: { extend: {}, }, - plugins: [ - require('tw-elements/dist/plugin') - ], -}; \ No newline at end of file + plugins: [require("tw-elements/dist/plugin")], +}; diff --git a/tests/unit/api-mock-tests/apiutil-communityHome-mock.spec.js b/tests/unit/api-mock-tests/apiutil-communityHome-mock.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..4ab75d6469cf79e31546054eebae45ce5976284d --- /dev/null +++ b/tests/unit/api-mock-tests/apiutil-communityHome-mock.spec.js @@ -0,0 +1,55 @@ +import { GetCommunity, GetListingsInCommunity } from "@/utils/apiutil"; +import axios from "axios"; + +jest.mock("axios"); + +describe("testing mocking of apiutil.js", () => { + it("check that existing group returns correctly", async () => { + const expectedResponse = { + communityId: 4040, + name: "Fisken i vannet", + description: "For vi som liker fjell fisk", + visibility: 1, + location: "Bergen brygge", + picture: "fish blub blub", + }; + + axios.get.mockImplementation(() => + Promise.resolve({ data: expectedResponse }) + ); + + const communityResponse = await GetCommunity(4040); + expect(communityResponse.name).toBe(expectedResponse.name); + }); + + it("check that existing group returns correct listings", async () => { + const expectedResponse = { + item1: { + title: "Fiskekurs", + description: "Fisking og sånn", + pricePerDay: 200, + address: "Vannet", + userID: 6, + categoryNames: null, + communityIDs: null, + }, + + item2: { + title: "TestFraFrontend", + description: "oslo", + pricePerDay: 500, + address: "oslo", + userID: 1, + categoryNames: null, + communityIDs: null, + }, + }; + + axios.get.mockImplementation(() => + Promise.resolve({ data: expectedResponse }) + ); + + const communityItemResponse = await GetListingsInCommunity(4040); + expect(communityItemResponse).toBe(expectedResponse); + }); +}); diff --git a/tests/unit/apiutil-login-mock.spec.js b/tests/unit/api-mock-tests/apiutil-login-mock.spec.js similarity index 100% rename from tests/unit/apiutil-login-mock.spec.js rename to tests/unit/api-mock-tests/apiutil-login-mock.spec.js diff --git a/tests/unit/api-mock-tests/apiutil-memberlist.spec.js b/tests/unit/api-mock-tests/apiutil-memberlist.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..34fb55066190781d9d2aead4d106b2c6ea3c8098 --- /dev/null +++ b/tests/unit/api-mock-tests/apiutil-memberlist.spec.js @@ -0,0 +1,35 @@ +import { GetMembersOfCommunity } from "@/utils/apiutil"; +import axios from "axios"; + +jest.mock("axios"); + +describe("testing mocking of apiutil.js", () => { + it("check that existing group returns correct members", async () => { + const expectedResponse = { + member1: { + userId: 2, + email: "erik@erik.com", + firstName: "erik", + lastName: "hansen", + address: "gløshaugen", + picture: "ok", + }, + + member2: { + userId: 1, + email: "test@test.com", + firstName: "test", + lastName: "testesen", + address: "oslo", + picture: "ok", + }, + }; + + axios.get.mockImplementation(() => + Promise.resolve({ data: expectedResponse }) + ); + + const communityMembersResponse = await GetMembersOfCommunity(4040); + expect(communityMembersResponse).toBe(expectedResponse); + }); +}); diff --git a/tests/unit/apiutil-user-mock.spec.js b/tests/unit/api-mock-tests/apiutil-user-mock.spec.js similarity index 100% rename from tests/unit/apiutil-user-mock.spec.js rename to tests/unit/api-mock-tests/apiutil-user-mock.spec.js diff --git a/tests/unit/component-tests/base-component-tests/__snapshots__/color-button.spec.js.snap b/tests/unit/component-tests/base-component-tests/__snapshots__/color-button.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..4a8d6370547ec8f2d5faee8131dc1432a0d3a7e5 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/__snapshots__/color-button.spec.js.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ColoredButtonComponent renders correctly 1`] = ` +<button + class="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" +> + hei +</button> +`; diff --git a/tests/unit/component-tests/base-component-tests/__snapshots__/community-header.spec.js.snap b/tests/unit/component-tests/base-component-tests/__snapshots__/community-header.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..73847104b73bc72ff7ee7c2c3693159fe201b6b1 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/__snapshots__/community-header.spec.js.snap @@ -0,0 +1,62 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CommunityHeader component renders correctly 1`] = ` +<div + class="flex items-center justify-between mx-4" +> + <div + class="flex-1 min-w-0" + > + <h2 + class="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate" + > + String + </h2> + <div + class="mt-1 flex flex-col sm:flex-row sm:flex-wrap sm:mt-0 sm:space-x-6" + > + <div + class="mt-2 flex items-center text-sm text-gray-500" + > + <svg + aria-hidden="true" + class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + clip-rule="evenodd" + d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" + fill-rule="evenodd" + /> + </svg> + String + </div> + </div> + </div> + <div> + <span + class="hidden sm:block" + > + <!-- Legg dette til i button: v-if="adminStatus" --> + <svg + class="w-9 h-9 cursor-pointer" + fill="none" + stroke="currentColor" + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M4 6h16M4 12h16M4 18h16" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + /> + </svg> + <!--v-if--> + <!-- class="absolute" --> + </span> + </div> +</div> +`; diff --git a/tests/unit/component-tests/base-component-tests/__snapshots__/custom-footer-modal.spec.js.snap b/tests/unit/component-tests/base-component-tests/__snapshots__/custom-footer-modal.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..f178175b1fa2913054cc18585b8dd831f1099858 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/__snapshots__/custom-footer-modal.spec.js.snap @@ -0,0 +1,73 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`IconButtonComponent renders correctly 1`] = ` +<div + data-v-app="" +> + + <!-- Main modal --> + <div + class="fixed grid place-items-center bg-gray-600 bg-opacity-50 top-0 left-0 right-0 z-50 w-full overflow-x-hidden overflow-y-auto md:inset-0 h-modal md:h-full" + > + <div + class="relative w-full h-full max-w-2xl p-4 md:h-auto" + > + <!-- Modal content --> + <div + class="relative bg-white rounded-lg shadow dark:bg-gray-700" + > + <!-- Modal header --> + <div + class="flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600" + > + <h3 + class="text-xl font-semibold text-gray-900 dark:text-white" + > + String + </h3> + <button + class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" + > + <svg + class="w-5 h-5" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + clip-rule="evenodd" + d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" + fill-rule="evenodd" + /> + </svg> + </button> + </div> + <!-- Modal body --> + <div + class="p-6 space-y-6" + > + <p + class="text-base leading-relaxed text-gray-500 dark:text-gray-400" + > + String + </p> + </div> + <!-- Modal footer --> + <div + class="rounded-b border-t border-gray-200 dark:border-gray-600" + > + <!-- Slot: Add any html you want here --> + + <div + class="fake-msg" + > + String + </div> + + </div> + </div> + </div> + </div> + +</div> +`; diff --git a/tests/unit/component-tests/base-component-tests/__snapshots__/icon-button.spec.js.snap b/tests/unit/component-tests/base-component-tests/__snapshots__/icon-button.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..62007d4ff8d81f1ece9bf91271163ca179d7383d --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/__snapshots__/icon-button.spec.js.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`IconButtonComponent renders correctly 1`] = ` +<div + data-v-app="" +> + + <!-- Icon button --> + <button + class="block w-fit text-white text-base bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" + > + <div + class="flex flex-row px-5 py-2.5 h-10" + > + <!-- Icon slot: Default content "Ban"-icon --> + <div + class="h-6 w-6" + > + + <svg + aria-hidden="true" + fill="none" + stroke="currentColor" + stroke-width="2" + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" + stroke-linecap="round" + stroke-linejoin="round" + /> + </svg> + + </div> + <p> + hei + </p> + </div> + </button> + +</div> +`; diff --git a/tests/unit/component-tests/base-component-tests/__snapshots__/nav-bar.spec.js.snap b/tests/unit/component-tests/base-component-tests/__snapshots__/nav-bar.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..3929918739cf7ffa3409de46e8c6bd3b6abd14f8 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/__snapshots__/nav-bar.spec.js.snap @@ -0,0 +1,42 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NavBar component renders correctly 1`] = ` +<nav + class="flex items-center justify-between bg-white h-14 border-1 border-b border-gray-300 border-solid sticky top-0 z-50" +> + <div + class="logo" + > + <img + alt="BoCo logo" + class="m-1 ml-4 cursor-pointer h-12" + src="" + /> + </div> + <ul + class="flex" + > + <li> + <img + alt="Legg til" + class="m-6 cursor-pointer h-7" + src="" + /> + </li> + <li> + <img + alt="Meldinger" + class="m-6 cursor-pointer h-7" + src="" + /> + </li> + <li> + <img + alt="Profil" + class="m-6 cursor-pointer h-7" + src="" + /> + </li> + </ul> +</nav> +`; diff --git a/tests/unit/component-tests/base-component-tests/__snapshots__/notification-modal.spec.js.snap b/tests/unit/component-tests/base-component-tests/__snapshots__/notification-modal.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..6c2259b3f623090effe8ff37ced149d9e72da832 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/__snapshots__/notification-modal.spec.js.snap @@ -0,0 +1,60 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NotificationModal component renders correctly 1`] = ` +<div + data-v-app="" +> + + <!-- Main modal --> + <div + class="fixed grid place-items-center bg-gray-600 bg-opacity-50 top-0 left-0 right-0 z-50 w-full overflow-x-hidden overflow-y-auto md:inset-0 h-modal md:h-full" + > + <div + class="relative w-full h-full max-w-2xl p-4 md:h-auto" + > + <!-- Modal content --> + <div + class="relative bg-white rounded-lg shadow dark:bg-gray-700" + > + <!-- Modal header --> + <div + class="flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600" + > + <h3 + class="text-xl font-semibold text-gray-900 dark:text-white" + > + String + </h3> + <button + class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" + > + <svg + class="w-5 h-5" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + clip-rule="evenodd" + d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" + fill-rule="evenodd" + /> + </svg> + </button> + </div> + <!-- Modal body --> + <div + class="p-6 space-y-6" + > + <p + class="text-base leading-relaxed text-gray-500 dark:text-gray-400" + > + String + </p> + </div> + </div> + </div> + </div> + +</div> +`; diff --git a/tests/unit/component-tests/base-component-tests/color-button.spec.js b/tests/unit/component-tests/base-component-tests/color-button.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..ca9efb412b59485756b500dcbe8fb283e2464d31 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/color-button.spec.js @@ -0,0 +1,23 @@ +import { mount } from "@vue/test-utils"; +import ColoredButton from "@/components/BaseComponents/ColoredButton.vue"; + +describe("ColoredButtonComponent", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(ColoredButton, { + //passing prop to component + props: { + text: "hei", + }, + }); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/base-component-tests/community-header.spec.js b/tests/unit/component-tests/base-component-tests/community-header.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..7dd3c446f57353aae804f8b7f6cf6e95fe5af7da --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/community-header.spec.js @@ -0,0 +1,31 @@ +import { mount } from "@vue/test-utils"; +import CommunityHeader from "@/components/BaseComponents/CommunityHeader.vue"; + +describe("CommunityHeader component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(CommunityHeader, { + //passing prop to component + props: { + adminStatus: true, + community: { + communityId: 1, + name: "String", + description: "String", + visibility: 0, + location: "String", + picture: "String", + }, + }, + }); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/base-component-tests/custom-footer-modal.spec.js b/tests/unit/component-tests/base-component-tests/custom-footer-modal.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..4d4db9169c1d7c90402aa4e78be331938ebf487f --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/custom-footer-modal.spec.js @@ -0,0 +1,28 @@ +import { mount } from "@vue/test-utils"; +import CustomFooterModal from "@/components/BaseComponents/CustomFooterModal.vue"; + +describe("IconButtonComponent", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(CustomFooterModal, { + //passing prop to component + props: { + visible: true, + title: "String", + message: "String", + }, + slots: { + default: '<div class="fake-msg">String</div>', + }, + }); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/base-component-tests/icon-button.spec.js b/tests/unit/component-tests/base-component-tests/icon-button.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..57b6f0fbc8450074c308627cd845f61085cb6743 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/icon-button.spec.js @@ -0,0 +1,23 @@ +import { mount } from "@vue/test-utils"; +import IconButton from "@/components/BaseComponents/IconButton.vue"; + +describe("IconButtonComponent", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(IconButton, { + //passing prop to component + props: { + text: "hei", + }, + }); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/base-component-tests/nav-bar.spec.js b/tests/unit/component-tests/base-component-tests/nav-bar.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..dd5f979fef779d7b5235c2853b8c0b938f184b46 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/nav-bar.spec.js @@ -0,0 +1,18 @@ +import { mount } from "@vue/test-utils"; +import NavBar from "@/components/BaseComponents/NavBar.vue"; + +describe("NavBar component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(NavBar); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/base-component-tests/notification-modal.spec.js b/tests/unit/component-tests/base-component-tests/notification-modal.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..0fb2c913ba0efa291df6a397a8dd0ee7370da776 --- /dev/null +++ b/tests/unit/component-tests/base-component-tests/notification-modal.spec.js @@ -0,0 +1,25 @@ +import { mount } from "@vue/test-utils"; +import NotificationModal from "@/components/BaseComponents/NotificationModal.vue"; + +describe("NotificationModal component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(NotificationModal, { + //passing prop to component + props: { + visible: true, + title: "String", + message: "String", + }, + }); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/community-component-tests/__snapshots__/community-list-item.spec.js.snap b/tests/unit/component-tests/community-component-tests/__snapshots__/community-list-item.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..25c734add5c0ca6ad6f94cec526e074008da6782 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/__snapshots__/community-list-item.spec.js.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CommunityListItem component renders correctly 1`] = ` +<div + data-v-app="" +> + + + <!-- Main modal --> + <!--v-if--> + + <div + class="bg-white shadow dark:bg-gray-800 select-none cursor-pointer hover:bg-gray-50 flex items-center p-4" + > + <div + class="h-10 w-10 flex flex-col justify-center items-center mr-4" + > + <svg + aria-hidden="true" + fill="none" + stroke="currentColor" + stroke-width="2" + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" + stroke-linecap="round" + stroke-linejoin="round" + /> + </svg> + <!-- TODO: USE COMMUNITY IMAGE <img alt="Felleskapets bilde" src="@/assets/group.png" /> --> + </div> + <div + class="flex-1 pl-1 overflow-hidden" + > + <div + class="font-medium dark:text-white truncate" + > + string + </div> + </div> + <div + class="flex flex-row justify-center items-center" + > + <svg + aria-hidden="true" + class="max-h-6 max-w-6 shrink m-2" + fill="none" + stroke="currentColor" + stroke-width="2" + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" + stroke-linecap="round" + stroke-linejoin="round" + /> + </svg> + </div> + </div> + +</div> +`; diff --git a/tests/unit/component-tests/community-component-tests/__snapshots__/community-list.spec.js.snap b/tests/unit/component-tests/community-component-tests/__snapshots__/community-list.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..0feda8234936c3b8b7a1ec27d48066f90615cdaf --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/__snapshots__/community-list.spec.js.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CommunityList component renders correctly 1`] = ` +<ul + grouplist="[object Object],[object Object]" +> + + +</ul> +`; diff --git a/tests/unit/component-tests/community-component-tests/__snapshots__/create-new-group.spec.js.snap b/tests/unit/component-tests/community-component-tests/__snapshots__/create-new-group.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..a9b5043d55edf9d7bd0a52eb64e803ffc04f50e5 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/__snapshots__/create-new-group.spec.js.snap @@ -0,0 +1,181 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CreateNewGroup elements rendering renders correctly 1`] = ` +<div + class="m-6" +> + <!-- Component heading --> + <div + class="flex justify-center mt-6" + > + <p + class="text-4xl" + > + Opprett Gruppe + </p> + </div> + <!-- Radio boxes --> + <div + class="mt-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + id="radioBoxLabel" + > + Synlighet + </label> + <div + class="form-check" + > + <input + class="form-check-input appearance-none rounded-full h-4 w-4 border border-gray-300 bg-white checked:bg-blue-600 checked:border-blue-600 focus:outline-none transition duration-200 mt-1 align-top bg-no-repeat bg-center bg-contain float-left mr-2 cursor-pointer" + id="flexRadioOpen" + name="flexRadioDefault" + type="radio" + value="Åpen" + /> + <label + class="form-check-label inline-block text-gray-800" + for="flexRadioOpen" + id="radioBoxOpenLabel" + > + Åpen + </label> + </div> + <div + class="form-check" + > + <input + class="form-check-input appearance-none rounded-full h-4 w-4 border border-gray-300 bg-white checked:bg-blue-600 checked:border-blue-600 focus:outline-none transition duration-200 mt-1 align-top bg-no-repeat bg-center bg-contain float-left mr-2 cursor-pointer" + id="flexRadioPrivate" + name="flexRadioDefault" + type="radio" + value="Privat" + /> + <label + class="form-check-label inline-block text-gray-800" + for="flexRadioPrivate" + id="radioBoxPrivateLabel" + > + Privat + </label> + </div> + </div> + <!-- Title --> + <div + class="mt-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + id="titleLabel" + > + Gruppenavn + </label> + <input + class="bg-gray-200 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="title" + required="" + type="text" + /> + <!-- error message for title--> + + + </div> + <!-- Place --> + <div + class="mt-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + > + By/Sted + </label> + <input + class="bg-gray-200 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + required="" + type="text" + /> + <!-- error message for place--> + + + </div> + <!-- Description --> + <div + class="mt-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400" + id="descriptionLabel" + > + Beskrivelse + </label> + <textarea + class="block p-2.5 w-full text-sm text-gray-900 bg-gray-200 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="description" + required="" + rows="4" + /> + <!-- error message for description --> + + + </div> + <!-- Images --> + <div + class="mt-6" + > + <label + class="block mb-2 text-xl font-medium text-gray-900 dark:text-gray-400" + id="imageLabel" + > + Bilde + </label> + <input + accept="image/png, image/jpeg" + multiple="" + style="display: none;" + type="file" + /> + <!-- Button for adding an image --> + <div + class="inline-flex rounded-md shadow-sm" + > + <div + class="text-red-500 uppercase text-center" + > + midlertidig fjernet + </div> + <!-- <button + @click="$refs.file.click()" + class="text-black bg-gray-200 hover:bg-grey-800 focus:ring-4 focus:outline-none focus:ring-grey-300 font-medium rounded-lg text-sm sm:w-auto px-5 py-2.5 text-center dark:bg-grey-600 dark:hover:bg-grey-700 dark:focus:ring-grey-800 disabled:opacity-50" + :disabled="imageAdded" + > + Velg bilde + </button> --> + <!-- Button for removing an image --> + <button + class="w-1/12 ml-5 text-white bg-white-500 font-medium rounded-lg text-sm" + style="display: none;" + > + <img + alt="Remove icon image" + src="" + /> + </button> + </div> + <!-- Div box for showing all chosen images --> + + + </div> + <!-- Save item button --> + <div + class="flex justify-center mt-10" + > + <button + class="content-center text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" + id="saveButton" + > + Lagre + </button> + </div> +</div> +`; diff --git a/tests/unit/component-tests/community-component-tests/__snapshots__/item-card.spec.js.snap b/tests/unit/component-tests/community-component-tests/__snapshots__/item-card.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..a6765453f028760966f7f76701f1f0eea6877ec6 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/__snapshots__/item-card.spec.js.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ItemCard component renders correctly 1`] = ` +<div + class="mt-5" +> + <div + class="w-52 rounded bg-gray-200" + > + <img + alt="Item image" + class="w-full" + src="String" + /> + <div + class="p-1 m-1" + > + <p + class="text-gray-700 text-xs font-bold" + id="adress" + > + String + </p> + <p + class="font-bold text-sm" + id="title" + > + String + </p> + <p + class="text-gray-700 text-xs" + id="price" + > + 0 kr + </p> + </div> + </div> +</div> +`; diff --git a/tests/unit/component-tests/community-component-tests/__snapshots__/new-item-form.spec.js.snap b/tests/unit/component-tests/community-component-tests/__snapshots__/new-item-form.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..a975fa560f988edeb59aee0a62e951b18b9192e2 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/__snapshots__/new-item-form.spec.js.snap @@ -0,0 +1,214 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NewItemForm component renders correctly 1`] = ` +<div + class="m-6" +> + <!-- Component heading --> + <div + class="flex justify-center" + > + <p + class="text-4xl mb-6 mt-6" + > + Utleie + </p> + </div> + <!-- Title --> + <div + class="mb-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + id="titleLabel" + > + Tittel + </label> + <input + class="bg-gray-200 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="title" + required="" + type="text" + /> + <!-- error message for title--> + + + </div> + <!-- Select category --> + <div + class="mb-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400" + id="selectCategoryLabel" + > + Kategori + </label> + <select + class="bg-gray-200 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="categories" + > + <option + class="text-gray-400" + disabled="" + value="" + > + Select a category + </option> + + <option + class="text-gray-900 text-sm" + > + Hage + </option> + <option + class="text-gray-900 text-sm" + > + Kjøkken + </option> + <option + class="text-gray-900 text-sm" + > + Musikk + </option> + <option + class="text-gray-900 text-sm" + > + Annet + </option> + + </select> + <!-- error message for select box --> + + + </div> + <!-- Select Group --> + <div + class="mb-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400" + > + Gruppe + </label> + <select + class="bg-gray-200 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + > + <option + class="text-gray-400" + disabled="" + value="" + > + Select a Group + </option> + + <option + class="text-gray-900 text-sm" + > + 4040 + </option> + <option + class="text-gray-900 text-sm" + > + 4041 + </option> + + </select> + <!-- error message for select box --> + + + </div> + <!-- price --> + <div + class="mb-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + id="priceLabel" + > + Pris + </label> + <input + class="bg-gray-200 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="price" + required="" + type="number" + /> + <!-- error message for price --> + + + </div> + <!-- Description --> + <div + class="mb-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400" + id="descriptionLabel" + > + Beskrivelse + </label> + <textarea + class="block p-2.5 w-full text-sm text-gray-900 bg-gray-200 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="description" + required="" + rows="4" + /> + <!-- error message for description --> + + + </div> + <!-- Address --> + <div + class="mb-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + > + Adresse + </label> + <input + class="bg-gray-200 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="adress" + required="" + type="text" + /> + <!-- error message for address--> + + + </div> + <!-- Images --> + <div> + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-400" + id="imageLabel" + > + Bilder + </label> + <input + accept="image/png, image/jpeg" + multiple="" + style="display: none;" + type="file" + /> + <button + class="text-black bg-gray-200 hover:bg-grey-800 focus:ring-4 focus:outline-none focus:ring-grey-300 font-medium rounded-lg text-sm sm:w-auto px-5 py-2.5 text-center dark:bg-grey-600 dark:hover:bg-grey-700 dark:focus:ring-grey-800" + > + Velg bilde + </button> + + + </div> + <!-- Save item button --> + <div + class="flex justify-center" + > + <button + class="content-center text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" + id="saveButton" + > + Lagre + </button> + </div> +</div> +`; diff --git a/tests/unit/component-tests/community-component-tests/__snapshots__/search-item-list.spec.js.snap b/tests/unit/component-tests/community-component-tests/__snapshots__/search-item-list.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..d00db1aa89b9e18df7639635f6bf0fe7b6de9820 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/__snapshots__/search-item-list.spec.js.snap @@ -0,0 +1,55 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SearchItemListComponent elements rendering renders correctly 1`] = ` +<section + class="relative w-full max-w-md px-5 py-4 mx-auto rounded-md" +> + <div + class="relative" + id="searchComponent" + > + <span + class="absolute inset-y-0 left-0 flex items-center pl-3" + > + <svg + class="w-5 h-5 text-gray-400" + fill="none" + viewBox="0 0 24 24" + > + <path + d="M21 21L15 15M17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10Z" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + /> + </svg> + </span> + <input + class="w-full py-3 pl-10 pr-4 text-gray-700 bg-white border rounded-md dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 focus:border-blue-500 dark:focus:border-blue-500 focus:outline-none focus:ring" + id="searchInput" + placeholder="Search" + type="text" + /> + </div> + <div + class="absolute inset-x-0 px-6 py-3 mt-4 border-2 border-slate-500" + > + <div + class="grid grid-cols-2" + > + + <item-card-stub + item="[object Object]" + /> + <item-card-stub + item="[object Object]" + /> + <item-card-stub + item="[object Object]" + /> + + </div> + </div> +</section> +`; diff --git a/tests/unit/add-new-item.spec.js b/tests/unit/component-tests/community-component-tests/add-new-item.spec.js similarity index 100% rename from tests/unit/add-new-item.spec.js rename to tests/unit/component-tests/community-component-tests/add-new-item.spec.js diff --git a/tests/unit/component-tests/community-component-tests/community-hamburger.spec.js b/tests/unit/component-tests/community-component-tests/community-hamburger.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..a6834e8680d1d61c29962436e568165fb8c2b937 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/community-hamburger.spec.js @@ -0,0 +1,13 @@ +import { shallowMount } from "@vue/test-utils"; +import CommunityHamburger from "@/components/CommunityComponents/CommunityHamburger.vue"; + +describe("CommunityHamburger elements rendering", () => { + it("renders all li fields", () => { + const wrapper = shallowMount(CommunityHamburger); + + expect(wrapper.find("#newItem").text()).toMatch("Opprett Utleie"); + expect(wrapper.find("#getMembers").text()).toMatch("Se Medlemmer"); + expect(wrapper.find("#adminGroup").text()).toMatch("Administrer Gruppe"); + expect(wrapper.find("#leaveGroup").text()).toMatch("Forlat Gruppe"); + }); +}); diff --git a/tests/unit/component-tests/community-component-tests/community-list-item.spec.js b/tests/unit/component-tests/community-component-tests/community-list-item.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..3610f19312ab656bfbe7881c21e072626b164cb1 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/community-list-item.spec.js @@ -0,0 +1,31 @@ +import { mount } from "@vue/test-utils"; +import CommunityListItem from "@/components/CommunityComponents/CommunityListItem.vue"; + +describe("CommunityListItem component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(CommunityListItem, { + //passing prop to component + props: { + community: { + communityId: 0, + name: "string", + description: "string", + visibility: 0, + location: "string", + picture: "string", + }, + member: false, + }, + }); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/community-component-tests/community-list.spec.js b/tests/unit/component-tests/community-component-tests/community-list.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..fbd0968070e19814478e839c92245089f09013b8 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/community-list.spec.js @@ -0,0 +1,39 @@ +import { mount } from "@vue/test-utils"; +import CommunityList from "@/components/CommunityComponents/CommunityList.vue"; + +describe("CommunityList component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(CommunityList, { + props: { + groupList: [ + { + communityId: 0, + name: "string", + description: "string", + visibility: 0, + location: "string", + picture: "string", + }, + { + communityId: 0, + name: "string", + description: "string", + visibility: 0, + location: "string", + picture: "string", + }, + ], + }, + }); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/create-new-group.spec.js b/tests/unit/component-tests/community-component-tests/create-new-group.spec.js similarity index 78% rename from tests/unit/create-new-group.spec.js rename to tests/unit/component-tests/community-component-tests/create-new-group.spec.js index 0d6a36443297eb891b6d62f89fa5f2c023a0b07a..2110350f78d1d1703141561173eb1727e602d26e 100644 --- a/tests/unit/create-new-group.spec.js +++ b/tests/unit/component-tests/community-component-tests/create-new-group.spec.js @@ -2,37 +2,36 @@ import { shallowMount } from "@vue/test-utils"; import CreateNewGroup from "@/components/CommunityComponents/NewCommunityForm.vue"; describe("CreateNewGroup elements rendering", () => { - it("renders all labels", () => { - const wrapper = shallowMount(CreateNewGroup); + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(CreateNewGroup); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + it("renders all labels", () => { expect(wrapper.find("#radioBoxLabel").text()).toMatch("Synlighet"); expect(wrapper.find("#radioBoxOpenLabel").text()).toMatch("Åpen"); expect(wrapper.find("#radioBoxPrivateLabel").text()).toMatch("Privat"); expect(wrapper.find("#titleLabel").text()).toMatch("Gruppenavn"); - expect(wrapper.find("#selectCategoryLabel").text()).toMatch("Kategori"); expect(wrapper.find("#descriptionLabel").text()).toMatch("Beskrivelse"); expect(wrapper.find("#imageLabel").text()).toMatch("Bilde"); }); it("Tests setting values of input field", async () => { - const wrapper = shallowMount(CreateNewGroup); - const titleInput = wrapper.find("#title"); await titleInput.setValue("Fjellgata"); expect(titleInput.element.value).toBe("Fjellgata"); - const selectedCategory = wrapper.find("#categories"); - await selectedCategory.setValue("Borettslag"); - expect(selectedCategory.element.value).toBe("Borettslag"); - const descriptionInput = wrapper.find("#description"); await descriptionInput.setValue("Dette er et borettslag"); expect(descriptionInput.element.value).toBe("Dette er et borettslag"); }); it("Tests if radio box checks", async () => { - const wrapper = shallowMount(CreateNewGroup); - const radioInputOpen = wrapper.find("#flexRadioOpen"); await radioInputOpen.setChecked(); expect(radioInputOpen.element.checked).toBeTruthy(); diff --git a/tests/unit/component-tests/community-component-tests/item-card.spec.js b/tests/unit/component-tests/community-component-tests/item-card.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..a03b348b8070bd4b572f33ec33d2aa641253458c --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/item-card.spec.js @@ -0,0 +1,27 @@ +import { mount } from "@vue/test-utils"; +import ItemCard from "@/components/CommunityComponents/ItemCard.vue"; + +describe("ItemCard component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(ItemCard, { + props: { + item: { + img: "String", + address: "String", + title: "String", + pricePerDay: 0, + }, + }, + }); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/community-component-tests/new-item-form.spec.js b/tests/unit/component-tests/community-component-tests/new-item-form.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..8271342651aaae430c68cbac6f3a924b482384e1 --- /dev/null +++ b/tests/unit/component-tests/community-component-tests/new-item-form.spec.js @@ -0,0 +1,18 @@ +import { mount } from "@vue/test-utils"; +import NewItemForm from "@/components/CommunityComponents/NewItemForm.vue"; + +describe("NewItemForm component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(NewItemForm); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/search-item-list.spec.js b/tests/unit/component-tests/community-component-tests/search-item-list.spec.js similarity index 52% rename from tests/unit/search-item-list.spec.js rename to tests/unit/component-tests/community-component-tests/search-item-list.spec.js index 1ad4cff4313ee641059e386856a18e79fa2f7a0f..145a56a66093be7fb062785bafbd11fa6c116f7a 100644 --- a/tests/unit/search-item-list.spec.js +++ b/tests/unit/component-tests/community-component-tests/search-item-list.spec.js @@ -1,10 +1,22 @@ import { shallowMount } from "@vue/test-utils"; import SearchItemListComponent from "@/components/CommunityComponents/SearchItemList.vue"; -describe("CreateNewGroup elements rendering", () => { - it("Tests setting values of input field", async () => { - const wrapper = shallowMount(SearchItemListComponent); +describe("SearchItemListComponent elements rendering", () => { + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(SearchItemListComponent); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); + it("Tests setting values of input field", async () => { const searchInput = wrapper.find("#searchInput"); await searchInput.setValue("Dyson"); expect(searchInput.element.value).toBe("Dyson"); diff --git a/tests/unit/component-tests/user-component-tests/__snapshots__/login-form.spec.js.snap b/tests/unit/component-tests/user-component-tests/__snapshots__/login-form.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..c712a500effa0e3f64c2187aaa330efdc6fb68a6 --- /dev/null +++ b/tests/unit/component-tests/user-component-tests/__snapshots__/login-form.spec.js.snap @@ -0,0 +1,101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LoginForm component renders correctly 1`] = ` +<div + class="max-w-md p-6 mx-auto rounded-md shadow-lg mt-16" +> + <div + class="flex justify-center text-2xl" + > + Logg inn + </div> + <div + class="m-6" + id="emailField" + > + <div + class="mb-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + for="email" + > + E-post + </label> + <input + class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="email" + placeholder="eksempel@eksempel.no" + required="" + type="email" + /> + <!-- error message --> + + + </div> + </div> + <div + class="m-6" + id="passwordField" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + for="password" + > + Passord + </label> + <input + class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" + id="password" + required="" + type="password" + /> + <!-- error message --> + + + </div> + <div + class="m-6" + id="buttonsField" + > + <div + class="align-items: flex-end; mb-6" + > + <div + class="ml-3 text-sm" + > + <router-link + class="text-blue-600 flex justify-end" + to="/resetPassword" + > + Glemt passord + </router-link> + </div> + </div> + <button + class="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5" + > + Logg inn + </button> + <div + class="align-items: flex-end; mb-6 mt-12" + > + <div + class="text-sm" + > + <router-link + class="text-blue-600 flex justify-center" + to="register" + > + Ny bruker + </router-link> + </div> + </div> + <div + class="flex justify-center" + > + <label /> + </div> + </div> +</div> +`; diff --git a/tests/unit/component-tests/user-component-tests/__snapshots__/new-password-form.spec.js.snap b/tests/unit/component-tests/user-component-tests/__snapshots__/new-password-form.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..8ecfffa14f203f189c5ed8a266f9787f14eeb86d --- /dev/null +++ b/tests/unit/component-tests/user-component-tests/__snapshots__/new-password-form.spec.js.snap @@ -0,0 +1,58 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NewPasswordForm component renders correctly 1`] = ` +<div + class="w-full max-w-sm p-6 m-auto bg-white rounded-md shadow-md dark:bg-gray-800 mt-8" +> + <div + class="" + id="firstPasswordField" + > + <label + class="block text-sm text-gray-800 dark:text-gray-200" + for="password" + > + Nytt passord + </label> + <input + class="block w-full px-4 py-2 mt-2 text-gray-700 bg-white border rounded-md dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 focus:border-blue-400 dark:focus:border-blue-300 focus:ring-blue-300 focus:outline-none focus:ring focus:ring-opacity-40" + type="password" + /> + <!-- error message --> + + + </div> + <div + class="mt-4" + id="secondPasswordField" + > + <div + class="flex items-center justify-between" + > + <label + class="block text-sm text-gray-800 dark:text-gray-200" + for="rePassword" + > + Gjenta nytt passord + </label> + </div> + <input + class="block w-full px-4 py-2 mt-2 text-gray-700 bg-white border rounded-md dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 focus:border-blue-400 dark:focus:border-blue-300 focus:ring-blue-300 focus:outline-none focus:ring focus:ring-opacity-40" + type="password" + /> + <!-- error message --> + + + </div> + <div + class="mt-6" + id="buttonsField" + > + <button + class="w-full px-4 py-2 tracking-wide text-white transition-colors duration-200 transform bg-gray-700 rounded-md hover:bg-gray-600 focus:outline-none focus:bg-gray-600" + > + Endre passord + </button> + </div> +</div> +`; diff --git a/tests/unit/component-tests/user-component-tests/__snapshots__/rating.spec.js.snap b/tests/unit/component-tests/user-component-tests/__snapshots__/rating.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..e7d04a61c2d249a8bda1825ed17ed7be65bcf319 --- /dev/null +++ b/tests/unit/component-tests/user-component-tests/__snapshots__/rating.spec.js.snap @@ -0,0 +1,84 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Rating component renders correctly 1`] = ` +<ul + class="flex justify-center" +> + <li> + <p + class="ml-2 text-sm font-medium text-gray-500 dark:text-gray-400" + > + : + </p> + </li> + + <li> + <svg + class="w-5 h-5 text-gray-300 dark:text-gray-500" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" + /> + </svg> + </li> + <li> + <svg + class="w-5 h-5 text-gray-300 dark:text-gray-500" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" + /> + </svg> + </li> + <li> + <svg + class="w-5 h-5 text-gray-300 dark:text-gray-500" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" + /> + </svg> + </li> + <li> + <svg + class="w-5 h-5 text-gray-300 dark:text-gray-500" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" + /> + </svg> + </li> + <li> + <svg + class="w-5 h-5 text-gray-300 dark:text-gray-500" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" + /> + </svg> + </li> + + <li> + <p + class="ml-2 text-sm font-medium text-gray-500 dark:text-gray-400" + > + out of 5 + </p> + </li> +</ul> +`; diff --git a/tests/unit/__snapshots__/RegisterUserComponent.spec.js.snap b/tests/unit/component-tests/user-component-tests/__snapshots__/register-user-component.spec.js.snap similarity index 100% rename from tests/unit/__snapshots__/RegisterUserComponent.spec.js.snap rename to tests/unit/component-tests/user-component-tests/__snapshots__/register-user-component.spec.js.snap diff --git a/tests/unit/component-tests/user-component-tests/__snapshots__/reset-password-form.spec.js.snap b/tests/unit/component-tests/user-component-tests/__snapshots__/reset-password-form.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..e2fd53153e1a948a06f396c1f77ad5b978e48eb0 --- /dev/null +++ b/tests/unit/component-tests/user-component-tests/__snapshots__/reset-password-form.spec.js.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ResetPasswordForm component renders correctly 1`] = ` +<div + class="resetPassword" +> + <div + class="m-6" + id="emailField" + > + <div + class="mb-6" + > + <label + class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300" + for="email" + > + E-post + </label> + <input + class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" + id="email" + placeholder="eksempel@eksempel.no" + required="" + type="email" + /> + <!-- error message --> + + + </div> + </div> + <button + class="flex justify-center align-items: flex-end; text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" + > + Send e-post + </button> +</div> +`; diff --git a/tests/unit/component-tests/user-component-tests/login-form.spec.js b/tests/unit/component-tests/user-component-tests/login-form.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..40fa711393e969435a609474c0f550f179513135 --- /dev/null +++ b/tests/unit/component-tests/user-component-tests/login-form.spec.js @@ -0,0 +1,18 @@ +import { mount } from "@vue/test-utils"; +import LoginForm from "@/components/FormComponents/LoginForm.vue"; + +describe("LoginForm component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(LoginForm); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/user-component-tests/new-password-form.spec.js b/tests/unit/component-tests/user-component-tests/new-password-form.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..638e597bd9b130a6b2a1c69a0b724b3414436648 --- /dev/null +++ b/tests/unit/component-tests/user-component-tests/new-password-form.spec.js @@ -0,0 +1,18 @@ +import { mount } from "@vue/test-utils"; +import NewPasswordForm from "@/components/FormComponents/NewPasswordForm.vue"; + +describe("NewPasswordForm component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(NewPasswordForm); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/component-tests/user-component-tests/rating.spec.js b/tests/unit/component-tests/user-component-tests/rating.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..cdbcee60fc44be8c4e04b9f2dc4a42756f5a6699 --- /dev/null +++ b/tests/unit/component-tests/user-component-tests/rating.spec.js @@ -0,0 +1,18 @@ +import { mount } from "@vue/test-utils"; +import Rating from "@/components/UserProfileComponents/Rating.vue"; + +describe("Rating component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(Rating); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/tests/unit/RegisterUserComponent.spec.js b/tests/unit/component-tests/user-component-tests/register-user-component.spec.js similarity index 100% rename from tests/unit/RegisterUserComponent.spec.js rename to tests/unit/component-tests/user-component-tests/register-user-component.spec.js diff --git a/tests/unit/component-tests/user-component-tests/reset-password-form.spec.js b/tests/unit/component-tests/user-component-tests/reset-password-form.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..1dc9f0a4f379129d888436a42d40bf354ae56f66 --- /dev/null +++ b/tests/unit/component-tests/user-component-tests/reset-password-form.spec.js @@ -0,0 +1,18 @@ +import { mount } from "@vue/test-utils"; +import ResetPasswordForm from "@/components/FormComponents/ResetPasswordForm.vue"; + +describe("ResetPasswordForm component", () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(ResetPasswordForm); + }); + + it("renders correctly", () => { + expect(wrapper.element).toMatchSnapshot(); + }); + + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); +}); diff --git a/vue.config.js b/vue.config.js index e5c2653994c18b4929deb9393289529e17b15c15..3ec0170c3cb07b201b38bd62b0da6f140b0713a9 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,10 +1,11 @@ const { defineConfig } = require("@vue/cli-service"); + module.exports = defineConfig({ transpileDependencies: true, - - pluginOptions: { - vuetify: { - // https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vuetify-loader - }, + chainWebpack: (config) => { + config.plugin("html").tap((args) => { + args[0].title = "Borrow Company"; + return args; + }); }, });