Skip to content
Snippets Groups Projects
Commit 1fbcefc8 authored by Henrik's avatar Henrik
Browse files

Merge branch 'ProfileStats' into 'main'

Global error catcher

See merge request !87
parents 7a9ce6ed 7186e89b
No related branches found
No related tags found
1 merge request!87Global error catcher
Pipeline #283727 failed
Showing with 250 additions and 162 deletions
......@@ -157,6 +157,7 @@ import { useRouter, useRoute } from "vue-router";
import { useUserInfoStore } from '@/stores/UserStore';
import {onMounted, ref} from "vue";
import { BadgeService, type NotificationDTO, NotificationService } from '@/api'
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
const router = useRouter();
const route = useRoute();
......@@ -207,6 +208,7 @@ const getNotifications = async () => {
await BadgeService.updateUnlockedBadges();
notificationListRef.value = await NotificationService.getUnreadNotificationByUser()
} catch (error) {
handleUnknownError(error);
notificationListRef.value = []
}
}
......@@ -217,6 +219,7 @@ const readNotification = async (notification: NotificationDTO) => {
await NotificationService.updateNotification({requestBody: notification});
notificationListRef.value = await NotificationService.getUnreadNotificationByUser()
} catch (error) {
handleUnknownError(error);
notificationListRef.value = [];
}
}
......
<script setup lang="ts">
import { BudgetService } from '@/api'
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
const emit = defineEmits(['errorEvent', 'deletedEvent'])
const props = defineProps({
......@@ -25,6 +26,7 @@ const deleteBudget = async () => {
await BudgetService.deleteBudget({budgetId: props.budgetId})
emit('deletedEvent')
} catch (error) {
handleUnknownError(error);
emit('errorEvent', error)
}
}
......
......@@ -4,6 +4,7 @@ import { ref } from 'vue'
import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
import { useRouter } from 'vue-router'
import {type CreateGoalDTO, GoalService} from "@/api";
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
const router = useRouter();
const emit = defineEmits(['changeRouterEvent'])
......@@ -35,6 +36,7 @@ const handleSubmit = async () => {
await GoalService.createGoal({ requestBody: createGoalPayload });
await router.push("/")
} catch (error: any) {
handleUnknownError(error);
console.log(error.message);
errorMessage.value = error.message;
}
......
......@@ -124,6 +124,7 @@ import { type Ref, ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { FriendService, UserService } from '@/api';
import type { UserDTO } from '@/api';
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
const router = useRouter();
const friends = ref();
......@@ -155,6 +156,7 @@ const searchProfile = async (searchTerm: string) => {
searchedUsers.value = response;
console.log(response);
} catch (error) {
handleUnknownError(error);
console.error('Failed to search for profile', error);
}
};
......@@ -169,6 +171,7 @@ const addNewFriends = async () => {
searchedUsers.value = response;
showAddFriend.value = true;
} catch (error) {
handleUnknownError(error);
console.error('Failed to add friend', error);
}
};
......@@ -179,6 +182,7 @@ async function addFriend(friendID: number) {
// Use a spread to update the state and keep immutability
friendRequestsSent.value = { ...friendRequestsSent.value, [friendID]: true };
} catch (error) {
handleUnknownError(error);
console.error('Failed to send friend request', error);
}
}
......@@ -192,6 +196,7 @@ async function requestFriend() {
elementsInFriendRequest.value = response.length > 0;
console.log("Friend requests: " + response);
} catch (error) {
handleUnknownError(error);
console.error('Failed to fetch friend requests', error);
}
}
......@@ -206,6 +211,7 @@ const removeFriend = async (friendID: number) => {
const responseFriends = await FriendService.getFriends();
friends.value = responseFriends;
} catch (error) {
handleUnknownError(error);
console.error('Failed to remove friend', error);
}
};
......@@ -219,6 +225,7 @@ const setupFriends = async () => {
elementsInFriends.value = response.length > 0;
console.log(response);
} catch (error) {
handleUnknownError(error);
console.error('Failed to fetch friends', error);
}
};
......@@ -231,6 +238,7 @@ const acceptRequest = async (requestID: number) => {
const responseFriends = await FriendService.getFriends();
friends.value = responseFriends;
} catch (error) {
handleUnknownError(error);
console.error('Failed to accept friend request', error);
}
};
......@@ -241,6 +249,7 @@ const rejectRequest = async (requestID: number) => {
const response = await FriendService.getFriendRequests();
friendRequests.value = response;
} catch (error) {
handleUnknownError(error);
console.error('Failed to reject friend request', error);
}
};
......
......@@ -46,6 +46,7 @@
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import Leaderboard from '@/components/Leaderboard/LeaderboardTable.vue';
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
import { LeaderboardService } from '@/api';
let streakLeaderboardData = ref([] as any);
......@@ -72,44 +73,49 @@ onMounted(() => {
});
async function global() {
let globalPoints = await LeaderboardService.getLeaderboard({
type: "TOTAL_POINTS",
filter: "GLOBAL",
});
let globalStreak = await LeaderboardService.getLeaderboard({
type: "TOP_STREAK",
filter: "GLOBAL",
});
let globalCurrentStreak = await LeaderboardService.getLeaderboard({
type: "CURRENT_STREAK",
filter: "GLOBAL",
});
let globalPointsYou = await LeaderboardService.getSurrounding({
type: "TOTAL_POINTS",
filter: "GLOBAL",
entryCount: 2,
});
let globalStreakYou = await LeaderboardService.getSurrounding({
type: "TOP_STREAK",
filter: "GLOBAL",
entryCount: 2,
});
let globalCurrentStreakYou = await LeaderboardService.getSurrounding({
type: "CURRENT_STREAK",
filter: "GLOBAL",
entryCount: 2,
});
pointsLeaderboardData.value = globalPoints.entries;
currentLeaderboardData.value = globalCurrentStreak.entries;
streakLeaderboardData.value = globalStreak.entries;
pointsLeaderboardDataExtra.value = globalPointsYou.entries;
currentLeaderboardDataExtra.value = globalCurrentStreakYou.entries;
streakLeaderboardDataExtra.value = globalStreakYou.entries;
try {
let globalPoints = await LeaderboardService.getLeaderboard({
type: "TOTAL_POINTS",
filter: "GLOBAL",
});
let globalStreak = await LeaderboardService.getLeaderboard({
type: "TOP_STREAK",
filter: "GLOBAL",
});
let globalCurrentStreak = await LeaderboardService.getLeaderboard({
type: "CURRENT_STREAK",
filter: "GLOBAL",
});
let globalPointsYou = await LeaderboardService.getSurrounding({
type: "TOTAL_POINTS",
filter: "GLOBAL",
entryCount: 2,
});
let globalStreakYou = await LeaderboardService.getSurrounding({
type: "TOP_STREAK",
filter: "GLOBAL",
entryCount: 2,
});
let globalCurrentStreakYou = await LeaderboardService.getSurrounding({
type: "CURRENT_STREAK",
filter: "GLOBAL",
entryCount: 2,
});
pointsLeaderboardData.value = globalPoints.entries;
currentLeaderboardData.value = globalCurrentStreak.entries;
streakLeaderboardData.value = globalStreak.entries;
pointsLeaderboardDataExtra.value = globalPointsYou.entries;
currentLeaderboardDataExtra.value = globalCurrentStreakYou.entries;
streakLeaderboardDataExtra.value = globalStreakYou.entries;
} catch (error) {
handleUnknownError(error);
}
}
async function friends() {
try {
let friendsPoints = await LeaderboardService.getLeaderboard({
type: "TOTAL_POINTS",
filter: "FRIENDS",
......@@ -138,7 +144,6 @@ async function friends() {
entryCount: 2,
});
pointsLeaderboardData.value = friendsPoints.entries;
currentLeaderboardData.value = friendsCurrentStreak.entries;
streakLeaderboardData.value = friendsStreak.entries;
......@@ -146,6 +151,9 @@ async function friends() {
pointsLeaderboardDataExtra.value = friendsPointsYou.entries;
currentLeaderboardDataExtra.value = friendsStreakYou.entries;
streakLeaderboardDataExtra.value = friendsCurrentStreakYou.entries;
} catch (error) {
handleUnknownError(error);
}
}
const navigateToUserProfile = (userId: number) => {
......
......@@ -30,6 +30,7 @@
import { ref } from 'vue';
import { UserService } from '@/api';
import BaseButton from '@/components/BaseComponents/Buttons/BaseButton.vue'
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
const formRef = ref()
const form = formRef.value;
......@@ -49,6 +50,7 @@
confirmationMessage.value = 'An email has been sent to your email address with a link to reset your password.';
errorMessage.value = '';
} catch (error) {
handleUnknownError(error);
errorMessage.value = 'Failed to send email. Please try again.';
confirmationMessage.value = '';
}
......
......@@ -4,6 +4,7 @@ import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue';
import { useUserInfoStore } from "@/stores/UserStore";
import { UserService } from '@/api';
import type { UserUpdateDTO } from '@/api';
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
const emailRef = ref('')
const errorMsg = ref('')
......@@ -22,6 +23,7 @@ async function setupForm() {
confirmationMsg.value = '';
errorMsg.value = '';
} catch (err) {
handleUnknownError(err);
errorMsg.value = 'Error fetching email, try again!'
confirmationMsg.value = ''
}
......@@ -40,6 +42,7 @@ const handleSubmit = async () => {
confirmationMsg.value = 'Email updated successfully!'
errorMsg.value = '';
} catch (err) {
handleUnknownError(err);
errorMsg.value = "Error updating email, try again!";
confirmationMsg.value = ''
}
......
......@@ -37,6 +37,7 @@
import { ref } from 'vue'
import BaseInput from '@/components/BaseComponents/Input/BaseInput.vue'
import { type PasswordUpdateDTO, UserService } from '@/api'
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
const oldPasswordRef = ref('');
const newPasswordRef = ref('');
......@@ -71,13 +72,8 @@ const handleSubmit = async () => {
const response = UserService.updatePassword({ requestBody: updateUserPayload })
console.log(response)
} catch (err) {
handleUnknownError(err);
console.error(err)
}
}
</script>
<style scoped></style>
\ No newline at end of file
</script>
\ No newline at end of file
<template>
<div id="background">
<br>
<div id="dropdownContainer">
<br />
<div id="dropdownContainer">
<h1 class="box">Butikk</h1>
<div>
<p class="mb-1 h2" data-cy="points">{{points}}<img src="@/assets/items/pigcoin.png" style="width: 4rem"></p>
<p class="mb-1 h2" data-cy="points">{{ points }}<img src="@/assets/items/pigcoin.png" style="width: 4rem" /></p>
</div>
</div>
<div class="container d-flex justify-content-center">
</div>
<div class="container d-flex justify-content-center">
<div class="row col-md-10">
<div class="col-md-12">
<h1>Stash</h1>
<div class="category row justify-content-between mb-5 m-2">
<div class="card text-center" style="width: 16rem; border: none">
<img src="../../assets/items/adfree.png" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Adfree</h5>
<button type="button" class="btn btn-primary" id="buttonStyle" @click="buyNoAds">
+35kr</button>
</div>
</div>
<div class="card text-center" style="width: 16rem; border: none">
<img src="../../assets/items/piggybank.webp" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Premium</h5>
<button type="button" class="btn btn-primary" id="buttonStyle"
@click="buyPremium">+50kr</button>
</div>
</div>
<div class="col-md-12">
<h1>Stash</h1>
<div class="category row mb-2 m-2">
<div class="card text-center justify-content-center align-items-center" style="width: 8rem; border: none">
<img src="../../assets/items/adfree.png" class="card-img-top" alt="..." style="width: 100px; height: 100px;" />
<div class="card-body">
<h5 class="card-title">Adfree</h5>
<button type="button" class="btn btn-primary" id="buttonStyle" @click="buyNoAds">
+35kr
</button>
</div>
</div>
<div class="card text-center justify-content-center align-items-center" style="width: 8rem; border: none">
<img src="../../assets/items/piggybank.webp" class="card-img-top" alt="..." style="width: 100px; height: 100px;" />
<div class="card-body">
<h5 class="card-title">Premium</h5>
<button type="button" class="btn btn-primary" id="buttonStyle" @click="buyPremium">
+50kr
</button>
</div>
</div>
</div>
<div class="col-md-12">
<h1>Items</h1>
<div class="category row justify-content-between mb-5 m-2">
<div v-for="product in products" :key="product.id" class="card text-center"
style="width: 16rem; border: none">
<img :src="`http://localhost:8080/api/images/${product.imageId}`" class="card-img-top"
alt="..." />
<div class="card-body">
<h5 class="card-title">{{ product.itemName }}</h5>
<ShopButton v-if="!product.alreadyBought" :button-text="product.price"
@click="buyItem(product.id)"></ShopButton>
<p v-else>Owned</p>
</div>
</div>
</div>
<div class="col-md-12">
<h1>Items</h1>
<div class="category row mb-2 m-2">
<div v-for="product in products" :key="product.id" class="card text-center d-flex justify-content-center align-items-center"
style="width: 8rem; border: none">
<img :src="`http://localhost:8080/api/images/${product.imageId}`" style="width: 100px; height: 100px;" class="card-img-top" alt="..." />
<div class="card-body">
<h5 class="card-title">{{ product.itemName }}</h5>
<h6>{{ product.price }}<img src="../../assets/items/pigcoin.png" style="width: 2rem" /></h6>
<ShopButton
v-if="!product.alreadyBought"
button-text="Buy item"
:disabled="product.price > points"
@click="buyItem(product.id)"
/>
<p v-else>Owned</p>
</div>
</div>
</div>
<div class="col-md-12">
<h1>Stash</h1>
<div class="category row justify-content-between mb-5 m-2">
<div class="card text-center" style="width: 16rem; border: none">
<img src="../../assets/items/coffee.jpg" class="card-img-top" alt="...">
</div>
<div class="col-md-12">
<h1>Cool items</h1>
<div class="category row mb-2 m-2">
<div class="card text-center d-flex justify-content-center align-items-center" style="width: 8rem; border: none">
<img src="../../assets/items/coffee.jpg" class="card-img-top" alt="..." style="width: 100px; height: 100px;">
<div class="card-body">
<h5 class="card-title">Free Coffee</h5>
<ShopButton button-text="500"></ShopButton>
<h6>500<img src="../../assets/items/pigcoin.png" style="width: 2rem"></h6>
<ShopButton
button-text="Buy item"
:disabled="500 > points"
@click="buySomething()"
/>
</div>
</div>
<div class="card text-center" style="width: 16rem; border: none">
<img src="../../assets/items/viaplay.jpg" class="card-img-top" alt="...">
<div class="card text-center d-flex justify-content-center align-items-center" style="width: 8rem; border: none">
<img src="../../assets/items/viaplay.jpg" class="card-img-top" alt="..." style="width: 100px; height: 100px;">
<div class="card-body">
<h5 class="card-title">1 Month Viaplay</h5>
<ShopButton button-text="10000"></ShopButton>
<h5 class="card-title">1 Month</h5>
<h6>10 000<img src="../../assets/items/pigcoin.png" style="width: 2rem"></h6>
<ShopButton
button-text="Buy item"
:disabled="10000 > points"
@click="buySomething()"
/>
</div>
</div>
<div class="card text-center" style="width: 16rem; border: none">
<img src="../../assets/items/pirbad.png" class="card-img-top" alt="...">
<div class="card text-center d-flex justify-content-center align-items-center" style="width: 8rem; border: none">
<img src="../../assets/items/pirbad.png" class="card-img-top" alt="..." style="width: 100px; height: 100px;">
<div class="card-body">
<h5 class="card-title">-10% rabatt</h5>
<ShopButton button-text="1000"></ShopButton>
<h6>1000<img src="../../assets/items/pigcoin.png" style="width: 2rem"></h6>
<ShopButton
button-text="Buy item"
:disabled="1000 > points"
@click="buySomething()"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import ShopButton from '@/components/Shop/ShopButton.vue';
import { ref, onMounted } from 'vue';
import { UserService } from '@/api';
import { useUserInfoStore } from '@/stores/UserStore';
import { ItemService } from '@/api';
const products = ref([] as any);
const points = ref();
const getStore = async () => {
</template>
<script setup lang="ts">
import ShopButton from '@/components/Shop/ShopButton.vue';
import { ref, onMounted } from 'vue';
import { UserService } from '@/api';
import { useUserInfoStore } from '@/stores/UserStore';
import { ItemService } from '@/api';
import handleUnknownError from '@/components/Exceptions/unkownErrorHandler';
const products = ref([] as any);
const points = ref();
const getStore = async () => {
try {
const response = await ItemService.getStore();
products.value = response;
const response = await ItemService.getStore();
products.value = response;
} catch (error) {
console.log(error);
handleUnknownError(error);
console.log(error);
}
}
const getPoints = async () => {
}
const getPoints = async () => {
try {
const response = await UserService.getUser();
points.value = response.point?.currentPoints;
const response = await UserService.getUser();
points.value = response.point?.currentPoints;
} catch (error) {
console.log(error);
handleUnknownError(error);
console.log(error);
}
}
const buyItem = async (itemId: number) => {
}
const buyItem = async (itemId: number) => {
try {
const response = await ItemService.buyItem({ itemId: itemId });
console.log(response);
getStore();
getPoints();
const response = await ItemService.buyItem({ itemId: itemId });
console.log(response);
getStore();
getPoints();
} catch (error) {
console.log(error);
handleUnknownError(error);
console.log(error);
}
}
const buyPremium = async () => {
}
const buyPremium = async () => {
try {
const response = await UserService.updateSubscriptionLevel({ subscriptionLevel: 'PREMIUM' });
useUserInfoStore().setUserInfo({
subscriptionLevel: 'PREMIUM',
})
const response = await UserService.updateSubscriptionLevel({ subscriptionLevel: 'PREMIUM' });
useUserInfoStore().setUserInfo({
subscriptionLevel: 'PREMIUM',
})
} catch (error) {
console.log(error);
handleUnknownError(error);
console.log(error);
}
}
const buyNoAds = async () => {
}
const buyNoAds = async () => {
try {
const response = await UserService.updateSubscriptionLevel({ subscriptionLevel: 'NO_ADS' });
useUserInfoStore().setUserInfo({
subscriptionLevel: 'NO_ADS',
})
const response = await UserService.updateSubscriptionLevel({ subscriptionLevel: 'NO_ADS' });
useUserInfoStore().setUserInfo({
subscriptionLevel: 'NO_ADS',
})
} catch (error) {
console.log(error);
handleUnknownError(error);
console.log(error);
}
}
//Just a random code generator for the feature's sake
function generateRandomCode(length = 8) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
onMounted(() => {
const buySomething = async () => {
try {
const randomCode = generateRandomCode();
alert(`Thank you for your purchase! Your code is: ${randomCode}`);
} catch (error) {
handleUnknownError(error);
console.log(error);
}
}
onMounted(() => {
getStore();
getPoints();
})
</script>
})
</script>
<style scoped>
.card {
......@@ -152,7 +198,7 @@ onMounted(() => {
border-radius: 8px;
padding-left: 5px;
padding-right: 5px;
/* Rounded corners */
height: 225px;
}
.box {
......
<!-- ShopButton.vue -->
<template>
<button type="button" class="btn btn-primary" id="buttonStyle"><img src="../../assets/items/pigcoin.png" style="width: 2rem"> +{{ buttonText }}</button>
<button
:disabled="disabled"
:class="['btn', { 'btn-primary': !disabled, 'btn-secondary': disabled }]"
id="buttonStyle"
@click="handleClick"
>
{{ buttonText }}
</button>
</template>
<script setup lang="ts">
defineProps<{ buttonText: string }>();
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
buttonText: String,
disabled: Boolean,
});
const emit = defineEmits(['click']);
const handleClick = () => {
if (!props.disabled) {
emit('click');
}
};
</script>
<style scoped>
#buttonStyle {
border-radius: 3rem;
}
</style>
\ No newline at end of file
#buttonStyle {
border-radius: 1rem;
cursor: pointer;
}
#buttonStyle[disabled] {
cursor: not-allowed;
}
</style>
......@@ -20,9 +20,6 @@ describe('ImageButtonComponent', () => {
const button = wrapper.find('#buttonStyle')
expect(button.exists()).toBe(true)
expect(button.text()).toContain('+Add Coin')
const image = button.find('img')
expect(image.exists()).toBe(true)
expect(image.attributes('src')).toBe('/src/assets/items/pigcoin.png')
expect(button.text()).toContain('Add Coin')
})
})
......@@ -7,15 +7,9 @@ import { useUserInfoStore } from '@/stores/UserStore';
<template>
<Menu data-cy="menu"></Menu>
<div v-if="!useUserInfoStore().isPremium && !useUserInfoStore().isNoAds" style="display: flex; flex-direction: row;">
<img v-for="item in 7" src="@/assets/coca.webp" style="width: 100%; height: 100px; margin: 5px; border-radius: 1rem;" alt="picture">
</div>
<div id="minHeight">
<RouterView />
</div>
<div v-if="!useUserInfoStore().isPremium && !useUserInfoStore().isNoAds" style="display: flex; flex-direction: row;">
<img v-for="item in 7" src="@/assets/coca.webp" style="width: 100%; height: 100px; margin: 5px; border-radius: 1rem;" alt="picture">
</div>
<Footer></Footer>
</template>
......
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