From d0582185d201971d67f5c060f28af1d51a9bc14a Mon Sep 17 00:00:00 2001 From: Dominic Villemure Date: Sat, 24 Aug 2024 18:37:29 -0400 Subject: [PATCH] Added Reaction component to use and fixed some warning from vue --- index.html | 9 +- src/Constants/Reactions.js | 9 + src/views/contents/ContentCard.vue | 9 +- src/views/contents/Reaction.vue | 286 ++++++++++++++++++ .../contents/contentcards/NContentCard.vue | 9 +- .../contents/contentcards/SmContentCard.vue | 9 +- .../contentfullscreen/FullScreenContentMd.vue | 9 +- .../contentfullscreen/FullScreenContentSm.vue | 9 +- src/views/creators/DonationButton.vue | 8 +- 9 files changed, 317 insertions(+), 40 deletions(-) create mode 100644 src/Constants/Reactions.js create mode 100644 src/views/contents/Reaction.vue diff --git a/index.html b/index.html index f5eff92..02beed0 100644 --- a/index.html +++ b/index.html @@ -2,10 +2,11 @@ - - - - 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 aab866e..150b553 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); + +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}`, + }; + await client.post("/api/content/reaction/", request); + + adjustReactionCount(reaction, true); + hasReacted.value = true; + console.log(`Added ${reaction} reaction to content.`); + } else if (reaction !== currentReaction.value) { + adjustReactionCount(currentReaction.value, false); + 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}`, + }; + await client.post("/api/content/reaction/", requestAdd); + + adjustReactionCount(reaction, true); + console.log(`Changed reaction to ${reaction} on content.`); + } else { + const requestRemove = { + ContentId: contentId.value, + userId: userStore.user.id, + }; + await client.post("/api/content/reaction/remove", requestRemove); + + adjustReactionCount(reaction, false); + hasReacted.value = false; + console.log("Reaction to content removed."); + } +} + +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; + }, 1500); // Delay for 0.5 seconds before hiding +} + +function onMouseDown() { + holdTimeout.value = setTimeout(showReactions, 1500); +} + +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 50a8acf..96f396c 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)