From a0a4d55469127747076f666522ec068bd67faeb6 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Sun, 12 Oct 2025 22:10:11 +0000
Subject: [PATCH] Menambahkan Fitur Hashtag, Profil Pengguna, dan Simpan Konten
Fitur-fitur berikut telah ditambahkan:
- Hashtag: Pengguna sekarang dapat menambahkan hashtag ke postingan, dan mengklik hashtag akan menampilkan umpan postingan dengan hashtag yang sama.
- Profil Pengguna: Pengguna sekarang dapat melihat halaman profil mereka sendiri dan pengguna lain, yang menampilkan informasi pengguna dan postingan mereka.
- Simpan Konten: Pengguna sekarang dapat menyimpan atau mem-bookmark postingan dan melihatnya di halaman "Disimpan" yang baru.
Perubahan ini juga mencakup perbaikan bug yang diidentifikasi selama tinjauan kode untuk memastikan fungsionalitas yang benar dari fitur hashtag.
---
app.js | 260 +++++++++++++++++-
index.html | 4 +
jules-scratch/verification/verify_features.py | 78 ------
style.css | 102 +++++++
4 files changed, 353 insertions(+), 91 deletions(-)
delete mode 100644 jules-scratch/verification/verify_features.py
diff --git a/app.js b/app.js
index 0afda91..18aba8a 100644
--- a/app.js
+++ b/app.js
@@ -295,7 +295,7 @@
if (!imageUrl) return; // Upload failed
}
- const { data, error } = await supabase
+ const { data: postData, error } = await supabase
.from('posts')
.insert([
{
@@ -304,10 +304,19 @@
image_url: imageUrl
}
])
- .select()
- .single();
+ .select();
if (error) throw error;
+ if (!postData || postData.length === 0) {
+ throw new Error("Failed to create post.");
+ }
+ const post = postData[0];
+
+ // Extract and add hashtags
+ const hashtags = extractHashtags(content);
+ if (hashtags.length > 0) {
+ await addHashtagsToPost(post.id, hashtags);
+ }
// Reset form
document.getElementById('postContent').value = '';
@@ -332,7 +341,8 @@
*,
profiles!posts_user_id_fkey (*),
likes (*),
- comments (count)
+ comments (count),
+ bookmarks (*)
`)
.order('created_at', { ascending: false });
@@ -387,9 +397,87 @@
}
function searchHashtag(hashtag) {
- const searchInput = document.getElementById('searchInputModal');
- searchInput.value = `#${hashtag}`;
- handleSearch();
+ // No need to use the search modal, just load the posts directly
+ loadPostsByHashtag(hashtag);
+ }
+
+ async function loadPostsByHashtag(hashtag) {
+ try {
+ document.getElementById('feedTitle').textContent = `#${hashtag}`;
+
+ const { data, error } = await supabase
+ .from('posts')
+ .select(`
+ *,
+ profiles!posts_user_id_fkey (*),
+ likes (*),
+ comments (count),
+ post_hashtags!inner(hashtags!inner(name))
+ `)
+ .eq('post_hashtags.hashtags.name', hashtag)
+ .order('created_at', { ascending: false });
+
+ if (error) throw error;
+
+ posts = data || [];
+ renderPosts();
+ closeSearch(); // Close search modal after clicking a hashtag
+
+ } catch (error) {
+ console.error('Error loading posts by hashtag:', error);
+ showNotification(`Gagal memuat zen untuk #${hashtag}`, 'error');
+ }
+ }
+
+ function extractHashtags(content) {
+ const regex = /#(\w+)/g;
+ const matches = content.match(regex);
+ if (matches) {
+ // Return unique hashtags without the '#' symbol
+ return [...new Set(matches.map(tag => tag.substring(1)))];
+ }
+ return [];
+ }
+
+ async function addHashtagsToPost(postId, hashtags) {
+ try {
+ // 1. Find existing hashtags or create new ones
+ const { data: existingHashtags, error: findError } = await supabase
+ .from('hashtags')
+ .select('id, name')
+ .in('name', hashtags);
+
+ if (findError) throw findError;
+
+ const existingHashtagNames = existingHashtags.map(h => h.name);
+ const newHashtagNames = hashtags.filter(h => !existingHashtagNames.includes(h));
+
+ let newHashtagIds = [];
+ if (newHashtagNames.length > 0) {
+ const { data: createdHashtags, error: createError } = await supabase
+ .from('hashtags')
+ .insert(newHashtagNames.map(name => ({ name })))
+ .select('id');
+
+ if (createError) throw createError;
+ newHashtagIds = createdHashtags.map(h => h.id);
+ }
+
+ const allHashtagIds = [...existingHashtags.map(h => h.id), ...newHashtagIds];
+
+ // 2. Link hashtags to the post in the join table
+ const links = allHashtagIds.map(hashtagId => ({
+ post_id: postId,
+ hashtag_id: hashtagId
+ }));
+
+ const { error: linkError } = await supabase.from('post_hashtags').insert(links);
+ if (linkError) throw linkError;
+
+ } catch (error) {
+ console.error('Error adding hashtags:', error);
+ // We don't show a notification here to not bother the user for a background task.
+ }
}
function createPostElement(post) {
@@ -399,6 +487,7 @@
const timeAgo = getTimeAgo(new Date(post.created_at));
const isLiked = post.likes && post.likes.some(like => like.user_id === currentUser?.id);
+ const isBookmarked = post.bookmarks && post.bookmarks.some(bookmark => bookmark.user_id === currentUser?.id);
const verifiedBadge = getVerifiedBadge(post.profiles.username);
div.innerHTML = `
@@ -440,9 +529,9 @@
Bagikan Tautan Postingan
-