We'll email you a magic link — no password needed

Not a member? Join the network

🌱 5 Regions · 🤝 500+ Producers · 🔄 8 Active Trades · 📅 10 Events
IntroConnected is a community connection platform. We do not provide business, financial, or legal advice. All trade relationships are between members — verify independently before entering agreements.  |  Terms  |  Privacy  |  © 2026 The Sovereign Economy
+ c.price : 'Free') + '' + '' + '
' + (c.name||c.title||'') + '
' + '
' + (c.description||'').substring(0,120) + (c.description && c.description.length > 120 ? '...' : '') + '
' + '
' + '
' + (c.lessons||'—') + ' lessons · ' + (c.level||'all levels') + '
' + (c.source === 'academy' ? 'Enroll →' : '') + '
' + ''; }).join(''); sec.innerHTML = '
' + '
' + '

Sovereign Academy

' + '

Heritage skills across the entire Sovereign Economy

' + '
' + courses.length + ' courses
' + '
' + filterHtml + '
' + courseHtml + '
' + '
' + '
' + '

Community Requests

' + '
Vote for courses you want to see
' + '
' + '
' + '
' + '
'; loadCourseRequests(); } catch(e) { sec.innerHTML = '
Failed to load courses

' + e.message + '

'; } } function showCourseRequest() { var overlay = document.createElement('div'); overlay.id = 'courseRequestOverlay'; overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center;z-index:9999'; overlay.innerHTML = '
' + '
' + '

Request a Course

' + '' + '
' + '

What heritage skill would you like to learn? We\'ll add it to the Academy if there\'s enough interest.

' + '' + '' + '' + '' + '
'; document.body.appendChild(overlay); } function closeCourseRequest() { var el = document.getElementById('courseRequestOverlay'); if (el) el.remove(); } async function submitCourseRequest() { var title = document.getElementById('crTitle').value.trim(); var details = document.getElementById('crDetails').value.trim(); var category = document.getElementById('crCategory').value; if (!title) return alert('Please enter a course topic'); try { var res = await fetch('/api/ic-course-requests', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-session-token': localStorage.getItem('session_token') || '' }, body: JSON.stringify({ action: 'submit', title: title, description: details, category: category }) }); var data = await res.json(); if (data.error) return alert(data.error); closeCourseRequest(); loadCourses(); } catch(e) { alert('Error: ' + e.message); } } async function loadCourseRequests() { var grid = document.getElementById('requestsGrid'); if (!grid) return; try { var res = await fetch('/api/ic-course-requests', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-session-token': localStorage.getItem('session_token') || '' }, body: JSON.stringify({ action: 'list' }) }); var data = await res.json(); var requests = data.requests || []; var myVotes = data.my_votes || []; if (requests.length === 0) { grid.innerHTML = '
No course requests yet. Be the first to suggest one!
'; return; } grid.innerHTML = requests.map(function(r) { var voted = myVotes.includes(r.id); var statusBadge = r.status === 'approved' ? 'APPROVED' : ''; return '
' + '' + '
' + '
' + r.title + '
' + statusBadge + '
' + (r.description ? '
' + r.description.substring(0,100) + '
' : '') + '
' + r.category + ' · by ' + (r.member_name||'Member') + '
' + '
' + '
'; }).join(''); } catch(e) { grid.innerHTML = '
Failed to load requests
'; } } async function voteCourse(id, btn) { try { var res = await fetch('/api/ic-course-requests', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-session-token': localStorage.getItem('session_token') || '' }, body: JSON.stringify({ action: 'vote', request_id: id }) }); var data = await res.json(); if (data.already_voted) return; if (data.error) return alert(data.error); loadCourseRequests(); } catch(e) { alert('Error: ' + e.message); } } function filterCourses(cat, btn) { document.querySelectorAll('.course-filter').forEach(b => { b.style.background = 'white'; b.style.color = 'var(--charcoal)'; b.classList.remove('active'); }); if (btn) { btn.style.background = 'var(--gold)'; btn.style.color = 'white'; btn.classList.add('active'); } document.querySelectorAll('.course-card').forEach(c => { c.style.display = (!cat || c.dataset.category === cat) ? '' : 'none'; }); } function loadProfile() { const sec = document.getElementById('sec-profile'); const u = currentUser; const initials = getInitials(u.display_name || u.first_name); const avatarHtml = u.avatar_url ? '' : initials; sec.innerHTML = '' + '
' + '
' + '
' + // Avatar with upload '
' + '
' + '
' + avatarHtml + '
' + '
Upload
' + '' + '
' + '
' + esc(u.display_name || u.first_name || '') + '
' + '
' + esc(u.email) + '
' + // Tabs '
' + '' + '' + '' + '' + '
' + // Tab: Basics '
' + '
' + profileField('Display Name', 'prof_name', u.display_name || u.first_name || '') + profileField('Business Name', 'prof_biz', u.business_name || '') + profileField('Location (City, Province)', 'prof_location', [u.location_city, u.location_state].filter(Boolean).join(', ')) + profileField('Website', 'prof_website', u.website_url || '') + profileField('Instagram Handle', 'prof_insta', u.instagram_handle || '') + profileField('Heritage Methods', 'prof_heritage', u.heritage_methods || '') + '
' + // Tab: About & Bio '
' + '
' + '' + '' + '
' + '
' + '
' + '
' + '
' + // Tab: Products & Links '
' + '

Add links to your products, store, or services. These show on your public profile.

' + '' + '' + '
' + // Tab: Gallery '' + // Save '
' + '' + '' + '
'; // Init product links initProductLinks(); initGallery(); } function switchProfileTab(tab) { document.querySelectorAll('.profile-tab').forEach(function(t) { t.classList.remove('active'); }); document.querySelectorAll('.profile-tab-content').forEach(function(t) { t.classList.remove('active'); }); event.target.classList.add('active'); var el = document.getElementById('profTab-' + tab); if (el) el.classList.add('active'); } // Product links management var profileProductLinks = []; function initProductLinks() { try { profileProductLinks = JSON.parse(currentUser.product_links || '[]'); } catch(e) { profileProductLinks = []; } if (profileProductLinks.length === 0) profileProductLinks.push({ name: '', url: '', price: '' }); renderProductLinks(); } function renderProductLinks() { var el = document.getElementById('productLinksContainer'); if (!el) return; el.innerHTML = profileProductLinks.map(function(pl, i) { return ''; }).join(''); } function addProductLink() { profileProductLinks.push({ name: '', url: '', price: '' }); renderProductLinks(); } function removeProductLink(i) { profileProductLinks.splice(i, 1); if (profileProductLinks.length === 0) profileProductLinks.push({ name: '', url: '', price: '' }); renderProductLinks(); } // Gallery management var profileGalleryImages = []; function initGallery() { try { profileGalleryImages = JSON.parse(currentUser.gallery_images || '[]'); } catch(e) { profileGalleryImages = []; } renderGallery(); } function renderGallery() { var el = document.getElementById('galleryGrid'); if (!el) return; var html = profileGalleryImages.map(function(url, i) { return ''; }).join(''); // Add empty slots up to 6 for (var j = profileGalleryImages.length; j < 6; j++) { html += ''; } el.innerHTML = html; } function addGalleryImage() { var input = document.getElementById('galleryUrlInput'); var url = input.value.trim(); if (!url) return; if (profileGalleryImages.length >= 6) return toast('Maximum 6 images'); profileGalleryImages.push(url); input.value = ''; renderGallery(); } function removeGalleryImage(i) { profileGalleryImages.splice(i, 1); renderGallery(); } function previewProfile() { viewMember(currentUser.id); } function uploadAvatar(input) { if (!input.files || !input.files[0]) return; var file = input.files[0]; if (file.size > 2 * 1024 * 1024) return toast('Image must be under 2MB'); var reader = new FileReader(); reader.onload = function(e) { // Store as data URL for now — production would upload to storage currentUser.avatar_url = e.target.result; toast('Avatar updated — click Save to keep'); loadProfile(); }; reader.readAsDataURL(file); } function profileField(label, id, value) { return '
' + '
'; } async function saveProfile() { var bioEl = document.getElementById('prof_bio'); var bizEl = document.getElementById('prof_biz'); var heritageEl = document.getElementById('prof_heritage'); const fields = { display_name: document.getElementById('prof_name').value.trim(), business_name: bizEl ? bizEl.value.trim() : '', website_url: document.getElementById('prof_website').value.trim(), instagram_handle: document.getElementById('prof_insta').value.trim(), products_offered: document.getElementById('prof_offers').value.trim(), materials_needed: document.getElementById('prof_needs').value.trim(), bio: bioEl ? bioEl.value.trim() : '', heritage_methods: heritageEl ? heritageEl.value.trim() : '', avatar_url: currentUser.avatar_url || '', product_links: JSON.stringify(profileProductLinks.filter(function(p) { return p.name || p.url; })), gallery_images: JSON.stringify(profileGalleryImages), }; const loc = document.getElementById('prof_location').value.split(','); if (loc.length >= 2) { fields.location_city = loc[0].trim(); fields.location_state = loc[1].trim(); } else if (loc.length === 1) fields.location_city = loc[0].trim(); const r = await fetch(API + '/ic-capture', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ action:'update_profile', profile_id:currentUser.id, ...fields }) }).then(r => r.json()); if (r.success || r.profile) { Object.assign(currentUser, fields); localStorage.setItem('ic_user', JSON.stringify(currentUser)); toast('Profile saved!'); } else toast(r.error || 'Failed to save'); } // ═══ HELPERS ═══ function getInitials(name) { if (!name) return 'M'; const parts = name.replace(/[^a-zA-Z\s]/g, '').split(/\s+/).filter(Boolean); if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase(); return (parts[0] || 'M').charAt(0).toUpperCase(); } function esc(s) { if (!s) return ''; return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); } function tagColor(tag) { const m = { 'Heritage Tip':'#5A7A5A', 'Best Practice':'#8B6B61', 'Trade':'#C4836A', 'Question':'#6B5044', 'Milestone':'#D4A574' }; return m[tag] || '#C4836A'; } function toast(msg) { const t = document.getElementById('toast'); t.textContent = msg; t.style.display = 'block'; setTimeout(() => t.style.display = 'none', 3000); } // ═══ INIT ═══ (function() { const params = new URLSearchParams(window.location.search); const token = params.get('token'); if (token) { fetch(API + '/ic-auth', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ action:'verify_token', token }) }).then(r => r.json()).then(d => { if (d.success && d.profile) { localStorage.setItem('ic_session', d.session_token); localStorage.setItem('ic_user', JSON.stringify(d.profile)); window.history.replaceState({}, '', '/portal'); loadUser(d.profile); if (d.first_login && d.show_marketplace_prompt) { setTimeout(function() { showMarketplacePrompt(d.profile); }, 2000); } } else showLoginError(d.error || 'Invalid login link'); }).catch(() => showLoginError('Connection error')); return; } const session = localStorage.getItem('ic_session'); if (session) { fetch(API + '/ic-auth', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ action:'verify_session', session_token:session }) }).then(r => r.json()).then(d => { if (d.success && d.profile) { localStorage.setItem('ic_user', JSON.stringify(d.profile)); loadUser(d.profile); } else { localStorage.removeItem('ic_session'); const saved = localStorage.getItem('ic_user'); if (saved) try { loadUser(JSON.parse(saved)); } catch(e) {} } }).catch(() => { const saved = localStorage.getItem('ic_user'); if (saved) try { loadUser(JSON.parse(saved)); } catch(e) {} }); return; } const saved = localStorage.getItem('ic_user'); if (saved) try { loadUser(JSON.parse(saved)); } catch(e) {} document.getElementById('loginEmail').addEventListener('keydown', e => { if (e.key === 'Enter') doLogin(); }); })();