Repository navigation
Expand file tree
/
Copy pathposts.js
More file actions
200 lines (174 loc) · 7.88 KB
/
Copy pathposts.js
File metadata and controls
200 lines (174 loc) · 7.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// static/js/posts.js
console.log("posts.js loaded successfully!");
// Load all posts
async function loadPosts(filter = 'all') {
console.log("Loading posts with filter:", filter);
const loading = document.getElementById('loading');
const postsContainer = document.getElementById('posts-container');
const noPosts = document.getElementById('no-posts');
if (loading) loading.style.display = 'block';
if (postsContainer) postsContainer.innerHTML = '';
if (noPosts) noPosts.style.display = 'none';
try {
let url = '/api/posts';
if (filter === 'my') {
url = '/api/posts/my';
}
console.log("Fetching from:", url);
const response = await fetch(url);
const data = await response.json();
console.log("Posts data:", data);
if (loading) loading.style.display = 'none';
if (data.success && data.posts && data.posts.length > 0) {
renderPosts(data.posts);
} else {
if (noPosts) noPosts.style.display = 'block';
}
} catch (error) {
console.error('Error loading posts:', error);
if (loading) loading.style.display = 'none';
if (noPosts) noPosts.style.display = 'block';
showAlert('Error loading posts', 'error');
}
}
// Render posts to the page
function renderPosts(posts) {
const postsContainer = document.getElementById('posts-container');
if (!postsContainer) {
console.error("Posts container not found!");
return;
}
console.log("Rendering", posts.length, "posts");
postsContainer.innerHTML = posts.map(post => `
<div class="post-card animate-fade-in-up">
<div class="post-header">
<div>
<h3 class="post-title">${escapeHtml(post.title)}</h3>
<div class="author-info">
<img src="${post.author_profile_picture || '/static/images/default-avatar.png'}"
alt="${post.author_display_name}" class="author-avatar"
onerror="this.src='/static/images/default-avatar.png'">
<div>
<div class="post-meta">
<strong>${escapeHtml(post.author_display_name)}</strong>
<span>• ${formatDate(post.created_at)}</span>
</div>
${post.updated_at !== post.created_at ?
`<div class="post-meta" style="font-size: 0.8rem; color: #999;">
📝 Edited ${formatDate(post.updated_at)}
</div>` : ''}
</div>
</div>
</div>
</div>
<div class="post-content">
<p class="post-preview">${escapeHtml(post.content.substring(0, 200))}${post.content.length > 200 ? '...' : ''}</p>
</div>
<div class="post-actions">
<a href="/post/${post.id}" class="btn btn-primary">📖 Read More</a>
${window.currentUser && window.currentUser.id === post.author_id ? `
<a href="/edit/${post.id}" class="btn btn-secondary">✏️ Edit</a>
<button onclick="deletePost(${post.id})" class="btn btn-danger">🗑️ Delete</button>
` : ''}
</div>
</div>
`).join('');
}
// Load single post
async function loadSinglePost(postId) {
const postContainer = document.getElementById('post-container');
if (!postContainer) return;
try {
const response = await fetch(`/api/posts/${postId}`);
const data = await response.json();
if (data.success) {
postContainer.innerHTML = `
<article class="single-post glass-card" style="padding: 2rem;">
<header class="post-header">
<h1 class="post-title">${escapeHtml(data.post.title)}</h1>
<div class="author-info">
<img src="${data.post.author_profile_picture || '/static/images/default-avatar.png'}"
alt="${data.post.author_display_name}" class="author-avatar"
onerror="this.src='/static/images/default-avatar.png'">
<div>
<div class="post-meta">
<strong>${escapeHtml(data.post.author_display_name)}</strong>
<span>• ${formatDate(data.post.created_at)}</span>
</div>
${data.post.updated_at !== data.post.created_at ?
`<div class="post-meta" style="font-size: 0.8rem; color: #999;">
📝 Edited ${formatDate(data.post.updated_at)}
</div>` : ''}
</div>
</div>
</header>
<div class="post-content" style="font-size: 1.1rem; line-height: 1.8; margin: 2rem 0;">
<p>${escapeHtml(data.post.content).replace(/\n/g, '<br>')}</p>
</div>
${window.currentUser && window.currentUser.id === data.post.author_id ? `
<div class="post-actions">
<a href="/edit/${data.post.id}" class="btn btn-primary">✏️ Edit Post</a>
<button onclick="deletePost(${data.post.id})" class="btn btn-danger">🗑️ Delete Post</button>
</div>
` : ''}
</article>
`;
} else {
postContainer.innerHTML = `<div class="message error">Post not found</div>`;
}
} catch (error) {
console.error('Error loading post:', error);
postContainer.innerHTML = `<div class="message error">Error loading post</div>`;
}
}
// Delete post
async function deletePost(postId) {
if (!confirm('Are you sure you want to delete this post? This action cannot be undone.')) {
return;
}
try {
const response = await fetch(`/api/posts/${postId}`, {
method: 'DELETE'
});
const data = await response.json();
if (data.success) {
showAlert('Post deleted successfully');
setTimeout(() => {
window.location.href = '/my-posts';
}, 1000);
} else {
showAlert('Error deleting post: ' + data.message, 'error');
}
} catch (error) {
console.error('Error deleting post:', error);
showAlert('Error deleting post', 'error');
}
}
// Filter posts
function filterPosts(type) {
console.log("Filtering posts by:", type);
// Update active filter button
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.classList.remove('active');
});
document.getElementById(`${type}-posts`).classList.add('active');
// Load posts with filter
loadPosts(type);
}
// Utility function to escape HTML
function escapeHtml(unsafe) {
if (!unsafe) return '';
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// Make functions globally available
window.loadPosts = loadPosts;
window.loadSinglePost = loadSinglePost;
window.deletePost = deletePost;
window.filterPosts = filterPosts;
window.escapeHtml = escapeHtml;
console.log("posts.js initialization complete!");