// ======================================== // Paraguay LLC & SRL — Main JS // ======================================== const API_URL = 'https://n8n.odoo4projects.com/webhook/paraguay/login'; const NEWSLETTER_URL = 'https://n8n.odoo4projects.com/webhook/paraguay/newsletter'; const USER_URL = 'https://n8n.odoo4projects.com/webhook/paraguay/user'; const PROFILE_URL = 'https://n8n.odoo4projects.com/webhook/paraguay/profile'; const WIKI_URL = 'https://n8n.odoo4projects.com/webhook/paraguay/wiki'; const COMMUNITY_URL = 'https://n8n.odoo4projects.com/webhook/paraguay/community'; let currentLang = 'de'; document.addEventListener('DOMContentLoaded', () => { currentLang = document.body.dataset.lang || 'de'; checkSession(); loadCommunityStats(); // Smooth scroll nav links document.querySelectorAll('.nav-link').forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const target = document.querySelector(link.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth' }); } // Close mobile nav document.getElementById('nav-menu').classList.remove('open'); }); }); // Mobile nav toggle const navToggle = document.getElementById('nav-toggle'); const navMenu = document.getElementById('nav-menu'); if (navToggle) { navToggle.addEventListener('click', () => { navMenu.classList.toggle('open'); }); } // Navbar scroll effect window.addEventListener('scroll', () => { const nav = document.getElementById('main-nav'); if (nav) { nav.classList.toggle('scrolled', window.scrollY > 20); } }); // Language toggle document.querySelectorAll('.lang-btn').forEach(btn => { btn.addEventListener('click', () => { const lang = btn.dataset.lang; setLanguage(lang); // Reload content in new language if (isLoggedIn) { if (document.querySelector('.notebook') || document.getElementById('members-list')) loadUsers(); if (document.getElementById('wiki-grid')) loadWiki(); } }); }); // Member search const memberSearch = document.getElementById('member-search'); if (memberSearch) { memberSearch.addEventListener('input', (e) => { filterMembers(e.target.value); }); } // Wiki search const wikiSearch = document.getElementById('wiki-search'); if (wikiSearch) { wikiSearch.addEventListener('input', (e) => { searchWiki(e.target.value); }); } // Close modals on overlay click document.querySelectorAll('.modal-overlay').forEach(overlay => { overlay.addEventListener('click', (e) => { if (e.target === overlay) { overlay.classList.remove('active'); } }); }); // Close modals on Escape document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { document.querySelectorAll('.modal-overlay.active').forEach(m => m.classList.remove('active')); } }); // Login button const loginBtn = document.getElementById('login-btn'); if (loginBtn) { loginBtn.addEventListener('click', () => { openLoginModal(); }); } }); // ======================================== // LANGUAGE // ======================================== function setLanguage(lang) { currentLang = lang; document.body.dataset.lang = lang; document.querySelectorAll('.lang-btn').forEach(b => { b.classList.toggle('active', b.dataset.lang === lang); }); } function isDE() { return currentLang !== 'en'; } // ======================================== // COMMUNITY STATS // ======================================== async function loadCommunityStats() { try { const response = await fetch(COMMUNITY_URL); if (!response.ok) throw new Error('Failed to fetch'); const json = await response.json(); // API returns an array: [{"users": 4, "topics": 27, "posts": 58}] const d = Array.isArray(json) ? json[0] : json; if (d.users !== undefined) { animateCounter('stat-members', d.users); } if (d.posts !== undefined) { animateCounter('stat-posts', d.posts); } if (d.topics !== undefined) { animateCounter('stat-wiki', d.topics); } } catch (error) { console.error('Failed to load community stats:', error); } } function animateCounter(elementId, targetNumber) { const element = document.getElementById(elementId); if (!element) return; let current = 0; const duration = 1500; // ms const steps = 40; const increment = targetNumber / steps; const stepTime = duration / steps; const timer = setInterval(() => { current += increment; if (current >= targetNumber) { element.textContent = targetNumber; clearInterval(timer); } else { element.textContent = Math.floor(current); } }, stepTime); } // ======================================== // AUTH / SESSION // ======================================== let isLoggedIn = false; function isSessionValid() { const sid = getCookie('sessionid'); return sid.length > 0; } function checkSession() { isLoggedIn = isSessionValid(); if (isLoggedIn) { document.body.dataset.loggedIn = 'true'; document.getElementById('login-btn').style.display = 'none'; document.getElementById('logout-btn').style.display = 'inline-flex'; document.getElementById('profile-btn').style.display = 'inline-flex'; document.getElementById('telegram-banner').style.display = 'none'; document.getElementById('main-content').style.display = 'block'; document.getElementById('newsletter-section').style.display = 'block'; loadUsers(); loadWiki(); } else { document.body.dataset.loggedIn = 'false'; document.getElementById('login-btn').style.display = 'inline-flex'; document.getElementById('logout-btn').style.display = 'none'; document.getElementById('profile-btn').style.display = 'none'; document.getElementById('telegram-banner').style.display = 'block'; document.getElementById('main-content').style.display = 'none'; document.getElementById('newsletter-section').style.display = 'none'; } } // ======================================== // LOGIN MODAL // ======================================== function openLoginModal() { document.getElementById('login-modal-overlay').classList.add('active'); // Reset to step 1 document.querySelectorAll('.login-step').forEach(s => s.classList.remove('active')); document.getElementById('login-step-1').classList.add('active'); document.getElementById('telegram-user').value = ''; document.getElementById('verification-code').value = ''; } function closeLoginModal() { document.getElementById('login-modal-overlay').classList.remove('active'); } // ======================================== // PROFILE MODAL // ======================================== function openProfileModal() { const sid = getCookie('sessionid'); if (!sid) { alert('Bitte anmelden.'); return; } fetch(PROFILE_URL + '?sessionid=' + encodeURIComponent(sid)) .then(r => r.json()) .then(user => { document.getElementById('profile-username-display').textContent = user.username || ''; const rank = getRank(user.posts || 0); const badge = document.getElementById('profile-rank-badge'); badge.innerHTML = `${rank.emoji} ${rank.title}`; document.getElementById('profile-company').value = user.company || ''; document.getElementById('profile-email').value = user.email || ''; document.getElementById('profile-homepage').value = user.homepage || ''; document.getElementById('profile-image').value = user.image || ''; document.getElementById('profile-location').value = user.location || ''; document.getElementById('profile-description').value = user.Description || ''; document.getElementById('profile-publish').checked = true; document.getElementById('profile-modal-overlay').classList.add('active'); }) .catch(() => alert('Fehler beim Laden des Profils.')); } function closeProfileModal() { document.getElementById('profile-modal-overlay').classList.remove('active'); } function saveProfile() { const sid = getCookie('sessionid'); fetch(PROFILE_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: document.getElementById('profile-username-display').textContent, company: document.getElementById('profile-company').value.trim(), email: document.getElementById('profile-email').value, homepage: document.getElementById('profile-homepage').value, image: document.getElementById('profile-image').value, location: document.getElementById('profile-location').value, Description: document.getElementById('profile-description').value, sessionid: sid, publish: document.getElementById('profile-publish').checked }) }) .then(r => r.ok ? alert('Profil gespeichert!') : alert('Fehler beim Speichern.')) .catch(() => alert('Fehler bei der Verbindung.')); } // ======================================== // USER DETAIL MODAL // ======================================== function openUserDetailModal(user) { const avatar = document.getElementById('user-detail-avatar'); if (user.image) { avatar.innerHTML = `${user.username}`; } else { avatar.innerHTML = `${(user.username || '?').charAt(0).toUpperCase()}`; } document.getElementById('user-detail-initial').textContent = ''; document.getElementById('user-detail-username').textContent = '@' + (user.username || 'Unknown'); const rank = getRank(user.posts || 0); document.getElementById('user-detail-rank-badge').className = `rank-badge rank-${rank.level}`; document.getElementById('user-detail-rank-badge').textContent = rank.emoji + ' ' + rank.title; document.getElementById('user-detail-company').textContent = user.company || ''; const emailEl = document.getElementById('user-detail-email'); emailEl.innerHTML = user.email ? `${user.email}` : '-'; const hpEl = document.getElementById('user-detail-homepage'); const hp = user.homepage || ''; hpEl.innerHTML = hp ? `${hp}` : '-'; document.getElementById('user-detail-location').textContent = user.location || '-'; document.getElementById('user-detail-description').innerHTML = (user.Description || '-').replace(/\n/g, '
'); document.getElementById('user-detail-modal-overlay').classList.add('active'); } function closeUserDetailModal() { document.getElementById('user-detail-modal-overlay').classList.remove('active'); } // ======================================== // LOGIN FLOW // ======================================== function sendTelegramUser() { const user = document.getElementById('telegram-user').value.trim(); if (!user) { alert('Bitte geben Sie einen Telegram-Nutzernamen ein.'); return; } const btn = event.target; btn.disabled = true; btn.textContent = isDE() ? 'Sende...' : 'Sending...'; fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: user }) }) .then(r => r.json()) .then(data => { if (data.sessionid) { setCookie('sessionid', data.sessionid, 1); document.getElementById('login-step-1').classList.remove('active'); document.getElementById('login-step-3').classList.add('active'); } else if (data.status === 'code send') { document.getElementById('login-step-1').classList.remove('active'); document.getElementById('login-step-2').classList.add('active'); } else { alert(isDE() ? 'Benutzername nicht gefunden. Bitte über Telegram Bot anmelden.' : 'Username not found. Please sign up via Telegram bot.'); } }) .catch(() => { btn.disabled = false; alert(isDE() ? 'Verbindungsfehler' : 'Connection error'); }); } function verifyCode() { const code = document.getElementById('verification-code').value.trim(); if (!code) { alert('Bitte geben Sie den Code ein.'); return; } fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: document.getElementById('telegram-user').value, code: code, sessionid: getCookie('sessionid') }) }) .then(r => r.json()) .then(data => { if (data.sessionid) { setCookie('sessionid', data.sessionid, 1); checkSession(); closeLoginModal(); } else { alert(isDE() ? 'Ungültiger Code' : 'Invalid code'); } }) .catch(() => alert(isDE() ? 'Verbindungsfehler' : 'Connection error')); } function submitLoginData() { const name = document.getElementById('full-name').value.trim(); const llc = document.getElementById('llc-name').value.trim(); if (!name || !llc) { alert(isDE() ? 'Bitte Name und LLC eintragen' : 'Please enter name and LLC'); return; } fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: document.getElementById('telegram-user').value, name: name, llc: llc }) }) .then(r => r.json()) .then(data => { if (data.sessionid) { setCookie('sessionid', data.sessionid, 1); checkSession(); closeLoginModal(); } else { alert(isDE() ? 'Registrierung fehlgeschlagen' : 'Registration failed'); } }) .catch(() => alert(isDE() ? 'Verbindungsfehler' : 'Connection error')); } function logout() { setCookie('sessionid', '', -1); checkSession(); } // ======================================== // NEWSLETTER // ======================================== function subscribeNewsletter() { const email = document.getElementById('newsletter-email').value.trim(); if (!email) { alert(isDE() ? 'Bitte E-Mail eingeben' : 'Please enter email'); return; } fetch(NEWSLETTER_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email }) }) .then(r => { if (r.ok) { document.getElementById('newsletter-form').classList.add('hidden'); document.getElementById('newsletter-success').classList.remove('hidden'); } else { alert(isDE() ? 'Fehler beim Abonnieren' : 'Error subscribing'); } }) .catch(() => alert(isDE() ? 'Verbindungsfehler' : 'Connection error')); } // ======================================== // USERS / MEMBERS // ======================================== async function loadUsers() { try { const response = await fetch(USER_URL); if (!response.ok) throw new Error('Failed to fetch'); const data = await response.json(); const container = document.getElementById('members-list'); if (data.data && Array.isArray(data.data)) { container.innerHTML = ''; container.style.display = 'grid'; data.data.forEach(user => { const card = createMemberCard(user); container.appendChild(card); }); // Update stats will be handled by loadCommunityStats } else { container.innerHTML = '

' + (isDE() ? 'Keine Mitglieder gefunden' : 'No members found') + '

'; } } catch (error) { const container = document.getElementById('members-list'); container.innerHTML = '

' + (isDE() ? 'Fehler beim Laden' : 'Error loading') + '

'; } } function createMemberCard(user) { const card = document.createElement('div'); card.className = 'member-card'; const rank = getRank(user.posts || 0); const avatarContent = user.image ? `${user.username}` : (user.username || '?').charAt(0).toUpperCase(); card.innerHTML = `
${avatarContent}

${user.username || 'N/A'}

${user.company || ''}

${user.location ? `

📍 ${user.location}

` : ''} ${user.posts ? `

${user.posts} ${isDE() ? 'Beiträge' : 'posts'}

` : ''} ${rank.emoji} ${rank.title}
`; card.addEventListener('click', () => openUserDetailModal(user)); return card; } function filterMembers(term) { const cards = document.querySelectorAll('.member-card'); const t = term.toLowerCase(); cards.forEach(card => { const text = card.textContent.toLowerCase(); card.style.display = text.includes(t) ? 'flex' : 'none'; }); } // ======================================== // RANKS // ======================================== function getRank(posts) { if (posts >= 500) return { level: 'legend', title: isDE() ? 'Legende' : 'Legend', emoji: '👑' }; if (posts >= 200) return { level: 'expert', title: isDE() ? 'Experte' : 'Expert', emoji: '🏆' }; if (posts >= 100) return { level: 'veteran', title: isDE() ? 'Veteran' : 'Veteran', emoji: '💎' }; if (posts >= 50) return { level: 'contributor', title: isDE() ? 'Mitwirkender' : 'Contributor', emoji: '⭐' }; if (posts >= 30) return { level: 'member', title: isDE() ? 'Mitglied' : 'Member', emoji: '🌳' }; if (posts >= 5) return { level: 'beginner', title: isDE() ? 'Einsteiger' : 'Beginner', emoji: '🌿' }; return { level: 'rookie', title: isDE() ? 'Anfänger' : 'Rookie', emoji: '🌱' }; } // ======================================== // WIKI // ======================================== let wikiData = []; async function loadWiki() { try { const response = await fetch(WIKI_URL); if (!response.ok) throw new Error('Failed to fetch'); const result = await response.json(); if (result.data && Array.isArray(result.data)) { wikiData = result.data; renderWikiCards(wikiData); // Wiki count will be loaded from community webhook } else { document.getElementById('wiki-grid').innerHTML = '

' + (isDE() ? 'Keine Wiki-Daten' : 'No wiki data') + '

'; } } catch (error) { document.getElementById('wiki-grid').innerHTML = '

' + (isDE() ? 'Fehler beim Laden' : 'Error loading') + '

'; } } function renderWikiCards(data) { const grid = document.getElementById('wiki-grid'); grid.innerHTML = ''; if (data.length === 0) { grid.innerHTML = '

' + (isDE() ? 'Keine Ergebnisse gefunden' : 'No results found') + '

'; return; } // Group by topic const topics = {}; data.forEach(item => { const topicKey = (item.topic_en && currentLang === 'en') ? item.topic_en : (item.topic || 'Unknown'); if (!topics[topicKey]) topics[topicKey] = []; topics[topicKey].push(item); }); const colors = ['blue', 'teal', 'green', 'orange', 'purple', 'pink', 'yellow']; Object.entries(topics).forEach(([topicName, subtopics], idx) => { const card = document.createElement('div'); card.className = 'wiki-card'; card.dataset.color = colors[idx % colors.length]; // Get excerpt from first subtopic const firstSub = subtopics[0]; const excerpt = currentLang === 'en' && firstSub.wiki_en ? firstSub.wiki_en : (firstSub.wiki || ''); const subtopicTitle = currentLang === 'en' && firstSub.subtopic_en ? firstSub.subtopic_en : (firstSub.subtopic || ''); card.innerHTML = `
${escapeHtml(topicName)}
${escapeHtml(excerpt.substring(0, 150))}${excerpt.length > 150 ? '...' : ''}
`; // Open modal on click card.addEventListener('click', () => openWikiModal(topicName, subtopics)); grid.appendChild(card); }); } function openWikiModal(topicName, subtopics) { // Create modal if not exists let modalOverlay = document.getElementById('wiki-modal-overlay'); if (!modalOverlay) { modalOverlay = document.createElement('div'); modalOverlay.id = 'wiki-modal-overlay'; modalOverlay.className = 'modal-overlay'; document.body.appendChild(modalOverlay); } let html = ''; modalOverlay.innerHTML = html; modalOverlay.classList.add('active'); } function closeWikiModal() { const overlay = document.getElementById('wiki-modal-overlay'); if (overlay) overlay.classList.remove('active'); } function searchWiki(term) { if (!term.trim()) { renderWikiCards(wikiData); return; } const t = term.toLowerCase(); const filtered = wikiData.filter(item => { const topic = ((item.topic_en && currentLang === 'en') ? item.topic_en : (item.topic || '')) + ' ' + ((item.subtopic_en && currentLang === 'en') ? item.subtopic_en : (item.subtopic || '')) + ' ' + ((item.wiki_en && currentLang === 'en') ? item.wiki_en : (item.wiki || '')); return topic.toLowerCase().includes(t); }); renderWikiCards(filtered); } // ======================================== // COOKIES // ======================================== function getCookie(name) { const localVal = localStorage.getItem('paraguay_' + name); if (localVal) return localVal; const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) { return parts.pop().split(';').shift().replace(/^"|"$/g, ''); } return ''; } function setCookie(name, value, days) { const expires = new Date(); expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000); document.cookie = name + '=' + encodeURIComponent(value) + ';expires=' + expires.toUTCString() + ';path=/'; localStorage.setItem('paraguay_' + name, value); } // ======================================== // UTILS // ======================================== function escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }