diff --git a/index.html b/index.html index f5eff92..805ae6f 100644 --- a/index.html +++ b/index.html @@ -2,10 +2,10 @@ - - - - Hutopy + + + + Hutopy diff --git a/src/Constants/Reactions.js b/src/Constants/Reactions.js new file mode 100644 index 0000000..14ae0b1 --- /dev/null +++ b/src/Constants/Reactions.js @@ -0,0 +1,9 @@ +export const REACTIONS = { + LIKE: 'Like', + DISLIKE: 'Dislike', + LOVE: 'Love', + HAHA: 'Haha', + WOW: 'Wow', + SAD: 'Sad', + ANGRY: 'Angry' +}; \ No newline at end of file diff --git a/src/views/contents/ContentCard.vue b/src/views/contents/ContentCard.vue index 4a6c400..aa6ea25 100644 --- a/src/views/contents/ContentCard.vue +++ b/src/views/contents/ContentCard.vue @@ -64,12 +64,8 @@
- - mdi-thumb-up-outline - - - mdi-thumb-down-outline - + + +import { useUserStore } from "@/stores/userStore.js"; +import { REACTIONS } from "@/Constants/Reactions.js"; +import { computed, ref } from "vue"; +import { useClient } from "@/plugins/api.js"; + +const userStore = useUserStore(); + +const props = defineProps({ + content: { + type: Object, + required: true, + }, +}); + +const contentId = computed(() => props.content.id); + +const hasReacted = ref(false); +const currentReaction = ref(null); +const likeCount = ref(0); +const dislikeCount = ref(0); +const loveCount = ref(0); +const hahaCount = ref(0); +const wowCount = ref(0); +const sadCount = ref(0); +const angryCount = ref(0); + +const menuVisible = ref(false); +const holdTimeout = ref(null); +const hideTimeout = ref(null); +const touchTimeout = ref(null); + +initializeReactions(); + +async function reactToContent(reaction) { + const client = useClient(); + + if (!hasReacted.value) { + const request = { + ContentId: contentId.value, + reaction: reaction, + userId: userStore.user.id, + userName: `${userStore.user.firstName} ${userStore.user.lastName}`, + }; + adjustReactionCount(reaction); + await client.post("/api/content/reaction/", request); + + hasReacted.value = true; + console.log(`Added ${reaction} reaction to content.`); + } else if (reaction !== currentReaction.value) { + adjustReactionCount(currentReaction.value); + const requestRemove = { + ContentId: contentId.value, + userId: userStore.user.id, + }; + await client.post("/api/content/reaction/remove", requestRemove); + + const requestAdd = { + ContentId: contentId.value, + reaction: reaction, + userId: userStore.user.id, + userName: `${userStore.user.firstName} ${userStore.user.lastName}`, + }; + adjustReactionCount(reaction); + await client.post("/api/content/reaction/", requestAdd); + + console.log(`Changed reaction to ${reaction} on content.`); + } else { + const requestRemove = { + ContentId: contentId.value, + userId: userStore.user.id, + }; + adjustReactionCount(reaction); + await client.post("/api/content/reaction/remove", requestRemove); + + hasReacted.value = false; + console.log("Reaction to content removed."); + } + setTimeout(() => { + menuVisible.value = false; + }, 500); +} + +function adjustReactionCount(newReaction) { + if (currentReaction.value === newReaction) { + switch (newReaction) { + case REACTIONS.LIKE: + if (likeCount.value > 0) likeCount.value--; + break; + case REACTIONS.DISLIKE: + if (dislikeCount.value > 0) dislikeCount.value--; + break; + case REACTIONS.LOVE: + if (loveCount.value > 0) loveCount.value--; + break; + case REACTIONS.HAHA: + if (hahaCount.value > 0) hahaCount.value--; + break; + case REACTIONS.WOW: + if (wowCount.value > 0) wowCount.value--; + break; + case REACTIONS.SAD: + if (sadCount.value > 0) sadCount.value--; + break; + case REACTIONS.ANGRY: + if (angryCount.value > 0) angryCount.value--; + break; + } + currentReaction.value = null; + hasReacted.value = false; + } else { + if (currentReaction.value) { + switch (currentReaction.value) { + case REACTIONS.LIKE: + if (likeCount.value > 0) likeCount.value--; + break; + case REACTIONS.DISLIKE: + if (dislikeCount.value > 0) dislikeCount.value--; + break; + case REACTIONS.LOVE: + if (loveCount.value > 0) loveCount.value--; + break; + case REACTIONS.HAHA: + if (hahaCount.value > 0) hahaCount.value--; + break; + case REACTIONS.WOW: + if (wowCount.value > 0) wowCount.value--; + break; + case REACTIONS.SAD: + if (sadCount.value > 0) sadCount.value--; + break; + case REACTIONS.ANGRY: + if (angryCount.value > 0) angryCount.value--; + break; + } + } + + switch (newReaction) { + case REACTIONS.LIKE: + likeCount.value++; + break; + case REACTIONS.DISLIKE: + dislikeCount.value++; + break; + case REACTIONS.LOVE: + loveCount.value++; + break; + case REACTIONS.HAHA: + hahaCount.value++; + break; + case REACTIONS.WOW: + wowCount.value++; + break; + case REACTIONS.SAD: + sadCount.value++; + break; + case REACTIONS.ANGRY: + angryCount.value++; + break; + } + + currentReaction.value = newReaction; + hasReacted.value = true; + } +} + +function initializeReactions() { + const userReaction = props.content.reactions.find((x) => x.userId === userStore.user.id); + if (userReaction) { + currentReaction.value = userReaction.reaction; + hasReacted.value = true; + } else { + currentReaction.value = null; + hasReacted.value = false; + } + + likeCount.value = props.content.reactions.filter((x) => x.reaction === REACTIONS.LIKE).length; + dislikeCount.value = props.content.reactions.filter((x) => x.reaction === REACTIONS.DISLIKE).length; + loveCount.value = props.content.reactions.filter((x) => x.reaction === REACTIONS.LOVE).length; + hahaCount.value = props.content.reactions.filter((x) => x.reaction === REACTIONS.HAHA).length; + wowCount.value = props.content.reactions.filter((x) => x.reaction === REACTIONS.WOW).length; + sadCount.value = props.content.reactions.filter((x) => x.reaction === REACTIONS.SAD).length; + angryCount.value = props.content.reactions.filter((x) => x.reaction === REACTIONS.ANGRY).length; +} + +function showReactions() { + clearTimeout(hideTimeout.value); + menuVisible.value = true; +} + +function hideReactions() { + hideTimeout.value = setTimeout(() => { + menuVisible.value = false; + }, 250); +} + +function onTouchStart() { + touchTimeout.value = setTimeout(() => { + menuVisible.value = true; + }, 250); +} +function onTouchEnd() { + clearTimeout(touchTimeout.value); +} + +function onMouseUp() { + clearTimeout(holdTimeout.value); + hideReactions(); +} + +function onMouseOver() { + if (!isMobileDevice()) { + showReactions(); + } +} + +function onMouseLeave() { + if (!isMobileDevice()) { + hideReactions(); + } +} + +function keepReactionMenuOpen(){ + clearTimeout(hideTimeout.value); +} + +function isMobileDevice() { + return window.innerWidth <= 800; +} + + + + + diff --git a/src/views/contents/contentcards/NContentCard.vue b/src/views/contents/contentcards/NContentCard.vue index 76d5faf..d2a187b 100644 --- a/src/views/contents/contentcards/NContentCard.vue +++ b/src/views/contents/contentcards/NContentCard.vue @@ -64,12 +64,8 @@
- - mdi-thumb-up-outline - - - mdi-thumb-down-outline - + +
- - mdi-thumb-up-outline - - - mdi-thumb-down-outline - + +
- - mdi-thumb-up-outline - - - mdi-thumb-down-outline - + { try { const response = await client.get(`/api/contents/${contentId}`); data.value = response.data; - console.table(data.value) } catch (error) { console.error(`Error fetching content: ${error}`); } diff --git a/src/views/contents/contentfullscreen/FullScreenContentSm.vue b/src/views/contents/contentfullscreen/FullScreenContentSm.vue index 4b1efc7..bd2db26 100644 --- a/src/views/contents/contentfullscreen/FullScreenContentSm.vue +++ b/src/views/contents/contentfullscreen/FullScreenContentSm.vue @@ -53,12 +53,7 @@
- - mdi-thumb-up-outline - - - mdi-thumb-down-outline - + { try { const response = await client.get(`/api/contents/${contentId}`); data.value = response.data; - console.table(data.value) } catch (error) { console.error(`Error fetching content: ${error}`); } diff --git a/src/views/creators/DonationButton.vue b/src/views/creators/DonationButton.vue index 9b66620..361f94f 100644 --- a/src/views/creators/DonationButton.vue +++ b/src/views/creators/DonationButton.vue @@ -76,12 +76,12 @@ import {loadStripe} from '@stripe/stripe-js'; import {computed, onMounted, ref} from 'vue'; const props = defineProps({ - colorBorder: {type: String, required: true}, - colorAccent: {type: String, required: true}, + colorBorder: {required: true}, + colorAccent: {required: true}, creatorId: {type: String, required: true}, creatorName: {type: String, required: true}, - creatorLogo: {type: String, required: true}, - iconColorClass: {type: String, default: 'text-black'} + creatorLogo: {required: true}, + iconColorClass: {default: 'text-black'} }); const colorBorder = computed(() => props.colorBorder) diff --git a/src/views/main/Header.vue b/src/views/main/Header.vue index 62f74d5..dad4fda 100644 --- a/src/views/main/Header.vue +++ b/src/views/main/Header.vue @@ -78,7 +78,7 @@ - {{ selectedLanguage === 'fr' ? 'Fr' : 'Eng' }} + {{ selectedLanguage === 'fr' ? 'Fr' : 'En' }}
@@ -160,7 +160,7 @@ const router = useRouter(); const searchQuery = ref(""); const showSearch = ref(false); -const selectedLanguage = ref(locale.value); +let selectedLanguage = ref(locale.value); function toggleLanguage() { const newLang = selectedLanguage.value === 'fr' ? 'en' : 'fr'; @@ -204,6 +204,18 @@ onBeforeUnmount(() => { document.removeEventListener('click', handleClickOutside); }); +function initializeLocale(){ + const preferredLocale = localStorage.getItem('preferredLocale'); + selectedLanguage = ref(preferredLocale === null ? locale.value : preferredLocale); + locale.value = selectedLanguage.value; +} + +function changeLanguage(lang) { + locale.value = lang; + selectedLanguage.value = lang; + localStorage.setItem('preferredLocale', lang); +} +