diff --git a/src/components/BaseComponents/NavBar.vue b/src/components/BaseComponents/NavBar.vue index f12e691777c15a59e01ec4b1eec9d3002c621556..39941c5321ede2b107b3750ae38f38d198202e67 100644 --- a/src/components/BaseComponents/NavBar.vue +++ b/src/components/BaseComponents/NavBar.vue @@ -13,21 +13,21 @@ <ul class="flex"> <li> <PlusIcon - class="m-6 cursor-pointer h-7" + class="m-6 cursor-pointer h-7 text-primary-medium" alt="Legg til" @click="$router.push('/newItem')" /> </li> <li> <ChatAlt2Icon - class="m-6 cursor-pointer h-7" + class="m-6 cursor-pointer h-7 text-primary-medium" alt="Meldinger" @click="$router.push('/messages')" /> </li> <li> <UserCircleIcon - class="m-6 cursor-pointer h-7" + class="m-6 cursor-pointer h-7 text-primary-medium" alt="Profil" @click="loadProfile" /> diff --git a/src/components/FormComponents/NewPasswordForm.vue b/src/components/FormComponents/NewPasswordForm.vue index 519a3c6677ce3e85668f2567e9833b4873055f65..d32c15d65f1d4938f01c9c862fe70cc49f58929c 100644 --- a/src/components/FormComponents/NewPasswordForm.vue +++ b/src/components/FormComponents/NewPasswordForm.vue @@ -8,8 +8,35 @@ Endre passord </h3> + <div + id="oldPasswordField" + :class="{ error: v$.user.oldPassword.$errors.length }" + > + <label + for="oldPassword" + class="block text-sm text-gray-800 dark:text-gray-200" + >Gammelt passord</label + > + <input + type="password" + v-model="v$.user.oldPassword.$model" + class="block w-full px-4 py-2 mt-2 text-gray-700 placeholder-gray-500 bg-white border rounded-md dark:bg-gray-800 dark:border-gray-600 dark:placeholder-gray-400 focus:border-blue-400 dark:focus:border-blue-300 focus:ring-opacity-40 focus:outline-none focus:ring focus:ring-blue-300" + /> + <!-- error message --> + <div v-for="(error, index) of v$.user.oldPassword.$errors" :key="index"> + <div + class="text-red-600 text-sm" + v-show="showError" + id="oldPasswordErrorId" + > + {{ error.$message }} + </div> + </div> + </div> + <div id="firstPasswordField" + class="mt-4" :class="{ error: v$.user.password.$errors.length }" > <label @@ -71,6 +98,12 @@ :text="'Sett ny passord'" /> </div> + <div class="flex items-center justify-center text-center bg-gray-50"> + <label + class="mx-2 text-sm font-bold text-error-medium dark:text-primary-light hover:underline" + >{{ message }}</label + > + </div> </div> </template> @@ -93,6 +126,9 @@ export default { validations() { return { user: { + oldPassword: { + required: helpers.withMessage(`Feltet må være utfylt`, required), + }, password: { required: helpers.withMessage(`Feltet må være utfylt`, required), minLength: helpers.withMessage( @@ -112,7 +148,9 @@ export default { }, data() { return { + message: "", user: { + oldPassword: "", password: "", rePassword: "", }, @@ -133,13 +171,24 @@ export default { return; } - const newPassword = this.user.password; + const newPassword = { + newPassword: this.user.password, + oldPassword: this.user.oldPassword, + }; const newPasswordResponse = await doNewPassword(newPassword); - if (newPasswordResponse != null) { - this.$store.commit("saveToken", newPasswordResponse); + if (newPasswordResponse.correctPassword) { + //New password was set + this.message = ""; + this.$store.commit("saveToken", newPasswordResponse.token); await this.$router.push("/"); + } else if (!newPasswordResponse.correctPassword) { + //The old password was not correct + this.message = "Det gamle passordet stemmer ikke for denne brukeren"; + } else { + //Ops something went wrong + this.message = "Ops noe gikk galt"; } }, validate() { diff --git a/src/components/TimepickerComponents/DatepickerRange/DatepickerRange.vue b/src/components/TimepickerComponents/DatepickerRange/DatepickerRange.vue index 53c92481e3318bfe86ccc699f80c6ed24ffbceb7..49fd65dc1249dc57add5e7c73d69a60bca2a1736 100644 --- a/src/components/TimepickerComponents/DatepickerRange/DatepickerRange.vue +++ b/src/components/TimepickerComponents/DatepickerRange/DatepickerRange.vue @@ -26,22 +26,6 @@ :blockedDaysRange="blockedDaysRange" ></calendar-component> </div> - <div class="split"></div> - <div> - <month-selector - @back="back" - type="monghM" - @forward="forward('monghM')" - :month="monghM" - ></month-selector> - <calendar-component - :month="monghM" - :start="startDate" - :end="endDate" - @selectDate="selectDate" - :blockedDaysRange="blockedDaysRange" - ></calendar-component> - </div> </div> <div class="footer"> <p v-if="error" class="error">{{ errorMessage }}</p> diff --git a/src/components/UserProfileComponents/RatingComponents/Rating.vue b/src/components/UserProfileComponents/RatingComponents/Rating.vue index 8aff6bad071841e4f6baf1c2825ca748b46c095f..1db98bfb010248d1cf3d554df1f946a6867e6dc9 100644 --- a/src/components/UserProfileComponents/RatingComponents/Rating.vue +++ b/src/components/UserProfileComponents/RatingComponents/Rating.vue @@ -31,7 +31,7 @@ </li> <li> <p class="ml-2 text-sm font-medium text-gray-500 dark:text-gray-400"> - Rating ikke tilgjengelig + Ingen vurderinger </p> </li> </ul> @@ -47,7 +47,7 @@ export default { methods: { getFill(i) { if (i <= this.rating) { - return "w-5 h-5 text-warn"; + return "w-5 h-5 text-warn-medium"; } return "w-5 h-5 text-gray-300 dark:text-gray-500"; }, diff --git a/src/components/UserProfileComponents/UserProfile.vue b/src/components/UserProfileComponents/UserProfile.vue index 09850d5d264d6b8ccee7dc3e8f5bad812e7e0be2..199265e51c2953316fcc5aa636f1860a5235fd36 100644 --- a/src/components/UserProfileComponents/UserProfile.vue +++ b/src/components/UserProfileComponents/UserProfile.vue @@ -70,7 +70,7 @@ <li> <router-link to="" - class="block py-2 px-4 text-sm text-error hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white" + class="block py-2 px-4 text-sm text-error-dark hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white" >Slett bruker</router-link > </li> @@ -88,7 +88,7 @@ {{ user.firstName }} {{ user.lastName }} </h5> <div> - <rating-component :rating="renterRating" :ratingType="'Leietaker'" /> + <rating-component :rating="renterRating" :ratingType="'Leietaker'"/> <rating-component :rating="ownerRating" :ratingType="'Utleier'" /> </div> @@ -106,7 +106,8 @@ <script> import RatingComponent from "@/components/UserProfileComponents/RatingComponents/Rating.vue"; import { parseCurrentUser } from "@/utils/token-utils"; -import { getUser, getAverageRating } from "@/utils/apiutil"; +import { getUser} from "@/utils/apiutil"; +import UserService from "@/services/user.service" export default { name: "LargeProfileCard", @@ -135,10 +136,14 @@ export default { return; } this.user = await getUser(this.id); - let rating = await getAverageRating(this.id); - if (rating >= 0 && rating <= 5) { - this.renterRating = rating; - this.ownerRating = rating; + let ratingAsOwner = await UserService.getUserRatingAsOwner(this.id); + let ratingAsRenter = await UserService.getUserRatingAsRenter(this.id) + + if (ratingAsOwner >= 0 && ratingAsOwner <= 5) { + this.ownerRating = ratingAsOwner; + } + if (ratingAsRenter >= 0 && ratingAsRenter <= 5){ + this.renterRating = ratingAsRenter; } }, getProfilePicture() { diff --git a/src/services/community-admin.service.js b/src/services/community-admin.service.js index 9a71b83ea37b434e8b0f2a54bb74b077c72094f7..c935f1181ea5d8c81306dddae21a8015d95a8d9d 100644 --- a/src/services/community-admin.service.js +++ b/src/services/community-admin.service.js @@ -21,7 +21,8 @@ class CommunityAdminService { async acceptUserIntoCommunity(communityID, userID) { return await axios.post( API_URL + "communities/" + communityID + "/requests", - { params: { userId: userID } } + null, + { headers: tokenHeader(), params: { userId: userID } } ); } @@ -29,9 +30,8 @@ class CommunityAdminService { async rejectUserFromCommunity(communityID, userID) { return await axios.patch( API_URL + "communitites/" + communityID + "/requests/reject", - { - params: { userId: userID }, - } + null, + { headers: tokenHeader(), params: { userId: userID } } ); } diff --git a/src/services/community.service.js b/src/services/community.service.js index d2bf0954527324357777de183dda46891b321418..11bc85817db76d285c028434a7e8df2f64cc5f46 100644 --- a/src/services/community.service.js +++ b/src/services/community.service.js @@ -17,9 +17,24 @@ class CommunityService { }); } - async getPublicCommunities() { + async getAllCommunities() { return await axios - .get(API_URL + "communities") + .get(API_URL + "communities", { + headers: tokenHeader(), + }) + .then((response) => { + return response.data; + }) + .catch((error) => { + console.error(error); + }); + } + + async getUserCommunities() { + return await axios + .get(API_URL + "user/communities", { + headers: tokenHeader(), + }) .then((response) => { return response.data; }) diff --git a/src/services/user.service.js b/src/services/user.service.js index d15407bf2cabd6ca8db35608b732b50901492184..5c6ebb84dd73c423d690adda4a336089bd81cd55 100644 --- a/src/services/user.service.js +++ b/src/services/user.service.js @@ -1,36 +1,31 @@ +// import { tokenHeader } from "@/utils/token-utils"; import { tokenHeader } from "@/utils/token-utils"; import axios from "axios"; const API_URL = process.env.VUE_APP_BASEURL; class UserService { - async getUserFromId(userId) { - return await axios - .get(API_URL + "users/" + userId + "/profile", { - headers: tokenHeader(), - }) - .then((res) => { - return res.data; - }) - .catch((err) => console.error(err)); - } + async getUserFromId(userId) { + return await axios + .get(API_URL + "users/" + userId + "/profile", { + headers: tokenHeader(), + }) + .then((res) => { + return res.data; + }) + .catch((err) => console.error(err)); + } - async getUserRatingAverage(userId) { - return await axios - .get(API_URL + "rating/" + userId + "/average", { - headers: tokenHeader(), - }) - .then((res) => { - return res.data; - }) - .catch((err) => console.error(err)); - } - - //TODO - async getUserRatingAsOwner() {} - - //TODO - async getUserRatingAsRenter() {} + async getUserRatingAverage(userId) { + return await axios + .get(API_URL + "rating/" + userId + "/average", { + headers: tokenHeader(), + }) + .then((res) => { + return res.data; + }) + .catch((err) => console.error(err)); + } async getRenterHistory() { return await axios @@ -71,6 +66,30 @@ class UserService { console.error(err); }); } -} -export default new UserService(); + async getUserRatingAsRenter(userId) { + return await axios + .get(API_URL + "rating/" + userId + "/average/renter", { + headers: tokenHeader(), + }) + .then((res) => { + return res.data; + }) + .catch((err) => console.error(err)) + } + + async getUserRatingAsOwner(userId) { + return await axios + .get(API_URL + "rating/" + userId + "/average/owner", { + headers: tokenHeader(), + }) + .then((res) => { + return res.data; + }) + .catch((err) => console.error(err)) + } +} + export + default + new + UserService(); \ No newline at end of file diff --git a/src/utils/apiutil.js b/src/utils/apiutil.js index 00c6d6fb0345f063325fa8a76c43fac34db4cd11..2f8fabcb74dc13da2e74888291ee8b581c721b16 100644 --- a/src/utils/apiutil.js +++ b/src/utils/apiutil.js @@ -85,21 +85,25 @@ export function getAverageRating(userid) { }); } export async function doNewPassword(password) { + const auth = { correctPassword: false, token: "" }; let res = await axios({ method: "put", - url: API_URL + "user/profile/password", + url: API_URL + "user/password/change", headers: tokenHeader(), data: { password: password, }, }) .then((response) => { - return response; + auth.correctPassword = true; + auth.token = response.data; + return auth; }) .catch((error) => { - console.error(error); + console.log(error); + return auth; }); - return res.data; + return res; } export function postNewItem(itemInfo) { diff --git a/src/views/CommunityViews/CommunityView.vue b/src/views/CommunityViews/CommunityView.vue index 4bf6345d4af82773fc196bc0847648692b1bd3e0..bd7b2ea53207acf14628dc4aff86c896d12c275b 100644 --- a/src/views/CommunityViews/CommunityView.vue +++ b/src/views/CommunityViews/CommunityView.vue @@ -6,7 +6,7 @@ Mine grupper </div> <UserAddIcon - class="cursor-pointer max-h-6 max-w-6 float-right grow" + class="cursor-pointer max-h-6 max-w-6 float-right grow text-primary-dark" @click="$router.push('/newCommunity')" alt="Opprett ny gruppe" /> @@ -32,15 +32,9 @@ <!-- Search field --> <div class="relative mt-1 mx-2" 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"> - <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-width="2" - stroke-linecap="round" - stroke-linejoin="round" - ></path> - </svg> + <div class="w-5 h-5 text-gray-400"> + <SearchIcon /> + </div> </span> <input @@ -74,9 +68,9 @@ <script> import CommunityList from "@/components/CommunityComponents/CommunityList.vue"; -import { getMyGroups, getVisibleGroups } from "@/utils/apiutil"; -import { UserAddIcon } from "@heroicons/vue/outline"; +import { UserAddIcon, SearchIcon } from "@heroicons/vue/outline"; import PaginationTemplate from "@/components/BaseComponents/PaginationTemplate"; +import CommunityService from "@/services/community.service"; export default { name: "HomeView", @@ -102,6 +96,7 @@ export default { CommunityList, UserAddIcon, PaginationTemplate, + SearchIcon, }, computed: { searchPublicCommunities() { @@ -152,26 +147,21 @@ export default { this.updatePageMyCommunities(this.currentPageMyCommunities - 1); } }, - //Triggers when search field input is changed - searchWritten: function () { + searchWritten() { //This method triggers when search input field is changed - if (this.search.length > 0) { - this.showPaginated = false; - this.showSearched = true; - } else { - this.showPaginated = true; - this.showSearched = false; - } + this.showPaginated = this.search.length < 1; + this.showSearched = this.search.length > 0; + }, + async load() { + this.publicCommunities = await CommunityService.getAllCommunities(); + this.loggedIn = this.$store.state.user.token !== null; + if (!this.loggedIn) return; + this.myCommunities = await CommunityService.getUserCommunities(); }, }, - async beforeMount() { - this.publicCommunities = await getVisibleGroups(); - this.loggedIn = this.$store.state.user.token !== null; - if (!this.loggedIn) return; - this.myCommunities = await getMyGroups(); - - // Double loop is bad; find a better way to do this - // Loops through both arrays and removes myCommunities from public + async mounted() { + await this.load(); + //Double loop not bad :) for (var i = 0; i < this.publicCommunities.length; i++) { for (var j = 0; j < this.myCommunities.length; j++) { if ( 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 index 2aa391a34e4b72f291cf5fe3bcb6173ea20e7e06..129085284ce0c40121b0be19e799ac65b7361f12 100644 --- 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 @@ -11,6 +11,24 @@ exports[`NewPasswordForm component renders correctly 1`] = ` </h3> <div class="" + id="oldPasswordField" + > + <label + class="block text-sm text-gray-800 dark:text-gray-200" + for="oldPassword" + > + Gammelt passord + </label> + <input + class="block w-full px-4 py-2 mt-2 text-gray-700 placeholder-gray-500 bg-white border rounded-md dark:bg-gray-800 dark:border-gray-600 dark:placeholder-gray-400 focus:border-blue-400 dark:focus:border-blue-300 focus:ring-opacity-40 focus:outline-none focus:ring focus:ring-blue-300" + type="password" + /> + <!-- error message --> + + + </div> + <div + class="mt-4" id="firstPasswordField" > <label @@ -59,5 +77,12 @@ exports[`NewPasswordForm component renders correctly 1`] = ` Sett ny passord </button> </div> + <div + class="flex items-center justify-center text-center bg-gray-50" + > + <label + class="mx-2 text-sm font-bold text-error-medium dark:text-primary-light hover:underline" + /> + </div> </div> `;