diff --git a/src/components/ItemComponents/NewItemForm.vue b/src/components/ItemComponents/NewItemForm.vue index c465454ce47d792b479751e67bad7d1645e02a6e..3ef622f2dfe0e9fa3cbb8dcbca343f5bf9c3bfac 100644 --- a/src/components/ItemComponents/NewItemForm.vue +++ b/src/components/ItemComponents/NewItemForm.vue @@ -328,7 +328,6 @@ export default { }; }, methods: { - /** * Checks validation. Checks also if any community is selected. * If no community is selected or any other field isn't valid @@ -424,7 +423,6 @@ export default { } }, - async removeImage(image) { let newImages = []; for (let i in this.item.images) { diff --git a/src/components/RentingComponents/ItemInfo.vue b/src/components/RentingComponents/ItemInfo.vue index bfe9c9af67080b66f1e26e13f7a021f4772b05c9..c8637741f83349dccec7ccb99ab25a4142fe537e 100644 --- a/src/components/RentingComponents/ItemInfo.vue +++ b/src/components/RentingComponents/ItemInfo.vue @@ -51,10 +51,11 @@ </p> </div> </div> - <div class="mt-2"> + <div class="mt-2" v-if="userForId"> <UserListItemCard :buttons="['chat']" :user="userForId" + :rating="rating" ></UserListItemCard> </div> <div class="mt-4"> @@ -75,7 +76,7 @@ <p class="text-xl font-semibold text-gray-900"> Total pris: {{ totPrice }} kr </p> - <p v-if="error" style="color: red;">Dato er påkrevd</p> + <p v-if="error" class="text-error-medium">Dato er påkrevd</p> <button class="px-4 py-2 font-medium tracking-wide text-white capitalize transition-colors duration-200 transform bg-gray-500 rounded-md focus:outline-none focus:ring focus:ring-opacity-80" v-bind:class="{ colorChange: allowForRent }" @@ -142,6 +143,7 @@ export default { dateMessage: "Venligst velg dato for leieperioden", allowForRent: false, nonAvailableTimes: [], + rating: 0, }; }, components: { @@ -224,11 +226,24 @@ export default { amountOfDays = Math.ceil(amountOfDays / 86400000); this.totPrice = this.item.pricePerDay * amountOfDays; }, + async getUserRating() { + let maybeRating = await UserService.getUserRatingAverage( + this.userForId.userId + ); + if (isNaN(maybeRating)) { + this.rating = NaN; + } else { + this.rating = maybeRating; + if (this.rating > 5) this.rating = 5; + else if (this.rating < 1) this.rating = 1; + } + }, }, - async beforeMount() { + async created() { await this.getItemPictures(); await this.getItem(); await this.getUser(this.item.userID); + await this.getUserRating(); await this.getAvailableTimesForListing(); }, }; diff --git a/src/components/UserProfileComponents/RatingComponents/Rating.vue b/src/components/UserProfileComponents/RatingComponents/Rating.vue index 6b35e957e56a88604530d108196e954c57a7df8e..dc8eee3eefd29f3f2014d8babf87ea3a08cd47d5 100644 --- a/src/components/UserProfileComponents/RatingComponents/Rating.vue +++ b/src/components/UserProfileComponents/RatingComponents/Rating.vue @@ -43,7 +43,7 @@ export default { methods: { //Fills the rating stars getFill(i) { - if (i <= this.rating) { + if (i <= Math.round(this.rating)) { 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/UserItems.vue b/src/components/UserProfileComponents/UserItems.vue index 5ae1e7558efea5cbb62b872074e110c0840e9f34..9a988f48e44e66bfc65d3f786e5c97ffa56cc91c 100644 --- a/src/components/UserProfileComponents/UserItems.vue +++ b/src/components/UserProfileComponents/UserItems.vue @@ -42,15 +42,15 @@ :key="item" > <div class="w-full"> - <ItemCard - id="ItemCardPage" - class="ItemCard w-full h-full" - :item="item" - /> - </div> + <ItemCard + id="ItemCardPage" + class="ItemCard w-full h-full" + :item="item" + /> + </div> <!-- Dropdown menu with options for editing an item and deleting an item --> - <TripleDotButton class="DotButton" @click="openDotMenu(item)"/> + <TripleDotButton class="DotButton" @click="openDotMenu(item)" /> <div v-show="item.toggle" @@ -124,7 +124,7 @@ </div> <!-- Dropdown menu with options for editing an item and deleting an item --> - <TripleDotButton class="DotButton" @click="openDotMenu(item)"/> + <TripleDotButton class="DotButton" @click="openDotMenu(item)" /> <div v-show="item.toggle" class="options z-10 w-44 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700" diff --git a/src/components/UserProfileComponents/UserListItemCard.vue b/src/components/UserProfileComponents/UserListItemCard.vue index c94d796903940d7db729648f465677f385cc8464..0a6bd91d528dee33666d47cd8498829c6a3bb466 100644 --- a/src/components/UserProfileComponents/UserListItemCard.vue +++ b/src/components/UserProfileComponents/UserListItemCard.vue @@ -65,7 +65,6 @@ <script> import RatingComponent from "@/components/UserProfileComponents/RatingComponents/Rating.vue"; import IconButton from "@/components/BaseComponents/IconButton.vue"; -import UserService from "@/services/user.service"; import CommunityAdminService from "@/services/community-admin.service"; import { @@ -79,7 +78,6 @@ export default { name: "UserListItem", data() { return { - rating: -1.0, communityID: -1, profileImage: { src: require("../../assets/defaultUserProfileImage.jpg"), @@ -97,6 +95,7 @@ export default { props: { user: Object, buttons: Array, + rating: Number, }, computed: { /** @@ -145,17 +144,7 @@ export default { ); }, }, - /** - * Gets the user's rating before mounting the page - */ - async beforeMount() { - const maybeRating = await UserService.getUserRatingAverage( - this.user.userId - ); - if (isNaN(maybeRating)) this.rating = NaN; - else this.rating = maybeRating; - if (this.rating > 5) this.rating = 5; - if (this.rating < 1) this.rating = 1; + async beforeMounted() { this.communityID = this.$route.params.communityID; }, }; diff --git a/src/components/UserProfileComponents/UserProfile.vue b/src/components/UserProfileComponents/UserProfile.vue index 2b79e9d1ef3a8e6ab2f2299761a288c1a1def7b6..3ad810dc8a65986670aac5e217a1fe3f91eafee6 100644 --- a/src/components/UserProfileComponents/UserProfile.vue +++ b/src/components/UserProfileComponents/UserProfile.vue @@ -103,7 +103,10 @@ </h5> <div> <rating-component :rating="renterRating" :ratingType="'Leietaker'" /> - <rating-component :rating="ownerRating" :ratingType="'Utleier'" /> + <RatingComponent + :rating="ownerRating" + :ratingType="'Utleier'" + ></RatingComponent> </div> <div @@ -172,11 +175,13 @@ export default { this.isCurrentUser = true; this.user = this.currentUser; this.user = await UserService.getUserFromId(this.user.accountId); - return; + } else { + this.user = await getUser(this.id); } - this.user = await getUser(this.id); - let ratingAsOwner = await UserService.getUserRatingAsOwner(this.id); - let ratingAsRenter = await UserService.getUserRatingAsRenter(this.id); + let ratingAsOwner = await UserService.getUserRatingAverageOwner(this.id); + let ratingAsRenter = await UserService.getUserRatingAverageRenter( + this.id + ); if (ratingAsOwner >= 0 && ratingAsOwner <= 5) { this.ownerRating = ratingAsOwner; @@ -201,8 +206,8 @@ export default { this.logout(); }, }, - beforeMount() { - this.getUser(); + async beforeMount() { + await this.getUser(); }, }; </script> diff --git a/src/router/index.js b/src/router/index.js index d3da75ae0cbae2ac6d2432d41d97add0f06aec5d..7804eca4ed872f85fa920b0ce83cffbdd5daa974 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -24,11 +24,9 @@ function authGuardRoute(to, from, next) { function adminGuardRoute(to, from, next) { if (store.state.user.adminList.includes(parseInt(from.params.communityID))) next(); // allow to enter route - else - next("/"); // go to the home page + else next("/"); // go to the home page } - const routes = [ { path: "/", diff --git a/src/services/user.service.js b/src/services/user.service.js index 1639127d4706c607415316a00f95829f00e3eef5..5aeb0201f8a3c32d04b6eae18808d0ec2f763fb3 100644 --- a/src/services/user.service.js +++ b/src/services/user.service.js @@ -39,6 +39,28 @@ class UserService { .catch((err) => console.error(err)); } + async getUserRatingAverageOwner(userId) { + return await axios + .get(API_URL + "rating/" + userId + "/average/owner", { + headers: tokenHeader(), + }) + .then((res) => { + return res.data; + }) + .catch((err) => console.error(err)); + } + + async getUserRatingAverageRenter(userId) { + return await axios + .get(API_URL + "rating/" + userId + "/average/renter", { + headers: tokenHeader(), + }) + .then((res) => { + return res.data; + }) + .catch((err) => console.error(err)); + } + async setListingToDeleted(listingId) { return await axios .delete(API_URL + "listing/" + listingId, { diff --git a/src/views/ItemViews/EditItemView.vue b/src/views/ItemViews/EditItemView.vue index cdb4f27044b4c7e19c1431a7579edef43ba38871..6ae71767e398bd1f4d768bdb4682817dcde913d3 100644 --- a/src/views/ItemViews/EditItemView.vue +++ b/src/views/ItemViews/EditItemView.vue @@ -1,7 +1,7 @@ <template> <!-- A view for editing the item --> <div class="h-screen grid md:mt-8"> - <edit-item-form/> + <edit-item-form /> </div> </template> diff --git a/src/views/UserProfileViews/MyCommunitiesView.vue b/src/views/UserProfileViews/MyCommunitiesView.vue index 1c3d2f354fd54572a1a0ea2d327a3c275818f566..bee55d4487fbdcfdcdec30435f0ba00f70ca02bb 100644 --- a/src/views/UserProfileViews/MyCommunitiesView.vue +++ b/src/views/UserProfileViews/MyCommunitiesView.vue @@ -25,7 +25,7 @@ import CommunityList from "@/components/CommunityComponents/CommunityList.vue"; import CommunityService from "@/services/community.service"; import { UserAddIcon } from "@heroicons/vue/outline"; -import LoaderSpinner from "@/components/BaseComponents/LoaderSpinner" +import LoaderSpinner from "@/components/BaseComponents/LoaderSpinner"; export default { data() { diff --git a/tests/unit/component-tests/ChatComponentsTest/RentalMessage.spec.js b/tests/unit/component-tests/ChatComponentsTest/RentalMessage.spec.js index 5dd91c096296e40b474abc2d8e1fb61525eafc8d..9c520a8c89f7a1157b68f29f9c2ed77ba2fbf9a1 100644 --- a/tests/unit/component-tests/ChatComponentsTest/RentalMessage.spec.js +++ b/tests/unit/component-tests/ChatComponentsTest/RentalMessage.spec.js @@ -29,7 +29,7 @@ describe("RentalMessage.vue", () => { let wrapper; const mockRouter = { go: jest.fn(), - } + }; beforeEach(() => { wrapper = shallowMount(RentalMessage, { propsData: { @@ -54,7 +54,7 @@ describe("RentalMessage.vue", () => { mocks: { $router: mockRouter, }, - } + }, }); }); diff --git a/tests/unit/component-tests/renting-compnents-tests/item-info.spec.js b/tests/unit/component-tests/renting-compnents-tests/item-info.spec.js index e9874670c92f064b47df05e727f8e9dff03953e8..33b2c610f69ba97491214d3fab01476b32a0e270 100644 --- a/tests/unit/component-tests/renting-compnents-tests/item-info.spec.js +++ b/tests/unit/component-tests/renting-compnents-tests/item-info.spec.js @@ -1,109 +1,110 @@ import { shallowMount } from "@vue/test-utils"; -import ItemInfo from "@/components/RentingComponents/ItemInfo.vue"; +import ItemInfo from "@/components/RentingComponents/ItemInfo.vue"; + +const mockMethod = jest.spyOn(ItemInfo.methods, "sendToConfirm"); +const mockCreatePush = jest.spyOn(ItemInfo.methods, "createPushItem"); -const mockMethod = jest.spyOn(ItemInfo.methods, 'sendToConfirm') -const mockCreatePush = jest.spyOn(ItemInfo.methods, 'createPushItem') - jest.mock("@/utils/apiutil", () => { - return { - getItem: () => { - return new Promise((resolve) => { - resolve({ - listingID: 0, - title: "Title", - description: "Description", - pricePerDay: 100, - address: "ABC ROAD 3", - userID: 1, - categoryNames: [], - communityIDs: [], - }); - }); - }, - getItemPictures: () => { - return new Promise((resolve) => { - resolve([]); - }); - } - }; - }); + return { + getItem: () => { + return new Promise((resolve) => { + resolve({ + listingID: 0, + title: "Title", + description: "Description", + pricePerDay: 100, + address: "ABC ROAD 3", + userID: 1, + categoryNames: [], + communityIDs: [], + }); + }); + }, + getItemPictures: () => { + return new Promise((resolve) => { + resolve([]); + }); + }, + }; +}); describe("ItemInfo component", () => { - let wrapper; - const mockRouter = { - push: jest.fn(), - currentRoute: { - value: { - params: { - id: "1", - } - } - } - }; - const mockStore = { - commit: jest.fn(), - }; + let wrapper; + const mockRouter = { + push: jest.fn(), + currentRoute: { + value: { + params: { + id: "1", + }, + }, + }, + }; + const mockStore = { + commit: jest.fn(), + }; - beforeEach(() => { - wrapper = shallowMount(ItemInfo, { - global: { - mocks: { - $router: mockRouter, - $store: mockStore, - }, - }, - }); + beforeEach(() => { + wrapper = shallowMount(ItemInfo, { + global: { + mocks: { + $router: mockRouter, + $store: mockStore, + }, + }, }); + }); - it("is instantiated", () => { - expect(wrapper.exists()).toBeTruthy(); - }) + it("is instantiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); + + it("Check that title is displayed", () => { + expect(wrapper.findAll("h1")[0].text()).toBe("Title"); + }); - it("Check that title is displayed", () => { - expect(wrapper.findAll("h1")[0].text()).toBe("Title"); - }) + it("Check that button cannot be clicked if date is not selected", async () => { + const jestCreatePushItemMock = jest.fn(); + wrapper.vm.createPushItem = jestCreatePushItemMock; - it("Check that button cannot be clicked if date is not selected", async () => { - const jestCreatePushItemMock = jest.fn(); - wrapper.vm.createPushItem = jestCreatePushItemMock; - - // Click rent button - wrapper.find("button").trigger("click"); - - // wait a tick - await wrapper.vm.$nextTick(); + // Click rent button + wrapper.find("button").trigger("click"); - // Check that jestMock was not clicked - expect(mockMethod).toHaveBeenCalledTimes(1); - expect(mockCreatePush).toHaveBeenCalledTimes(0); - // Check that the last p contains "Dato er påkrevd" - expect(wrapper.findAll("p")[wrapper.findAll("p").length - 1].text()).toBe("Dato er påkrevd"); + // wait a tick + await wrapper.vm.$nextTick(); - }) + // Check that jestMock was not clicked + expect(mockMethod).toHaveBeenCalledTimes(1); + expect(mockCreatePush).toHaveBeenCalledTimes(0); + // Check that the last p contains "Dato er påkrevd" + expect(wrapper.findAll("p")[wrapper.findAll("p").length - 1].text()).toBe( + "Dato er påkrevd" + ); + }); - it("Check that send to confirm works", async () => { - // Set valid days - wrapper.vm.setDate({ - startDate: "2020-01-01", - endDate: "2020-02-01", - }) - wrapper.find("button").trigger("click"); - // wait a tick - await wrapper.vm.$nextTick(); + it("Check that send to confirm works", async () => { + // Set valid days + wrapper.vm.setDate({ + startDate: "2020-01-01", + endDate: "2020-02-01", + }); + wrapper.find("button").trigger("click"); + // wait a tick + await wrapper.vm.$nextTick(); - // Check that method to change component was called - expect(mockCreatePush).toHaveBeenCalledTimes(1); - }) + // Check that method to change component was called + expect(mockCreatePush).toHaveBeenCalledTimes(1); + }); - it("Test that price calculation works", async () => { - wrapper.vm.setDate({ - startDate: new Date("2022-01-01"), - endDate: new Date("2022-01-03"), - }) - // wait a tick - await wrapper.vm.$nextTick(); - await wrapper.vm.$nextTick(); + it("Test that price calculation works", async () => { + wrapper.vm.setDate({ + startDate: new Date("2022-01-01"), + endDate: new Date("2022-01-03"), + }); + // wait a tick + await wrapper.vm.$nextTick(); + await wrapper.vm.$nextTick(); - expect(wrapper.vm.totPrice).toBe(200); - }) -}); \ No newline at end of file + expect(wrapper.vm.totPrice).toBe(200); + }); +}); diff --git a/tests/unit/component-tests/renting-compnents-tests/new-rent.spec.js b/tests/unit/component-tests/renting-compnents-tests/new-rent.spec.js index c4cb88e85e7a68134b52dba817ebd7375e29888b..458147edeb2d729b82043ebecec97a9158d1d876 100644 --- a/tests/unit/component-tests/renting-compnents-tests/new-rent.spec.js +++ b/tests/unit/component-tests/renting-compnents-tests/new-rent.spec.js @@ -7,8 +7,8 @@ let mockRouter; describe("Confirm and send a rent request", () => { mockRouter = { - go: jest.fn() - } + go: jest.fn(), + }; let wrapper; beforeEach(() => { @@ -24,11 +24,11 @@ describe("Confirm and send a rent request", () => { isAccepted: false, }, }, - global:{ - mocks:{ - $router: mockRouter - } - } + global: { + mocks: { + $router: mockRouter, + }, + }, }); }); @@ -51,11 +51,11 @@ describe("Confirm and send a rent request", () => { expect(axios.post).toHaveBeenCalledTimes(1); }); - it("Checks that page is reloaded when cancelButton is press", async () =>{ + it("Checks that page is reloaded when cancelButton is press", async () => { const button = wrapper.find("#cancelButton"); button.trigger("click"); await wrapper.vm.$nextTick(); expect(mockRouter.go).toHaveBeenCalledTimes(1); expect(mockRouter.go).toHaveBeenCalledWith(0); - }) + }); });