diff --git a/core/plugins/groups/forum/assets/css/like.css b/core/plugins/groups/forum/assets/css/like.css new file mode 100644 index 00000000000..10592a9eadc --- /dev/null +++ b/core/plugins/groups/forum/assets/css/like.css @@ -0,0 +1,29 @@ +/* Should put this in the comments.less file */ +.comment-body a.like { + float: right; + color: gray; + margin-bottom: 10px; +} + +.comment-body a.userLiked { + color: red; +} + +.elementToHover { + display: inline-block; + position: relative; +} + +.elementToPopup { + display: none; + position: absolute; + top: 30px; + left: -80px; + background-color: #555; + color: #fff; + padding: 10px; + border-radius: 5px; + z-index: 1; + width: 151px; + text-align: right; +} \ No newline at end of file diff --git a/core/plugins/groups/forum/assets/js/like.js b/core/plugins/groups/forum/assets/js/like.js new file mode 100644 index 00000000000..01f361b2c72 --- /dev/null +++ b/core/plugins/groups/forum/assets/js/like.js @@ -0,0 +1,121 @@ +console.log("like on GROUP forum"); + +window.addEventListener('DOMContentLoaded', (domEvent) => { + // Find all the "like" button + const likeButton = document.querySelectorAll('.comment-body .like') + if (likeButton.length) { + for(let i = 0; i < likeButton.length;i++) { + likeButton[i].onclick = (e) => { + e.preventDefault(); + + let hasHeart = likeButton[i].classList.contains("userLiked"); + + const threadId = likeButton[i].dataset.thread; + const postId = likeButton[i].dataset.post; + const userId = likeButton[i].dataset.user; + const userName = likeButton[i].dataset.userName; + const likesList = likeButton[i].dataset.likesList; + const likeCount = likeButton[i].dataset.count; + + console.log(threadId, postId, userId, likeCount, userName, likesList); + + const likesListArray = likesList.split("/"); + + if (hasHeart) { + removeLike(threadId, postId, userId).then((res) => { + if (res.ok) { + const newLikeCount = Number(likeCount) - 1; + const newLikesString = likesListArray.filter(e => e !== userName).join('/'); + + // Create ELEMENT + const element = document.createElement('span'); + element.classList.add("elementToPopup"); + element.innerHTML = newLikesString.split("/").join("
"); + + likeButton[i].dataset.count = `${newLikeCount}`; + likeButton[i].innerHTML = (newLikeCount === 0) ? 'Like' : `Like (${newLikeCount})`; + likeButton[i].appendChild(element); + likeButton[i].classList.remove("userLiked"); + likeButton[i].dataset.likesList = newLikesString; + + console.warn(`Like removed for forum thread '${threadId}' of post '${postId}' for user ${userId}`); + } + }) + } else { + addLike(threadId, postId, userId).then((res) => { + if (res.ok) { + const newLikeCount = Number(likeCount) + 1; + const newLikesString = [...likesListArray, userName].join('/'); + + // Create ELEMENT + const element = document.createElement('span'); + element.classList.add("elementToPopup"); + element.innerHTML = newLikesString.split("/").join("
"); + + likeButton[i].dataset.count = `${newLikeCount}`; + likeButton[i].innerHTML = `Like (${newLikeCount})`; + likeButton[i].appendChild(element); + likeButton[i].classList.add("userLiked"); + likeButton[i].dataset.likesList = newLikesString; + + console.log(`Like recorded for forum thread '${threadId}' of post '${postId}' for user ${userId}`); + } + }) + } + + return false; + }; + + // Hover over and mouse leave + likeButton[i].onmouseover = (e) => { + likeButton[i].getElementsByClassName('elementToPopup')[0].style.display = 'block'; + }; + + likeButton[i].onmouseleave = (e) => { + likeButton[i].getElementsByClassName('elementToPopup')[0].style.display = 'none'; + }; + } + } +}); + +const addLike = async (threadId, postId, userId) => { + const postUrl = "/api/forum/likes/addLikeToPost"; + const data = {threadId, postId, userId}; + + try { + let response = await fetch(postUrl, { + method: "POST", headers: {"Content-Type": "application/x-www-form-urlencoded"}, + body: new URLSearchParams(data) // urlencoded form body + }); + + if (!response.ok) { + window.confirm("Server Error with API"); + console.error(`Error Code: ${response.status} / Error Message: ${response.statusText}`); + } + + return response; + } catch (error) { + if (error instanceof SyntaxError) { + console.error('There was a SyntaxError', error); + } else { + console.error('There was an error', error); + } + } +}; + +const removeLike = async (threadId, postId, userId) => { + const deleteAssertionUrl = "/api/forum/likes/deleteLikeFromPost"; + const data = {threadId, postId, userId}; + + const deleteAssertionResp = await fetch(deleteAssertionUrl, { + method: "DELETE", headers: {"Content-Type": "application/x-www-form-urlencoded"}, + body: new URLSearchParams(data) + }) + + if (!deleteAssertionResp.ok) { + window.confirm("Server Error with API"); + console.error(`Error Code: ${response.status} / Error Message: ${response.statusText}`); + } + + return deleteAssertionResp; +} \ No newline at end of file diff --git a/core/plugins/groups/forum/forum.php b/core/plugins/groups/forum/forum.php index 9dfb97f3d89..3642e7c0d84 100644 --- a/core/plugins/groups/forum/forum.php +++ b/core/plugins/groups/forum/forum.php @@ -1246,6 +1246,15 @@ public function threads() $this->_authorize('thread', $thread->get('id')); $this->_authorize('post'); + // Get all the likes of this thread + $db = \App::get('db'); + $queryLikes = "SELECT LIKES.threadId as 'threadId', LIKES.postId as 'postId', + LIKES.userId as 'userId', USERS.name as 'userName', USERS.email as 'userEmail' + FROM jos_forum_posts_like as LIKES, jos_users AS USERS + WHERE LIKES.userId = USERS.id AND LIKES.threadId = " . $thread->get('id'); + $db->setQuery($queryLikes); + $initialLikesList = $db->loadObjectList(); + // If the access is anything beyond public, // make sure they're logged in. if (User::isGuest() && !in_array($thread->get('access'), User::getAuthorisedViewLevels())) @@ -1280,6 +1289,7 @@ public function threads() ->set('section', $section) ->set('category', $category) ->set('thread', $thread) + ->set('likes', $initialLikesList) ->set('filters', $filters) ->setErrors($this->getErrors()) ->loadTemplate(); diff --git a/core/plugins/groups/forum/views/threads/tmpl/_comment.php b/core/plugins/groups/forum/views/threads/tmpl/_comment.php index 73811a2382a..e23930959d2 100644 --- a/core/plugins/groups/forum/views/threads/tmpl/_comment.php +++ b/core/plugins/groups/forum/views/threads/tmpl/_comment.php @@ -7,6 +7,24 @@ defined('_HZEXEC_') or die(); +$this->css('like.css') + ->js('like.js'); + + $likeArray = $this->like; + $countLike = count($likeArray); + $currentUserId = User::get('id'); + + $userLikesComment = false; + $userNameLikesArray = ""; + foreach ( $likeArray as $likeObj ) { + if ( $currentUserId == $likeObj->userId ) { + $userLikesComment = true; + } + + $userNameLikesArray .= "/" . ($likeObj->userName); + } + $userNameLikesArray = substr($userNameLikesArray,1); + $this->comment->set('section', $this->filters['section']); $this->comment->set('category', $this->category->get('alias')); @@ -60,6 +78,25 @@

+ + + " href="#" + data-thread="thread->get('id'); ?>" + data-post="comment->get('id'); ?>" + data-user="" + data-user-name="" + data-likes-list="" + data-count="" + > + 0) ? "Like (" . $countLike . ")" : "Like"; ?> + + ",$nameArray); + ?> + + +
likes)) { + foreach ($this->likes as $like){ + $postId = $like->postId; + if (isset($hash_map[$postId])) { + $hash_map[$postId][] = $like; + } else { + $hash_map[$postId] = array($like); + } + } +} + ?>
    depth++; - foreach ($this->comments as $comment) - { + foreach ($this->comments as $comment) { + $postId = $comment->get('id'); + $likesByPostId = isset($hash_map[$postId]) ? $hash_map[$postId] : []; + $this->view('_comment') ->set('option', $this->option) ->set('group', $this->group) ->set('comment', $comment) + ->set('like', $likesByPostId) ->set('thread', $this->thread) ->set('config', $this->config) ->set('depth', $this->depth) diff --git a/core/plugins/groups/forum/views/threads/tmpl/display.php b/core/plugins/groups/forum/views/threads/tmpl/display.php index fa193178ad0..069128c70c3 100644 --- a/core/plugins/groups/forum/views/threads/tmpl/display.php +++ b/core/plugins/groups/forum/views/threads/tmpl/display.php @@ -70,6 +70,7 @@ ->set('group', $this->group) ->set('comments', $posts) ->set('thread', $this->thread) + ->set('likes', $this->likes) ->set('parent', 0) ->set('config', $this->config) ->set('depth', 0)