Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 268 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@
async function loadUserData() {
if (!currentUser) return;

// Load user's communities for the post creator dropdown
loadUserCommunities();

let { data: profile, error } = await supabase
.from('profiles')
.select('*')
Expand Down Expand Up @@ -283,6 +286,13 @@
}

const content = document.getElementById('postContent').value.trim();
const communityId = document.getElementById('communitySelect').value;

if (!communityId) {
showNotification('Pilih komunitas untuk membagikan zen Anda', 'error');
return;
}

if (!content && !selectedFile) {
showNotification('Mohon tulis zen atau pilih gambar', 'error');
return;
Expand All @@ -301,7 +311,8 @@
{
user_id: currentUser.id,
content: content,
image_url: imageUrl
image_url: imageUrl,
community_id: communityId
}
])
.select()
Expand All @@ -325,7 +336,32 @@
}

async function loadPosts() {
if (!currentUser) {
// Handle non-logged-in user view - maybe show popular posts?
// For now, just show an empty feed.
posts = [];
renderPosts();
return;
}

try {
// First, get the list of communities the user is a member of
const { data: memberships, error: memberError } = await supabase
.from('community_members')
.select('community_id')
.eq('user_id', currentUser.id);

if (memberError) throw memberError;

const communityIds = memberships.map(m => m.community_id);

if (communityIds.length === 0) {
posts = [];
renderPosts(); // Render an empty state or a "join communities" prompt
return;
}

// Then, fetch posts only from those communities
const { data, error } = await supabase
.from('posts')
.select(`
Expand All @@ -334,6 +370,7 @@
likes (*),
comments (count)
`)
.in('community_id', communityIds)
.order('created_at', { ascending: false });

if (error) throw error;
Expand Down Expand Up @@ -591,6 +628,8 @@
// Navigation functions
function showFeed() {
document.getElementById('feedTitle').textContent = 'Beranda';
document.getElementById('postsFeed').classList.remove('hidden');
document.getElementById('communitiesPage').classList.add('hidden');
loadPosts();
}

Expand All @@ -617,6 +656,13 @@
showUserProfile(currentUser.id);
}

function showCommunities() {
document.getElementById('feedTitle').textContent = 'Komunitas';
document.getElementById('postsFeed').classList.add('hidden');
document.getElementById('communitiesPage').classList.remove('hidden');
loadCommunities();
}

function showCreatePost() {
if (!currentUser) {
toggleAuth();
Expand All @@ -625,6 +671,227 @@
document.getElementById('postContent').focus();
}

// Community functions
async function loadCommunities() {
try {
// Fetch all communities and the user's memberships in parallel
const [{ data: communities, error: commError }, { data: memberships, error: memberError }] = await Promise.all([
supabase.from('communities').select('*'),
supabase.from('community_members').select('community_id').eq('user_id', currentUser?.id || '')
]);

if (commError) throw commError;
if (memberError) throw memberError;

const memberSet = new Set(memberships.map(m => m.community_id));
renderCommunities(communities, memberSet);

} catch (error) {
console.error('Error loading communities:', error);
showNotification('Gagal memuat komunitas', 'error');
}
}

function renderCommunities(communities, memberSet) {
const list = document.getElementById('communitiesList');
list.innerHTML = ''; // Clear existing list

if (communities.length === 0) {
list.innerHTML = `<p>Belum ada komunitas. Buat yang pertama!</p>`;
return;
}

communities.forEach(community => {
const isMember = memberSet.has(community.id);
const buttonHtml = isMember
? `<button onclick="leaveCommunity(${community.id})" class="zen-button" style="background: #ccc;">Keluar</button>`
: `<button onclick="joinCommunity(${community.id})" class="zen-button">Gabung</button>`;

const div = document.createElement('div');
div.className = 'zen-card';
div.innerHTML = `
<div class="post-header" style="justify-content: space-between;">
<div style="display: flex; gap: 1rem;">
<img src="${community.avatar_url || createAvatarPlaceholder(community.name)}" alt="${community.name}" class="post-avatar-large">
<div class="post-meta">
<h4 class="post-username">${community.name}</h4>
<p>${community.description}</p>
</div>
</div>
${buttonHtml}
</div>
`;
list.appendChild(div);
});
}

function showCreateCommunityModal() {
document.getElementById('createCommunityModal').classList.add('active');
}

function closeCreateCommunityModal() {
document.getElementById('createCommunityModal').classList.remove('active');
}

async function createCommunity() {
if (!currentUser) {
toggleAuth();
return;
}

const name = document.getElementById('communityName').value.trim();
const description = document.getElementById('communityDescription').value.trim();
const avatarFile = document.getElementById('communityAvatarUpload').files[0];

if (!name) {
showNotification('Nama komunitas tidak boleh kosong', 'error');
return;
}

try {
let avatarUrl = null;
if (avatarFile) {
const fileName = `${currentUser.id}/${Date.now()}-${avatarFile.name}`;
const { data, error } = await supabase.storage
.from('community-avatars')
.upload(fileName, avatarFile);

if (error) throw error;

const { data: { publicUrl } } = supabase.storage
.from('community-avatars')
.getPublicUrl(data.path);
avatarUrl = publicUrl;
}

const { data: community, error } = await supabase
.from('communities')
.insert([
{
name: name,
description: description,
created_by: currentUser.id,
avatar_url: avatarUrl
}
])
.select()
.single();

if (error) throw error;

// Add the creator as a member of the community
const { error: memberError } = await supabase
.from('community_members')
.insert([
{
community_id: community.id,
user_id: currentUser.id,
role: 'admin'
}
]);

if (memberError) throw memberError;

// Reset form and close modal
document.getElementById('createCommunityForm').reset();
document.getElementById('communityAvatarPreview').classList.add('hidden');
closeCreateCommunityModal();

// Refresh the list of communities
await loadCommunities();
showNotification('Komunitas baru berhasil dibuat! 🎉');

} catch (error) {
showNotification('Gagal membuat komunitas: ' + error.message, 'error');
}
}

async function loadUserCommunities() {
if (!currentUser) return;

const select = document.getElementById('communitySelect');
select.innerHTML = '<option value="">Pilih Komunitas...</option>'; // Default option

try {
const { data: memberships, error: memberError } = await supabase
.from('community_members')
.select('community_id')
.eq('user_id', currentUser.id);

if (memberError) throw memberError;

const communityIds = memberships.map(m => m.community_id);

if (communityIds.length === 0) {
select.innerHTML = '<option value="">Anda belum bergabung dengan komunitas manapun</option>';
return;
}

const { data: communities, error: commError } = await supabase
.from('communities')
.select('id, name')
.in('id', communityIds);

if (commError) throw commError;

communities.forEach(community => {
const option = document.createElement('option');
option.value = community.id;
option.textContent = community.name;
select.appendChild(option);
});

} catch (error) {
console.error('Error loading user communities:', error);
select.innerHTML = '<option value="">Gagal memuat komunitas</option>';
}
}

async function joinCommunity(communityId) {
if (!currentUser) {
toggleAuth();
return;
}

try {
const { error } = await supabase
.from('community_members')
.insert({ community_id: communityId, user_id: currentUser.id });

if (error) throw error;

showNotification('Berhasil bergabung dengan komunitas! 🤝');
await loadCommunities(); // Refresh the main community list
await loadUserCommunities(); // Refresh the dropdown list

} catch (error) {
showNotification('Gagal bergabung dengan komunitas: ' + error.message, 'error');
}
}

async function leaveCommunity(communityId) {
if (!currentUser) {
toggleAuth();
return;
}

try {
const { error } = await supabase
.from('community_members')
.delete()
.match({ community_id: communityId, user_id: currentUser.id });

if (error) throw error;

showNotification('Anda telah meninggalkan komunitas. 👋');
await loadCommunities(); // Refresh the main community list
await loadUserCommunities(); // Refresh the dropdown list

} catch (error) {
showNotification('Gagal meninggalkan komunitas: ' + error.message, 'error');
}
}

function showSearch() {
document.getElementById('searchModal').classList.add('active');
document.getElementById('searchInputModal').focus();
Expand Down
37 changes: 37 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ <h1 class="logo-text">ZenCom</h1>
<i class="fas fa-user nav-icon"></i>
<span class="nav-text">Profil</span>
</a>
<a href="#" onclick="showCommunities()" class="nav-item">
<i class="fas fa-users nav-icon"></i>
<span class="nav-text">Komunitas</span>
</a>
<button onclick="showCreatePost()" class="zen-button" style="width: 100%; margin-top: 1rem;">
<i class="fas fa-plus mr-2"></i>Buat Zen
</button>
Expand Down Expand Up @@ -112,6 +116,7 @@ <h2 id="feedTitle" class="feed-title">Beranda</h2>
<img id="currentUserAvatar" src="https://picsum.photos/seed/currentuser/60/60" alt="User" class="post-avatar">
<div class="post-input-container">
<textarea id="postContent" placeholder="Bagikan zen Anda..." class="post-textarea" rows="4"></textarea>
<select id="communitySelect" class="form-input" style="margin-top: 1rem;"></select>
<input type="file" id="imageUpload" class="hidden" accept="image/*" onchange="handleImageSelection(event)">
<img id="imagePreview" src="" alt="Pratinjau Gambar" class="hidden" style="max-width: 100%; border-radius: 0.75rem; margin-top: 1rem;">
<div class="post-actions">
Expand All @@ -138,6 +143,14 @@ <h2 id="feedTitle" class="feed-title">Beranda</h2>
<div id="postsFeed" class="posts-feed">
<!-- Posts will be dynamically inserted here -->
</div>

<!-- Communities Page -->
<div id="communitiesPage" class="hidden">
<div id="communitiesList"></div>
<button onclick="showCreateCommunityModal()" class="zen-button" style="margin-top: 1rem;">
<i class="fas fa-plus mr-2"></i>Buat Komunitas Baru
</button>
</div>
</main>

<!-- Right Sidebar -->
Expand Down Expand Up @@ -270,6 +283,30 @@ <h3 class="detail-title">Detail Zen</h3>
</div>
</div>

<!-- Create Community Modal -->
<div id="createCommunityModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-logo-text">Buat Komunitas Baru</h2>
<button onclick="closeCreateCommunityModal()" class="close-button">
<i class="fas fa-times"></i>
</button>
</div>
<form id="createCommunityForm" onsubmit="event.preventDefault(); createCommunity();">
<input type="text" id="communityName" placeholder="Nama Komunitas" class="form-input">
<textarea id="communityDescription" placeholder="Deskripsi Komunitas" class="form-input" rows="4"></textarea>
<input type="file" id="communityAvatarUpload" class="hidden" accept="image/*">
<button type="button" onclick="document.getElementById('communityAvatarUpload').click()" class="zen-button">
<i class="fas fa-image mr-2"></i>Pilih Avatar
</button>
<img id="communityAvatarPreview" src="" alt="Pratinjau Avatar" class="hidden" style="max-width: 100%; border-radius: 0.75rem; margin-top: 1rem;">
<button type="submit" class="zen-button" style="width: 100%; margin-top: 1rem;">
Buat Komunitas
</button>
</form>
</div>
</div>

<!-- Terms and Conditions Modal -->
<div id="termsModal" class="modal">
<div class="modal-content" style="max-width: 48rem; max-height: 90vh; overflow-y: auto;">
Expand Down
Loading