Skip to content
Snippets Groups Projects
Commit 25498281 authored by Titus Netland's avatar Titus Netland
Browse files

Merge branch 'rent-history' into 'main'

Rent history

See merge request !98
parents e0393e74 7f10483d
No related branches found
No related tags found
1 merge request!98Rent history
Pipeline #180520 passed
Showing with 261 additions and 74 deletions
......@@ -32,9 +32,7 @@
</div>
<!-- Modal body -->
<div class="p-6 space-y-6">
<p
class="text-lg text-base leading-relaxed text-gray-500 dark:text-gray-400"
>
<p class="text-lg leading-relaxed text-gray-500 dark:text-gray-400">
{{ title }}
</p>
</div>
......@@ -190,7 +188,7 @@ export default {
};
await postNewRating(ratingInfo);
this.$router.push("/");
this.$emit("reload");
},
},
};
......
<template>
<div
class="bg-white shadow dark:bg-gray-800 select-none cursor-pointer hover:bg-gray-50"
>
<p class="font-bold mx-4" id="title">
{{ historyItem.listing.title }}
</p>
<div class="flex flex-row items-center">
<div class="flex flex-col px-4 flex-1">
<router-link :to="{ path: '/profile/' + user.userId }">
Leid til: {{ user.firstName }} {{ user.lastName }}
</router-link>
</div>
<div class="flex flex-col flex-1">
<div>
Fra:
{{ this.getDateString(historyItem.fromTime, isMultipleDays) }}
</div>
<div>
Til: {{ this.getDateString(historyItem.toTime, isMultipleDays) }}
</div>
</div>
<colored-button
v-if="!isRated"
:text="'Vurder'"
class="px-4 flex-1"
@click="
$emit('rate', {
show: true,
name: user.firstName + ' ' + user.lastName,
title: historyItem.listing.title,
rentID: historyItem.rentId,
renterIsReceiverOfRating: !currentUserIsRenter,
})
"
/>
</div>
</div>
</template>
<script>
import ColoredButton from "@/components/BaseComponents/ColoredButton.vue";
import { parseCurrentUser } from "@/utils/token-utils";
import userService from "@/services/user.service";
export default {
name: "RentHistoryItem",
components: {
ColoredButton,
},
data() {
return {
user: {},
isRated: true,
};
},
props: {
historyItem: {
rentId: Number,
fromTime: Number,
toTime: Number,
isAccepted: Boolean,
listing: {
listingID: Number,
title: String,
pricePerDay: Number,
address: String,
userID: Number,
},
renterId: Number,
},
},
computed: {
currentUser() {
return parseCurrentUser();
},
isMultipleDays() {
if (this.historyItem.toTime - this.historyItem.fromTime < 86400000) {
return false;
}
return true;
},
price() {
if (this.isMultipleDays) {
let numDays = Math.round(
(this.historyItem.toTime - this.historyItem.fromTime) / 86400000
);
return this.historyItem.listing.pricePerDay * numDays;
}
return this.historyItem.listing.pricePerDay;
},
currentUserIsRenter() {
return this.isCurrentUser(this.historyItem.renterId);
},
},
methods: {
getDateString(milliseconds) {
let today = new Date();
let date = new Date(milliseconds);
let dateString = date.getDate() + "." + (date.getMonth()+1);
if (date.getFullYear() != today.getFullYear()) {
dateString += "." + date.getFullYear();
}
return dateString;
},
isCurrentUser(id) {
return id == this.currentUser.accountId;
},
},
async beforeCreate() {
if (this.currentUserIsRenter) {
this.user = await userService.getUserFromId(
this.historyItem.listing.userID
);
} else {
this.user = await userService.getUserFromId(this.historyItem.renterId);
}
this.isRated = await userService.isRated(this.historyItem.rentId);
},
};
</script>
......@@ -60,7 +60,7 @@
</template>
<script>
import RatingComponent from "@/components/UserProfileComponents/Rating.vue";
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";
......
......@@ -47,7 +47,7 @@
</li>
<li>
<router-link
to=""
to="/profile/history"
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"
>Leiehistorikk</router-link
>
......@@ -104,7 +104,7 @@
</template>
<script>
import RatingComponent from "@/components/UserProfileComponents/Rating.vue";
import RatingComponent from "@/components/UserProfileComponents/RatingComponents/Rating.vue";
import { parseCurrentUser } from "@/utils/token-utils";
import { getUser} from "@/utils/apiutil";
import UserService from "@/services/user.service"
......
......@@ -26,6 +26,12 @@ const routes = [
component: () => import("../views/UserProfileViews/ProfileView.vue"),
beforeEnter: guardRoute,
},
{
path: "/profile/history",
name: "history",
component: () => import("../views/UserProfileViews/RentHistoryView.vue"),
beforeEnter: guardRoute,
},
{
path: "/register",
name: "register",
......
......@@ -27,16 +27,45 @@ class UserService {
.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))
}
async getRenterHistory() {
return await axios
.get(API_URL + "user/profile/rent/history", {
headers: tokenHeader(),
})
.then((res) => {
return res.data;
})
.catch((err) => {
console.error(err);
return [];
});
}
async getOwnerHistory() {
return await axios
.get(API_URL + "user/profile/rent/history/owner", {
headers: tokenHeader(),
})
.then((res) => {
return res.data;
})
.catch((err) => {
console.error(err);
});
}
async isRated(rentID) {
return await axios
.get(API_URL + "rating/" + rentID + "/israted", {
headers: tokenHeader(),
})
.then((res) => {
return res.data;
})
.catch((err) => {
console.error(err);
});
}
async getUserRatingAsRenter(userId) {
return await axios
......@@ -48,6 +77,17 @@ class UserService {
})
.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
......
<template>
<rating-modal
:visible="modal.show"
:name="modal.name"
:title="modal.title"
:rentID="modal.rentID"
:renterIsReceiverOfRating="modal.renterIsReceiverOfRating"
@close="modal.show = false"
@reload="this.$forceUpdate()"
/>
<ul>
<li v-for="historyItem in fullHistory" :key="historyItem.rentId">
<rent-history-item
:historyItem="historyItem"
@rate="(modal) => openModal(modal)"
/>
</li>
</ul>
</template>
<script>
import RentHistoryItem from "@/components/UserProfileComponents/RentHistoryComponents/RentHistoryItem.vue";
import RatingModal from "@/components/UserProfileComponents/RatingComponents/RatingModal.vue";
import UserService from "@/services/user.service";
export default {
components: {
RentHistoryItem,
RatingModal,
},
data() {
return {
renterHistory: [],
ownerHistory: [],
modal: {
show: false,
name: "",
title: "",
rentID: -1,
renterIsReceiverOfRating: false,
},
};
},
computed: {
fullHistory() {
function compareHistoryItems(itemA, itemB) {
if (itemA.fromTime < itemB.fromTime) {
return -1;
}
if (itemA.fromTime > itemB.fromTime) {
return 1;
}
return 0;
}
let fullHistory = this.renterHistory.concat(this.ownerHistory);
fullHistory.filter((item) => item.isAccepted);
fullHistory.sort(compareHistoryItems);
return fullHistory;
},
hasNoHistory() {
return this.renterHistory.length == 0 && this.ownerHistory.length == 0;
},
},
methods: {
openModal(modal) {
this.modal = modal;
},
},
async beforeCreate() {
this.renterHistory = await UserService.getRenterHistory();
this.ownerHistory = await UserService.getOwnerHistory();
},
};
</script>
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);
});
});
import { mount } from "@vue/test-utils";
import Rating from "@/components/UserProfileComponents/Rating.vue";
import Rating from "@/components/UserProfileComponents/RatingComponents/Rating.vue";
describe("Rating component", () => {
let wrapper;
......
......@@ -4,7 +4,7 @@ module.exports = defineConfig({
transpileDependencies: true,
chainWebpack: (config) => {
config.plugin("html").tap((args) => {
args[0].title = "Borrow Community";
args[0].title = "BoCo - Borrow Community";
return args;
});
},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment