Skip to content
Snippets Groups Projects
Commit 3a1940cf authored by Richard Githuba's avatar Richard Githuba
Browse files

now updating the html using javascript

parent 756960f6
No related branches found
No related tags found
No related merge requests found
......@@ -44,6 +44,7 @@ public class FeedApisController {
}
}
// updating the post
@PutMapping("/{postId}")
public ResponseEntity<Void> updatePost(@PathVariable int postId, @RequestBody FeedImpl feed) {
try {
......@@ -54,6 +55,7 @@ public class FeedApisController {
}
}
// deleting a post
@DeleteMapping("/{postId}")
public ResponseEntity<Void> deletePost(@PathVariable int postId) {
try {
......@@ -64,6 +66,7 @@ public class FeedApisController {
}
}
// liking a post
@PostMapping("/{postId}/like")
public ResponseEntity<Void> likePost(@PathVariable int postId, @RequestParam int userId) {
try {
......@@ -74,6 +77,7 @@ public class FeedApisController {
}
}
// removing a like from post
@DeleteMapping("/{postId}/like")
public ResponseEntity<Void> unlikePost(@PathVariable int postId, @RequestParam int userId) {
try {
......@@ -84,6 +88,7 @@ public class FeedApisController {
}
}
// getting list of likes from a post
@GetMapping("/{postId}/hasLiked")
public ResponseEntity<Boolean> hasUserLikedPost(@PathVariable int postId, @RequestParam int userId) {
try {
......
const API_BASE_URL = '/api/feed';
const MOCK_USER_ID = 1; // just for testing since the user class is yet to be put
const postFeed = document.getElementById('postFeed');
const postTemplate = document.getElementById('post-template');
// maintaining state
let posts = [];
// getting all posts using api
async function fetchPosts() {
try {
const response = await fetch(API_BASE_URL);
if (!response.ok) throw new Error('Failed to fetch posts');
posts = await response.json();
renderPosts();
} catch (error) {
console.error('Error fetching posts:', error);
}
}
// render all posts after getting them
function renderPosts() {
postFeed.innerHTML = ''; // clear any posts
posts.forEach(post => renderPost(post)); // go over each item in post array and call the function renderPost on it
}
// a single post
function renderPost(post) {
const postElement = postTemplate.content.cloneNode(true);
postElement.querySelector('.author').textContent = post.postAuthor;
postElement.querySelector('.author-title').textContent = post.authorTitle;
postElement.querySelector('.post-title').textContent = post.postTitle;
postElement.querySelector('.post-description').textContent = post.postDescription;
const postImage = postElement.querySelector('.post-image img');
if (post.postImageUrl) {
postImage.src = post.postImageUrl;
} else {
postImage.style.display = 'none';
}
// Render tags
const tagsContainer = postElement.querySelector('.post-tags');
if (post.tags && post.tags.length > 0) {
post.tags.forEach(tag => {
const tagSpan = document.createElement('span');
tagSpan.innerHTML = `<i class="bi bi-tag"></i> ${tag}`;
tagsContainer.appendChild(tagSpan);
});
}
// Set likes count
const likeCount = postElement.querySelector('.like-count');
likeCount.textContent = post.likesCount || 0;
// Set timestamp
const timestamp = postElement.querySelector('.timestamp');
timestamp.textContent = new Date(post.postTime).toLocaleDateString();
// Add like button functionality
const likeButton = postElement.querySelector('.like-button');
likeButton.addEventListener('click', () => handleLike(post.postId, likeCount));
// Set data attributes for reference
const postDiv = postElement.querySelector('.post');
postDiv.dataset.postId = post.postId;
postFeed.appendChild(postElement);
}
// Handle like button click
async function handleLike(postId, likeCountElement) {
try {
// Check if user has already liked the post
const checkResponse = await fetch(`${API_BASE_URL}/${postId}/hasLiked?userId=${MOCK_USER_ID}`);
const hasLiked = await checkResponse.json();
const method = hasLiked ? 'DELETE' : 'POST';
const response = await fetch(`${API_BASE_URL}/${postId}/like?userId=${MOCK_USER_ID}`, {
method: method
});
if (!response.ok) throw new Error('Failed to update like');
// Update like count in UI
const currentCount = parseInt(likeCountElement.textContent);
likeCountElement.textContent = hasLiked ? currentCount - 1 : currentCount + 1;
// Toggle like button appearance
const button = likeCountElement.closest('.like-button');
button.classList.toggle('liked', !hasLiked);
} catch (error) {
console.error('Error updating like:', error);
}
}
// Initialize the feed
document.addEventListener('DOMContentLoaded', () => {
fetchPosts();
});
// Optional: Add auto-refresh functionality
// setInterval(fetchPosts, 60000); // Refresh every minute
\ No newline at end of file
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}"
>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Post Feed</title>
<link rel="stylesheet" href="/css/feed/feed.css">
<script defer src="/js/feed/feed.js"></script>
</head>
<section class="feed-container" layout:fragment="content">
<div class="feed-hero">
<h1> Community Posts Feed </h1>
</div>
<!-- &lt;!&ndash; Sort By Filter &ndash;&gt;-->
<!-- <div class="sort-container">-->
<!-- <label for="sortBy">Sort By:</label>-->
<!-- <select id="sortBy">-->
<!-- <option value="date">Date</option>-->
<!-- <option value="chronology">Chronology</option>-->
<!-- </select>-->
<!-- </div>-->
layout:decorate="~{layout/layout}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Post Feed</title>
<link rel="stylesheet" href="/css/feed/feed.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<script defer src="/js/feed/feed.js"></script>
</head>
<section class="feed-container" layout:fragment="content">
<div class="feed-hero">
<h1>Community Posts Feed</h1>
</div>
<!-- Posts Container (Scrollable) -->
<div id="postFeed" class="post-feed">
<!-- Loop through the posts list -->
<div th:each="post : ${posts}" class="post">
<div class="author-details">
<div class="profile-picture">
<!--add the profile picture later -->
</div>
<div class="text-details">
<h5 class="author" th:text="${post.getPost_author()}"></h5>
<p class="author-title" >City Council Member</p>
</div>
<!-- posts will appear here -->
<div id="postFeed" class="post-feed">
<!-- using template since I want to use it in javascript -->
<template id="post-template">
<div class="post">
<div class="author-details">
<div class="profile-picture">
<!--add the profile picture later -->
</div>
<div class="post-details">
<h3 class="post-title" th:text="${post.getPost_title()}"></h3>
<p class="post-description" th:text="${post.getPost_description()}"></p>
<div class="post-image">
<img th:src="${post.getPostImageUrl()}" alt="Post Image">
</div>
<div class="post-tags">
<!-- later this will loop over each tag and create an individual tag for it -->
<span><i class="bi bi-tag"></i> Environment</span>
<span><i class="bi bi-tag"></i> Community</span>
</div>
<div class="text-details">
<h5 class="author"></h5>
<p class="author-title"></p>
</div>
<div class="post-meta">
<div class="post-actions">
<button><i class="bi bi-hand-thumbs-up"></i> 124</button>
<button><i class="bi bi-chat-left"></i> 35</button>
<button><i class="bi bi-share"></i></button>
</div>
<span class="timestamp" th:text="${post.getPost_time()}"></span>
</div>
<div class="post-details">
<h3 class="post-title"></h3>
<p class="post-description"></p>
<div class="post-image">
<img src="" alt="Post Image">
</div>
<div class="post-tags">
<!-- Tags will be dynamically inserted -->
</div>
</div>
<div class="post-meta">
<div class="post-actions">
<button class="like-button">
<i class="bi bi-hand-thumbs-up"></i>
<span class="like-count">0</span>
</button>
<button>
<i class="bi bi-chat-left"></i>
<span>35</span>
</button>
<button>
<i class="bi bi-share"></i>
</button>
</div>
<span class="timestamp"></span>
</div>
</div>
</section>
</html>
</template>
</div>
</section>
</html>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment