const GAS_URL = "AKfycbws8lb2vX3aFWE_WUOMCxifgE-5Ido_OXu8B8C-czfss65VkUHBfEJowNxNQt1nVXqY"; // Masukkan link web app Anda async function loadData() { showLoading(true); try { const response = await fetch(`${GAS_URL}?action=getCafes`); const result = await response.json(); if (result.success) { globalCafes = result.data; renderCafes(); } } catch (err) { showToast("Error memuat data: " + err); } finally { showLoading(false); } } // Gunakan fetch untuk POST data (misal: buat sesi) async function submitSession(sessionObj) { const response = await fetch(`${GAS_URL}?action=createSession`, { method: 'POST', body: JSON.stringify(sessionObj) }); return await response.json(); } function showLoading(show) { document.getElementById('loading-overlay').classList.toggle('hidden', !show); } function loadData() { showLoading(true); google.script.run .withSuccessHandler(response => { if (response.success) { globalCafes = response.data; renderCafes(); renderMapPins(); loadSessions(); } else { showLoading(false); showToast("Database Error: " + response.message); } }) .withFailureHandler(err => { showLoading(false); showToast("Error koneksi: " + err); }) .getCafes(); } function loadSessions() { google.script.run .withSuccessHandler(response => { if (response.success) { globalSessions = response.data; renderSessions(); loadCheckInsHistory(); // Selesaikan dengan memuat riwayat check-in } else { showLoading(false); } }) .getSessions(); } function loadCheckInsHistory() { google.script.run .withSuccessHandler(response => { showLoading(false); if (response.success) { globalCheckIns = response.data; } }) .getCheckIns(); } function renderMapPins() { if (!mapInstance || globalCafes.length === 0) return; mapMarkers.forEach(m => m.setMap(null)); mapMarkers = []; globalCafes.forEach(c => { let pinColor = '#10b981'; if (c.Status === 'Ramai') pinColor = '#f59e0b'; if (c.Status === 'Penuh') pinColor = '#ef4444'; if (c.Koordinat) { const coords = c.Koordinat.split(','); const latVal = parseFloat(coords[0]); const lngVal = parseFloat(coords[1]); const marker = new google.maps.Marker({ position: { lat: latVal, lng: lngVal }, map: mapInstance, title: `${c.Nama} (${c.Status})`, icon: { path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW, fillColor: pinColor, fillOpacity: 1, strokeColor: '#FFFFFF', strokeWeight: 2, scale: 6 } }); const infowindow = new google.maps.InfoWindow({ content: `
${c.Nama}

${c.Alamat}

Status: ${c.Status}
` }); marker.addListener('click', () => { infowindow.open(mapInstance, marker); openCafeDetailModal(c.ID); }); mapMarkers.push(marker); } }); } function openCafeDetailModal(cafeId) { const c = globalCafes.find(item => item.ID === cafeId); if (!c) return; selectedDetailCafeId = cafeId; // Update Detail UI document.getElementById('detail-cafe-name').innerText = c.Nama; document.getElementById('detail-cafe-rating').innerText = `Rating: ⭐ ${c.Rating || '4.5'}`; document.getElementById('detail-cafe-address').innerText = c.Alamat; document.getElementById('detail-cafe-desc').innerText = c.Deskripsi || 'Suasana santai Watampone.'; document.getElementById('detail-cafe-img').src = c.Foto || 'https://images.unsplash.com/photo-1554118811-1e0d58224f24?w=600&auto=format&fit=crop&q=80'; // Kepadatan badge let badge = document.getElementById('detail-cafe-badge-status'); badge.innerText = c.Status.toUpperCase(); badge.className = "text-[10px] text-white font-black uppercase tracking-wider px-2.5 py-0.5 rounded-md "; if (c.Status === 'Sepi') badge.classList.add('bg-emerald-500'); else if (c.Status === 'Ramai') badge.classList.add('bg-amber-500'); else badge.classList.add('bg-rose-500'); // Fasilitas const amenitiesContainer = document.getElementById('detail-cafe-amenities'); amenitiesContainer.innerHTML = ''; if (c.amenities) { c.amenities.forEach(a => { amenitiesContainer.innerHTML += `${a}`; }); } // Google Maps Embed Iframe gratis sesuai lat/lng koordinat if (c.Koordinat) { const coords = c.Koordinat.trim(); document.getElementById('detail-cafe-map-iframe').src = `https://maps.google.com/maps?q=${coords}&z=16&output=embed&iwloc=`; } // Render Checkins History untuk Kafe ini const checkinsContainer = document.getElementById('detail-cafe-checkins-container'); checkinsContainer.innerHTML = ''; const filteredCheckins = globalCheckIns.filter(chk => chk.CafeID === cafeId); if (filteredCheckins.length === 0) { checkinsContainer.innerHTML = '

Belum ada laporan kondisi di kafe ini hari ini.

'; } else { filteredCheckins.forEach(chk => { let chkBadgeColor = 'bg-emerald-100 text-emerald-800 border-emerald-200'; if (chk['Status Dilaporkan'] === 'Ramai') chkBadgeColor = 'bg-amber-100 text-amber-800 border-amber-200'; if (chk['Status Dilaporkan'] === 'Penuh') chkBadgeColor = 'bg-rose-100 text-rose-800 border-rose-200'; checkinsContainer.innerHTML += `
👤 ${chk.User} ${chk.Waktu}
${chk['Status Dilaporkan']}

"${chk['Ulasan/Keadaan'] || '-'}"

`; }); } document.getElementById('cafe-detail-modal').classList.remove('hidden'); lucide.createIcons(); } function closeCafeDetailModal() { document.getElementById('cafe-detail-modal').classList.add('hidden'); } function hostNewSessionFromDetail() { if (selectedDetailCafeId) { closeCafeDetailModal(); switchTab('social'); openCreateSessionModal(); document.getElementById('ses-cafe').value = selectedDetailCafeId; } } function renderCafes() { const list = document.getElementById('cafe-list-container'); const checkinSelect = document.getElementById('checkin-cafe'); const sessionSelect = document.getElementById('ses-cafe'); const searchQuery = document.getElementById('cafe-search').value.toLowerCase(); list.innerHTML = ''; checkinSelect.innerHTML = ''; sessionSelect.innerHTML = ''; globalCafes.forEach(c => { if (!c.Nama.toLowerCase().includes(searchQuery)) return; if (selectedStatusFilter !== 'all' && c.Status !== selectedStatusFilter) return; let statusBadgeColor = 'bg-green-100 text-green-800'; if (c.Status === 'Ramai') statusBadgeColor = 'bg-amber-100 text-amber-800'; if (c.Status === 'Penuh') statusBadgeColor = 'bg-red-100 text-red-800'; list.innerHTML += `
${c.Nama}
${c.Status}

${c.Alamat}

${c.amenities ? c.amenities.map(a => `${a}`).join('') : ''}
Rating: ⭐ ${c.Rating || '4.5'} Lihat Detail
`; checkinSelect.innerHTML += ``; sessionSelect.innerHTML += ``; }); lucide.createIcons(); } function filterByStatus(status) { selectedStatusFilter = status; document.querySelectorAll('.filter-btn').forEach(btn => btn.className = "filter-btn border border-stone-200 text-stone-600 px-4 py-2 rounded-xl text-xs font-semibold"); document.getElementById(`filter-status-${status.toLowerCase()}`).className = "filter-btn active bg-amber-900 text-amber-50 px-4 py-2 rounded-xl text-xs font-semibold"; renderCafes(); } function hostNewSessionDirect(id) { switchTab('social'); openCreateSessionModal(); document.getElementById('ses-cafe').value = id; } function renderSessions() { const container = document.getElementById('session-cards-container'); container.innerHTML = ''; globalSessions.forEach(s => { container.innerHTML += `
${s.Kategori || 'Kerja Fokus'} ${s.Waktu} WITA

${s['Judul Sesi']} di ${s.CafeNama}

${s.Deskripsi}

👤 Host: ${s.Host}
`; }); } function joinActiveSession(sid) { if (!currentUser.isLoggedIn) { showToast("⚠️ Silakan masuk (login) atau mendaftar akun terlebih dahulu untuk bergabung ke sesi!"); switchTab('portal'); toggleAuthTab('login-public'); return; } showLoading(true); google.script.run .withSuccessHandler(response => { showLoading(false); if (response.success) { openChatroom(sid); } else { showToast(response.message); } }) .joinSession(sid, userName); } function openChatroom(sid) { activeSessionId = sid; const s = globalSessions.find(item => item.ID === sid); document.getElementById('chat-header').innerText = s['Judul Sesi']; getChats(); } function getChats() { if (!activeSessionId) return; google.script.run .withSuccessHandler(response => { showLoading(false); if (response.success) { const list = document.getElementById('chat-messages'); list.innerHTML = ''; response.data.forEach(msg => { list.innerHTML += `
${msg.sender}: ${msg.text}
`; }); list.scrollTop = list.scrollHeight; } }) .getChats(activeSessionId); } function sendMessage(e) { e.preventDefault(); if (!currentUser.isLoggedIn) { showToast("⚠️ Silakan masuk (login) atau mendaftar akun terlebih dahulu untuk mengirim pesan!"); switchTab('portal'); toggleAuthTab('login-public'); return; } const txt = document.getElementById('chat-text').value.trim(); if (!txt || !activeSessionId) return; showLoading(true); google.script.run .withSuccessHandler(() => { document.getElementById('chat-text').value = ''; getChats(); }) .sendChatMessage(activeSessionId, userName, txt); } function openCreateSessionModal() { if (!currentUser.isLoggedIn) { showToast("⚠️ Silakan masuk (login) atau mendaftar akun terlebih dahulu untuk membuat sesi!"); switchTab('portal'); toggleAuthTab('login-public'); return; } document.getElementById('create-modal').classList.remove('hidden'); } function closeCreateSessionModal() { document.getElementById('create-modal').classList.add('hidden'); } function submitSession(e) { e.preventDefault(); if (!currentUser.isLoggedIn) { showToast("⚠️ Silakan masuk (login) atau mendaftar akun terlebih dahulu!"); switchTab('portal'); return; } const cafeId = document.getElementById('ses-cafe').value; const cafe = globalCafes.find(c => c.ID === cafeId); if (!cafe) { showToast("Error: Silakan pilih kafe terlebih dahulu!"); return; } const sessionObj = { title: document.getElementById('ses-title').value, cafeId: cafeId, cafeNama: cafe.Nama, time: document.getElementById('ses-time').value, description: document.getElementById('ses-desc').value, host: userName, maxSeats: 4, category: "Kerja Fokus" }; showLoading(true); google.script.run .withSuccessHandler(response => { if (response.success) { showToast("Sesi berhasil dibagikan di Watampone!"); closeCreateSessionModal(); // Reset input fields document.getElementById('ses-title').value = ''; document.getElementById('ses-time').value = ''; document.getElementById('ses-desc').value = ''; loadData(); // Memperbarui daftar sesi & peta secara real-time } else { showLoading(false); showToast("Gagal membuat sesi: " + response.message); } }) .withFailureHandler(err => { showLoading(false); showToast("Error koneksi: " + err); }) .createSession(sessionObj); } function submitCheckIn(e) { e.preventDefault(); if (!currentUser.isLoggedIn) { showToast("⚠️ Silakan masuk (login) atau mendaftar akun terlebih dahulu untuk melaporkan check-in!"); switchTab('portal'); toggleAuthTab('login-public'); return; } const cafeId = document.getElementById('checkin-cafe').value; const statusReported = document.getElementById('checkin-status').value; const wifiStatus = document.getElementById('checkin-wifi').value; const reviewText = document.getElementById('checkin-review').value.trim(); const fullReview = `[Fasilitas/WiFi: ${wifiStatus}] ${reviewText}`; showLoading(true); google.script.run .withSuccessHandler(response => { if (response.success) { showToast("Sukses checkpoint! Poin Anda bertambah +10 dan status kafe terupdate."); // Reset Form document.getElementById('checkin-status').value = "Sepi"; document.getElementById('checkin-wifi').value = "Sangat Baik"; document.getElementById('checkin-review').value = ""; if (currentUser.isLoggedIn && currentUser.role === 'public') { currentUser.points += 10; updateHeaderUI(); } loadData(); // reload map pins, cafe lists, and checkin history } else { showLoading(false); showToast("Gagal: " + response.message); } }) .withFailureHandler(err => { showLoading(false); showToast("Error koneksi: " + err); }) .addCheckIn(userName, cafeId, statusReported, fullReview); } function toggleAuthTab(tabId) { document.getElementById('form-auth-login-public').classList.add('hidden'); document.getElementById('form-auth-register-public').classList.add('hidden'); document.getElementById('form-auth-login-admin').classList.add('hidden'); document.querySelectorAll('#portal-login-section button').forEach(btn => { btn.className = "flex-1 py-2 text-center border-b-2 border-transparent"; }); if (tabId === 'login-public') { document.getElementById('form-auth-login-public').classList.remove('hidden'); document.getElementById('tab-auth-login-public').className = "flex-1 py-2 text-center border-b-2 border-amber-600 text-amber-600"; } else if (tabId === 'register-public') { document.getElementById('form-auth-register-public').classList.remove('hidden'); document.getElementById('tab-auth-register-public').className = "flex-1 py-2 text-center border-b-2 border-amber-600 text-amber-600"; } else if (tabId === 'login-admin') { document.getElementById('form-auth-login-admin').classList.remove('hidden'); document.getElementById('tab-auth-login-admin').className = "flex-1 py-2 text-center border-b-2 border-amber-600 text-amber-600"; } } function handlePublicLogin(e) { e.preventDefault(); const user = document.getElementById('public-login-username').value.trim(); const pass = document.getElementById('public-login-password').value.trim(); showLoading(true); google.script.run .withSuccessHandler(response => { showLoading(false); if (response.success) { currentUser.isLoggedIn = true; currentUser.role = 'public'; currentUser.name = response.name; currentUser.points = response.points; currentUser.badge = response.badge; currentUser.gender = response.gender || '-'; currentUser.pekerjaan = response.pekerjaan || '-'; userName = response.name; showToast(response.message); document.getElementById('public-login-username').value = ''; document.getElementById('public-login-password').value = ''; updatePortalUI(); updateHeaderUI(); } else { showToast(response.message); } }) .loginUser(user, pass); } function handlePublicRegister(e) { e.preventDefault(); const name = document.getElementById('public-reg-name').value.trim(); const user = document.getElementById('public-reg-username').value.trim(); const pass = document.getElementById('public-reg-password').value.trim(); showLoading(true); google.script.run .withSuccessHandler(response => { showLoading(false); if (response.success) { showToast(response.message); document.getElementById('public-reg-name').value = ''; document.getElementById('public-reg-username').value = ''; document.getElementById('public-reg-password').value = ''; toggleAuthTab('login-public'); } else { showToast(response.message); } }) .registerPublicUser(user, pass, name); } function handleUpdateProfile(e) { e.preventDefault(); if (!currentUser.isLoggedIn || currentUser.role !== 'public') return; const gender = document.getElementById('profile-gender-input').value; const job = document.getElementById('profile-job-input').value.trim(); showLoading(true); google.script.run .withSuccessHandler(response => { showLoading(false); if (response.success) { showToast(response.message); currentUser.gender = response.gender; currentUser.pekerjaan = response.pekerjaan; // Refresh Dashboard UI document.getElementById('profile-display-gender').innerText = response.gender; document.getElementById('profile-display-job').innerText = response.pekerjaan; } else { showToast("Gagal update: " + response.message); } }) .updateUserProfile(currentUser.name, gender, job); } function handlePortalLogin(e) { e.preventDefault(); const user = document.getElementById('login-username').value.trim(); const pass = document.getElementById('login-password').value.trim(); showLoading(true); google.script.run .withSuccessHandler(response => { showLoading(false); if (response.success) { currentUser.isLoggedIn = true; currentUser.role = response.role; currentUser.name = response.name; currentUser.cafeId = response.cafeId || null; showToast(response.message); document.getElementById('login-username').value = ''; document.getElementById('login-password').value = ''; updatePortalUI(); } else { showToast(response.message); } }) .loginUser(user, pass); } function handleLogout() { currentUser.isLoggedIn = false; currentUser.role = 'public'; currentUser.name = 'Pengunjung'; currentUser.points = 0; currentUser.badge = 'Tamu'; currentUser.cafeId = null; currentUser.gender = '-'; currentUser.pekerjaan = '-'; userName = "Pemuda Bone"; showToast("Berhasil keluar."); updatePortalUI(); updateHeaderUI(); } function updateHeaderUI() { document.getElementById('header-user-name').innerText = currentUser.name; document.getElementById('header-badge').innerText = currentUser.badge; document.getElementById('header-points').innerText = currentUser.points + " Poin"; } function updatePortalUI() { const loginSec = document.getElementById('portal-login-section'); const publicSec = document.getElementById('portal-public-dashboard'); const superSec = document.getElementById('portal-superadmin-dashboard'); const cafeSec = document.getElementById('portal-cafeadmin-dashboard'); const navLabel = document.getElementById('nav-portal-label'); loginSec.classList.add('hidden'); publicSec.classList.add('hidden'); superSec.classList.add('hidden'); cafeSec.classList.add('hidden'); if (!currentUser.isLoggedIn) { loginSec.classList.remove('hidden'); navLabel.innerText = "Portal Akun & Mitra"; } else if (currentUser.role === 'public') { publicSec.classList.remove('hidden'); // Update dashboard details document.getElementById('public-welcome-name').innerText = currentUser.name; document.getElementById('profile-display-points').innerText = currentUser.points + " Poin"; document.getElementById('profile-display-badge').innerText = currentUser.badge; document.getElementById('profile-display-gender').innerText = currentUser.gender || '-'; document.getElementById('profile-display-job').innerText = currentUser.pekerjaan || '-'; // Prepopulate edit inputs document.getElementById('profile-gender-input').value = currentUser.gender !== '-' ? currentUser.gender : ''; document.getElementById('profile-job-input').value = currentUser.pekerjaan !== '-' ? currentUser.pekerjaan : ''; navLabel.innerText = "👤 Profil Saya"; } else if (currentUser.role === 'superadmin') { superSec.classList.remove('hidden'); navLabel.innerText = "⭐ Admin Utama"; loadSuperAdminData(); } else if (currentUser.role === 'cafeadmin') { cafeSec.classList.remove('hidden'); navLabel.innerText = "🏢 Dashboard Mitra"; loadCafeAdminData(); } lucide.createIcons(); } function loadSuperAdminData() { showLoading(true); google.script.run .withSuccessHandler(response => { showLoading(false); if (response.success) { const tableBody = document.getElementById('superadmin-cafe-rows'); tableBody.innerHTML = ''; response.data.forEach(c => { tableBody.innerHTML += ` ${c.ID} ${c.Nama} ${c.Username || 'N/A'} ${c.Password || 'N/A'} `; }); lucide.createIcons(); } }) .getCafesForSuperAdmin(); } function handleAddNewCafe(e) { e.preventDefault(); const cafeObj = { nama: document.getElementById('new-cafe-name').value.trim(), alamat: document.getElementById('new-cafe-address').value.trim(), fasilitas: document.getElementById('new-cafe-amenities').value.trim(), koordinat: document.getElementById('new-cafe-coords').value.trim(), username: document.getElementById('new-cafe-user').value.trim(), password: document.getElementById('new-cafe-pass').value.trim() }; showLoading(true); google.script.run .withSuccessHandler(response => { if (response.success) { showToast(response.message); document.getElementById('new-cafe-name').value = ''; document.getElementById('new-cafe-address').value = ''; document.getElementById('new-cafe-amenities').value = ''; document.getElementById('new-cafe-coords').value = ''; document.getElementById('new-cafe-user').value = ''; document.getElementById('new-cafe-pass').value = ''; loadData(); loadSuperAdminData(); } else { showLoading(false); showToast("Gagal: " + response.message); } }) .registerNewCafe(cafeObj); } function handleDeleteCafe(id, name) { if (confirm(`Apakah Anda yakin ingin menghapus kafe "${name}"?`)) { showLoading(true); google.script.run .withSuccessHandler(response => { if (response.success) { showToast(response.message); loadData(); loadSuperAdminData(); } else { showLoading(false); showToast("Gagal hapus: " + response.message); } }) .deleteCafeBySuperAdmin(id); } } function loadCafeAdminData() { const cafe = globalCafes.find(c => c.ID === currentUser.cafeId); if (!cafe) return; document.getElementById('cafeadmin-title').innerText = cafe.Nama; document.getElementById('cafeadmin-address').value = cafe.Alamat; document.getElementById('cafeadmin-facilities').value = cafe.amenities.join(','); renderCafeAdminStatusButtons(cafe.Status); } function renderCafeAdminStatusButtons(activeStatus) { const statuses = ['Sepi', 'Ramai', 'Penuh']; const container = document.getElementById('cafeadmin-status-buttons'); container.innerHTML = ''; statuses.forEach(status => { const isActive = status === activeStatus; let colorClass = ""; let badgeColor = ""; let emoji = ""; if (status === 'Sepi') { colorClass = "hover:bg-green-50 border-green-200 text-green-800"; badgeColor = "bg-green-500 text-white"; emoji = "🟢"; } if (status === 'Ramai') { colorClass = "hover:bg-amber-50 border-amber-200 text-amber-800"; badgeColor = "bg-amber-500 text-amber-950"; emoji = "🟡"; } if (status === 'Penuh') { colorClass = "hover:bg-red-50 border-red-200 text-red-800"; badgeColor = "bg-red-500 text-white"; emoji = "🔴"; } if (isActive) { container.innerHTML += ` `; } else { container.innerHTML += ` `; } }); } function handleCafeAdminUpdateStatus(newStatus) { showLoading(true); google.script.run .withSuccessHandler(response => { if (response.success) { showToast(response.message); const cafe = globalCafes.find(c => c.ID === currentUser.cafeId); if (cafe) cafe.Status = newStatus; renderCafes(); renderMapPins(); loadCafeAdminData(); } else { showLoading(false); showToast("Gagal: " + response.message); } }) .updateCafeStatus(currentUser.cafeId, newStatus); } function handleUpdateCafeDetails(e) { e.preventDefault(); const address = document.getElementById('cafeadmin-address').value.trim(); const facilities = document.getElementById('cafeadmin-facilities').value.trim(); showLoading(true); google.script.run .withSuccessHandler(response => { if (response.success) { showToast(response.message); loadData(); } else { showLoading(false); showToast("Gagal: " + response.message); } }) .updateCafeDetailsByAdmin(currentUser.cafeId, address, facilities); } function openDonationModal() { document.getElementById('donation-modal').classList.remove('hidden'); } function closeDonationModal() { document.getElementById('donation-modal').classList.add('hidden'); } function switchTab(id) { document.querySelectorAll('.tab-pane').forEach(el => el.classList.add('hidden')); document.getElementById(`tab-content-${id}`).classList.remove('hidden'); document.querySelectorAll('.nav-tab').forEach(el => el.classList.remove('bg-amber-500', 'text-white')); const activeBtn = document.getElementById(`btn-tab-${id}`); if (activeBtn) activeBtn.classList.add('bg-amber-500', 'text-white'); if (id === 'portal') { updatePortalUI(); } if (id === 'discovery' && mapInstance) { google.maps.event.trigger(mapInstance, 'resize'); } } function showToast(msg) { const toast = document.createElement('div'); toast.className = "fixed top-5 left-1/2 -translate-x-1/2 z-50 bg-stone-950 text-white px-5 py-3 rounded-2xl text-xs font-bold border border-stone-800 shadow animate-in fade-in zoom-in-95 duration-150"; toast.innerText = msg; document.body.appendChild(toast); setTimeout(() => { toast.remove(); }, 3000); }