diff --git a/src/components/CommunityComponents/CommunityHome.vue b/src/components/CommunityComponents/CommunityHome.vue index c3bf82cba6a7ea5ecaf82b2a0f33a2fa7534132a..0f0790dadcd232f9d7a90a0fe4451fdeec4fc7e1 100644 --- a/src/components/CommunityComponents/CommunityHome.vue +++ b/src/components/CommunityComponents/CommunityHome.vue @@ -116,7 +116,7 @@ export default { title: "", pricePerDay: 0, }, - search: "", + communityID: -1, community: {}, diff --git a/src/components/RentingComponents/NewRent.vue b/src/components/RentingComponents/NewRent.vue index 32073aa24a66328935b56876748e554e8dc00925..7ced0d6da6b8575e6fa37f287ddc3ae464fa0072 100644 --- a/src/components/RentingComponents/NewRent.vue +++ b/src/components/RentingComponents/NewRent.vue @@ -32,8 +32,12 @@ <button id="cancelButton" @click="cancelRent" class="text-primary-medium"> Tilbake </button> - <div id="confirmButton"> - <colored-button @click="sendRent" :text="'Send'"></colored-button> + <div id="confirm"> + <colored-button + id="confirmButton" + @click="sendRent" + :text="'Send'" + ></colored-button> </div> </div> <div> @@ -75,7 +79,6 @@ export default { newRentBox: { renterId: Number, title: String, - description: String, fromTime: Date, toTime: Date, listingID: Number, @@ -100,40 +103,40 @@ export default { let monthString = ""; //Gives the month the proper name switch (dateMonth) { - case 1: + case 0: monthString = "Januar"; break; - case 2: + case 1: monthString = "Februar"; break; - case 3: + case 2: monthString = "Mars"; break; - case 4: + case 3: monthString = "April"; break; - case 5: + case 4: monthString = "Mai"; break; - case 6: + case 5: monthString = "Juni"; break; - case 7: + case 6: monthString = "Juli"; break; - case 8: + case 7: monthString = "August"; break; - case 9: + case 8: monthString = "September"; break; - case 10: + case 9: monthString = "Oktober"; break; - case 11: + case 10: monthString = "November"; break; - case 12: + case 11: monthString = "Desember"; break; default: @@ -209,7 +212,7 @@ export default { grid-column: 1/3; grid-row: 6/7; } -#confirmButton { +#confirm { grid-column: 1/3; grid-row: 7/8; align-content: center; diff --git a/src/components/UserProfileComponents/UserItems.vue b/src/components/UserProfileComponents/UserItems.vue new file mode 100644 index 0000000000000000000000000000000000000000..73ae23b432b772e2718ce69230478a99c23a027f --- /dev/null +++ b/src/components/UserProfileComponents/UserItems.vue @@ -0,0 +1,164 @@ +<template> + <div id = "headline" class = "text-xl md:text-2xl text-gray-600 font-medium w-full"> + Dine gjenstander + </div> + <!-- 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"> + <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> + </span> + + <input + type="text" + id="searchInput" + 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-primary-medium dark:focus:border-primary-medium focus:outline-none focus:ring" + placeholder="Search" + v-model="search" + @change="searchWritten" + /> + </div> + + <div class="absolute inset-x-0 px-5 py-3"> + <!-- ItemCards --> + <div class="flex items-center justify-center w-screen"> + <!-- Shows items based on pagination --> + <div + class="grid grid-flow-row-dense grid-cols-2 md:grid-cols-4 lg:grid-cols-5 w-full" + v-if="showItems" + > + <ItemCard + v-for="item in visibleItems" + :key="item" + :item="item" + /> + </div> + + <!-- Shows items based on search field input --> + <div + class="grid grid-flow-row-dense grid-cols-2 md:grid-cols-4 lg:grid-cols-5 w-full place-items-center" + v-if="showSearchedItems" + > + <ItemCard + v-for="item in searchedItems" + :key="item" + :item="item" + /> + </div> + </div> + <!-- pagination --> + <div class="flex justify-center" v-if="showItems"> + <PaginationTemplate + v-bind:items="items" + v-on:page:update="updatePage" + v-bind:currentPage="currentPage" + v-bind:pageSize="pageSize" + class="mt-10" + /> + </div> + </div> +</template> +<script> +import { GetUserListings, getItemPictures } from "@/utils/apiutil"; +import ItemCard from "@/components/ItemComponents/ItemCard.vue"; +import PaginationTemplate from "@/components/BaseComponents/PaginationTemplate"; + +export default { + name: "UserItems", + components: { + ItemCard, + PaginationTemplate + }, + data() { + return { + items: [], + item: { + listingID: 0, + img: "", + address: "", + title: "", + pricePerDay: 0, + }, + showItems: true, + showSearchedItems: false, + search: "", + //Variables connected to pagination + currentPage: 0, + pageSize: 12, + visibleItems: [], + }; + }, + computed: { + searchedItems() { + let filteredItems = []; + + filteredItems = this.items.filter( + (p) => + p.title.toLowerCase().includes(this.search.toLowerCase()) || + p.address.toLowerCase().includes(this.search.toLowerCase()) || + p.pricePerDay === Number(this.search) + ); + + return filteredItems; + }, + }, + methods: { + getUserListingsFromAPI: async function () { + this.items = await GetUserListings(); + for (var i = 0; i < this.items.length; i++) { + let images = await getItemPictures(this.items[i].listingID); + if (images.length > 0) { + this.items[i].img = images[0].picture; + } + } + }, + //Pagination + updatePage(pageNumber) { + this.currentPage = pageNumber; + this.updateVisibleTodos(); + }, + updateVisibleTodos() { + this.visibleItems = this.items.slice( + this.currentPage * this.pageSize, + this.currentPage * this.pageSize + this.pageSize + ); + + // if we have 0 visible items, go back a page + if (this.visibleItems.length === 0 && this.currentPage > 0) { + this.updatePage(this.currentPage - 1); + } + }, + searchWritten: function () { + //This method triggers when search input field is changed + if (this.search.length > 0) { + this.showItems = false; + this.showSearchedItems = true; + } else { + this.showItems = true; + this.showSearchedItems = false; + } + }, + }, + async beforeMount() { + await this.getUserListingsFromAPI(); + this.updateVisibleTodos(); + + }, +}; +</script> + +<style> +#headline { + display: block; + margin-top: 10px; + margin-bottom: 10px; + +} +</style> \ No newline at end of file diff --git a/src/components/UserProfileComponents/UserProfile.vue b/src/components/UserProfileComponents/UserProfile.vue index 9235ab472cdd07769260c182f5acc0fddd9632a8..aa280f2bd99842d2e6ddd4fcf9ad0f3d2e3fddf7 100644 --- a/src/components/UserProfileComponents/UserProfile.vue +++ b/src/components/UserProfileComponents/UserProfile.vue @@ -33,7 +33,8 @@ > <li> <router-link - to="" + + to="/user/userItems" 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" >Mine gjenstander</router-link > diff --git a/src/router/index.js b/src/router/index.js index 2f0d2e5ac5f619305ebf5431e4c0267a20dbe201..1f12a1c3eff8df8f9df225df171f3af8f226fa57 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -117,6 +117,11 @@ const routes = [ component: () => import("../views/RentingViews/ItemInfoPageView.vue"), beforeEnter: guardRoute, }, + { + path: "/user/userItems", + name: "UserItems", + component: () => import("../views/UserProfileViews/UserItemsView.vue"), + } ]; const router = createRouter({ diff --git a/src/utils/apiutil.js b/src/utils/apiutil.js index 3323521fff3d19eff9aa4a1394fb7e20ed888e52..4a3becfcd9e287a3c7873d0ddd35c36daaf5a4e6 100644 --- a/src/utils/apiutil.js +++ b/src/utils/apiutil.js @@ -300,6 +300,19 @@ export async function LeaveCommunity(communityID) { }); } +export async function GetUserListings() { + return axios + .get(API_URL + "listing/userListings", { + headers: tokenHeader(), + }) + .then((response) => { + return response.data; + }) + .catch((error) => { + console.error(error); + }); +} + export function postNewRating(ratingInfo) { return axios .post(API_URL + "rating/save", ratingInfo, { @@ -313,4 +326,4 @@ export function postNewRating(ratingInfo) { console.log(error.response); return error; }); -} \ No newline at end of file +} diff --git a/src/views/UserProfileViews/UserItemsView.vue b/src/views/UserProfileViews/UserItemsView.vue new file mode 100644 index 0000000000000000000000000000000000000000..68183febcadb884441a48db2a600e4e305bd4878 --- /dev/null +++ b/src/views/UserProfileViews/UserItemsView.vue @@ -0,0 +1,18 @@ +<template> + <user-items> </user-items> +</template> + +<script> +import UserItems from "@/components/UserProfileComponents/UserItems.vue" +export default { + name: "UserItemsView", + components:{ + UserItems + } + +} +</script> + +<style> + +</style> 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 new file mode 100644 index 0000000000000000000000000000000000000000..3f8ffafa68bf5dd606afdeda9214b57871ff174f --- /dev/null +++ b/tests/unit/component-tests/renting-compnents-tests/new-rent.spec.js @@ -0,0 +1,46 @@ +import { mount } from "@vue/test-utils"; +import NewRent from "@/components/RentingComponents/NewRent.vue"; + +describe("Confirm and send a rent request", () => { + let wrapper; + const route = { + params: { + id: 1, + }, + }; + const router = { + push: jest.fn(), + }; + beforeEach(() => { + wrapper = mount(NewRent, { + props: { + newRentBox: { + title: "Telt", + listingID: 1, + fromTime: "2022-09-19", + toTime: "2022-09-23", + price: 200, + renterId: 1, + isAccepted: false, + }, + }, + global: { + mocks: { + $route: route, + $router: router, + }, + }, + }); + }); + + it("Is instansiated", () => { + expect(wrapper.exists()).toBeTruthy(); + }); + + it("Check if fields show correct informations", () => { + expect(wrapper.find("#rentTitle").text()).toEqual("Telt"); + expect(wrapper.find("#fromTime").text()).toMatch("19. September 2022"); + expect(wrapper.find("#toTime").text()).toMatch("23. September 2022"); + expect(wrapper.find("#price").text()).toEqual("Totaltpris: 200 kr"); + }); +});